mirror of
https://github.com/ipfs/kubo.git
synced 2025-12-19 01:30:17 +08:00
main: move InterruptHandler to util
License: MIT Signed-off-by: Łukasz Magiera <magik6k@gmail.com>
This commit is contained in:
committed by
Steven Allen
parent
fe666657ab
commit
435a3da07f
@@ -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.
|
||||
|
||||
77
cmd/ipfs/util/signal.go
Normal file
77
cmd/ipfs/util/signal.go
Normal file
@@ -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
|
||||
}
|
||||
18
cmd/ipfs/util/signal_wasm.go
Normal file
18
cmd/ipfs/util/signal_wasm.go
Normal file
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user