1use std::{
2 collections::HashMap,
3 ffi::OsString,
4 fs::File,
5 io::BufReader,
6 path::{Component, Path, PathBuf},
7 sync::Arc,
8};
9
10use async_trait::async_trait;
11use ron::ser::PrettyConfig;
12use serde::{Deserialize, Serialize};
13
14use crate::{
15 connector::{
16 Connector, ConnectorOutbox, DocIdent, FilterResponse, GetDocResponse, GetResourceResponse, OpExecResponse,
17 PlanResponseElement, SkeletonResponse, TaskExecResponse, VirtToPhyResponse,
18 },
19 diag::DiagnosticResponse,
20 util::RON,
21};
22
23#[derive(Serialize, Deserialize)]
24#[serde(deny_unknown_fields)]
25pub enum BundleMapFile {
26 Bundle,
27 ChildOf { parent: PathBuf },
28}
29
30impl BundleMapFile {
31 pub fn path(prefix: &Path, addr: &Path) -> PathBuf {
32 let mut output = prefix.to_path_buf();
33
34 output.push(".bundle");
35
36 if let Some(parent) = addr.parent() {
38 for comp in parent.components() {
41 if let Component::Normal(_) = comp {
42 output.push(comp)
43 }
44 }
45 }
46
47 let mut new_filename = OsString::new();
48 if let Some(fname) = addr.file_name() {
49 new_filename.push(fname);
50 } else {
51 }
55 new_filename.push(".bun.ron");
56
57 output.push(new_filename);
58
59 output
60 }
61
62 pub fn read(prefix: &Path, addr: &Path) -> anyhow::Result<Option<Self>> {
63 let bundle_path = Self::path(prefix, addr);
64
65 if bundle_path.is_file() {
66 let file = File::open(&bundle_path)?;
67 let reader = BufReader::new(file);
68
69 let bundle: Self = RON.from_reader(reader)?;
70
71 return Ok(Some(bundle));
72 }
73
74 Ok(None)
75 }
76
77 pub fn read_recurse(prefix: &Path, addr: &Path) -> anyhow::Result<Option<Self>> {
78 let bundle_path = Self::path(prefix, addr);
79
80 if bundle_path.is_file() {
81 let file = File::open(&bundle_path)?;
82 let reader = BufReader::new(file);
83
84 let bundle: Self = RON.from_reader(reader)?;
85
86 match &bundle {
87 BundleMapFile::ChildOf { parent } => {
88 return Self::read_recurse(prefix, parent);
89 }
90 BundleMapFile::Bundle => return Ok(Some(bundle)),
91 }
92 }
93
94 Ok(None)
95 }
96
97 pub fn write(&self, prefix: &Path, addr: &Path) -> anyhow::Result<PathBuf> {
98 let bundle_path = Self::path(prefix, addr);
99 let pretty_config = PrettyConfig::default();
100
101 let contents = RON.to_string_pretty(self, pretty_config)?;
102
103 if let Some(parent) = bundle_path.parent() {
104 std::fs::create_dir_all(parent)?;
105 }
106 if bundle_path.exists() {
107 std::fs::remove_file(&bundle_path)?;
108 }
109
110 std::fs::write(&bundle_path, contents)?;
111
112 Ok(bundle_path)
113 }
114
115 pub fn write_link(prefix: &Path, child: &Path, parent: &Path) -> anyhow::Result<PathBuf> {
116 let child_map = Self::ChildOf {
117 parent: parent.to_owned(),
118 };
119 child_map.write(prefix, child)?;
120 Ok(Self::path(prefix, child))
121 }
122
123 pub fn delete(prefix: &Path, addr: &Path) -> anyhow::Result<Option<PathBuf>> {
124 let path = Self::path(prefix, addr);
125 if path.is_file() {
126 std::fs::remove_file(&path)?;
127 Ok(Some(path))
128 } else {
129 Ok(None)
130 }
131 }
132}
133
134#[derive(Debug, Clone, Serialize, Deserialize)]
135pub struct UnbundleResponseElement {
136 pub addr: PathBuf,
137 pub contents: Vec<u8>,
138}
139
140impl UnbundleResponseElement {}
141
142#[async_trait]
143pub trait Bundle
144where
145 Self: Send + Sync,
146{
147 #[allow(clippy::new_ret_no_self)]
148 async fn new(name: &str, prefix: &Path) -> Result<Arc<dyn Bundle>, anyhow::Error>
149 where
150 Self: Sized;
151
152 async fn init(&self) -> Result<(), anyhow::Error>;
153
154 async fn version(&self) -> Result<String, anyhow::Error>;
155
156 async fn filter(&self, addr: &Path) -> Result<FilterResponse, anyhow::Error>;
157
158 async fn unbundle(&self, addr: &Path, resource: &[u8]) -> anyhow::Result<Vec<UnbundleResponseElement>>;
159
160 async fn get_skeletons(&self) -> Result<Vec<SkeletonResponse>, anyhow::Error> {
161 Ok(Vec::new())
162 }
163 async fn get_docstring(&self, _addr: &Path, _ident: DocIdent) -> anyhow::Result<Option<GetDocResponse>> {
164 Ok(None)
165 }
166 async fn eq(&self, _addr: &Path, a: &[u8], b: &[u8]) -> Result<bool, anyhow::Error> {
167 Ok(a == b)
168 }
169 async fn diag(&self, _addr: &Path, _a: &[u8]) -> Result<Option<DiagnosticResponse>, anyhow::Error> {
170 Ok(None)
171 }
172}
173
174#[async_trait]
175impl Bundle for Arc<dyn Bundle> {
176 async fn new(name: &str, prefix: &Path) -> Result<Arc<dyn Bundle>, anyhow::Error> {
177 return <Arc<dyn Bundle> as Bundle>::new(name, prefix).await;
178 }
179
180 async fn init(&self) -> Result<(), anyhow::Error> {
181 Bundle::init(self.as_ref()).await
182 }
183
184 async fn version(&self) -> Result<String, anyhow::Error> {
185 Bundle::version(self.as_ref()).await
186 }
187
188 async fn filter(&self, addr: &Path) -> Result<FilterResponse, anyhow::Error> {
189 Bundle::filter(self.as_ref(), addr).await
190 }
191
192 async fn get_docstring(&self, addr: &Path, ident: DocIdent) -> anyhow::Result<Option<GetDocResponse>> {
193 Bundle::get_docstring(self.as_ref(), addr, ident).await
194 }
195
196 async fn eq(&self, addr: &Path, a: &[u8], b: &[u8]) -> Result<bool, anyhow::Error> {
197 Bundle::eq(self.as_ref(), addr, a, b).await
198 }
199
200 async fn diag(&self, addr: &Path, a: &[u8]) -> Result<Option<DiagnosticResponse>, anyhow::Error> {
201 Bundle::diag(self.as_ref(), addr, a).await
202 }
203
204 async fn unbundle(&self, addr: &Path, resource: &[u8]) -> anyhow::Result<Vec<UnbundleResponseElement>> {
205 Bundle::unbundle(self.as_ref(), addr, resource).await
206 }
207}
208
209#[async_trait]
210impl Connector for Arc<dyn Bundle> {
211 async fn new(name: &str, prefix: &Path, _outbox: ConnectorOutbox) -> Result<Arc<dyn Connector>, anyhow::Error> {
212 let bundle: Arc<dyn Bundle> = <Arc<dyn Bundle + 'static> as Bundle>::new(name, prefix).await?;
213 Ok(Arc::new(bundle))
214 }
215
216 async fn init(&self) -> Result<(), anyhow::Error> {
217 Bundle::init(self).await
218 }
219
220 async fn version(&self) -> Result<String, anyhow::Error> {
221 Bundle::version(self).await
222 }
223
224 async fn filter(&self, addr: &Path) -> Result<FilterResponse, anyhow::Error> {
225 Bundle::filter(self, addr).await
226 }
227
228 async fn list(&self, _subpath: &Path) -> anyhow::Result<Vec<PathBuf>> {
229 Ok(Vec::new())
230 }
231
232 async fn subpaths(&self) -> anyhow::Result<Vec<PathBuf>> {
233 Ok(Vec::new())
234 }
235
236 async fn get(&self, _addr: &Path) -> Result<Option<GetResourceResponse>, anyhow::Error> {
237 Ok(None)
238 }
239
240 async fn plan(
241 &self,
242 _addr: &Path,
243 _current: Option<Vec<u8>>,
244 _desired: Option<Vec<u8>>,
245 ) -> Result<Vec<PlanResponseElement>, anyhow::Error> {
246 Ok(Vec::new())
247 }
248
249 async fn op_exec(&self, _addr: &Path, _op: &str) -> Result<OpExecResponse, anyhow::Error> {
250 Ok(OpExecResponse {
251 outputs: Some(HashMap::new()),
252 friendly_message: Some(String::from("Bundle: No-op!")),
253 })
254 }
255
256 async fn addr_virt_to_phy(&self, addr: &Path) -> Result<VirtToPhyResponse, anyhow::Error> {
257 Ok(VirtToPhyResponse::Present(addr.into()))
258 }
259
260 async fn addr_phy_to_virt(&self, addr: &Path) -> Result<Option<PathBuf>, anyhow::Error> {
261 Ok(Some(addr.into()))
262 }
263
264 async fn get_skeletons(&self) -> Result<Vec<SkeletonResponse>, anyhow::Error> {
265 Bundle::get_skeletons(self).await
266 }
267
268 async fn get_docstring(&self, addr: &Path, ident: DocIdent) -> anyhow::Result<Option<GetDocResponse>> {
269 Bundle::get_docstring(self, addr, ident).await
270 }
271
272 async fn eq(&self, addr: &Path, a: &[u8], b: &[u8]) -> Result<bool, anyhow::Error> {
273 Bundle::eq(self, addr, a, b).await
274 }
275
276 async fn diag(&self, addr: &Path, a: &[u8]) -> Result<Option<DiagnosticResponse>, anyhow::Error> {
277 Bundle::diag(self, addr, a).await
278 }
279
280 async fn task_exec(
281 &self,
282 _addr: &Path,
283 _body: Vec<u8>,
284 _arg: Option<Vec<u8>>,
285 _state: Option<Vec<u8>>,
286 ) -> anyhow::Result<TaskExecResponse> {
287 Ok(TaskExecResponse::default())
288 }
289
290 async fn unbundle(&self, addr: &Path, bundle: &[u8]) -> anyhow::Result<Vec<UnbundleResponseElement>> {
291 Bundle::unbundle(self, addr, bundle).await
292 }
293}