PicoBot/src/gateway/cancel_manager.rs

62 lines
2.1 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::{Mutex, watch};
/// 共享的 Agent 取消注册表。
///
/// 每个正在执行的 Agent 在启动前按 topic_id 注册一个 watch::Sender
/// 外部(如 /stop 命令)通过 cancel_by_topic() 发送取消信号。
/// Agent 循环内部通过 watch::Receiver::has_changed() 检测取消。
///
/// key 使用 topic_idUUID全局唯一精确到话题级别。
#[derive(Clone)]
pub struct CancelManager {
tokens: Arc<Mutex<HashMap<String, watch::Sender<()>>>>,
}
impl CancelManager {
pub fn new() -> Self {
Self {
tokens: Arc::new(Mutex::new(HashMap::new())),
}
}
/// 按 topic_id 注册一个取消通道,返回 receiver 供 Agent 持有。
///
/// 如果同 topic_id 已有注册,旧 sender 被覆盖并 drop
/// 旧 receiver 将收到通道关闭信号。
pub async fn register(&self, topic_id: &str) -> watch::Receiver<()> {
let (tx, rx) = watch::channel(());
self.tokens.lock().await.insert(topic_id.to_string(), tx);
rx
}
/// 按 topic_id 发送取消信号并移除注册条目。
///
/// 返回 `true` 表示找到了对应的任务并发送了取消信号,
/// 返回 `false` 表示没有找到对应的任务(可能已经完成或从未注册)。
pub async fn cancel_by_topic(&self, topic_id: &str) -> bool {
if let Some(tx) = self.tokens.lock().await.remove(topic_id) {
// send 可能失败receiver 已被 drop这不影响语义
let _ = tx.send(());
true
} else {
false
}
}
/// 按 topic_id 正常完成后清理注册条目(幂等)。
///
/// 与 cancel_by_topic() 不同,此方法不发送取消信号,仅移除条目。
/// 如果条目已被 cancel_by_topic() 移除,此调用为 no-op。
pub async fn remove_by_topic(&self, topic_id: &str) {
self.tokens.lock().await.remove(topic_id);
}
}
impl Default for CancelManager {
fn default() -> Self {
Self::new()
}
}