diff --git a/cmd/ipfs/main.go b/cmd/ipfs/main.go index b5a628fc5dd..6b0cfbdfa88 100644 --- a/cmd/ipfs/main.go +++ b/cmd/ipfs/main.go @@ -5,17 +5,14 @@ import ( "context" "errors" "fmt" - "io" "math/rand" "os" - "os/signal" "path/filepath" "runtime/pprof" "strings" - "sync" - "syscall" "time" + util "github.com/ipfs/go-ipfs/cmd/ipfs/util" oldcmds "github.com/ipfs/go-ipfs/commands" core "github.com/ipfs/go-ipfs/core" corecmds "github.com/ipfs/go-ipfs/core/commands" @@ -106,7 +103,7 @@ func mainRet() int { } defer stopFunc() // to be executed as late as possible - intrh, ctx := setupInterruptHandler(ctx) + intrh, ctx := util.SetupInterruptHandler(ctx) defer intrh.Close() // Handle `ipfs version` or `ipfs help` @@ -355,70 +352,6 @@ func writeHeapProfileToFile() error { return pprof.WriteHeapProfile(mprof) } -// IntrHandler helps set up an interrupt handler that can -// be cleanly shut down through the io.Closer interface. -type IntrHandler struct { - sig chan os.Signal - wg sync.WaitGroup -} - -func NewIntrHandler() *IntrHandler { - ih := &IntrHandler{} - ih.sig = make(chan os.Signal, 1) - return ih -} - -func (ih *IntrHandler) Close() error { - close(ih.sig) - ih.wg.Wait() - return nil -} - -// Handle starts handling the given signals, and will call the handler -// callback function each time a signal is catched. The function is passed -// the number of times the handler has been triggered in total, as -// well as the handler itself, so that the handling logic can use the -// handler's wait group to ensure clean shutdown when Close() is called. -func (ih *IntrHandler) Handle(handler func(count int, ih *IntrHandler), sigs ...os.Signal) { - signal.Notify(ih.sig, sigs...) - ih.wg.Add(1) - go func() { - defer ih.wg.Done() - count := 0 - for range ih.sig { - count++ - handler(count, ih) - } - signal.Stop(ih.sig) - }() -} - -func setupInterruptHandler(ctx context.Context) (io.Closer, context.Context) { - intrh := NewIntrHandler() - ctx, cancelFunc := context.WithCancel(ctx) - - handlerFunc := func(count int, ih *IntrHandler) { - switch count { - case 1: - fmt.Println() // Prevent un-terminated ^C character in terminal - - ih.wg.Add(1) - go func() { - defer ih.wg.Done() - cancelFunc() - }() - - default: - fmt.Println("Received another interrupt before graceful shutdown, terminating...") - os.Exit(-1) - } - } - - intrh.Handle(handlerFunc, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM) - - return intrh, ctx -} - func profileIfEnabled() (func(), error) { // FIXME this is a temporary hack so profiling of asynchronous operations // works as intended. diff --git a/cmd/ipfs/util/signal.go b/cmd/ipfs/util/signal.go new file mode 100644 index 00000000000..1f290c0b7aa --- /dev/null +++ b/cmd/ipfs/util/signal.go @@ -0,0 +1,77 @@ +// +build !wasm + +package util + +import ( + "context" + "fmt" + "io" + "os" + "os/signal" + "sync" + "syscall" +) + +// IntrHandler helps set up an interrupt handler that can +// be cleanly shut down through the io.Closer interface. +type IntrHandler struct { + sig chan os.Signal + wg sync.WaitGroup +} + +func NewIntrHandler() *IntrHandler { + ih := &IntrHandler{} + ih.sig = make(chan os.Signal, 1) + return ih +} + +func (ih *IntrHandler) Close() error { + close(ih.sig) + ih.wg.Wait() + return nil +} + +// Handle starts handling the given signals, and will call the handler +// callback function each time a signal is catched. The function is passed +// the number of times the handler has been triggered in total, as +// well as the handler itself, so that the handling logic can use the +// handler's wait group to ensure clean shutdown when Close() is called. +func (ih *IntrHandler) Handle(handler func(count int, ih *IntrHandler), sigs ...os.Signal) { + signal.Notify(ih.sig, sigs...) + ih.wg.Add(1) + go func() { + defer ih.wg.Done() + count := 0 + for range ih.sig { + count++ + handler(count, ih) + } + signal.Stop(ih.sig) + }() +} + +func SetupInterruptHandler(ctx context.Context) (io.Closer, context.Context) { + intrh := NewIntrHandler() + ctx, cancelFunc := context.WithCancel(ctx) + + handlerFunc := func(count int, ih *IntrHandler) { + switch count { + case 1: + fmt.Println() // Prevent un-terminated ^C character in terminal + + ih.wg.Add(1) + go func() { + defer ih.wg.Done() + cancelFunc() + }() + + default: + fmt.Println("Received another interrupt before graceful shutdown, terminating...") + os.Exit(-1) + } + } + + intrh.Handle(handlerFunc, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM) + + return intrh, ctx +} diff --git a/cmd/ipfs/util/signal_wasm.go b/cmd/ipfs/util/signal_wasm.go new file mode 100644 index 00000000000..12879d594dd --- /dev/null +++ b/cmd/ipfs/util/signal_wasm.go @@ -0,0 +1,18 @@ +package util + +import ( + "context" + "io" +) + +type ctxCloser context.CancelFunc + +func (c ctxCloser) Close() error { + c() + return nil +} + +func SetupInterruptHandler(ctx context.Context) (io.Closer, context.Context) { + ctx, cancel := context.WithCancel(ctx) + return ctxCloser(cancel), ctx +}