github.com/Mrs4s/go-cqhttp@v1.2.0/global/signal_windows.go (about) 1 //go:build windows 2 // +build windows 3 4 package global 5 6 import ( 7 "errors" 8 "fmt" 9 "net" 10 "os" 11 "os/signal" 12 "strings" 13 "sync" 14 "syscall" 15 "time" 16 17 "github.com/Microsoft/go-winio" 18 log "github.com/sirupsen/logrus" 19 ) 20 21 var validTasks = map[string]func(){ 22 "dumpstack": dumpStack, 23 } 24 25 // SetupMainSignalHandler is for main to use at last 26 func SetupMainSignalHandler() <-chan struct{} { 27 mainOnce.Do(func() { 28 // for stack trace collecting on windows 29 pipeName := fmt.Sprintf(`\\.\pipe\go-cqhttp-%d`, os.Getpid()) 30 pipe, err := winio.ListenPipe(pipeName, &winio.PipeConfig{}) 31 if err != nil { 32 log.Errorf("创建 named pipe 失败. 将无法使用 dumpstack 功能: %v", err) 33 } else { 34 maxTaskLen := 0 35 for t := range validTasks { 36 if l := len(t); l > maxTaskLen { 37 maxTaskLen = l 38 } 39 } 40 go func() { 41 for { 42 c, err := pipe.Accept() 43 if err != nil { 44 if errors.Is(err, net.ErrClosed) || strings.Contains(err.Error(), "closed") { 45 return 46 } 47 log.Errorf("accept named pipe 失败: %v", err) 48 continue 49 } 50 go func() { 51 defer c.Close() 52 _ = c.SetReadDeadline(time.Now().Add(5 * time.Second)) 53 buf := make([]byte, maxTaskLen) 54 n, err := c.Read(buf) 55 if err != nil { 56 log.Errorf("读取 named pipe 失败: %v", err) 57 return 58 } 59 cmd := string(buf[:n]) 60 if task, ok := validTasks[cmd]; ok { 61 task() 62 return 63 } 64 log.Warnf("named pipe 读取到未知指令: %q", cmd) 65 }() 66 } 67 }() 68 } 69 // setup the main stop channel 70 mainStopCh = make(chan struct{}) 71 mc := make(chan os.Signal, 2) 72 closeOnce := sync.Once{} 73 signal.Notify(mc, os.Interrupt, syscall.SIGTERM) 74 go func() { 75 for { 76 switch <-mc { 77 case os.Interrupt, syscall.SIGTERM: 78 closeOnce.Do(func() { 79 close(mainStopCh) 80 if pipe != nil { 81 _ = pipe.Close() 82 } 83 }) 84 } 85 } 86 }() 87 }) 88 return mainStopCh 89 }