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)
}
}
}
}
|