Skip to main content

DevelopmentNodeEnvironment_MicrosoftVSCodeDependency_22NodeVersion_Bundle_Clean_Debug_ElectronProfile_EsbuildCompiler_Mountain/RPC/CocoonService/FileSystem/
WatchFile.rs

1#![allow(non_snake_case)]
2
3//! `watch_file` gRPC endpoint - Cocoon calls this when an extension uses
4//! `vscode.workspace.createFileSystemWatcher`. Routes to Mountain's
5//! `FileWatcherProvider::RegisterWatcher` so OS events (FSEvents on macOS,
6//! inotify on Linux) flow back to Cocoon as `$fileWatcher:event` gRPC
7//! notifications which Cocoon fans out to extension `onDidChangeFile`
8//! listeners.
9//!
10//! The proto `WatchFileRequest` only carries a `uri` field. We derive the
11//! watch handle from a hash of the URI so dedup-by-triple logic in
12//! `FileWatcherProvider` can collapse identical registrations from multiple
13//! extensions watching the same root.
14
15use std::{
16	path::PathBuf,
17	sync::atomic::{AtomicU64, Ordering},
18};
19
20use CommonLibrary::FileSystem::FileWatcherProvider::FileWatcherProvider;
21use tonic::{Response, Status};
22
23use crate::{
24	RPC::CocoonService::CocoonServiceImpl,
25	Vine::Generated::{Empty, WatchFileRequest},
26	dev_log,
27};
28
29static WATCH_SEQ:AtomicU64 = AtomicU64::new(1);
30
31pub async fn Fn(Service:&CocoonServiceImpl, Request:WatchFileRequest) -> Result<Response<Empty>, Status> {
32	let URI = Request.uri.as_ref().map(|U| U.value.as_str()).unwrap_or("").to_string();
33
34	if URI.is_empty() {
35		return Ok(Response::new(Empty {}));
36	}
37
38	let Handle = format!("grpc-watch-{}", WATCH_SEQ.fetch_add(1, Ordering::Relaxed));
39
40	dev_log!("filewatcher", "[CocoonService] watch_file handle={} uri={}", Handle, URI);
41
42	let Root = if let Ok(Url) = url::Url::parse(&URI) {
43		Url.to_file_path().unwrap_or_else(|_| PathBuf::from(&URI))
44	} else {
45		PathBuf::from(&URI)
46	};
47
48	// Register recursive with no pattern filter - Cocoon's FileSystemWatcher
49	// subscribers apply their own glob matching on the extension side.
50	Service
51		.environment
52		.RegisterWatcher(Handle, Root, true, None)
53		.await
54		.map_err(|E| Status::internal(format!("watch_file: {E}")))?;
55
56	Ok(Response::new(Empty {}))
57}