agtrace_runtime/client/
monitor.rs

1use crate::runtime::{SessionStreamer, WatchContext, WorkspaceEvent, WorkspaceSupervisor};
2use agtrace_index::Database;
3use anyhow::Result;
4use std::path::PathBuf;
5use std::sync::mpsc::Receiver;
6use std::sync::{Arc, Mutex};
7
8pub struct MonitorBuilder {
9    db: Arc<Mutex<Database>>,
10    provider_configs: Arc<Vec<(String, PathBuf)>>,
11    project_root: Option<PathBuf>,
12}
13
14impl MonitorBuilder {
15    pub fn new(db: Arc<Mutex<Database>>, provider_configs: Arc<Vec<(String, PathBuf)>>) -> Self {
16        Self {
17            db,
18            provider_configs,
19            project_root: None,
20        }
21    }
22
23    pub fn with_project_root(mut self, project_root: PathBuf) -> Self {
24        self.project_root = Some(project_root);
25        self
26    }
27
28    pub fn start_background_scan(self) -> Result<WorkspaceMonitor> {
29        let mut contexts = Vec::new();
30
31        for (provider_name, root) in self.provider_configs.iter() {
32            if let Ok(adapter) = agtrace_providers::create_adapter(provider_name) {
33                contexts.push(WatchContext {
34                    provider_name: provider_name.clone(),
35                    provider: Arc::new(adapter),
36                    root: root.clone(),
37                });
38            }
39        }
40
41        let supervisor = WorkspaceSupervisor::start(contexts, self.db.clone(), self.project_root)?;
42
43        Ok(WorkspaceMonitor {
44            db: self.db,
45            supervisor,
46            provider_configs: self.provider_configs,
47        })
48    }
49}
50
51pub struct WorkspaceMonitor {
52    db: Arc<Mutex<Database>>,
53    supervisor: WorkspaceSupervisor,
54    provider_configs: Arc<Vec<(String, PathBuf)>>,
55}
56
57impl WorkspaceMonitor {
58    pub fn receiver(&self) -> &Receiver<WorkspaceEvent> {
59        self.supervisor.receiver()
60    }
61
62    pub fn next_event(&self) -> Option<WorkspaceEvent> {
63        self.supervisor.receiver().recv().ok()
64    }
65
66    pub fn attach(&self, session_id: &str, provider_name: Option<&str>) -> Result<StreamHandle> {
67        let provider_name = if let Some(name) = provider_name {
68            name.to_string()
69        } else {
70            self.provider_configs
71                .first()
72                .map(|(n, _)| n.clone())
73                .ok_or_else(|| anyhow::anyhow!("No providers available"))?
74        };
75
76        let adapter = agtrace_providers::create_adapter(&provider_name)?;
77
78        let streamer =
79            SessionStreamer::attach(session_id.to_string(), self.db.clone(), Arc::new(adapter))?;
80
81        Ok(StreamHandle { streamer })
82    }
83}
84
85pub struct StreamHandle {
86    streamer: SessionStreamer,
87}
88
89impl StreamHandle {
90    pub(crate) fn new(streamer: SessionStreamer) -> Self {
91        Self { streamer }
92    }
93
94    pub fn receiver(&self) -> &Receiver<WorkspaceEvent> {
95        self.streamer.receiver()
96    }
97}