systemprompt_runtime/
context.rs1use std::sync::Arc;
8
9use systemprompt_analytics::{AnalyticsService, FingerprintRepository, GeoIpReader};
10use systemprompt_database::DbPool;
11use systemprompt_extension::ExtensionRegistry;
12use systemprompt_models::{AppPaths, Config, ContentConfigRaw, ContentRouting, RouteClassifier};
13use systemprompt_users::UserService;
14
15use crate::builder::AppContextBuilder;
16use crate::context_loaders;
17use crate::error::RuntimeResult;
18use crate::registry::ModuleApiRegistry;
19
20#[derive(Clone)]
21pub struct AppContext {
22 pub(crate) config: Arc<Config>,
23 pub(crate) database: DbPool,
24 pub(crate) api_registry: Arc<ModuleApiRegistry>,
25 pub(crate) extension_registry: Arc<ExtensionRegistry>,
26 pub(crate) geoip_reader: Option<GeoIpReader>,
27 pub(crate) content_config: Option<Arc<ContentConfigRaw>>,
28 pub(crate) route_classifier: Arc<RouteClassifier>,
29 pub(crate) analytics_service: Arc<AnalyticsService>,
30 pub(crate) fingerprint_repo: Option<Arc<FingerprintRepository>>,
31 pub(crate) user_service: Option<Arc<UserService>>,
32 pub(crate) app_paths: Arc<AppPaths>,
33}
34
35impl std::fmt::Debug for AppContext {
36 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37 f.debug_struct("AppContext")
38 .field("config", &"Config")
39 .field("database", &"DbPool")
40 .field("api_registry", &"ModuleApiRegistry")
41 .field("extension_registry", &self.extension_registry)
42 .field("geoip_reader", &self.geoip_reader.is_some())
43 .field("content_config", &self.content_config.is_some())
44 .field("route_classifier", &"RouteClassifier")
45 .field("analytics_service", &"AnalyticsService")
46 .field("fingerprint_repo", &self.fingerprint_repo.is_some())
47 .field("user_service", &self.user_service.is_some())
48 .field("app_paths", &"AppPaths")
49 .finish()
50 }
51}
52
53#[derive(Debug)]
54pub struct AppContextParts {
55 pub config: Arc<Config>,
56 pub database: DbPool,
57 pub api_registry: Arc<ModuleApiRegistry>,
58 pub extension_registry: Arc<ExtensionRegistry>,
59 pub geoip_reader: Option<GeoIpReader>,
60 pub content_config: Option<Arc<ContentConfigRaw>>,
61 pub route_classifier: Arc<RouteClassifier>,
62 pub analytics_service: Arc<AnalyticsService>,
63 pub fingerprint_repo: Option<Arc<FingerprintRepository>>,
64 pub user_service: Option<Arc<UserService>>,
65 pub app_paths: Arc<AppPaths>,
66}
67
68impl AppContext {
69 pub async fn new() -> RuntimeResult<Self> {
70 Self::builder().build().await
71 }
72
73 #[must_use]
74 pub fn builder() -> AppContextBuilder {
75 AppContextBuilder::new()
76 }
77
78 pub fn from_parts(parts: AppContextParts) -> Self {
79 Self {
80 config: parts.config,
81 database: parts.database,
82 api_registry: parts.api_registry,
83 extension_registry: parts.extension_registry,
84 geoip_reader: parts.geoip_reader,
85 content_config: parts.content_config,
86 route_classifier: parts.route_classifier,
87 analytics_service: parts.analytics_service,
88 fingerprint_repo: parts.fingerprint_repo,
89 user_service: parts.user_service,
90 app_paths: parts.app_paths,
91 }
92 }
93
94 pub fn load_geoip_database(config: &Config, show_warnings: bool) -> Option<GeoIpReader> {
95 context_loaders::load_geoip_database(config, show_warnings)
96 }
97
98 pub fn load_content_config(
99 config: &Config,
100 app_paths: &AppPaths,
101 ) -> Option<Arc<ContentConfigRaw>> {
102 context_loaders::load_content_config(config, app_paths)
103 }
104
105 pub fn config(&self) -> &Config {
106 &self.config
107 }
108
109 pub fn content_config(&self) -> Option<&ContentConfigRaw> {
110 self.content_config.as_ref().map(AsRef::as_ref)
111 }
112
113 pub fn content_routing(&self) -> Option<Arc<dyn ContentRouting>> {
114 let concrete = Arc::clone(self.content_config.as_ref()?);
115 let routing: Arc<dyn ContentRouting> = concrete;
116 Some(routing)
117 }
118
119 pub const fn db_pool(&self) -> &DbPool {
120 &self.database
121 }
122
123 pub const fn database(&self) -> &DbPool {
124 &self.database
125 }
126
127 pub fn api_registry(&self) -> &ModuleApiRegistry {
128 &self.api_registry
129 }
130
131 pub fn extension_registry(&self) -> &ExtensionRegistry {
132 &self.extension_registry
133 }
134
135 pub fn server_address(&self) -> String {
136 format!("{}:{}", self.config.host, self.config.port)
137 }
138
139 pub fn get_provided_audiences() -> Vec<String> {
140 vec!["a2a".to_string(), "api".to_string(), "mcp".to_string()]
141 }
142
143 pub fn get_valid_audiences(_module_name: &str) -> Vec<String> {
144 Self::get_provided_audiences()
145 }
146
147 pub fn get_server_audiences(_server_name: &str, _port: u16) -> Vec<String> {
148 Self::get_provided_audiences()
149 }
150
151 pub const fn geoip_reader(&self) -> Option<&GeoIpReader> {
152 self.geoip_reader.as_ref()
153 }
154
155 pub const fn analytics_service(&self) -> &Arc<AnalyticsService> {
156 &self.analytics_service
157 }
158
159 pub const fn route_classifier(&self) -> &Arc<RouteClassifier> {
160 &self.route_classifier
161 }
162
163 pub fn app_paths(&self) -> &AppPaths {
164 &self.app_paths
165 }
166
167 pub const fn app_paths_arc(&self) -> &Arc<AppPaths> {
168 &self.app_paths
169 }
170}