JavaScript is disabled, refresh for a better experience. ambee/giterated

ambee/giterated

Git repository hosting, collaboration, and discovery for the Fediverse.

The long awaited, exhalted huge networking stack change.

Amber - ⁨2⁩ years ago

parent: tbd commit: ⁨21b6a72

⁨giterated-stack/src/substack.rs⁩ - ⁨11842⁩ bytes
Raw
1 use std::{collections::HashMap, marker::PhantomData, sync::Arc};
2
3 use anyhow::Error;
4 use futures_util::FutureExt;
5 use giterated_models::{
6 error::OperationError,
7 instance::Instance,
8 object::{GiteratedObject, ObjectRequest, ObjectResponse},
9 operation::GiteratedOperation,
10 settings::Setting,
11 value::GiteratedObjectValue,
12 };
13 use tracing::{info, trace};
14
15 use crate::{
16 handler::HandlerWrapper, provider::MetadataProvider, AnyFailure, AnyObject, AnyOperation,
17 AnySetting, AnySuccess, AnyValue, GiteratedStack, GiteratedStackState, HandlerResolvable,
18 IntoGiteratedHandler, MaybeDynamicObject, MaybeDynamicValue, ObjectOperationPair,
19 ObjectSettingPair, ObjectValuePair, OperationHandler, OperationState, RuntimeMetadata,
20 SettingChange, SettingGetter, StackOperationState, ValueChange, ValueGetter,
21 };
22
23 pub struct SubstackBuilder<S: GiteratedStackState, OS> {
24 pub(crate) operation_handlers: HashMap<ObjectOperationPair<'static>, OperationHandler<OS>>,
25 pub(crate) value_getters: HashMap<ObjectValuePair<'static>, ValueGetter<OS>>,
26 pub(crate) setting_getters: HashMap<&'static str, SettingGetter<OS>>,
27 pub(crate) metadata: RuntimeMetadata,
28 pub(crate) value_change: HashMap<ObjectValuePair<'static>, ValueChange<OS>>,
29 pub(crate) metadata_providers: Vec<Box<dyn MetadataProvider>>,
30 pub(crate) setting_change: HashMap<ObjectSettingPair<'static>, SettingChange<OS>>,
31
32 pub(crate) state: S,
33 _marker: PhantomData<OS>,
34 }
35
36 impl<S: GiteratedStackState + 'static, OS> SubstackBuilder<S, OS> {
37 pub fn new(state: S) -> Self {
38 Self {
39 operation_handlers: Default::default(),
40 value_getters: Default::default(),
41 setting_getters: Default::default(),
42 metadata: Default::default(),
43 value_change: Default::default(),
44 metadata_providers: Default::default(),
45 setting_change: Default::default(),
46 state,
47 _marker: PhantomData::default(),
48 }
49 }
50 }
51
52 impl<S: Send + Sync + Clone + 'static, OS: Clone + 'static> SubstackBuilder<S, OS> {
53 /// Insert an operation handler into the runtime builder.
54 ///
55 /// # Type Registration
56 /// Inserting the handler will automatically, if required, register the operation type of the
57 /// handler. It will **not** register the object type automatically.
58 pub fn operation<O, D, A, H>(&mut self, handler: H) -> &mut Self
59 where
60 O: GiteratedObject + Clone,
61 D: GiteratedOperation<O> + Clone,
62 H: IntoGiteratedHandler<(O, D), A, S, OS, Result<D::Success, OperationError<D::Failure>>>
63 + Send
64 + Sync
65 + 'static,
66 O: 'static,
67 D: 'static,
68 D::Failure: std::fmt::Debug + 'static,
69 D::Success: 'static,
70 OS: Clone,
71 {
72 let wrapped = HandlerWrapper::new(self.state.clone(), handler);
73
74 let wrapped = wrapped.map(
75 |(any_object, any_operation): &(AnyObject, AnyOperation), _state: &OS| {
76 Ok((
77 any_object.downcast_ref::<O>().unwrap().clone(),
78 any_operation.downcast_ref::<D>().unwrap().clone(),
79 ))
80 },
81 );
82
83 let wrapped = wrapped.map_return(|ret_val, _state| match ret_val {
84 Ok(success) => Ok(AnySuccess(Arc::new(success))),
85 Err(err) => Err(match err {
86 OperationError::Operation(failure) => {
87 OperationError::Operation(AnyFailure(Arc::new(failure)))
88 }
89 OperationError::Internal(err) => OperationError::Internal(err),
90 OperationError::Unhandled => OperationError::Unhandled,
91 }),
92 });
93
94 let pair = ObjectOperationPair::from_types::<O, D>();
95
96 self.operation_handlers.insert(pair, wrapped);
97
98 self.metadata.register_operation::<O, D>();
99
100 self
101 }
102
103 /// Register a [`GiteratedObjectValue<O>`] type with the runtime, providing
104 /// its associated handler for [`GetValue`].
105 ///
106 /// # Type Registration
107 /// This will register the provided [`GiteratedObjectValue`] type for its matching / specified
108 /// object type. It will **not** register the object type automatically.
109 pub fn dynamic_value<O, A, F>(&mut self, handler: F) -> &mut Self
110 where
111 O: MaybeDynamicObject + 'static,
112 F: IntoGiteratedHandler<
113 (O, String),
114 A,
115 S,
116 OS,
117 Result<AnyValue, OperationError<anyhow::Error>>,
118 > + Send
119 + Sync,
120 F: 'static,
121 {
122 let wrapped = HandlerWrapper::new(self.state.clone(), handler);
123
124 let wrapped = wrapped.map(|(any_object, name): &(AnyObject, String), _state: &OS| {
125 Ok((O::from_any(any_object), name.clone()))
126 });
127
128 let wrapped = wrapped.map_return(|ret_val, _state| match ret_val {
129 Ok(success) => Ok(success.into_any()),
130 Err(err) => Err(match err {
131 OperationError::Operation(failure) => OperationError::Internal(failure.into()),
132 OperationError::Internal(err) => OperationError::Internal(err),
133 OperationError::Unhandled => OperationError::Unhandled,
134 }),
135 });
136
137 assert!(self
138 .value_getters
139 .insert(
140 ObjectValuePair {
141 object_kind: O::object_name(),
142 value_kind: "any"
143 },
144 wrapped
145 )
146 .is_none());
147
148 self
149 }
150
151 pub fn value_change<O, A, F, V>(&mut self, handler: F) -> &mut Self
152 where
153 F: IntoGiteratedHandler<(O, V), A, S, OS, Result<(), OperationError<anyhow::Error>>>
154 + Send
155 + Sync,
156 V: MaybeDynamicValue + Clone + 'static,
157 O: 'static + MaybeDynamicObject,
158 V: 'static,
159 F: 'static,
160 {
161 let wrapped = HandlerWrapper::new(self.state.clone(), handler);
162
163 let wrapped = wrapped.map(
164 |(any_object, any_value): &(AnyObject, AnyValue), _state: &OS| {
165 Ok((O::from_any(any_object), V::from_any(any_value)))
166 },
167 );
168
169 assert!(self
170 .value_change
171 .insert(
172 ObjectValuePair {
173 object_kind: O::object_name(),
174 value_kind: V::value_name()
175 },
176 wrapped
177 )
178 .is_none());
179
180 self
181 }
182
183 pub fn object_metadata_provider(&mut self, provider: Box<dyn MetadataProvider>) -> &mut Self {
184 self.metadata_providers.push(provider);
185
186 self
187 }
188
189 /// Register a [`GiteratedObject`] type with the runtime.
190 ///
191 /// # Type Registration
192 /// This will register the provided object type.
193 pub fn object<O: GiteratedObject + 'static>(&mut self) -> &mut Self
194 where
195 GiteratedStack<OS>: HandlerResolvable<(Instance, ObjectRequest), OS>,
196 <GiteratedStack<OS> as HandlerResolvable<(Instance, ObjectRequest), OS>>::Error:
197 Into<Error>,
198 {
199 self.metadata.register_object::<O>();
200
201 // Insert handler so ObjectRequest is handled properly
202
203 self.operation(
204 move |_object: Instance,
205 operation: ObjectRequest,
206 _state: S,
207 stack: GiteratedStack<OS>| {
208 let operation = operation.clone();
209 async move {
210 for (_object_name, object_meta) in stack.inner.metadata.objects.iter() {
211 if (object_meta.from_str)(&operation.0).is_ok() {
212 return Ok(ObjectResponse(operation.0.clone()));
213 }
214 }
215
216 Err(OperationError::Unhandled)
217 }
218 .boxed_local()
219 },
220 );
221
222 self
223 }
224 }
225
226 impl<S: Send + Sync + Clone + 'static> SubstackBuilder<S, StackOperationState> {
227 /// Register a [`Setting`] type with the runtime.
228 ///
229 /// # Type Registration
230 /// This will register the provided setting type.
231 pub fn setting<O: GiteratedObject + 'static, T: Setting + 'static + Clone>(
232 &mut self,
233 ) -> &mut Self {
234 self.metadata.register_setting::<O, T>();
235
236 self
237 }
238
239 /// Register a [`GiteratedObjectValue`] that is also a [`Setting`], which
240 /// allows for automatic value updates.
241 pub fn value_setting<
242 O: GiteratedObject + 'static + Clone,
243 T: GiteratedObjectValue<Object = O> + Setting + 'static + Clone,
244 >(
245 &mut self,
246 ) -> &mut Self {
247 self.metadata.register_setting::<O, T>();
248 self.metadata.register_value::<O, T>();
249
250 self.setting_change.insert(
251 ObjectSettingPair::from_types::<O, T>(),
252 HandlerWrapper::new(
253 (),
254 move |object: AnyObject,
255 setting: AnySetting,
256 _state: _,
257 OperationState(operation_state): OperationState<StackOperationState>,
258 stack: GiteratedStack<StackOperationState>| {
259 trace!(
260 "value setting updated {}::{}",
261 O::object_name(),
262 T::value_name()
263 );
264 let object = object.clone();
265 async move {
266 let object = object.downcast_ref::<O>().unwrap();
267 let setting = setting.downcast_ref::<T>().unwrap();
268 stack
269 .value_update(
270 object.clone(),
271 AnyValue::new(setting.clone()),
272 &operation_state,
273 )
274 .await;
275 Ok(())
276 }
277 .boxed_local()
278 },
279 ),
280 );
281
282 let wrapped = HandlerWrapper::new(
283 self.state.clone(),
284 |object: AnyObject,
285 _name: String,
286 _state: _,
287 stack: GiteratedStack<StackOperationState>| {
288 info!("a setting handler called");
289 let object = object.clone();
290 async move {
291 match stack
292 .new_get_setting::<O, T>(object.downcast_ref().unwrap())
293 .await
294 {
295 Ok(setting) => Ok(AnyValue::new(setting)),
296 Err(err) => {
297 panic!("Error: {:?}", err);
298 }
299 }
300 }
301 .boxed_local()
302 },
303 );
304
305 self.value_getters
306 .insert(ObjectValuePair::from_types::<O, T>(), wrapped);
307
308 self
309 }
310 }
311
312 // Placeholder
313 impl<S: Send + Sync + Clone + 'static, OS> SubstackBuilder<S, OS> {
314 pub fn dynamic_operation<A, H>(&mut self, handler: H) -> &mut Self
315 where
316 H: IntoGiteratedHandler<
317 (AnyObject, AnyOperation),
318 A,
319 S,
320 OS,
321 Result<AnySuccess, OperationError<AnyFailure>>,
322 > + Send
323 + Sync
324 + 'static,
325 OS: Clone + Send + Sync + 'static,
326 {
327 let wrapped = HandlerWrapper::new(self.state.clone(), handler);
328
329 self.operation_handlers.insert(
330 ObjectOperationPair {
331 object_name: "any",
332 operation_name: "any",
333 },
334 wrapped,
335 );
336
337 self
338 }
339 }
340 #[derive(Debug, Clone, thiserror::Error)]
341 #[error("downcast error")]
342 pub struct DowncastError;
343