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