| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228 |
- package main
- import (
- "log"
- "os"
- "os/exec"
- "sync"
- "syscall"
- "time"
- )
- // ScannerType identifies scanner type
- type ScannerType string
- const (
- ScannerBLE ScannerType = "ble"
- ScannerWiFi ScannerType = "wifi"
- )
- // ScannerManager manages BLE and WiFi scanner processes
- type ScannerManager struct {
- binDir string
- debug bool
- bleCmd *exec.Cmd
- wifiCmd *exec.Cmd
- bleRunning bool
- wifiRunning bool
- mu sync.Mutex
- stopChan chan struct{}
- }
- // NewScannerManager creates a new scanner manager
- func NewScannerManager(binDir string, debug bool) *ScannerManager {
- return &ScannerManager{
- binDir: binDir,
- debug: debug,
- stopChan: make(chan struct{}),
- }
- }
- // StartBLE starts the BLE scanner process
- func (m *ScannerManager) StartBLE(zmqAddr string) error {
- m.mu.Lock()
- defer m.mu.Unlock()
- if m.bleRunning {
- return nil
- }
- binPath := m.binDir + "/ble-scanner"
- args := []string{"-zmq", zmqAddr}
- if m.debug {
- args = append(args, "-debug")
- }
- cmd := exec.Command(binPath, args...)
- cmd.Stdout = os.Stdout
- cmd.Stderr = os.Stderr
- // Set process group for clean termination
- cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
- if err := cmd.Start(); err != nil {
- return err
- }
- m.bleCmd = cmd
- m.bleRunning = true
- log.Printf("[scanner] BLE scanner started (pid=%d)", cmd.Process.Pid)
- // Monitor process
- go m.monitorProcess(ScannerBLE, cmd)
- return nil
- }
- // StopBLE stops the BLE scanner process
- func (m *ScannerManager) StopBLE() {
- m.mu.Lock()
- defer m.mu.Unlock()
- if !m.bleRunning || m.bleCmd == nil {
- return
- }
- log.Printf("[scanner] Stopping BLE scanner...")
- // Send SIGTERM to process group
- if m.bleCmd.Process != nil {
- syscall.Kill(-m.bleCmd.Process.Pid, syscall.SIGTERM)
- }
- // Wait with timeout
- done := make(chan error, 1)
- go func() {
- done <- m.bleCmd.Wait()
- }()
- select {
- case <-done:
- case <-time.After(3 * time.Second):
- // Force kill
- if m.bleCmd.Process != nil {
- syscall.Kill(-m.bleCmd.Process.Pid, syscall.SIGKILL)
- }
- }
- m.bleRunning = false
- m.bleCmd = nil
- log.Printf("[scanner] BLE scanner stopped")
- }
- // StartWiFi starts the WiFi scanner process
- func (m *ScannerManager) StartWiFi(zmqAddr, iface string) error {
- m.mu.Lock()
- defer m.mu.Unlock()
- if m.wifiRunning {
- return nil
- }
- binPath := m.binDir + "/wifi-scanner"
- args := []string{"-zmq", zmqAddr, "-iface", iface}
- if m.debug {
- args = append(args, "-debug")
- }
- cmd := exec.Command(binPath, args...)
- cmd.Stdout = os.Stdout
- cmd.Stderr = os.Stderr
- cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
- if err := cmd.Start(); err != nil {
- return err
- }
- m.wifiCmd = cmd
- m.wifiRunning = true
- log.Printf("[scanner] WiFi scanner started (pid=%d)", cmd.Process.Pid)
- // Monitor process
- go m.monitorProcess(ScannerWiFi, cmd)
- return nil
- }
- // StopWiFi stops the WiFi scanner process
- func (m *ScannerManager) StopWiFi() {
- m.mu.Lock()
- defer m.mu.Unlock()
- if !m.wifiRunning || m.wifiCmd == nil {
- return
- }
- log.Printf("[scanner] Stopping WiFi scanner...")
- if m.wifiCmd.Process != nil {
- syscall.Kill(-m.wifiCmd.Process.Pid, syscall.SIGTERM)
- }
- done := make(chan error, 1)
- go func() {
- done <- m.wifiCmd.Wait()
- }()
- select {
- case <-done:
- case <-time.After(3 * time.Second):
- if m.wifiCmd.Process != nil {
- syscall.Kill(-m.wifiCmd.Process.Pid, syscall.SIGKILL)
- }
- }
- m.wifiRunning = false
- m.wifiCmd = nil
- log.Printf("[scanner] WiFi scanner stopped")
- }
- // IsBLERunning returns true if BLE scanner is running
- func (m *ScannerManager) IsBLERunning() bool {
- m.mu.Lock()
- defer m.mu.Unlock()
- return m.bleRunning
- }
- // IsWiFiRunning returns true if WiFi scanner is running
- func (m *ScannerManager) IsWiFiRunning() bool {
- m.mu.Lock()
- defer m.mu.Unlock()
- return m.wifiRunning
- }
- // StopAll stops all scanners
- func (m *ScannerManager) StopAll() {
- close(m.stopChan)
- m.StopBLE()
- m.StopWiFi()
- }
- // monitorProcess monitors a scanner process and marks it as stopped when it exits
- func (m *ScannerManager) monitorProcess(typ ScannerType, cmd *exec.Cmd) {
- err := cmd.Wait()
- m.mu.Lock()
- defer m.mu.Unlock()
- switch typ {
- case ScannerBLE:
- m.bleRunning = false
- m.bleCmd = nil
- if err != nil {
- log.Printf("[scanner] BLE scanner exited: %v", err)
- } else {
- log.Printf("[scanner] BLE scanner exited normally")
- }
- case ScannerWiFi:
- m.wifiRunning = false
- m.wifiCmd = nil
- if err != nil {
- log.Printf("[scanner] WiFi scanner exited: %v", err)
- } else {
- log.Printf("[scanner] WiFi scanner exited normally")
- }
- }
- }
|