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

ambee/giterated

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

Fixes

Amber - ⁨2⁩ years ago

parent: tbd commit: ⁨b87f0a3

⁨giterated-daemon/src/database_backend/handler.rs⁩ - ⁨8836⁩ bytes
Raw
1 use std::{collections::HashMap, pin::Pin, sync::Arc};
2
3 use futures_util::{future::BoxFuture, Future, FutureExt};
4 use giterated_models::{
5 error::{GetValueError, OperationError, UserError},
6 object::{AnyObject, GiteratedObject},
7 operation::{AnyOperation, GiteratedOperation},
8 repository::{Repository, RepositorySummary},
9 settings::{AnySetting, GetSetting, GetSettingError, SetSetting, SetSettingError},
10 user::{User, UserRepositoriesRequest},
11 value::{AnyValue, GetValue},
12 };
13
14 use super::DatabaseBackend;
15
16 #[async_trait::async_trait]
17 pub trait GiteratedOperationHandler<
18 O: GiteratedObject,
19 D: GiteratedOperation<O>,
20 S: Send + Sync + Clone,
21 >
22 {
23 fn operation_name(&self) -> &str;
24 fn object_name(&self) -> &str;
25
26 async fn handle(
27 &self,
28 object: &O,
29 operation: D,
30 state: S,
31 ) -> Result<D::Success, OperationError<D::Failure>>;
32 }
33
34 #[async_trait::async_trait]
35 impl<O, D, F, S> GiteratedOperationHandler<O, D, S> for F
36 where
37 F: FnMut(
38 &O,
39 D,
40 S,
41 ) -> Pin<
42 Box<dyn Future<Output = Result<D::Success, OperationError<D::Failure>>> + Send>,
43 > + Send
44 + Sync
45 + Clone,
46 O: GiteratedObject + Send + Sync,
47 D: GiteratedOperation<O> + 'static,
48 <D as GiteratedOperation<O>>::Failure: Send,
49 S: Send + Sync + Clone + 'static,
50 {
51 fn operation_name(&self) -> &str {
52 D::operation_name()
53 }
54
55 fn object_name(&self) -> &str {
56 O::object_name()
57 }
58
59 async fn handle(
60 &self,
61 object: &O,
62 operation: D,
63 state: S,
64 ) -> Result<D::Success, OperationError<D::Failure>> {
65 self.clone()(object, operation, state).await
66 }
67 }
68
69 pub struct OperationWrapper<S: Send + Sync + Clone>(
70 Box<
71 dyn Fn(
72 AnyObject,
73 AnyOperation,
74 S,
75 )
76 -> Pin<Box<dyn Future<Output = Result<Vec<u8>, OperationError<Vec<u8>>>> + Send>>
77 + Send
78 + Sync,
79 >,
80 );
81
82 impl<S: Send + Sync + Clone + 'static> OperationWrapper<S> {
83 pub fn new<
84 O: GiteratedObject + Send + Sync,
85 D: GiteratedOperation<O> + 'static,
86 F: GiteratedOperationHandler<O, D, S> + Send + Sync + 'static + Clone,
87 >(
88 handler: F,
89 ) -> Self {
90 let handler = Arc::new(Box::pin(handler));
91 Self(Box::new(move |any_object, any_operation, state| {
92 let handler = handler.clone();
93 async move {
94 let handler = handler.clone();
95 let object: O = O::from_object_str(&any_object.0).unwrap();
96 let operation: D = serde_json::from_value(any_operation.0.clone()).unwrap();
97
98 let result = handler.handle(&object, operation, state).await;
99 result
100 .map(|success| serde_json::to_vec(&success).unwrap())
101 .map_err(|err| match err {
102 OperationError::Operation(err) => {
103 OperationError::Operation(serde_json::to_vec(&err).unwrap())
104 }
105 OperationError::Internal(internal) => OperationError::Internal(internal),
106 OperationError::Unhandled => OperationError::Unhandled,
107 })
108 }
109 .boxed()
110 }))
111 }
112
113 async fn handle(
114 &mut self,
115 object: AnyObject,
116 operation: AnyOperation,
117 state: S,
118 ) -> Result<Vec<u8>, OperationError<Vec<u8>>> {
119 self.0(object, operation, state).await
120 }
121 }
122
123 pub fn user_get_repositories(
124 object: &User,
125 operation: UserRepositoriesRequest,
126 state: DatabaseBackend,
127 ) -> BoxFuture<'static, Result<Vec<RepositorySummary>, OperationError<UserError>>> {
128 let object = object.clone();
129
130 async move {
131 let mut repositories_backend = state.repository_backend.lock().await;
132 let repositories = repositories_backend
133 .repositories_for_user(None, &object)
134 .await
135 .map_err(|e| OperationError::Internal(e.to_string()))?;
136
137 Ok(repositories)
138 }
139 .boxed()
140 }
141
142 pub fn user_get_value(
143 object: &User,
144 operation: GetValue<AnyValue<User>>,
145 state: DatabaseBackend,
146 ) -> BoxFuture<'static, Result<AnyValue<User>, OperationError<GetValueError>>> {
147 let object = object.clone();
148
149 async move {
150 let mut user_backend = state.user_backend.lock().await;
151 let value = user_backend
152 .get_value(&object, &operation.value_name)
153 .await
154 .map_err(|e| OperationError::Internal(e.to_string()))?;
155
156 Ok(value)
157 }
158 .boxed()
159 }
160
161 pub fn user_get_setting(
162 object: &User,
163 operation: GetSetting<AnySetting>,
164 state: DatabaseBackend,
165 ) -> BoxFuture<'static, Result<AnySetting, OperationError<GetSettingError>>> {
166 let object = object.clone();
167
168 async move {
169 let mut user_backend = state.user_backend.lock().await;
170 let value = user_backend
171 .get_setting(&object, &operation.setting_name)
172 .await
173 .map_err(|e| OperationError::Internal(e.to_string()))?;
174
175 Ok(value)
176 }
177 .boxed()
178 }
179
180 pub fn user_set_setting(
181 object: &User,
182 operation: SetSetting<AnySetting>,
183 state: DatabaseBackend,
184 ) -> BoxFuture<'static, Result<(), OperationError<SetSettingError>>> {
185 let object = object.clone();
186
187 async move {
188 let mut user_backend = state.user_backend.lock().await;
189 let value = user_backend
190 .write_setting(&object, &operation.setting_name, &operation.value.0)
191 .await
192 .map_err(|e| OperationError::Internal(e.to_string()))?;
193
194 Ok(value)
195 }
196 .boxed()
197 }
198
199 pub fn repository_get_value(
200 object: &Repository,
201 operation: GetValue<AnyValue<Repository>>,
202 state: DatabaseBackend,
203 ) -> BoxFuture<'static, Result<AnyValue<Repository>, OperationError<GetValueError>>> {
204 let object = object.clone();
205
206 async move {
207 let mut repository_backend = state.repository_backend.lock().await;
208 let value = repository_backend
209 .get_value(&object, &operation.value_name)
210 .await
211 .map_err(|e| OperationError::Internal(e.to_string()))?;
212
213 Ok(value)
214 }
215 .boxed()
216 }
217
218 pub fn repository_get_setting(
219 object: &Repository,
220 operation: GetSetting<AnySetting>,
221 state: DatabaseBackend,
222 ) -> BoxFuture<'static, Result<AnySetting, OperationError<GetSettingError>>> {
223 let object = object.clone();
224
225 async move {
226 let mut repository_backend = state.repository_backend.lock().await;
227 let value = repository_backend
228 .get_setting(&object, &operation.setting_name)
229 .await
230 .map_err(|e| OperationError::Internal(e.to_string()))?;
231
232 Ok(value)
233 }
234 .boxed()
235 }
236
237 pub fn repository_set_setting(
238 object: &Repository,
239 operation: SetSetting<AnySetting>,
240 state: DatabaseBackend,
241 ) -> BoxFuture<'static, Result<(), OperationError<SetSettingError>>> {
242 let object = object.clone();
243
244 async move {
245 let mut repository_backend = state.repository_backend.lock().await;
246 let value = repository_backend
247 .write_setting(&object, &operation.setting_name, &operation.value.0)
248 .await
249 .map_err(|e| OperationError::Internal(e.to_string()))?;
250
251 Ok(value)
252 }
253 .boxed()
254 }
255
256 pub struct OperationHandlers<S: Send + Sync + Clone> {
257 operations: HashMap<String, OperationWrapper<S>>,
258 }
259
260 impl<S: Send + Sync + Clone> Default for OperationHandlers<S> {
261 fn default() -> Self {
262 Self {
263 operations: HashMap::new(),
264 }
265 }
266 }
267
268 impl<S: Send + Sync + Clone + 'static> OperationHandlers<S> {
269 pub fn insert<
270 O: GiteratedObject + Send + Sync,
271 D: GiteratedOperation<O> + 'static,
272 H: GiteratedOperationHandler<O, D, S> + Send + Sync + 'static + Clone,
273 >(
274 &mut self,
275 handler: H,
276 ) -> &mut Self {
277 let operation_name = handler.operation_name().to_string();
278
279 let wrapped = OperationWrapper::new(handler);
280
281 self.operations.insert(operation_name, wrapped);
282
283 self
284 }
285
286 pub async fn handle<O: GiteratedObject>(
287 &mut self,
288 object: &O,
289 operation_name: &str,
290 operation: AnyOperation,
291 state: S,
292 ) -> Result<Vec<u8>, OperationError<Vec<u8>>> {
293 if let Some(handler) = self.operations.get_mut(operation_name) {
294 handler
295 .handle(AnyObject(object.to_string()), operation, state)
296 .await
297 } else {
298 Err(OperationError::Internal(format!(
299 "unknown operation: {}",
300 operation_name
301 )))
302 }
303 }
304 }
305