1use std::collections::BTreeMap;
4use std::time::Duration;
5
6use crate::build_loader::RpcHashMap;
7use crate::channel::{ChannelDef, ChannelMeta};
8use crate::context::{ContextConfig, ContextFieldDef};
9use crate::page::{I18nConfig, PageDef};
10use crate::procedure::{ProcedureDef, StreamDef, SubscriptionDef, UploadDef};
11use crate::resolve::ResolveStrategy;
12use crate::validation::ValidationMode;
13
14pub struct TransportConfig {
16 pub heartbeat_interval: Duration,
17 pub sse_idle_timeout: Duration,
18 pub pong_timeout: Duration,
19}
20
21impl Default for TransportConfig {
22 fn default() -> Self {
23 Self {
24 heartbeat_interval: Duration::from_secs(21),
25 sse_idle_timeout: Duration::from_secs(30),
26 pong_timeout: Duration::from_secs(5),
27 }
28 }
29}
30
31pub struct SeamParts {
34 pub procedures: Vec<ProcedureDef>,
35 pub subscriptions: Vec<SubscriptionDef>,
36 pub streams: Vec<StreamDef>,
37 pub uploads: Vec<UploadDef>,
38 pub pages: Vec<PageDef>,
39 pub rpc_hash_map: Option<RpcHashMap>,
40 pub i18n_config: Option<I18nConfig>,
41 pub strategies: Vec<Box<dyn ResolveStrategy>>,
42 pub channel_metas: BTreeMap<String, ChannelMeta>,
43 pub context_config: ContextConfig,
44 pub validation_mode: ValidationMode,
45 pub transport_config: TransportConfig,
46}
47
48impl SeamParts {
49 pub fn has_url_prefix(&self) -> bool {
50 self.strategies.iter().any(|s| s.kind() == "url_prefix")
51 }
52}
53
54pub struct SeamServer {
55 procedures: Vec<ProcedureDef>,
56 subscriptions: Vec<SubscriptionDef>,
57 streams: Vec<StreamDef>,
58 uploads: Vec<UploadDef>,
59 channels: Vec<ChannelDef>,
60 pages: Vec<PageDef>,
61 rpc_hash_map: Option<RpcHashMap>,
62 i18n_config: Option<I18nConfig>,
63 strategies: Vec<Box<dyn ResolveStrategy>>,
64 context_config: ContextConfig,
65 validation_mode: ValidationMode,
66 transport_config: TransportConfig,
67}
68
69impl SeamServer {
70 pub fn new() -> Self {
71 Self {
72 procedures: Vec::new(),
73 subscriptions: Vec::new(),
74 streams: Vec::new(),
75 uploads: Vec::new(),
76 channels: Vec::new(),
77 pages: Vec::new(),
78 rpc_hash_map: None,
79 i18n_config: None,
80 strategies: Vec::new(),
81 context_config: ContextConfig::new(),
82 validation_mode: ValidationMode::Dev,
83 transport_config: TransportConfig::default(),
84 }
85 }
86
87 pub fn procedure(mut self, proc: ProcedureDef) -> Self {
88 self.procedures.push(proc);
89 self
90 }
91
92 pub fn subscription(mut self, sub: SubscriptionDef) -> Self {
93 self.subscriptions.push(sub);
94 self
95 }
96
97 pub fn stream(mut self, stream: StreamDef) -> Self {
98 self.streams.push(stream);
99 self
100 }
101
102 pub fn upload(mut self, upload: UploadDef) -> Self {
103 self.uploads.push(upload);
104 self
105 }
106
107 pub fn channel(mut self, channel: ChannelDef) -> Self {
108 self.channels.push(channel);
109 self
110 }
111
112 pub fn namespace(mut self, prefix: &str, procedures: Vec<ProcedureDef>) -> Self {
114 for mut p in procedures {
115 p.name = format!("{prefix}.{}", p.name);
116 self.procedures.push(p);
117 }
118 self
119 }
120
121 pub fn namespace_subs(mut self, prefix: &str, subs: Vec<SubscriptionDef>) -> Self {
123 for mut s in subs {
124 s.name = format!("{prefix}.{}", s.name);
125 self.subscriptions.push(s);
126 }
127 self
128 }
129
130 pub fn namespace_streams(mut self, prefix: &str, streams: Vec<StreamDef>) -> Self {
132 for mut s in streams {
133 s.name = format!("{prefix}.{}", s.name);
134 self.streams.push(s);
135 }
136 self
137 }
138
139 pub fn page(mut self, page: PageDef) -> Self {
140 self.pages.push(page);
141 self
142 }
143
144 pub fn rpc_hash_map(mut self, map: RpcHashMap) -> Self {
145 self.rpc_hash_map = Some(map);
146 self
147 }
148
149 pub fn i18n_config(mut self, config: I18nConfig) -> Self {
150 self.i18n_config = Some(config);
151 self
152 }
153
154 pub fn resolve_strategies(mut self, strategies: Vec<Box<dyn ResolveStrategy>>) -> Self {
155 self.strategies = strategies;
156 self
157 }
158
159 pub fn context(mut self, key: &str, field: ContextFieldDef) -> Self {
160 self.context_config.insert(key.to_string(), field);
161 self
162 }
163
164 pub fn validation_mode(mut self, mode: ValidationMode) -> Self {
165 self.validation_mode = mode;
166 self
167 }
168
169 pub fn transport_config(mut self, config: TransportConfig) -> Self {
170 self.transport_config = config;
171 self
172 }
173
174 pub fn into_parts(self) -> SeamParts {
177 let mut procedures = self.procedures;
178 let mut subscriptions = self.subscriptions;
179 let mut channel_metas = BTreeMap::new();
180
181 for channel in self.channels {
182 let name = channel.name.clone();
183 let (procs, subs, meta) = channel.expand();
184 procedures.extend(procs);
185 subscriptions.extend(subs);
186 channel_metas.insert(name, meta);
187 }
188
189 SeamParts {
190 procedures,
191 subscriptions,
192 streams: self.streams,
193 uploads: self.uploads,
194 pages: self.pages,
195 rpc_hash_map: self.rpc_hash_map,
196 i18n_config: self.i18n_config,
197 strategies: self.strategies,
198 channel_metas,
199 context_config: self.context_config,
200 validation_mode: self.validation_mode,
201 transport_config: self.transport_config,
202 }
203 }
204}
205
206impl Default for SeamServer {
207 fn default() -> Self {
208 Self::new()
209 }
210}