File: cancel.go

package info (click to toggle)
incus 6.0.6-1
  • links: PTS, VCS
  • area: main
  • in suites: forky
  • size: 25,220 kB
  • sloc: sh: 16,810; ansic: 3,122; python: 460; makefile: 341; ruby: 51; sql: 50; lisp: 6
file content (74 lines) | stat: -rw-r--r-- 1,436 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package cmd

import (
	"errors"
	"fmt"
	"os"
	"os/signal"
	"time"

	incus "github.com/lxc/incus/v6/client"
	"github.com/lxc/incus/v6/internal/i18n"
)

// CancelableWait waits for an operation and cancel it on SIGINT/SIGTERM.
func CancelableWait(rawOp any, progress *ProgressRenderer) error {
	var op incus.Operation
	var rop incus.RemoteOperation

	// Check what type of operation we're dealing with
	switch v := rawOp.(type) {
	case incus.Operation:
		op = v
	case incus.RemoteOperation:
		rop = v
	default:
		return errors.New("Invalid operation type for CancelableWait")
	}

	// Signal handling
	chSignal := make(chan os.Signal, 1)
	signal.Notify(chSignal, os.Interrupt)

	// Operation handling
	chOperation := make(chan error)
	go func() {
		if op != nil {
			chOperation <- op.Wait()
		} else {
			chOperation <- rop.Wait()
		}

		close(chOperation)
	}()

	count := 0
	for {
		var err error

		select {
		case err := <-chOperation:
			return err
		case <-chSignal:
			if op != nil {
				err = op.Cancel()
			} else {
				err = rop.CancelTarget()
			}

			if err == nil {
				return errors.New(i18n.G("Remote operation canceled by user"))
			}

			count++

			if count == 3 {
				return errors.New(i18n.G("User signaled us three times, exiting. The remote operation will keep running"))
			}

			if progress != nil {
				progress.Warn(fmt.Sprintf(i18n.G("%v (interrupt two more times to force)"), err), time.Second*5)
			}
		}
	}
}