Skip to main content

seam_server/
server.rs

1/* src/server/core/rust/src/server.rs */
2
3use std::collections::BTreeMap;
4
5use crate::build_loader::RpcHashMap;
6use crate::channel::{ChannelDef, ChannelMeta};
7use crate::context::{ContextConfig, ContextFieldDef};
8use crate::page::{I18nConfig, PageDef};
9use crate::procedure::{ProcedureDef, SubscriptionDef};
10use crate::resolve::ResolveStrategy;
11
12/// Framework-agnostic parts extracted from `SeamServer`.
13/// Adapter crates consume this to build framework-specific routers.
14pub struct SeamParts {
15  pub procedures: Vec<ProcedureDef>,
16  pub subscriptions: Vec<SubscriptionDef>,
17  pub pages: Vec<PageDef>,
18  pub rpc_hash_map: Option<RpcHashMap>,
19  pub i18n_config: Option<I18nConfig>,
20  pub strategies: Vec<Box<dyn ResolveStrategy>>,
21  pub channel_metas: BTreeMap<String, ChannelMeta>,
22  pub context_config: ContextConfig,
23}
24
25impl SeamParts {
26  pub fn has_url_prefix(&self) -> bool {
27    self.strategies.iter().any(|s| s.kind() == "url_prefix")
28  }
29}
30
31pub struct SeamServer {
32  procedures: Vec<ProcedureDef>,
33  subscriptions: Vec<SubscriptionDef>,
34  channels: Vec<ChannelDef>,
35  pages: Vec<PageDef>,
36  rpc_hash_map: Option<RpcHashMap>,
37  i18n_config: Option<I18nConfig>,
38  strategies: Vec<Box<dyn ResolveStrategy>>,
39  context_config: ContextConfig,
40}
41
42impl SeamServer {
43  pub fn new() -> Self {
44    Self {
45      procedures: Vec::new(),
46      subscriptions: Vec::new(),
47      channels: Vec::new(),
48      pages: Vec::new(),
49      rpc_hash_map: None,
50      i18n_config: None,
51      strategies: Vec::new(),
52      context_config: ContextConfig::new(),
53    }
54  }
55
56  pub fn procedure(mut self, proc: ProcedureDef) -> Self {
57    self.procedures.push(proc);
58    self
59  }
60
61  pub fn subscription(mut self, sub: SubscriptionDef) -> Self {
62    self.subscriptions.push(sub);
63    self
64  }
65
66  pub fn channel(mut self, channel: ChannelDef) -> Self {
67    self.channels.push(channel);
68    self
69  }
70
71  pub fn page(mut self, page: PageDef) -> Self {
72    self.pages.push(page);
73    self
74  }
75
76  pub fn rpc_hash_map(mut self, map: RpcHashMap) -> Self {
77    self.rpc_hash_map = Some(map);
78    self
79  }
80
81  pub fn i18n_config(mut self, config: I18nConfig) -> Self {
82    self.i18n_config = Some(config);
83    self
84  }
85
86  pub fn resolve_strategies(mut self, strategies: Vec<Box<dyn ResolveStrategy>>) -> Self {
87    self.strategies = strategies;
88    self
89  }
90
91  pub fn context(mut self, key: &str, field: ContextFieldDef) -> Self {
92    self.context_config.insert(key.to_string(), field);
93    self
94  }
95
96  /// Consume the builder, returning framework-agnostic parts for an adapter.
97  /// Channels are expanded into their Level 0 primitives (commands + subscriptions).
98  pub fn into_parts(self) -> SeamParts {
99    let mut procedures = self.procedures;
100    let mut subscriptions = self.subscriptions;
101    let mut channel_metas = BTreeMap::new();
102
103    for channel in self.channels {
104      let name = channel.name.clone();
105      let (procs, subs, meta) = channel.expand();
106      procedures.extend(procs);
107      subscriptions.extend(subs);
108      channel_metas.insert(name, meta);
109    }
110
111    SeamParts {
112      procedures,
113      subscriptions,
114      pages: self.pages,
115      rpc_hash_map: self.rpc_hash_map,
116      i18n_config: self.i18n_config,
117      strategies: self.strategies,
118      channel_metas,
119      context_config: self.context_config,
120    }
121  }
122}
123
124impl Default for SeamServer {
125  fn default() -> Self {
126    Self::new()
127  }
128}