1use std::pin::Pin;
11use std::sync::Arc;
12
13use tracing::debug;
14
15use apcore::context::Context;
16use apcore::errors::ModuleError;
17use apcore::Registry;
18
19use crate::output::types::{Verifier, WriteResult};
20use crate::output::verifiers::{run_verifier_chain, RegistryVerifier};
21use crate::types::ScannedModule;
22
23pub type HandlerFn = Arc<
25 dyn for<'a> Fn(
26 serde_json::Value,
27 &'a Context<serde_json::Value>,
28 ) -> Pin<
29 Box<
30 dyn std::future::Future<Output = Result<serde_json::Value, ModuleError>>
31 + Send
32 + 'a,
33 >,
34 > + Send
35 + Sync,
36>;
37
38pub type HandlerFactory = Arc<dyn Fn(&str) -> Option<HandlerFn> + Send + Sync>;
55
56pub struct RegistryWriter {
70 handler_factory: Option<HandlerFactory>,
71}
72
73impl Default for RegistryWriter {
74 fn default() -> Self {
75 Self::new()
76 }
77}
78
79impl RegistryWriter {
80 pub fn new() -> Self {
82 Self {
83 handler_factory: None,
84 }
85 }
86
87 pub fn with_handler_factory(factory: HandlerFactory) -> Self {
89 Self {
90 handler_factory: Some(factory),
91 }
92 }
93}
94
95impl RegistryWriter {
96 pub fn write(
103 &self,
104 modules: &[ScannedModule],
105 registry: &mut Registry,
106 dry_run: bool,
107 verify: bool,
108 verifiers: Option<&[&dyn Verifier]>,
109 ) -> Vec<WriteResult> {
110 let mut results: Vec<WriteResult> = Vec::new();
111
112 for module in modules {
113 if dry_run {
114 results.push(WriteResult::new(module.module_id.clone()));
115 continue;
116 }
117
118 let fm = self.to_function_module(module);
119 let descriptor = apcore::registry::registry::ModuleDescriptor {
121 name: module.module_id.clone(),
122 annotations: module.annotations.clone().unwrap_or_default(),
123 input_schema: module.input_schema.clone(),
124 output_schema: module.output_schema.clone(),
125 enabled: true,
126 tags: module.tags.clone(),
127 dependencies: vec![],
128 };
129 if let Err(e) = registry.register(&module.module_id, Box::new(fm), descriptor) {
130 results.push(WriteResult::failed(
131 module.module_id.clone(),
132 None,
133 format!("Registration failed: {e}"),
134 ));
135 continue;
136 }
137 debug!("Registered module: {}", module.module_id);
138
139 let mut result = WriteResult::new(module.module_id.clone());
140 if verify {
141 result = verify_registry(&result, &module.module_id, registry);
142 }
143 if result.verified {
144 if let Some(vs) = verifiers {
145 let chain_result = run_verifier_chain(vs, "", &module.module_id);
146 if !chain_result.ok {
147 result = WriteResult::failed(
148 result.module_id,
149 result.path,
150 chain_result.error.unwrap_or_default(),
151 );
152 }
153 }
154 }
155 results.push(result);
156 }
157
158 results
159 }
160}
161
162impl RegistryWriter {
163 fn to_function_module(&self, module: &ScannedModule) -> apcore::decorator::FunctionModule {
169 let annotations = module.annotations.clone().unwrap_or_default();
170 let input_schema = module.input_schema.clone();
171 let output_schema = module.output_schema.clone();
172
173 if let Some(factory) = &self.handler_factory {
175 if let Some(handler) = factory(&module.target) {
176 return apcore::decorator::FunctionModule::new::<_, ()>(
177 annotations,
178 input_schema,
179 output_schema,
180 move |inputs: serde_json::Value,
181 ctx: &Context<serde_json::Value>|
182 -> Pin<
183 Box<
184 dyn std::future::Future<Output = Result<serde_json::Value, ModuleError>>
185 + Send
186 + '_,
187 >,
188 > { handler(inputs, ctx) },
189 );
190 }
191 }
192
193 fn passthrough<'a>(
195 inputs: serde_json::Value,
196 _ctx: &'a Context<serde_json::Value>,
197 ) -> Pin<
198 Box<
199 dyn std::future::Future<Output = Result<serde_json::Value, ModuleError>>
200 + Send
201 + 'a,
202 >,
203 > {
204 Box::pin(async move { Ok(inputs) })
205 }
206
207 apcore::decorator::FunctionModule::new::<_, ()>(
208 annotations,
209 input_schema,
210 output_schema,
211 passthrough,
212 )
213 }
214}
215
216fn verify_registry(result: &WriteResult, module_id: &str, registry: &Registry) -> WriteResult {
218 let verifier = RegistryVerifier::new(registry);
219 let vr = verifier.verify("", module_id);
220 if vr.ok {
221 result.clone()
222 } else {
223 WriteResult::failed(module_id.into(), None, vr.error.unwrap_or_default())
224 }
225}
226
227#[cfg(test)]
228mod tests {
229 use super::*;
230 use serde_json::json;
231
232 fn sample_module() -> ScannedModule {
233 ScannedModule::new(
234 "users.get".into(),
235 "Get user".into(),
236 json!({"type": "object"}),
237 json!({"type": "object"}),
238 vec!["users".into()],
239 "app:get_user".into(),
240 )
241 }
242
243 #[test]
244 fn test_write_dry_run() {
245 let writer = RegistryWriter::new();
246 let mut registry = Registry::new();
247 let modules = vec![sample_module()];
248 let results = writer.write(&modules, &mut registry, true, false, None);
249 assert_eq!(results.len(), 1);
250 assert_eq!(results[0].module_id, "users.get");
251 assert!(!registry.has("users.get"));
252 }
253
254 #[test]
255 fn test_write_registers_module() {
256 let writer = RegistryWriter::new();
257 let mut registry = Registry::new();
258 let modules = vec![sample_module()];
259 let results = writer.write(&modules, &mut registry, false, false, None);
260 assert_eq!(results.len(), 1);
261 assert!(registry.has("users.get"));
262 }
263
264 #[test]
265 fn test_write_with_verify() {
266 let writer = RegistryWriter::new();
267 let mut registry = Registry::new();
268 let modules = vec![sample_module()];
269 let results = writer.write(&modules, &mut registry, false, true, None);
270 assert_eq!(results.len(), 1);
271 assert!(results[0].verified);
272 }
273
274 #[test]
275 fn test_write_empty_list() {
276 let writer = RegistryWriter::new();
277 let mut registry = Registry::new();
278 let results = writer.write(&[], &mut registry, false, false, None);
279 assert!(results.is_empty());
280 }
281
282 #[test]
283 fn test_write_multiple_modules() {
284 let writer = RegistryWriter::new();
285 let mut registry = Registry::new();
286 let modules = vec![
287 ScannedModule::new(
288 "mod.a".into(),
289 "A".into(),
290 json!({"type": "object"}),
291 json!({"type": "object"}),
292 vec![],
293 "app:a".into(),
294 ),
295 ScannedModule::new(
296 "mod.b".into(),
297 "B".into(),
298 json!({"type": "object"}),
299 json!({"type": "object"}),
300 vec![],
301 "app:b".into(),
302 ),
303 ];
304 let results = writer.write(&modules, &mut registry, false, false, None);
305 assert_eq!(results.len(), 2);
306 assert!(registry.has("mod.a"));
307 assert!(registry.has("mod.b"));
308 assert!(results[0].verified);
309 assert!(results[1].verified);
310 }
311}