From 29ca6d9a03b30f0125ae35f4ed41149767b29ee5 Mon Sep 17 00:00:00 2001 From: sam80180 Date: Sun, 5 May 2024 02:16:49 +0800 Subject: [PATCH] fix: can choose to stop listening on Ctrl+C --- cmd/devmode/enable.go | 6 +- cmd/listen.go | 3 +- go.sum | 2 - src/util/log.go | 9 ++- src/util/usbmux.go | 166 ++++++++++++++++++++---------------------- 5 files changed, 93 insertions(+), 93 deletions(-) diff --git a/cmd/devmode/enable.go b/cmd/devmode/enable.go index 3ec425f..be71b27 100644 --- a/cmd/devmode/enable.go +++ b/cmd/devmode/enable.go @@ -60,11 +60,11 @@ var devmodeEnableCmd = &cobra.Command{ } else { logrus.Debugf("Device %s is %s.", device.SerialNumber, device.Status) } - }) + }, true) go (func(cancelFunc *context.CancelFunc) { // timer to cancel listening time.Sleep(time.Duration(intEnableWaitTimeout) * time.Second) logrus.Warnf("Timeout waiting for device %s to reboot.", udid) - if cancelFunc != nil { + if cancelFunc != nil && *cancelFunc != nil { (*cancelFunc)() } wg.Done() @@ -85,7 +85,7 @@ var devmodeEnableCmd = &cobra.Command{ func initDevModeEnableCmd() { devmodeRootCMD.AddCommand(devmodeEnableCmd) - devmodeEnableCmd.Flags().StringVarP(&udid, "udid", "u", "", "device's serialNumber") + devmodeEnableCmd.Flags().StringVarP(&udid, "udid", "u", "", "target specific device by UDID") devmodeEnableCmd.MarkFlagRequired("udid") devmodeEnableCmd.Flags().BoolVar(&bWaitReboot, "wait", false, "wait for reboot to complete") devmodeEnableCmd.Flags().IntVar(&intEnableWaitTimeout, "wait-timeout", 60, "wait timeout in seconds") diff --git a/cmd/listen.go b/cmd/listen.go index c51ac0e..f8383f1 100644 --- a/cmd/listen.go +++ b/cmd/listen.go @@ -50,6 +50,7 @@ var listenCmd = &cobra.Command{ device.SerialNumber = deviceIdMap[device.DeviceID] delete(deviceIdMap, device.DeviceID) } + logrus.Debugf("Device %s is %s", device.SerialNumber, device.Status) if device.Status == "online" { if isDetail { detail, err1 := entity.GetDetail(*gidevice) @@ -62,7 +63,7 @@ var listenCmd = &cobra.Command{ } data := util.ResultData(device) fmt.Println(util.Format(data, isFormat, isDetail)) - }) + }, true) wg.Wait() return nil }, diff --git a/go.sum b/go.sum index b83e39c..36b1a6c 100644 --- a/go.sum +++ b/go.sum @@ -98,8 +98,6 @@ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdko github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= -github.com/SonicCloudOrg/sonic-gidevice v0.7.7 h1:oWNtc5j0ke/VmDVaXYZOR5JAQ8Cr12Fo1UrMq51lVM4= -github.com/SonicCloudOrg/sonic-gidevice v0.7.7/go.mod h1:SEquP5doc1Xa9Y0556SJBpFg7Pex+jXk+y4XQ4i0yxo= github.com/SonicCloudOrg/sonic-gidevice v0.7.8 h1:lF8OEuEBIHnqBNq4SGNETwTbUphOrk4OThDPQKrCT3Y= github.com/SonicCloudOrg/sonic-gidevice v0.7.8/go.mod h1:SEquP5doc1Xa9Y0556SJBpFg7Pex+jXk+y4XQ4i0yxo= github.com/SonicCloudOrg/sonic-ios-webkit-adapter v0.0.7 h1:s4OTcJ0VG4mg3501Ec+aSR6gQ8eTWz26fdgCUjxlmJQ= diff --git a/src/util/log.go b/src/util/log.go index 1f548aa..780fa5d 100644 --- a/src/util/log.go +++ b/src/util/log.go @@ -86,10 +86,17 @@ func (LogrusWriter) Write(data []byte) (int, error) { if strings.HasSuffix(logmessage, "\n") { logmessage = logmessage[:len(logmessage)-1] } - if logmessage == "handle_events: error: libusb: interrupted [code -10]" { // handle this annoying message + if logmessage == "handle_events: error: libusb: interrupted [code -10]" { logrus.Debug(logmessage) } else { fmt.Printf("%s", string(data)) } return len(logmessage), nil } + +func GetGoRoutineLogger(name string) *logrus.Entry { + return logrus.WithFields(logrus.Fields{ + "goroutine": GoRoutineID(), + "goroutineName": name, + }) +} diff --git a/src/util/usbmux.go b/src/util/usbmux.go index accf7ff..1562e9b 100644 --- a/src/util/usbmux.go +++ b/src/util/usbmux.go @@ -10,28 +10,24 @@ import ( "time" giDevice "github.com/SonicCloudOrg/sonic-gidevice" - "github.com/SonicCloudOrg/sonic-gidevice/pkg/libimobiledevice" "github.com/SonicCloudOrg/sonic-ios-bridge/src/entity" "github.com/cenkalti/backoff/v4" "github.com/quintans/toolkit/latch" "github.com/sirupsen/logrus" ) -func UsbmuxListen(cbOnData func(gidevice *giDevice.Device, device *entity.Device, e error, cancelFunc context.CancelFunc)) context.CancelFunc { - usbmuxInput := make(chan giDevice.Device) +type UsbmuxListenCallback func(gidevice *giDevice.Device, device *entity.Device, e error, cancelFunc context.CancelFunc) + +func UsbmuxListen(cbOnData UsbmuxListenCallback, bExitOnCtrlC bool) context.CancelFunc { sigTerm := make(chan os.Signal, 1) signal.Notify(sigTerm, os.Interrupt, os.Kill) var funcCancelListen context.CancelFunc healthCheck := make(chan bool) mylatch := latch.NewCountDownLatch() - mylatch.Add(2) + mylatch.Add(1) go (func() { - goroutineId := GoRoutineID() - logger := logrus.WithFields(logrus.Fields{ - "goroutine": goroutineId, - "goroutineName": "healthCheck", - }) - backoffAlgorithm := backoff.NewConstantBackOff(30 * time.Second) + logger := GetGoRoutineLogger("healthCheck") + backoffAlgorithm := backoff.NewConstantBackOff(10 * time.Second) bIsOk := true backoff.RetryNotify(func() error { if mylatch.Counter() <= 0 { @@ -40,7 +36,7 @@ func UsbmuxListen(cbOnData func(gidevice *giDevice.Device, device *entity.Device logger.Debug("Connecting to usbmux...") usbMuxClient, err := giDevice.NewUsbmux() if err != nil { - return NewErrorPrint(ErrConnect, "usbMux", err) + return err } for { if mylatch.Counter() <= 0 { @@ -66,102 +62,100 @@ func UsbmuxListen(cbOnData func(gidevice *giDevice.Device, device *entity.Device logger.Trace("end health check") })() go (func(funcStop *context.CancelFunc) { - goroutineId := GoRoutineID() - logger := logrus.WithFields(logrus.Fields{ - "goroutine": goroutineId, - "goroutineName": "usbmuxListen", - }) - backoffAlgorithm := backoff.NewConstantBackOff(30 * time.Second) + logger := GetGoRoutineLogger("signalHandler") + for range sigTerm { + logger.Debugf("Stop listening by signal") + if funcStop != nil && *funcStop != nil { + (*funcStop)() + } + if bExitOnCtrlC { + os.Exit(128 + int(syscall.SIGTERM)) // https://itsfoss.com/linux-exit-codes/#code-143-or-sigterm + } + } + })(&funcCancelListen) + go (func(funcStop *context.CancelFunc) { + logger := GetGoRoutineLogger("usbmuxListen") + backoffAlgorithm := backoff.NewConstantBackOff(10 * time.Second) bIsOk := true backoff.RetryNotify(func() error { - if mylatch.Counter() <= 1 { // 'read channel input' go routine is stopped - return nil - } logger.Debug("Connecting to usbmux...") usbMuxClient, err := giDevice.NewUsbmux() if err != nil { - return NewErrorPrint(ErrConnect, "usbMux", err) + return err } + usbmuxInput := make(chan giDevice.Device) shutDownFun, errListen := usbMuxClient.Listen(usbmuxInput) - (*funcStop) = shutDownFun + *funcStop = func() { + logrus.Debugf("Call usbmux listen shutdown function") + mylatch.Done() + if shutDownFun != nil { + shutDownFun() + } + } if errListen != nil { - return NewErrorPrint(ErrSendCommand, string(libimobiledevice.MessageTypeListen), errListen) + return errListen } - logger.Info("Start listening...") - <-healthCheck // empty out the channel - if !bIsOk { // transition from not OK to OK + if !bIsOk { // transition from not OK to OK logger.Trace("Reset usbmux listen backoff algorithm") backoffAlgorithm.Reset() bIsOk = true } - for range healthCheck { - logger.Info("Cancel listening") - (*funcStop) = nil - return fmt.Errorf("usbmux listening is cancelled") + logger.Debugf("Start listening...") + numOnlineDevices := 0 + loopRead: + for { + select { + case bIsUnhealthy := <-healthCheck: + if bIsUnhealthy { + logger.Info("Cancel listening because usbmuxd is unhealthy") + return fmt.Errorf("usbmux listening is cancelled") + } + case d, ok := <-usbmuxInput: + if !ok { // channel is closed + logger.Info("usbmux input channel is closed") + if mylatch.Counter() > 0 { + return fmt.Errorf("usbmux listening stopped unexpectedly") + } + break loopRead + } + if d == nil { + continue + } + deviceByte, _ := json.Marshal(d.Properties()) + var device entity.Device + errDec := json.Unmarshal(deviceByte, &device) + var ptrEntityDevice *entity.Device = &device + if errDec == nil { + device.Status = device.GetStatus() + if device.Status == "online" { + numOnlineDevices += 1 + } else { + numOnlineDevices -= 1 + } + } else { + ptrEntityDevice = nil + } + var _fStop context.CancelFunc + if funcStop != nil { + _fStop = *funcStop + } + if cbOnData != nil { + cbOnData(&d, ptrEntityDevice, errDec, _fStop) + } + logger.Debugf("Number of online devices= %d", numOnlineDevices) + if numOnlineDevices <= 0 { + logger.Info("No devices are online") + } + } } return nil }, backoffAlgorithm, func(err error, d time.Duration) { bIsOk = false logger.Warnf("usbmux listening error: %+v", err) - logger.Debugf("next retry listening in %s", d.String()) + logger.Debugf("Next retry listening in %s", d.String()) }) mylatch.Done() logger.Trace("end usbmux listen") })(&funcCancelListen) - go (func(funcStop *context.CancelFunc) { - goroutineId := GoRoutineID() - logger := logrus.WithFields(logrus.Fields{ - "goroutine": goroutineId, - "goroutineName": "loopRead", - }) - numOnlineDevices := 0 - loopRead: - for { - select { - case d, ok := <-usbmuxInput: - if !ok { // channel is closed - logger.Info("usbmux input channel is closed") - break loopRead - } - if d == nil { - continue - } - deviceByte, _ := json.Marshal(d.Properties()) - var device entity.Device - errDec := json.Unmarshal(deviceByte, &device) - var ptrEntityDevice *entity.Device = &device - if errDec == nil { - device.Status = device.GetStatus() - if device.Status == "online" { - numOnlineDevices += 1 - } else { - numOnlineDevices -= 1 - } - } else { - ptrEntityDevice = nil - } - var _fStop context.CancelFunc - if funcStop != nil { - _fStop = *funcStop - } - if cbOnData != nil { - cbOnData(&d, ptrEntityDevice, errDec, _fStop) - } - logger.Debugf("Number of online devices= %d", numOnlineDevices) - if numOnlineDevices <= 0 { - logger.Info("No devices are online") - } - case <-sigTerm: - logger.Info("Stop listening") - if funcStop != nil { - (*funcStop)() - } - os.Exit(128 + int(syscall.SIGTERM)) // https://itsfoss.com/linux-exit-codes/#code-143-or-sigterm - break loopRead - } - } - mylatch.Done() - logger.Trace("end reading channel input") - })(&funcCancelListen) return funcCancelListen }