git_iris/companion/
mod.rs1mod branch_memory;
7mod session;
8mod storage;
9mod watcher;
10
11pub use branch_memory::{BranchMemory, FileFocus};
12pub use session::{FileActivity, SessionState};
13pub use storage::CompanionStorage;
14pub use watcher::{CompanionEvent, FileWatcherService};
15
16use anyhow::Result;
17use std::path::PathBuf;
18use std::sync::Arc;
19use tokio::sync::mpsc;
20
21pub struct CompanionService {
23 repo_path: PathBuf,
25 session: Arc<parking_lot::RwLock<SessionState>>,
27 storage: CompanionStorage,
29 watcher: Option<FileWatcherService>,
31 event_rx: mpsc::UnboundedReceiver<CompanionEvent>,
33 _event_tx: mpsc::UnboundedSender<CompanionEvent>,
35}
36
37impl CompanionService {
38 pub fn new(repo_path: PathBuf, branch: &str) -> Result<Self> {
40 let (event_tx, event_rx) = mpsc::unbounded_channel();
41
42 let storage = CompanionStorage::new(&repo_path)?;
44
45 let session = storage
47 .load_session()?
48 .filter(|s| s.branch == branch) .unwrap_or_else(|| SessionState::new(repo_path.clone(), branch.to_owned()));
50
51 let session = Arc::new(parking_lot::RwLock::new(session));
52
53 let watcher = match FileWatcherService::new(&repo_path, event_tx.clone()) {
55 Ok(w) => {
56 tracing::info!("Companion file watcher started");
57 Some(w)
58 }
59 Err(e) => {
60 tracing::warn!(
61 "Failed to start file watcher: {}. Companion will run without live updates.",
62 e
63 );
64 None
65 }
66 };
67
68 Ok(Self {
69 repo_path,
70 session,
71 storage,
72 watcher,
73 event_rx,
74 _event_tx: event_tx,
75 })
76 }
77
78 pub fn session(&self) -> &Arc<parking_lot::RwLock<SessionState>> {
80 &self.session
81 }
82
83 pub fn load_branch_memory(&self, branch: &str) -> Result<Option<BranchMemory>> {
85 self.storage.load_branch_memory(branch)
86 }
87
88 pub fn save_branch_memory(&self, memory: &BranchMemory) -> Result<()> {
90 self.storage.save_branch_memory(memory)
91 }
92
93 pub fn save_session(&self) -> Result<()> {
95 let session = self.session.read();
96 self.storage.save_session(&session)
97 }
98
99 pub fn touch_file(&self, path: PathBuf) {
101 let mut session = self.session.write();
102 session.touch_file(path);
103 }
104
105 pub fn record_commit(&self, hash: String) {
107 let mut session = self.session.write();
108 session.record_commit(hash);
109 }
110
111 pub fn try_recv_event(&mut self) -> Option<CompanionEvent> {
113 self.event_rx.try_recv().ok()
114 }
115
116 pub fn has_watcher(&self) -> bool {
118 self.watcher.is_some()
119 }
120
121 pub fn repo_path(&self) -> &PathBuf {
123 &self.repo_path
124 }
125}
126
127impl Drop for CompanionService {
128 fn drop(&mut self) {
129 if let Err(e) = self.save_session() {
131 tracing::warn!("Failed to save session on shutdown: {}", e);
132 }
133 }
134}