systemprompt_runtime/
registry.rs1use axum::Router;
10use serde::{Deserialize, Serialize};
11use std::collections::HashMap;
12
13pub use systemprompt_models::modules::ServiceCategory;
14
15use crate::AppContext;
16
17#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
18pub enum ModuleType {
19 Regular,
20 Proxy,
21}
22
23#[derive(Debug)]
24pub struct ModuleApiRegistry {
25 registry: HashMap<String, ModuleApiImpl>,
26}
27
28#[derive(Debug)]
29struct ModuleApiImpl {
30 category: ServiceCategory,
31 module_type: ModuleType,
32 router_fn: fn(&AppContext) -> Router,
33 auth_required: bool,
34}
35
36#[derive(Debug, Copy, Clone)]
37pub struct ModuleApiRegistration {
38 pub module_name: &'static str,
39 pub category: ServiceCategory,
40 pub module_type: ModuleType,
41 pub router_fn: fn(&AppContext) -> Router,
42 pub auth_required: bool,
43}
44
45inventory::collect!(ModuleApiRegistration);
46
47#[derive(Debug, Clone, Copy)]
48pub struct WellKnownRoute {
49 pub path: &'static str,
50 pub handler_fn: fn(&AppContext) -> Router,
51 pub methods: &'static [axum::http::Method],
52}
53
54inventory::collect!(WellKnownRoute);
55
56impl Default for ModuleApiRegistry {
57 fn default() -> Self {
58 Self::new()
59 }
60}
61
62impl ModuleApiRegistry {
63 pub fn new() -> Self {
64 let mut registry = HashMap::new();
65
66 for registration in inventory::iter::<ModuleApiRegistration> {
67 let api_impl = ModuleApiImpl {
68 category: registration.category,
69 module_type: registration.module_type,
70 router_fn: registration.router_fn,
71 auth_required: registration.auth_required,
72 };
73 registry.insert(registration.module_name.to_string(), api_impl);
74 }
75
76 Self { registry }
77 }
78
79 pub fn get_routes(&self, module_name: &str, ctx: &AppContext) -> Option<Router> {
80 self.registry
81 .get(module_name)
82 .map(|impl_| (impl_.router_fn)(ctx))
83 }
84
85 pub fn get_category(&self, module_name: &str) -> Option<ServiceCategory> {
86 self.registry.get(module_name).map(|impl_| impl_.category)
87 }
88
89 pub fn get_module_type(&self, module_name: &str) -> Option<ModuleType> {
90 self.registry
91 .get(module_name)
92 .map(|impl_| impl_.module_type)
93 }
94
95 pub fn get_auth_required(&self, module_name: &str) -> Option<bool> {
96 self.registry
97 .get(module_name)
98 .map(|impl_| impl_.auth_required)
99 }
100
101 pub fn modules_by_category(&self, category: ServiceCategory) -> Vec<String> {
102 self.registry
103 .iter()
104 .filter(|(_, impl_)| matches!(impl_.category, c if c as u8 == category as u8))
105 .map(|(name, _)| name.clone())
106 .collect()
107 }
108}