scanner.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. package main
  2. import (
  3. "log"
  4. "os"
  5. "os/exec"
  6. "sync"
  7. "syscall"
  8. "time"
  9. )
  10. // ScannerType identifies scanner type
  11. type ScannerType string
  12. const (
  13. ScannerBLE ScannerType = "ble"
  14. ScannerWiFi ScannerType = "wifi"
  15. )
  16. // ScannerManager manages BLE and WiFi scanner processes
  17. type ScannerManager struct {
  18. binDir string
  19. debug bool
  20. bleCmd *exec.Cmd
  21. wifiCmd *exec.Cmd
  22. bleRunning bool
  23. wifiRunning bool
  24. mu sync.Mutex
  25. stopChan chan struct{}
  26. }
  27. // NewScannerManager creates a new scanner manager
  28. func NewScannerManager(binDir string, debug bool) *ScannerManager {
  29. return &ScannerManager{
  30. binDir: binDir,
  31. debug: debug,
  32. stopChan: make(chan struct{}),
  33. }
  34. }
  35. // StartBLE starts the BLE scanner process
  36. func (m *ScannerManager) StartBLE(zmqAddr string) error {
  37. m.mu.Lock()
  38. defer m.mu.Unlock()
  39. if m.bleRunning {
  40. return nil
  41. }
  42. binPath := m.binDir + "/ble-scanner"
  43. args := []string{"-zmq", zmqAddr}
  44. if m.debug {
  45. args = append(args, "-debug")
  46. }
  47. cmd := exec.Command(binPath, args...)
  48. cmd.Stdout = os.Stdout
  49. cmd.Stderr = os.Stderr
  50. // Set process group for clean termination
  51. cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
  52. if err := cmd.Start(); err != nil {
  53. return err
  54. }
  55. m.bleCmd = cmd
  56. m.bleRunning = true
  57. log.Printf("[scanner] BLE scanner started (pid=%d)", cmd.Process.Pid)
  58. // Monitor process
  59. go m.monitorProcess(ScannerBLE, cmd)
  60. return nil
  61. }
  62. // StopBLE stops the BLE scanner process
  63. func (m *ScannerManager) StopBLE() {
  64. m.mu.Lock()
  65. defer m.mu.Unlock()
  66. if !m.bleRunning || m.bleCmd == nil {
  67. return
  68. }
  69. log.Printf("[scanner] Stopping BLE scanner...")
  70. // Send SIGTERM to process group
  71. if m.bleCmd.Process != nil {
  72. syscall.Kill(-m.bleCmd.Process.Pid, syscall.SIGTERM)
  73. }
  74. // Wait with timeout
  75. done := make(chan error, 1)
  76. go func() {
  77. done <- m.bleCmd.Wait()
  78. }()
  79. select {
  80. case <-done:
  81. case <-time.After(3 * time.Second):
  82. // Force kill
  83. if m.bleCmd.Process != nil {
  84. syscall.Kill(-m.bleCmd.Process.Pid, syscall.SIGKILL)
  85. }
  86. }
  87. m.bleRunning = false
  88. m.bleCmd = nil
  89. log.Printf("[scanner] BLE scanner stopped")
  90. }
  91. // StartWiFi starts the WiFi scanner process
  92. func (m *ScannerManager) StartWiFi(zmqAddr, iface string) error {
  93. m.mu.Lock()
  94. defer m.mu.Unlock()
  95. if m.wifiRunning {
  96. return nil
  97. }
  98. binPath := m.binDir + "/wifi-scanner"
  99. args := []string{"-zmq", zmqAddr, "-iface", iface}
  100. if m.debug {
  101. args = append(args, "-debug")
  102. }
  103. cmd := exec.Command(binPath, args...)
  104. cmd.Stdout = os.Stdout
  105. cmd.Stderr = os.Stderr
  106. cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
  107. if err := cmd.Start(); err != nil {
  108. return err
  109. }
  110. m.wifiCmd = cmd
  111. m.wifiRunning = true
  112. log.Printf("[scanner] WiFi scanner started (pid=%d)", cmd.Process.Pid)
  113. // Monitor process
  114. go m.monitorProcess(ScannerWiFi, cmd)
  115. return nil
  116. }
  117. // StopWiFi stops the WiFi scanner process
  118. func (m *ScannerManager) StopWiFi() {
  119. m.mu.Lock()
  120. defer m.mu.Unlock()
  121. if !m.wifiRunning || m.wifiCmd == nil {
  122. return
  123. }
  124. log.Printf("[scanner] Stopping WiFi scanner...")
  125. if m.wifiCmd.Process != nil {
  126. syscall.Kill(-m.wifiCmd.Process.Pid, syscall.SIGTERM)
  127. }
  128. done := make(chan error, 1)
  129. go func() {
  130. done <- m.wifiCmd.Wait()
  131. }()
  132. select {
  133. case <-done:
  134. case <-time.After(3 * time.Second):
  135. if m.wifiCmd.Process != nil {
  136. syscall.Kill(-m.wifiCmd.Process.Pid, syscall.SIGKILL)
  137. }
  138. }
  139. m.wifiRunning = false
  140. m.wifiCmd = nil
  141. log.Printf("[scanner] WiFi scanner stopped")
  142. }
  143. // IsBLERunning returns true if BLE scanner is running
  144. func (m *ScannerManager) IsBLERunning() bool {
  145. m.mu.Lock()
  146. defer m.mu.Unlock()
  147. return m.bleRunning
  148. }
  149. // IsWiFiRunning returns true if WiFi scanner is running
  150. func (m *ScannerManager) IsWiFiRunning() bool {
  151. m.mu.Lock()
  152. defer m.mu.Unlock()
  153. return m.wifiRunning
  154. }
  155. // StopAll stops all scanners
  156. func (m *ScannerManager) StopAll() {
  157. close(m.stopChan)
  158. m.StopBLE()
  159. m.StopWiFi()
  160. }
  161. // monitorProcess monitors a scanner process and marks it as stopped when it exits
  162. func (m *ScannerManager) monitorProcess(typ ScannerType, cmd *exec.Cmd) {
  163. err := cmd.Wait()
  164. m.mu.Lock()
  165. defer m.mu.Unlock()
  166. switch typ {
  167. case ScannerBLE:
  168. m.bleRunning = false
  169. m.bleCmd = nil
  170. if err != nil {
  171. log.Printf("[scanner] BLE scanner exited: %v", err)
  172. } else {
  173. log.Printf("[scanner] BLE scanner exited normally")
  174. }
  175. case ScannerWiFi:
  176. m.wifiRunning = false
  177. m.wifiCmd = nil
  178. if err != nil {
  179. log.Printf("[scanner] WiFi scanner exited: %v", err)
  180. } else {
  181. log.Printf("[scanner] WiFi scanner exited normally")
  182. }
  183. }
  184. }