1use super::*;
4use anyhow::Result;
5use async_trait::async_trait;
6use std::fs;
7
8pub struct FileSystemAdapter;
9
10#[async_trait]
11impl InputAdapter for FileSystemAdapter {
12 fn name(&self) -> &'static str {
13 "FileSystem"
14 }
15
16 fn supported_formats(&self) -> Vec<&'static str> {
17 vec!["dir", "directory", "folder", "path"]
18 }
19
20 async fn can_handle(&self, input: &InputSource) -> bool {
21 match input {
22 InputSource::Path(path) => path.exists(),
23 _ => false,
24 }
25 }
26
27 async fn parse(&self, input: InputSource) -> Result<ContextNode> {
28 match input {
29 InputSource::Path(path) => {
30 let metadata = fs::metadata(&path)?;
31 let name = path
32 .file_name()
33 .and_then(|n| n.to_str())
34 .unwrap_or("root")
35 .to_string();
36
37 let mut root = ContextNode {
38 id: path.to_string_lossy().to_string(),
39 name,
40 node_type: if metadata.is_dir() {
41 NodeType::Directory
42 } else {
43 NodeType::File
44 },
45 quantum_state: None,
46 children: vec![],
47 metadata: serde_json::json!({
48 "size": metadata.len(),
49 "modified": metadata.modified().ok(),
50 "readonly": metadata.permissions().readonly(),
51 }),
52 entanglements: vec![],
53 };
54
55 if metadata.is_dir() {
56 root.children = self.scan_directory(&path)?;
57 }
58
59 Ok(root)
60 }
61 _ => anyhow::bail!("FileSystem adapter only handles Path inputs"),
62 }
63 }
64}
65
66impl FileSystemAdapter {
67 #[allow(clippy::only_used_in_recursion)]
68 fn scan_directory(&self, path: &std::path::Path) -> Result<Vec<ContextNode>> {
69 let mut nodes = Vec::new();
70
71 for entry in fs::read_dir(path)? {
72 let entry = entry?;
73 let path = entry.path();
74 let metadata = entry.metadata()?;
75
76 let node = ContextNode {
77 id: path.to_string_lossy().to_string(),
78 name: entry.file_name().to_string_lossy().to_string(),
79 node_type: if metadata.is_dir() {
80 NodeType::Directory
81 } else {
82 NodeType::File
83 },
84 quantum_state: None,
85 children: if metadata.is_dir() {
86 self.scan_directory(&path).unwrap_or_default()
87 } else {
88 vec![]
89 },
90 metadata: serde_json::json!({
91 "size": metadata.len(),
92 "modified": metadata.modified().ok(),
93 }),
94 entanglements: vec![],
95 };
96
97 nodes.push(node);
98 }
99
100 Ok(nodes)
101 }
102}