fusabi_stdlib_ext/
registry.rs

1//! Stdlib module registry for registering modules with engines.
2
3use std::sync::Arc;
4
5use fusabi_host::HostRegistry;
6
7use crate::config::StdlibConfig;
8use crate::error::{Error, Result};
9use crate::safety::SafetyConfig;
10
11/// Registry for stdlib modules.
12pub struct StdlibRegistry {
13    config: StdlibConfig,
14    safety: Arc<SafetyConfig>,
15}
16
17impl StdlibRegistry {
18    /// Create a new stdlib registry.
19    pub fn new(config: StdlibConfig) -> Result<Self> {
20        let safety = Arc::new(config.safety.clone());
21
22        Ok(Self { config, safety })
23    }
24
25    /// Create with default configuration.
26    pub fn default_config() -> Result<Self> {
27        Self::new(StdlibConfig::default())
28    }
29
30    /// Get the configuration.
31    pub fn config(&self) -> &StdlibConfig {
32        &self.config
33    }
34
35    /// Get the safety configuration.
36    pub fn safety(&self) -> &SafetyConfig {
37        &self.safety
38    }
39
40    /// Register all enabled modules with a host registry.
41    pub fn register_all(&self, registry: &mut HostRegistry) -> Result<()> {
42        #[cfg(feature = "process")]
43        if self.config.process.enabled {
44            self.register_process(registry)?;
45        }
46
47        #[cfg(feature = "fs")]
48        if self.config.fs.enabled {
49            self.register_fs(registry)?;
50        }
51
52        #[cfg(feature = "path")]
53        if self.config.path.enabled {
54            self.register_path(registry)?;
55        }
56
57        #[cfg(feature = "env")]
58        if self.config.env.enabled {
59            self.register_env(registry)?;
60        }
61
62        #[cfg(feature = "format")]
63        if self.config.format.enabled {
64            self.register_format(registry)?;
65        }
66
67        #[cfg(feature = "net")]
68        if self.config.net.enabled {
69            self.register_net(registry)?;
70        }
71
72        #[cfg(feature = "time")]
73        if self.config.time.enabled {
74            self.register_time(registry)?;
75        }
76
77        #[cfg(feature = "metrics")]
78        if self.config.metrics.enabled {
79            self.register_metrics(registry)?;
80        }
81
82        Ok(())
83    }
84
85    /// Register the process module.
86    #[cfg(feature = "process")]
87    pub fn register_process(&self, registry: &mut HostRegistry) -> Result<()> {
88        use crate::process;
89
90        let safety = self.safety.clone();
91        let timeout = self.config.process.timeout;
92
93        registry.register_module("process", "exec", move |args, ctx| {
94            process::exec(&safety, timeout, args, ctx)
95        });
96
97        registry.register_module("process", "spawn", move |args, ctx| {
98            process::spawn(args, ctx)
99        });
100
101        Ok(())
102    }
103
104    /// Register the filesystem module.
105    #[cfg(feature = "fs")]
106    pub fn register_fs(&self, registry: &mut HostRegistry) -> Result<()> {
107        use crate::fs;
108
109        let safety = self.safety.clone();
110
111        let s = safety.clone();
112        registry.register_module("fs", "read", move |args, ctx| {
113            fs::read_file(&s, args, ctx)
114        });
115
116        let s = safety.clone();
117        registry.register_module("fs", "write", move |args, ctx| {
118            fs::write_file(&s, args, ctx)
119        });
120
121        let s = safety.clone();
122        registry.register_module("fs", "exists", move |args, ctx| {
123            fs::exists(&s, args, ctx)
124        });
125
126        let s = safety.clone();
127        registry.register_module("fs", "list", move |args, ctx| {
128            fs::list_dir(&s, args, ctx)
129        });
130
131        let s = safety.clone();
132        registry.register_module("fs", "mkdir", move |args, ctx| {
133            fs::mkdir(&s, args, ctx)
134        });
135
136        let s = safety.clone();
137        registry.register_module("fs", "remove", move |args, ctx| {
138            fs::remove(&s, args, ctx)
139        });
140
141        Ok(())
142    }
143
144    /// Register the path module.
145    #[cfg(feature = "path")]
146    pub fn register_path(&self, registry: &mut HostRegistry) -> Result<()> {
147        use crate::path;
148
149        registry.register_module("path", "join", |args, ctx| {
150            path::join(args, ctx)
151        });
152
153        registry.register_module("path", "dirname", |args, ctx| {
154            path::dirname(args, ctx)
155        });
156
157        registry.register_module("path", "basename", |args, ctx| {
158            path::basename(args, ctx)
159        });
160
161        registry.register_module("path", "extension", |args, ctx| {
162            path::extension(args, ctx)
163        });
164
165        registry.register_module("path", "normalize", |args, ctx| {
166            path::normalize(args, ctx)
167        });
168
169        registry.register_module("path", "is_absolute", |args, ctx| {
170            path::is_absolute(args, ctx)
171        });
172
173        Ok(())
174    }
175
176    /// Register the environment module.
177    #[cfg(feature = "env")]
178    pub fn register_env(&self, registry: &mut HostRegistry) -> Result<()> {
179        use crate::env;
180
181        let safety = self.safety.clone();
182
183        let s = safety.clone();
184        registry.register_module("env", "get", move |args, ctx| {
185            env::get(&s, args, ctx)
186        });
187
188        let s = safety.clone();
189        registry.register_module("env", "set", move |args, ctx| {
190            env::set(&s, args, ctx)
191        });
192
193        registry.register_module("env", "cwd", |args, ctx| {
194            env::cwd(args, ctx)
195        });
196
197        Ok(())
198    }
199
200    /// Register the format module.
201    #[cfg(feature = "format")]
202    pub fn register_format(&self, registry: &mut HostRegistry) -> Result<()> {
203        use crate::format;
204
205        registry.register_module("format", "sprintf", |args, ctx| {
206            format::sprintf(args, ctx)
207        });
208
209        registry.register_module("format", "template", |args, ctx| {
210            format::template(args, ctx)
211        });
212
213        registry.register_module("format", "json_encode", |args, ctx| {
214            format::json_encode(args, ctx)
215        });
216
217        registry.register_module("format", "json_decode", |args, ctx| {
218            format::json_decode(args, ctx)
219        });
220
221        Ok(())
222    }
223
224    /// Register the network module.
225    #[cfg(feature = "net")]
226    pub fn register_net(&self, registry: &mut HostRegistry) -> Result<()> {
227        use crate::net;
228
229        let safety = self.safety.clone();
230        let timeout = self.config.net.timeout;
231
232        let s = safety.clone();
233        registry.register_module("net", "get", move |args, ctx| {
234            net::http_get(&s, timeout, args, ctx)
235        });
236
237        let s = safety.clone();
238        registry.register_module("net", "post", move |args, ctx| {
239            net::http_post(&s, timeout, args, ctx)
240        });
241
242        Ok(())
243    }
244
245    /// Register the time module.
246    #[cfg(feature = "time")]
247    pub fn register_time(&self, registry: &mut HostRegistry) -> Result<()> {
248        use crate::time;
249
250        registry.register_module("time", "now", |args, ctx| {
251            time::now(args, ctx)
252        });
253
254        registry.register_module("time", "now_millis", |args, ctx| {
255            time::now_millis(args, ctx)
256        });
257
258        registry.register_module("time", "sleep", |args, ctx| {
259            time::sleep(args, ctx)
260        });
261
262        registry.register_module("time", "format", |args, ctx| {
263            time::format_time(args, ctx)
264        });
265
266        registry.register_module("time", "parse", |args, ctx| {
267            time::parse_time(args, ctx)
268        });
269
270        Ok(())
271    }
272
273    /// Register the metrics module.
274    #[cfg(feature = "metrics")]
275    pub fn register_metrics(&self, registry: &mut HostRegistry) -> Result<()> {
276        use crate::metrics;
277
278        registry.register_module("metrics", "counter_inc", |args, ctx| {
279            metrics::counter_inc(args, ctx)
280        });
281
282        registry.register_module("metrics", "gauge_set", |args, ctx| {
283            metrics::gauge_set(args, ctx)
284        });
285
286        registry.register_module("metrics", "histogram_observe", |args, ctx| {
287            metrics::histogram_observe(args, ctx)
288        });
289
290        Ok(())
291    }
292}
293
294impl std::fmt::Debug for StdlibRegistry {
295    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
296        f.debug_struct("StdlibRegistry")
297            .field("config", &self.config)
298            .finish()
299    }
300}
301
302#[cfg(test)]
303mod tests {
304    use super::*;
305
306    #[test]
307    fn test_registry_creation() {
308        let registry = StdlibRegistry::default_config().unwrap();
309        assert!(registry.config().fs.enabled);
310    }
311
312    #[test]
313    fn test_registry_permissive() {
314        let config = StdlibConfig::permissive();
315        let registry = StdlibRegistry::new(config).unwrap();
316
317        assert!(registry.config().process.enabled);
318        assert!(registry.config().net.enabled);
319    }
320
321    #[test]
322    fn test_registry_strict() {
323        let config = StdlibConfig::strict();
324        let registry = StdlibRegistry::new(config).unwrap();
325
326        assert!(!registry.config().process.enabled);
327        assert!(!registry.config().fs.enabled);
328    }
329}