package libs import ( "fmt" "log" "sync" "time" ) // ---------- WatchContext:简化版弹窗监控 ---------- // WatchCondition 定义一个监控条件和对应的操作 type WatchCondition struct { // Selectors 匹配条件列表(xpath 或文本),全部匹配时触发 Selectors []map[string]interface{} // Callback 匹配后的回调操作 Callback func(d *Device) error } // WatchContext 提供 UI 弹窗/对话框的自动监控和处理 // 对应 Python 版本的 WatchContext 和 Watcher type WatchContext struct { device *Device // 监控条件列表 conditions []WatchCondition // 当前正在构建的条件 pendingSelectors []map[string]interface{} // 状态管理 mu sync.Mutex stopCh chan struct{} stopped chan struct{} started bool triggerTime time.Time // 检查间隔(秒) interval float64 } // NewWatchContext 创建一个新的监控上下文 // builtin: 是否添加内置的中文弹窗处理规则 func NewWatchContext(device *Device, builtin bool) *WatchContext { wc := &WatchContext{ device: device, conditions: []WatchCondition{}, interval: 2.0, triggerTime: time.Now(), } if builtin { // 添加常见的中文弹窗自动处理规则 wc.WhenText("继续使用").Click() wc.WhenText("同意").Click() wc.WhenText("确定").Click() wc.WhenText("好的").Click() wc.WhenText("继续安装").Click() wc.WhenText("安装").Click() wc.WhenText("Agree").Click() wc.WhenText("ALLOW").Click() } return wc } // WhenText 添加按文本匹配的监控条件(支持链式调用) func (wc *WatchContext) WhenText(text string) *WatchContext { wc.pendingSelectors = append(wc.pendingSelectors, map[string]interface{}{ "text": text, }) return wc } // WhenDescription 添加按描述匹配的监控条件 func (wc *WatchContext) WhenDescription(desc string) *WatchContext { wc.pendingSelectors = append(wc.pendingSelectors, map[string]interface{}{ "description": desc, }) return wc } // WhenResourceID 添加按资源 ID 匹配的监控条件 func (wc *WatchContext) WhenResourceID(id string) *WatchContext { wc.pendingSelectors = append(wc.pendingSelectors, map[string]interface{}{ "resourceId": id, }) return wc } // Click 为当前待处理的条件设置点击操作 func (wc *WatchContext) Click() { if len(wc.pendingSelectors) == 0 { return } selectors := make([]map[string]interface{}, len(wc.pendingSelectors)) copy(selectors, wc.pendingSelectors) wc.pendingSelectors = nil wc.conditions = append(wc.conditions, WatchCondition{ Selectors: selectors, Callback: func(d *Device) error { // 点击最后一个匹配的选择器 lastSel := selectors[len(selectors)-1] obj, err := d.FindElement(lastSel) if err != nil { return err } return obj.Click(0) }, }) } // Press 为当前待处理的条件设置按键操作 func (wc *WatchContext) Press(key string) { if len(wc.pendingSelectors) == 0 { return } selectors := make([]map[string]interface{}, len(wc.pendingSelectors)) copy(selectors, wc.pendingSelectors) wc.pendingSelectors = nil wc.conditions = append(wc.conditions, WatchCondition{ Selectors: selectors, Callback: func(d *Device) error { return d.Press(key) }, }) } // Call 为当前待处理的条件设置自定义回调 func (wc *WatchContext) Call(fn func(d *Device) error) { if len(wc.pendingSelectors) == 0 { return } selectors := make([]map[string]interface{}, len(wc.pendingSelectors)) copy(selectors, wc.pendingSelectors) wc.pendingSelectors = nil wc.conditions = append(wc.conditions, WatchCondition{ Selectors: selectors, Callback: fn, }) } // ---------- 运行控制 ---------- // Start 开始后台监控 func (wc *WatchContext) Start() { wc.mu.Lock() defer wc.mu.Unlock() if wc.started { return } wc.started = true wc.stopCh = make(chan struct{}) wc.stopped = make(chan struct{}) go wc.runForever() } // Stop 停止监控 func (wc *WatchContext) Stop() { wc.mu.Lock() if !wc.started { wc.mu.Unlock() return } close(wc.stopCh) wc.mu.Unlock() // 等待停止 select { case <-wc.stopped: case <-time.After(10 * time.Second): } wc.mu.Lock() wc.started = false wc.mu.Unlock() } // Running 检查是否正在运行 func (wc *WatchContext) Running() bool { wc.mu.Lock() defer wc.mu.Unlock() return wc.started } // runForever 持续监控循环 func (wc *WatchContext) runForever() { defer close(wc.stopped) ticker := time.NewTicker(time.Duration(wc.interval * float64(time.Second))) defer ticker.Stop() for { select { case <-wc.stopCh: return case <-ticker.C: wc.runOnce() } } } // runOnce 执行一次监控检查 func (wc *WatchContext) runOnce() bool { wc.mu.Lock() defer wc.mu.Unlock() for _, cond := range wc.conditions { allMatched := true for _, sel := range cond.Selectors { exists, err := wc.device.Exists(sel) if err != nil || !exists { allMatched = false break } } if allMatched { log.Printf("[Watcher] 条件匹配,执行回调") if err := cond.Callback(wc.device); err != nil { log.Printf("[Watcher] 回调执行失败: %v", err) } wc.triggerTime = time.Now() return true } } return false } // WaitStable 等待直到监控不再触发(稳定状态) // stableSeconds: 稳定时间(秒) // timeout: 超时时间(秒) func (wc *WatchContext) WaitStable(stableSeconds, timeout float64) error { if stableSeconds <= 0 { stableSeconds = 5.0 } if timeout <= 0 { timeout = 60.0 } if !wc.started { wc.Start() } deadline := time.Now().Add(time.Duration(timeout * float64(time.Second))) for time.Now().Before(deadline) { wc.mu.Lock() stable := time.Since(wc.triggerTime).Seconds() > stableSeconds wc.mu.Unlock() if stable { return nil } time.Sleep(200 * time.Millisecond) } return fmt.Errorf("等待稳定超时") } // Reset 停止并移除所有监控条件 func (wc *WatchContext) Reset() { if wc.started { wc.Stop() } wc.conditions = nil } // Remove 移除所有监控条件 func (wc *WatchContext) Remove() { wc.conditions = nil }