Progress on refactor
parent: tbd commit: c9f076f
Showing 20 changed files with 776 insertions and 117 deletions
Cargo.lock
@@ -708,7 +708,6 @@ dependencies = [ | ||
708 | 708 | "tokio", |
709 | 709 | "tokio-tungstenite", |
710 | 710 | "toml", |
711 | "tower", | |
712 | 711 | "tracing", |
713 | 712 | "tracing-subscriber", |
714 | 713 | ] |
@@ -717,19 +716,14 @@ dependencies = [ | ||
717 | 716 | name = "giterated-models" |
718 | 717 | version = "0.1.0" |
719 | 718 | dependencies = [ |
720 | "aes-gcm", | |
721 | 719 | "anyhow", |
722 | "argon2", | |
723 | 720 | "async-trait", |
724 | 721 | "base64 0.21.3", |
725 | 722 | "bincode", |
726 | 723 | "chrono", |
727 | "futures-util", | |
728 | 724 | "git2", |
729 | 725 | "jsonwebtoken", |
730 | "log", | |
731 | 726 | "rand", |
732 | "reqwest", | |
733 | 727 | "rsa", |
734 | 728 | "secrecy", |
735 | 729 | "semver", |
@@ -737,12 +731,8 @@ dependencies = [ | ||
737 | 731 | "serde_json", |
738 | 732 | "sqlx", |
739 | 733 | "thiserror", |
740 | "tokio", | |
741 | "tokio-tungstenite", | |
742 | 734 | "toml", |
743 | "tower", | |
744 | 735 | "tracing", |
745 | "tracing-subscriber", | |
746 | 736 | ] |
747 | 737 | |
748 | 738 | [[package]] |
@@ -2401,23 +2391,6 @@ dependencies = [ | ||
2401 | 2391 | ] |
2402 | 2392 | |
2403 | 2393 | [[package]] |
2404 | name = "tower" | |
2405 | version = "0.4.13" | |
2406 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
2407 | checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" | |
2408 | dependencies = [ | |
2409 | "tower-layer", | |
2410 | "tower-service", | |
2411 | "tracing", | |
2412 | ] | |
2413 | ||
2414 | [[package]] | |
2415 | name = "tower-layer" | |
2416 | version = "0.3.2" | |
2417 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
2418 | checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" | |
2419 | ||
2420 | [[package]] | |
2421 | 2394 | name = "tower-service" |
2422 | 2395 | version = "0.3.2" |
2423 | 2396 | source = "registry+https://github.com/rust-lang/crates.io-index" |
giterated-daemon/Cargo.toml
@@ -22,7 +22,6 @@ reqwest = "*" | ||
22 | 22 | argon2 = "*" |
23 | 23 | aes-gcm = "0.10.2" |
24 | 24 | semver = {version = "*", features = ["serde"]} |
25 | tower = "*" | |
26 | 25 | giterated-models = { path = "../giterated-models" } |
27 | 26 | giterated-api = { path = "../../giterated-api" } |
28 | 27 | deadpool = "*" |
giterated-daemon/src/backend/mod.rs
@@ -16,6 +16,7 @@ use giterated_models::{ | ||
16 | 16 | repository::{ |
17 | 17 | IssueLabel, Repository, RepositoryIssue, RepositorySummary, RepositoryTreeEntry, |
18 | 18 | }, |
19 | settings::AnySetting, | |
19 | 20 | user::User, |
20 | 21 | }, |
21 | 22 | operation::{ |
@@ -25,10 +26,11 @@ use giterated_models::{ | ||
25 | 26 | RepositoryIssuesCountRequest, RepositoryIssuesRequest, |
26 | 27 | }, |
27 | 28 | }, |
29 | values::AnyValue, | |
28 | 30 | }; |
29 | 31 | |
30 | 32 | #[async_trait] |
31 | pub trait RepositoryBackend: IssuesBackend { | |
33 | pub trait RepositoryBackend { | |
32 | 34 | async fn create_repository( |
33 | 35 | &mut self, |
34 | 36 | user: &User, |
@@ -81,6 +83,14 @@ pub trait AuthBackend { | ||
81 | 83 | |
82 | 84 | #[async_trait::async_trait] |
83 | 85 | pub trait UserBackend: AuthBackend { |
86 | async fn get_value(&mut self, user: &User, name: &str) -> Result<AnyValue<User>, Error>; | |
87 | async fn get_setting(&mut self, user: &User, name: &str) -> Result<AnySetting, Error>; | |
88 | async fn write_setting( | |
89 | &mut self, | |
90 | user: &User, | |
91 | name: &str, | |
92 | setting: &Value, | |
93 | ) -> Result<(), Error>; | |
84 | 94 | async fn exists(&mut self, user: &User) -> Result<bool, Error>; |
85 | 95 | } |
86 | 96 |
giterated-daemon/src/backend/user.rs
@@ -6,8 +6,12 @@ use aes_gcm::{aead::Aead, AeadCore, Aes256Gcm, Key, KeyInit}; | ||
6 | 6 | use argon2::{password_hash::SaltString, Argon2, PasswordHash, PasswordHasher, PasswordVerifier}; |
7 | 7 | use base64::{engine::general_purpose::STANDARD, Engine as _}; |
8 | 8 | use giterated_models::{ |
9 | model::{authenticated::UserAuthenticationToken, instance::Instance, user::User}, | |
9 | model::{ | |
10 | authenticated::UserAuthenticationToken, instance::Instance, settings::AnySetting, | |
11 | user::User, | |
12 | }, | |
10 | 13 | operation::instance::{AuthenticationTokenRequest, RegisterAccountRequest}, |
14 | values::AnyValue, | |
11 | 15 | }; |
12 | 16 | use rsa::{ |
13 | 17 | pkcs8::{EncodePrivateKey, EncodePublicKey}, |
@@ -16,6 +20,7 @@ use rsa::{ | ||
16 | 20 | }; |
17 | 21 | |
18 | 22 | use secrecy::ExposeSecret; |
23 | use serde_json::Value; | |
19 | 24 | use sqlx::PgPool; |
20 | 25 | use tokio::sync::Mutex; |
21 | 26 | |
@@ -48,6 +53,20 @@ impl UserAuth { | ||
48 | 53 | |
49 | 54 | #[async_trait::async_trait] |
50 | 55 | impl UserBackend for UserAuth { |
56 | async fn get_value(&mut self, _user: &User, _name: &str) -> Result<AnyValue<User>, Error> { | |
57 | todo!() | |
58 | } | |
59 | async fn get_setting(&mut self, _user: &User, _name: &str) -> Result<AnySetting, Error> { | |
60 | todo!() | |
61 | } | |
62 | async fn write_setting( | |
63 | &mut self, | |
64 | _user: &User, | |
65 | _name: &str, | |
66 | _setting: &Value, | |
67 | ) -> Result<(), Error> { | |
68 | todo!() | |
69 | } | |
51 | 70 | async fn exists(&mut self, user: &User) -> Result<bool, Error> { |
52 | 71 | Ok(sqlx::query_as!( |
53 | 72 | UserRow, |
giterated-daemon/src/cache_backend.rs
@@ -0,0 +1,27 @@ | ||
1 | use giterated_models::{ | |
2 | error::OperationError, | |
3 | operation::{GiteratedObject, GiteratedOperation, Object, ObjectBackend, ObjectRequestError}, | |
4 | }; | |
5 | use std::fmt::Debug; | |
6 | ||
7 | #[derive(Clone, Debug)] | |
8 | pub struct CacheBackend; | |
9 | ||
10 | #[async_trait::async_trait] | |
11 | impl ObjectBackend for CacheBackend { | |
12 | async fn object_operation<O: GiteratedObject + Debug, D: GiteratedOperation<O> + Debug>( | |
13 | &self, | |
14 | _object: O, | |
15 | _operation: D, | |
16 | ) -> Result<D::Success, OperationError<D::Failure>> { | |
17 | // We don't handle operations with this backend | |
18 | Err(OperationError::Unhandled) | |
19 | } | |
20 | ||
21 | async fn get_object<O: GiteratedObject + Debug>( | |
22 | &self, | |
23 | _object_str: &str, | |
24 | ) -> Result<Object<O, Self>, OperationError<ObjectRequestError>> { | |
25 | Err(OperationError::Unhandled) | |
26 | } | |
27 | } |
giterated-daemon/src/connection/wrapper.rs
@@ -5,7 +5,10 @@ use std::{ | ||
5 | 5 | |
6 | 6 | use anyhow::Error; |
7 | 7 | use futures_util::{SinkExt, StreamExt}; |
8 | use giterated_models::model::instance::Instance; | |
8 | use giterated_models::{ | |
9 | model::{authenticated::AuthenticatedPayload, instance::Instance}, | |
10 | operation::{AnyObject, AnyOperation, GiteratedMessage, ObjectBackend}, | |
11 | }; | |
9 | 12 | |
10 | 13 | use serde::Serialize; |
11 | 14 | |
@@ -16,6 +19,7 @@ use toml::Table; | ||
16 | 19 | use crate::{ |
17 | 20 | authentication::AuthenticationTokenGranter, |
18 | 21 | backend::{RepositoryBackend, SettingsBackend, UserBackend}, |
22 | database_backend::Foobackend, | |
19 | 23 | federation::connections::InstanceConnections, |
20 | 24 | keys::PublicKeyCache, |
21 | 25 | }; |
@@ -34,7 +38,7 @@ pub async fn connection_wrapper( | ||
34 | 38 | instance_connections: Arc<Mutex<InstanceConnections>>, |
35 | 39 | config: Table, |
36 | 40 | ) { |
37 | let _connection_state = ConnectionState { | |
41 | let connection_state = ConnectionState { | |
38 | 42 | socket: Arc::new(Mutex::new(socket)), |
39 | 43 | connections, |
40 | 44 | repository_backend, |
@@ -51,6 +55,42 @@ pub async fn connection_wrapper( | ||
51 | 55 | |
52 | 56 | let _handshaked = false; |
53 | 57 | |
58 | loop { | |
59 | let mut socket = connection_state.socket.lock().await; | |
60 | let message = socket.next().await; | |
61 | drop(socket); | |
62 | ||
63 | match message { | |
64 | Some(Ok(message)) => { | |
65 | let payload = match message { | |
66 | Message::Binary(payload) => payload, | |
67 | Message::Ping(_) => { | |
68 | let mut socket = connection_state.socket.lock().await; | |
69 | let _ = socket.send(Message::Pong(vec![])).await; | |
70 | drop(socket); | |
71 | continue; | |
72 | } | |
73 | Message::Close(_) => return, | |
74 | _ => continue, | |
75 | }; | |
76 | ||
77 | let message: AuthenticatedPayload = bincode::deserialize(&payload).unwrap(); | |
78 | ||
79 | let message: GiteratedMessage<AnyObject, AnyOperation> = message.into_message(); | |
80 | ||
81 | let backend = Foobackend {}; | |
82 | ||
83 | backend | |
84 | .object_operation(message.object, message.payload) | |
85 | .await | |
86 | .unwrap(); | |
87 | } | |
88 | _ => { | |
89 | return; | |
90 | } | |
91 | } | |
92 | } | |
93 | ||
54 | 94 | // loop { |
55 | 95 | // let mut socket = connection_state.socket.lock().await; |
56 | 96 | // let message = socket.next().await; |
giterated-daemon/src/database_backend/handler.rs
@@ -0,0 +1,238 @@ | ||
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}, | |
6 | model::{repository::Repository, settings::AnySetting, user::User}, | |
7 | operation::{AnyObject, AnyOperation, GetValue, GiteratedObject, GiteratedOperation}, | |
8 | values::{AnyValue, GetSetting, GetSettingError, SetSetting, SetSettingError}, | |
9 | }; | |
10 | ||
11 | use super::DatabaseBackend; | |
12 | ||
13 | #[async_trait::async_trait] | |
14 | pub trait GiteratedOperationHandler< | |
15 | O: GiteratedObject, | |
16 | D: GiteratedOperation<O>, | |
17 | S: Send + Sync + Clone, | |
18 | > | |
19 | { | |
20 | fn operation_name(&self) -> &str; | |
21 | fn object_name(&self) -> &str; | |
22 | ||
23 | async fn handle( | |
24 | &self, | |
25 | object: &O, | |
26 | operation: D, | |
27 | state: S, | |
28 | ) -> Result<D::Success, OperationError<D::Failure>>; | |
29 | } | |
30 | ||
31 | #[async_trait::async_trait] | |
32 | impl<O, D, F, S> GiteratedOperationHandler<O, D, S> for F | |
33 | where | |
34 | F: FnMut( | |
35 | &O, | |
36 | D, | |
37 | S, | |
38 | ) -> Pin< | |
39 | Box<dyn Future<Output = Result<D::Success, OperationError<D::Failure>>> + Send>, | |
40 | > + Send | |
41 | + Sync | |
42 | + Clone, | |
43 | O: GiteratedObject + Send + Sync, | |
44 | D: GiteratedOperation<O> + 'static, | |
45 | <D as GiteratedOperation<O>>::Failure: Send, | |
46 | S: Send + Sync + Clone + 'static, | |
47 | { | |
48 | fn operation_name(&self) -> &str { | |
49 | D::operation_name() | |
50 | } | |
51 | ||
52 | fn object_name(&self) -> &str { | |
53 | O::object_name() | |
54 | } | |
55 | ||
56 | async fn handle( | |
57 | &self, | |
58 | object: &O, | |
59 | operation: D, | |
60 | state: S, | |
61 | ) -> Result<D::Success, OperationError<D::Failure>> { | |
62 | self.clone()(object, operation, state).await | |
63 | } | |
64 | } | |
65 | ||
66 | pub struct OperationWrapper<S: Send + Sync + Clone>( | |
67 | Box< | |
68 | dyn Fn( | |
69 | AnyObject, | |
70 | AnyOperation, | |
71 | S, | |
72 | ) | |
73 | -> Pin<Box<dyn Future<Output = Result<Vec<u8>, OperationError<Vec<u8>>>> + Send>> | |
74 | + Send | |
75 | + Sync, | |
76 | >, | |
77 | ); | |
78 | ||
79 | impl<S: Send + Sync + Clone + 'static> OperationWrapper<S> { | |
80 | pub fn new< | |
81 | O: GiteratedObject + Send + Sync, | |
82 | D: GiteratedOperation<O> + 'static, | |
83 | F: GiteratedOperationHandler<O, D, S> + Send + Sync + 'static + Clone, | |
84 | >( | |
85 | handler: F, | |
86 | ) -> Self { | |
87 | let handler = Arc::new(Box::pin(handler)); | |
88 | Self(Box::new(move |any_object, any_operation, state| { | |
89 | let handler = handler.clone(); | |
90 | async move { | |
91 | let handler = handler.clone(); | |
92 | let object: O = O::from_object_str(&any_object.0).unwrap(); | |
93 | let operation: D = serde_json::from_value(any_operation.0.clone()).unwrap(); | |
94 | ||
95 | let result = handler.handle(&object, operation, state).await; | |
96 | result | |
97 | .map(|success| serde_json::to_vec(&success).unwrap()) | |
98 | .map_err(|err| match err { | |
99 | OperationError::Operation(err) => { | |
100 | OperationError::Operation(serde_json::to_vec(&err).unwrap()) | |
101 | } | |
102 | OperationError::Internal(internal) => OperationError::Internal(internal), | |
103 | OperationError::Unhandled => OperationError::Unhandled, | |
104 | }) | |
105 | } | |
106 | .boxed() | |
107 | })) | |
108 | } | |
109 | ||
110 | async fn handle( | |
111 | &mut self, | |
112 | object: AnyObject, | |
113 | operation: AnyOperation, | |
114 | state: S, | |
115 | ) -> Result<Vec<u8>, OperationError<Vec<u8>>> { | |
116 | self.0(object, operation, state).await | |
117 | } | |
118 | } | |
119 | ||
120 | fn test_operation( | |
121 | _object: &User, | |
122 | _operation: SetSetting<AnySetting>, | |
123 | _state: (), | |
124 | ) -> Pin<Box<dyn Future<Output = Result<(), OperationError<SetSettingError>>> + Send + 'static>> { | |
125 | todo!() | |
126 | } | |
127 | ||
128 | fn foo() {} | |
129 | ||
130 | pub fn user_get_value( | |
131 | object: &User, | |
132 | operation: GetValue<AnyValue<User>>, | |
133 | state: DatabaseBackend, | |
134 | ) -> BoxFuture<'static, Result<AnyValue<User>, OperationError<GetValueError>>> { | |
135 | let object = object.clone(); | |
136 | ||
137 | async move { | |
138 | let mut user_backend = state.user_backend.lock().await; | |
139 | let value = user_backend | |
140 | .get_value(&object, &operation.value_name) | |
141 | .await | |
142 | .map_err(|e| OperationError::Internal(e.to_string()))?; | |
143 | ||
144 | Ok(value) | |
145 | } | |
146 | .boxed() | |
147 | } | |
148 | ||
149 | pub fn user_get_setting( | |
150 | _object: &User, | |
151 | _operation: GetSetting<AnySetting>, | |
152 | _state: DatabaseBackend, | |
153 | ) -> BoxFuture<'static, Result<AnySetting, OperationError<GetSettingError>>> { | |
154 | todo!() | |
155 | } | |
156 | ||
157 | pub fn user_set_setting( | |
158 | _object: &User, | |
159 | _operation: SetSetting<AnySetting>, | |
160 | _state: DatabaseBackend, | |
161 | ) -> BoxFuture<'static, Result<(), OperationError<SetSettingError>>> { | |
162 | todo!() | |
163 | } | |
164 | ||
165 | pub fn repository_get_value( | |
166 | _object: &Repository, | |
167 | _operation: GetValue<AnyValue<Repository>>, | |
168 | _state: DatabaseBackend, | |
169 | ) -> BoxFuture<'static, Result<AnyValue<Repository>, OperationError<GetValueError>>> { | |
170 | todo!() | |
171 | } | |
172 | ||
173 | pub fn repository_get_setting( | |
174 | _object: &Repository, | |
175 | _operation: GetSetting<AnySetting>, | |
176 | _state: DatabaseBackend, | |
177 | ) -> BoxFuture<'static, Result<AnySetting, OperationError<GetSettingError>>> { | |
178 | todo!() | |
179 | } | |
180 | ||
181 | pub fn repository_set_setting( | |
182 | _object: &Repository, | |
183 | _operation: SetSetting<AnySetting>, | |
184 | _state: DatabaseBackend, | |
185 | ) -> BoxFuture<'static, Result<(), OperationError<SetSettingError>>> { | |
186 | todo!() | |
187 | } | |
188 | ||
189 | pub struct OperationHandlers<S: Send + Sync + Clone> { | |
190 | operations: HashMap<String, OperationWrapper<S>>, | |
191 | } | |
192 | ||
193 | impl<S: Send + Sync + Clone> Default for OperationHandlers<S> { | |
194 | fn default() -> Self { | |
195 | Self { | |
196 | operations: HashMap::new(), | |
197 | } | |
198 | } | |
199 | } | |
200 | ||
201 | impl<S: Send + Sync + Clone + 'static> OperationHandlers<S> { | |
202 | pub fn insert< | |
203 | O: GiteratedObject + Send + Sync, | |
204 | D: GiteratedOperation<O> + 'static, | |
205 | H: GiteratedOperationHandler<O, D, S> + Send + Sync + 'static + Clone, | |
206 | >( | |
207 | &mut self, | |
208 | handler: H, | |
209 | ) -> &mut Self { | |
210 | let operation_name = handler.operation_name().to_string(); | |
211 | ||
212 | let wrapped = OperationWrapper::new(handler); | |
213 | ||
214 | self.operations.insert(operation_name, wrapped); | |
215 | ||
216 | self | |
217 | } | |
218 | ||
219 | pub async fn handle<O: GiteratedObject>( | |
220 | &mut self, | |
221 | object: &O, | |
222 | operation_name: &str, | |
223 | operation: AnyOperation, | |
224 | state: S, | |
225 | ) -> Result<Vec<u8>, OperationError<Vec<u8>>> { | |
226 | if let Some(handler) = self.operations.get_mut(operation_name) { | |
227 | handler | |
228 | .handle( | |
229 | AnyObject(serde_json::to_string(object).unwrap()), | |
230 | operation, | |
231 | state, | |
232 | ) | |
233 | .await | |
234 | } else { | |
235 | panic!() | |
236 | } | |
237 | } | |
238 | } |
giterated-daemon/src/database_backend/mod.rs
@@ -1,16 +1,23 @@ | ||
1 | pub mod handler; | |
2 | ||
1 | 3 | use std::{str::FromStr, sync::Arc}; |
2 | 4 | |
5 | use futures_util::TryFutureExt; | |
3 | 6 | use giterated_models::{ |
4 | 7 | error::OperationError, |
5 | 8 | model::{instance::Instance, repository::Repository, user::User}, |
6 | 9 | operation::{GiteratedObject, GiteratedOperation, Object, ObjectBackend, ObjectRequestError}, |
7 | 10 | }; |
8 | use sqlx::PgPool; | |
9 | 11 | use std::fmt::Debug; |
10 | 12 | use tokio::sync::Mutex; |
11 | 13 | |
12 | 14 | use crate::backend::{RepositoryBackend, UserBackend}; |
13 | 15 | |
16 | use self::handler::{ | |
17 | repository_get_setting, repository_get_value, repository_set_setting, user_get_setting, | |
18 | user_get_value, user_set_setting, OperationHandlers, | |
19 | }; | |
20 | ||
14 | 21 | #[derive(Clone, Debug)] |
15 | 22 | pub struct Foobackend {} |
16 | 23 | |
@@ -29,34 +36,78 @@ impl ObjectBackend for Foobackend { | ||
29 | 36 | &self, |
30 | 37 | _object_str: &str, |
31 | 38 | ) -> Result<Object<O, Self>, OperationError<ObjectRequestError>> { |
32 | todo!() | |
39 | Err(OperationError::Unhandled) | |
33 | 40 | } |
34 | 41 | } |
35 | 42 | |
36 | 43 | /// A backend implementation which attempts to resolve data from the instance's database. |
37 | 44 | #[derive(Clone)] |
38 | pub struct DatabaseBackend<'b> { | |
39 | our_instance: Object<'b, Instance, Foobackend>, | |
40 | user_backend: Arc<Mutex<dyn UserBackend + Send>>, | |
41 | repository_backend: Arc<Mutex<dyn RepositoryBackend + Send>>, | |
42 | pool: PgPool, | |
45 | pub struct DatabaseBackend { | |
46 | pub(self) our_instance: Instance, | |
47 | pub(self) user_backend: Arc<Mutex<dyn UserBackend + Send>>, | |
48 | pub(self) repository_backend: Arc<Mutex<dyn RepositoryBackend + Send>>, | |
43 | 49 | } |
44 | 50 | |
45 | impl Debug for DatabaseBackend<'_> { | |
51 | impl Debug for DatabaseBackend { | |
46 | 52 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
47 | 53 | f.debug_struct("DatabaseBackend").finish() |
48 | 54 | } |
49 | 55 | } |
50 | 56 | |
51 | 57 | #[async_trait::async_trait] |
52 | impl<'b> ObjectBackend for DatabaseBackend<'b> { | |
58 | impl ObjectBackend for DatabaseBackend { | |
53 | 59 | async fn object_operation<O: GiteratedObject + Debug, D: GiteratedOperation<O> + Debug>( |
54 | 60 | &self, |
55 | _object: O, | |
56 | _operation: D, | |
61 | object: O, | |
62 | operation: D, | |
57 | 63 | ) -> Result<D::Success, OperationError<D::Failure>> { |
58 | // We don't handle operations with this backend | |
59 | Err(OperationError::Unhandled) | |
64 | let serialized = | |
65 | serde_json::to_value(operation).map_err(|e| OperationError::Internal(e.to_string()))?; | |
66 | let object_name = object.to_string(); | |
67 | ||
68 | if let Ok(user) = User::from_str(&object_name) { | |
69 | let mut handler = OperationHandlers::default(); | |
70 | ||
71 | handler | |
72 | .insert(user_get_value) | |
73 | .insert(user_get_setting) | |
74 | .insert(user_set_setting); | |
75 | ||
76 | match handler | |
77 | .handle( | |
78 | &user, | |
79 | D::operation_name(), | |
80 | serde_json::from_value(serialized.clone()).unwrap(), | |
81 | self.clone(), | |
82 | ) | |
83 | .await | |
84 | { | |
85 | Ok(result) => Ok(serde_json::from_slice(&result) | |
86 | .map_err(|e| OperationError::Internal(e.to_string()))?), | |
87 | Err(err) => match err { | |
88 | OperationError::Internal(internal) => Err(OperationError::Internal(internal)), | |
89 | OperationError::Unhandled => Err(OperationError::Unhandled), | |
90 | OperationError::Operation(err) => Err(OperationError::Operation( | |
91 | serde_json::from_slice(&err) | |
92 | .map_err(|e| OperationError::Internal(e.to_string()))?, | |
93 | )), | |
94 | }, | |
95 | } | |
96 | } else if let Ok(_repository) = Repository::from_str(&object_name) { | |
97 | let mut handler = OperationHandlers::default(); | |
98 | ||
99 | handler | |
100 | .insert(repository_get_value) | |
101 | .insert(repository_get_setting) | |
102 | .insert(repository_set_setting); | |
103 | ||
104 | // handler.handle(&repository, D::operation_name(), bincode::deserialize(&serialized).unwrap(), DatabaseBackendState).await; | |
105 | todo!() | |
106 | } else if Instance::from_str(&object_name).is_ok() { | |
107 | Err(OperationError::Unhandled) | |
108 | } else { | |
109 | Err(OperationError::Unhandled) | |
110 | } | |
60 | 111 | } |
61 | 112 | |
62 | 113 | async fn get_object<O: GiteratedObject + Debug>( |
@@ -107,3 +158,129 @@ impl<'b> ObjectBackend for DatabaseBackend<'b> { | ||
107 | 158 | } |
108 | 159 | } |
109 | 160 | } |
161 | ||
162 | mod test { | |
163 | use std::{str::FromStr, sync::Arc}; | |
164 | ||
165 | use anyhow::Error; | |
166 | use giterated_models::{ | |
167 | model::{ | |
168 | authenticated::UserAuthenticationToken, | |
169 | instance::Instance, | |
170 | repository::{Repository, RepositorySummary, RepositoryTreeEntry}, | |
171 | settings::AnySetting, | |
172 | user::User, | |
173 | }, | |
174 | operation::{ | |
175 | instance::{ | |
176 | AuthenticationTokenRequest, RegisterAccountRequest, RepositoryCreateRequest, | |
177 | }, | |
178 | repository::RepositoryFileInspectRequest, | |
179 | GiteratedObjectValue, ObjectBackend, | |
180 | }, | |
181 | values::{user::DisplayName, AnyValue}, | |
182 | }; | |
183 | use serde_json::Value; | |
184 | use tokio::sync::Mutex; | |
185 | ||
186 | use crate::backend::{git::GitBackendError, AuthBackend, RepositoryBackend, UserBackend}; | |
187 | ||
188 | use super::DatabaseBackend; | |
189 | pub struct TestUserDatabaseBackend; | |
190 | ||
191 | #[async_trait::async_trait] | |
192 | impl UserBackend for TestUserDatabaseBackend { | |
193 | async fn get_value(&mut self, _user: &User, name: &str) -> Result<AnyValue<User>, Error> { | |
194 | assert_eq!(name, DisplayName::value_name()); | |
195 | ||
196 | Ok(serde_json::from_slice( | |
197 | &serde_json::to_vec(&DisplayName(String::from("test"))).unwrap(), | |
198 | ) | |
199 | .unwrap()) | |
200 | } | |
201 | async fn get_setting(&mut self, _user: &User, _name: &str) -> Result<AnySetting, Error> { | |
202 | todo!() | |
203 | } | |
204 | async fn write_setting( | |
205 | &mut self, | |
206 | _user: &User, | |
207 | _name: &str, | |
208 | _setting: &Value, | |
209 | ) -> Result<(), Error> { | |
210 | todo!() | |
211 | } | |
212 | async fn exists(&mut self, user: &User) -> Result<bool, Error> { | |
213 | Ok(user == &User::from_str("test_user:test.giterated.dev").unwrap()) | |
214 | } | |
215 | } | |
216 | ||
217 | #[async_trait::async_trait] | |
218 | impl AuthBackend for TestUserDatabaseBackend { | |
219 | async fn register( | |
220 | &mut self, | |
221 | _request: RegisterAccountRequest, | |
222 | ) -> Result<UserAuthenticationToken, Error> { | |
223 | todo!() | |
224 | } | |
225 | ||
226 | async fn login( | |
227 | &mut self, | |
228 | _source: &Instance, | |
229 | _request: AuthenticationTokenRequest, | |
230 | ) -> Result<UserAuthenticationToken, Error> { | |
231 | todo!() | |
232 | } | |
233 | } | |
234 | ||
235 | pub struct TestUserRepositoryBackend; | |
236 | ||
237 | #[async_trait::async_trait] | |
238 | impl RepositoryBackend for TestUserRepositoryBackend { | |
239 | async fn create_repository( | |
240 | &mut self, | |
241 | _user: &User, | |
242 | _request: &RepositoryCreateRequest, | |
243 | ) -> Result<Repository, GitBackendError> { | |
244 | todo!() | |
245 | } | |
246 | async fn repository_file_inspect( | |
247 | &mut self, | |
248 | _requester: Option<&User>, | |
249 | _request: &RepositoryFileInspectRequest, | |
250 | ) -> Result<Vec<RepositoryTreeEntry>, Error> { | |
251 | todo!() | |
252 | } | |
253 | async fn repositories_for_user( | |
254 | &mut self, | |
255 | _requester: Option<&User>, | |
256 | _user: &User, | |
257 | ) -> Result<Vec<RepositorySummary>, Error> { | |
258 | todo!() | |
259 | } | |
260 | async fn exists(&mut self, _repository: &Repository) -> Result<bool, Error> { | |
261 | todo!() | |
262 | } | |
263 | } | |
264 | ||
265 | fn test_backend() -> DatabaseBackend { | |
266 | DatabaseBackend { | |
267 | our_instance: Instance::from_str("testing.giterated.dev").unwrap(), | |
268 | user_backend: Arc::new(Mutex::new(TestUserDatabaseBackend)) as _, | |
269 | repository_backend: Arc::new(Mutex::new(TestUserRepositoryBackend)) as _, | |
270 | } | |
271 | } | |
272 | ||
273 | #[tokio::test] | |
274 | async fn test_user_get() { | |
275 | let backend = test_backend(); | |
276 | ||
277 | let mut user = backend | |
278 | .get_object::<User>("test_user:test.giterated.dev") | |
279 | .await | |
280 | .expect("object should have been returned"); | |
281 | ||
282 | user.get::<DisplayName>() | |
283 | .await | |
284 | .expect("object value should have been returned"); | |
285 | } | |
286 | } |
giterated-daemon/src/lib.rs
@@ -4,6 +4,7 @@ use semver::{Version, VersionReq}; | ||
4 | 4 | |
5 | 5 | pub mod authentication; |
6 | 6 | pub mod backend; |
7 | pub mod cache_backend; | |
7 | 8 | pub mod connection; |
8 | 9 | pub mod database_backend; |
9 | 10 | pub mod federation; |
giterated-models/Cargo.toml
@@ -6,35 +6,25 @@ edition = "2021" | ||
6 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html |
7 | 7 | |
8 | 8 | [dependencies] |
9 | tokio-tungstenite = "*" | |
10 | tokio = { version = "1.32.0", features = [ "full" ] } | |
11 | 9 | tracing = "*" |
12 | futures-util = "*" | |
13 | 10 | serde = { version = "1.0.188", features = [ "derive" ]} |
14 | 11 | serde_json = "1.0" |
15 | tracing-subscriber = "0.3" | |
16 | 12 | base64 = "0.21.3" |
17 | 13 | jsonwebtoken = { version = "*", features = ["use_pem"]} |
18 | log = "*" | |
19 | 14 | rand = "*" |
20 | 15 | rsa = {version = "0.9", features = ["sha2"]} |
21 | reqwest = "*" | |
22 | argon2 = "*" | |
23 | aes-gcm = "0.10.2" | |
24 | 16 | semver = {version = "*", features = ["serde"]} |
25 | tower = "*" | |
26 | 17 | bincode = "*" |
27 | 18 | secrecy = { version = "0.8.0", features = ["serde"] } |
28 | ||
19 | thiserror = "1" | |
20 | anyhow = "1" | |
29 | 21 | toml = { version = "0.7" } |
30 | ||
22 | # Git backend | |
23 | git2 = "0.17" | |
31 | 24 | chrono = { version = "0.4", features = [ "serde" ] } |
32 | 25 | async-trait = "0.1" |
33 | 26 | |
34 | 27 | # Git backend |
35 | git2 = "0.17" | |
36 | thiserror = "1" | |
37 | anyhow = "1" | |
38 | sqlx = { version = "0.7", features = [ "runtime-tokio", "tls-native-tls", "postgres", "macros", "migrate", "chrono" ] } | |
28 | sqlx = { version = "0.7", default-features = false, features = [ "macros", "chrono" ] } | |
39 | 29 | |
40 | 30 | #uuid = { version = "1.4", features = [ "v4", "serde" ] } |
giterated-models/src/model/authenticated.rs
@@ -8,9 +8,12 @@ use rsa::{ | ||
8 | 8 | RsaPrivateKey, |
9 | 9 | }; |
10 | 10 | use serde::{Deserialize, Serialize}; |
11 | use serde_json::Value; | |
11 | 12 | use tracing::info; |
12 | 13 | |
13 | use crate::operation::{GiteratedMessage, GiteratedObject, GiteratedOperation}; | |
14 | use crate::operation::{ | |
15 | AnyObject, AnyOperation, GiteratedMessage, GiteratedObject, GiteratedOperation, | |
16 | }; | |
14 | 17 | |
15 | 18 | use super::{instance::Instance, user::User, MessageTarget}; |
16 | 19 | |
@@ -27,12 +30,24 @@ pub struct Authenticated<O: GiteratedObject, D: GiteratedOperation<O>> { | ||
27 | 30 | pub message: GiteratedMessage<O, D>, |
28 | 31 | } |
29 | 32 | |
30 | #[derive(Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] | |
33 | #[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)] | |
31 | 34 | pub struct AuthenticatedPayload { |
32 | 35 | pub source: Vec<AuthenticationSource>, |
36 | pub object: String, | |
37 | pub operation: String, | |
33 | 38 | pub payload: Vec<u8>, |
34 | 39 | } |
35 | 40 | |
41 | impl AuthenticatedPayload { | |
42 | pub fn into_message(self) -> GiteratedMessage<AnyObject, AnyOperation> { | |
43 | GiteratedMessage { | |
44 | object: AnyObject(self.object), | |
45 | operation: self.operation, | |
46 | payload: AnyOperation(serde_json::from_slice::<Value>(&self.payload).unwrap()), | |
47 | } | |
48 | } | |
49 | } | |
50 | ||
36 | 51 | // impl<T: Serialize> From<Authenticated<T>> for AuthenticatedPayload { |
37 | 52 | // fn from(mut value: Authenticated<T>) -> Self { |
38 | 53 | // let payload = bincode::serialize(&value.message).unwrap(); |
@@ -103,9 +118,11 @@ impl<O: GiteratedObject, D: GiteratedOperation<O>> Authenticated<O, D> { | ||
103 | 118 | } |
104 | 119 | |
105 | 120 | pub fn into_payload(mut self) -> AuthenticatedPayload { |
106 | let payload = bincode::serialize(&self.message).unwrap(); | |
121 | let payload = bincode::serialize(&self.message.payload).unwrap(); | |
107 | 122 | |
108 | 123 | AuthenticatedPayload { |
124 | object: self.message.object.to_string(), | |
125 | operation: self.message.operation, | |
109 | 126 | source: self |
110 | 127 | .source |
111 | 128 | .drain(..) |
giterated-models/src/model/instance.rs
@@ -33,7 +33,7 @@ pub struct Instance { | ||
33 | 33 | } |
34 | 34 | |
35 | 35 | impl GiteratedObject for Instance { |
36 | fn object_name(&self) -> &str { | |
36 | fn object_name() -> &'static str { | |
37 | 37 | "instance" |
38 | 38 | } |
39 | 39 |
giterated-models/src/model/repository.rs
@@ -39,7 +39,7 @@ pub struct Repository { | ||
39 | 39 | } |
40 | 40 | |
41 | 41 | impl GiteratedObject for Repository { |
42 | fn object_name(&self) -> &str { | |
42 | fn object_name() -> &'static str { | |
43 | 43 | "repository" |
44 | 44 | } |
45 | 45 |
giterated-models/src/model/settings.rs
@@ -1,9 +1,19 @@ | ||
1 | use serde::{Deserialize, Serialize}; | |
1 | use serde::{de::DeserializeOwned, Deserialize, Serialize}; | |
2 | use serde_json::Value; | |
2 | 3 | |
3 | pub trait Setting: Serialize { | |
4 | pub trait Setting: Serialize + DeserializeOwned { | |
4 | 5 | fn name() -> &'static str; |
5 | 6 | } |
6 | 7 | |
8 | #[derive(Debug, Clone, Serialize, Deserialize)] | |
9 | pub struct AnySetting(Value); | |
10 | ||
11 | impl Setting for AnySetting { | |
12 | fn name() -> &'static str { | |
13 | "any" | |
14 | } | |
15 | } | |
16 | ||
7 | 17 | #[derive(Debug, Serialize, Deserialize)] |
8 | 18 | pub struct UserBio(pub String); |
9 | 19 |
giterated-models/src/model/user.rs
@@ -35,7 +35,7 @@ pub struct User { | ||
35 | 35 | } |
36 | 36 | |
37 | 37 | impl GiteratedObject for User { |
38 | fn object_name(&self) -> &str { | |
38 | fn object_name() -> &'static str { | |
39 | 39 | "user" |
40 | 40 | } |
41 | 41 |
giterated-models/src/operation/instance.rs
@@ -2,7 +2,7 @@ use secrecy::Secret; | ||
2 | 2 | use serde::{Deserialize, Serialize}; |
3 | 3 | |
4 | 4 | use crate::{ |
5 | error::InstanceError, | |
5 | error::{InstanceError, OperationError}, | |
6 | 6 | model::{ |
7 | 7 | authenticated::UserAuthenticationToken, |
8 | 8 | instance::Instance, |
@@ -112,24 +112,26 @@ impl<B: ObjectBackend + std::fmt::Debug> Object<'_, Instance, B> { | ||
112 | 112 | email: Option<&str>, |
113 | 113 | username: &str, |
114 | 114 | password: &Secret<Password>, |
115 | ) -> Result<UserAuthenticationToken, InstanceError> { | |
115 | ) -> Result<UserAuthenticationToken, OperationError<InstanceError>> { | |
116 | 116 | self.request::<RegisterAccountRequest>(RegisterAccountRequest { |
117 | 117 | username: username.to_string(), |
118 | 118 | email: email.map(|s| s.to_string()), |
119 | 119 | password: password.clone(), |
120 | 120 | }) |
121 | .await | |
121 | 122 | } |
122 | 123 | |
123 | 124 | pub async fn authentication_token( |
124 | 125 | &mut self, |
125 | 126 | username: &str, |
126 | 127 | password: &Secret<Password>, |
127 | ) -> Result<UserAuthenticationToken, InstanceError> { | |
128 | ) -> Result<UserAuthenticationToken, OperationError<InstanceError>> { | |
128 | 129 | self.request::<AuthenticationTokenRequest>(AuthenticationTokenRequest { |
129 | 130 | instance: self.inner.clone(), |
130 | 131 | username: username.to_string(), |
131 | 132 | password: password.clone(), |
132 | 133 | }) |
134 | .await | |
133 | 135 | } |
134 | 136 | |
135 | 137 | pub async fn authentication_token_for( |
@@ -137,21 +139,23 @@ impl<B: ObjectBackend + std::fmt::Debug> Object<'_, Instance, B> { | ||
137 | 139 | instance: &Instance, |
138 | 140 | username: &str, |
139 | 141 | password: &Secret<Password>, |
140 | ) -> Result<UserAuthenticationToken, InstanceError> { | |
142 | ) -> Result<UserAuthenticationToken, OperationError<InstanceError>> { | |
141 | 143 | self.request::<AuthenticationTokenRequest>(AuthenticationTokenRequest { |
142 | 144 | instance: instance.clone(), |
143 | 145 | username: username.to_string(), |
144 | 146 | password: password.clone(), |
145 | 147 | }) |
148 | .await | |
146 | 149 | } |
147 | 150 | |
148 | 151 | pub async fn token_extension( |
149 | 152 | &mut self, |
150 | 153 | token: &UserAuthenticationToken, |
151 | ) -> Result<Option<UserAuthenticationToken>, InstanceError> { | |
154 | ) -> Result<Option<UserAuthenticationToken>, OperationError<InstanceError>> { | |
152 | 155 | self.request::<TokenExtensionRequest>(TokenExtensionRequest { |
153 | 156 | token: token.clone(), |
154 | 157 | }) |
158 | .await | |
155 | 159 | } |
156 | 160 | |
157 | 161 | pub async fn create_repository( |
@@ -161,7 +165,7 @@ impl<B: ObjectBackend + std::fmt::Debug> Object<'_, Instance, B> { | ||
161 | 165 | visibility: RepositoryVisibility, |
162 | 166 | default_branch: &str, |
163 | 167 | owner: &User, |
164 | ) -> Result<Repository, InstanceError> { | |
168 | ) -> Result<Repository, OperationError<InstanceError>> { | |
165 | 169 | self.request::<RepositoryCreateRequest>(RepositoryCreateRequest { |
166 | 170 | instance: Some(instance.clone()), |
167 | 171 | name: name.to_string(), |
@@ -170,5 +174,6 @@ impl<B: ObjectBackend + std::fmt::Debug> Object<'_, Instance, B> { | ||
170 | 174 | default_branch: default_branch.to_string(), |
171 | 175 | owner: owner.clone(), |
172 | 176 | }) |
177 | .await | |
173 | 178 | } |
174 | 179 | } |
giterated-models/src/operation/mod.rs
@@ -2,18 +2,20 @@ use std::{any::type_name, fmt::Debug, marker::PhantomData}; | ||
2 | 2 | |
3 | 3 | use anyhow::Error; |
4 | 4 | use serde::{de::DeserializeOwned, Deserialize, Serialize}; |
5 | use serde_json::Value; | |
5 | 6 | |
6 | 7 | use crate::{ |
7 | 8 | error::{GetValueError, OperationError}, |
8 | model::{instance::Instance, MessageTarget}, | |
9 | model::{instance::Instance, settings::Setting, MessageTarget}, | |
10 | values::{GetSetting, GetSettingError, SetSetting, SetSettingError}, | |
9 | 11 | }; |
10 | 12 | |
11 | 13 | pub mod instance; |
12 | 14 | pub mod repository; |
13 | 15 | pub mod user; |
14 | 16 | |
15 | pub trait GiteratedObject: Send + Serialize + DeserializeOwned { | |
16 | fn object_name(&self) -> &str; | |
17 | pub trait GiteratedObject: Send + Serialize + DeserializeOwned + ToString { | |
18 | fn object_name() -> &'static str; | |
17 | 19 | |
18 | 20 | fn from_object_str(object_str: &str) -> Result<Self, Error>; |
19 | 21 | } |
@@ -22,7 +24,7 @@ pub trait GiteratedOperation<O: GiteratedObject>: Send + Serialize + Deserialize | ||
22 | 24 | type Success: Serialize + DeserializeOwned + Send; |
23 | 25 | type Failure: Serialize + DeserializeOwned + Send; |
24 | 26 | |
25 | fn operation_name(&self) -> &'static str { | |
27 | fn operation_name() -> &'static str { | |
26 | 28 | type_name::<Self>() |
27 | 29 | } |
28 | 30 | } |
@@ -73,43 +75,43 @@ impl<'b, B: ObjectBackend + Send + Sync + Clone, O: GiteratedObject> Object<'b, | ||
73 | 75 | impl<'b, O: GiteratedObject + Clone + Debug, B: ObjectBackend + Debug + Send + Sync + Clone> |
74 | 76 | Object<'b, O, B> |
75 | 77 | { |
76 | pub async fn get<V: GiteratedObjectValue<Object = O> + Send>( | |
77 | &self, | |
78 | ) -> Result<V, OperationError<ObjectRequestError>> { | |
79 | let operation: GetValue<V> = GetValue { | |
80 | value_name: V::value_name().to_string(), | |
81 | _marker: PhantomData, | |
82 | }; | |
83 | ||
84 | let _message: GiteratedMessage<O, _> = GiteratedMessage { | |
85 | object: self.inner.clone(), | |
86 | operation: operation.operation_name().to_string(), | |
87 | payload: operation, | |
88 | }; | |
89 | ||
90 | todo!() | |
91 | } | |
92 | ||
93 | pub fn request<R: GiteratedOperation<O> + Debug>( | |
94 | &mut self, | |
95 | request: R, | |
96 | ) -> Result<R::Success, R::Failure> { | |
97 | self.backend.object_operation(self.inner.clone(), request); | |
98 | ||
99 | todo!() | |
100 | } | |
78 | // pub async fn get<V: GiteratedObjectValue<Object = O> + Send>( | |
79 | // &self, | |
80 | // ) -> Result<V, OperationError<ObjectRequestError>> { | |
81 | // let operation: GetValue<V> = GetValue { | |
82 | // value_name: V::value_name().to_string(), | |
83 | // _marker: PhantomData, | |
84 | // }; | |
85 | ||
86 | // let _message: GiteratedMessage<O, _> = GiteratedMessage { | |
87 | // object: self.inner.clone(), | |
88 | // operation: operation.operation_name().to_string(), | |
89 | // payload: operation, | |
90 | // }; | |
91 | ||
92 | // todo!() | |
93 | // } | |
94 | ||
95 | // pub fn request<R: GiteratedOperation<O> + Debug>( | |
96 | // &mut self, | |
97 | // request: R, | |
98 | // ) -> Result<R::Success, R::Failure> { | |
99 | // self.backend.object_operation(self.inner.clone(), request); | |
100 | ||
101 | // todo!() | |
102 | // } | |
101 | 103 | } |
102 | 104 | |
103 | #[derive(Serialize, Deserialize)] | |
105 | #[derive(Serialize, Deserialize, Debug, Clone)] | |
104 | 106 | pub struct GetValue<V: GiteratedObjectValue> { |
105 | value_name: String, | |
107 | pub value_name: String, | |
106 | 108 | _marker: PhantomData<V>, |
107 | 109 | } |
108 | 110 | |
109 | 111 | impl<O: GiteratedObject + Send, V: GiteratedObjectValue<Object = O> + Send> GiteratedOperation<O> |
110 | 112 | for GetValue<V> |
111 | 113 | { |
112 | fn operation_name(&self) -> &'static str { | |
114 | fn operation_name() -> &'static str { | |
113 | 115 | "get_value" |
114 | 116 | } |
115 | 117 | type Success = V; |
@@ -124,6 +126,21 @@ pub struct GiteratedMessage<O: GiteratedObject, V: GiteratedOperation<O>> { | ||
124 | 126 | pub payload: V, |
125 | 127 | } |
126 | 128 | |
129 | impl GiteratedMessage<AnyObject, AnyOperation> { | |
130 | pub fn try_into<O: GiteratedObject, V: GiteratedOperation<O>>( | |
131 | &self, | |
132 | ) -> Result<GiteratedMessage<O, V>, ()> { | |
133 | let object = O::from_object_str(&self.object.0).map_err(|_| ())?; | |
134 | let payload = serde_json::from_value::<V>(self.payload.0.clone()).map_err(|_| ())?; | |
135 | ||
136 | Ok(GiteratedMessage { | |
137 | object, | |
138 | operation: self.operation.clone(), | |
139 | payload, | |
140 | }) | |
141 | } | |
142 | } | |
143 | ||
127 | 144 | impl<O: GiteratedObject, V: GiteratedOperation<O>> MessageTarget for GiteratedMessage<O, V> {} |
128 | 145 | |
129 | 146 | impl<V: GiteratedOperation<O> + Debug, O: GiteratedObject + Debug> Debug |
@@ -157,23 +174,74 @@ pub enum ObjectRequestError { | ||
157 | 174 | } |
158 | 175 | |
159 | 176 | #[derive(Clone, Debug, Serialize, Deserialize)] |
160 | pub struct AnyObject(Vec<u8>); | |
177 | #[repr(transparent)] | |
178 | pub struct AnyObject(pub String); | |
161 | 179 | |
162 | 180 | impl GiteratedObject for AnyObject { |
163 | fn object_name(&self) -> &str { | |
181 | fn object_name() -> &'static str { | |
164 | 182 | "any" |
165 | 183 | } |
166 | 184 | |
167 | 185 | fn from_object_str(object_str: &str) -> Result<Self, Error> { |
168 | Ok(Self(Vec::from(object_str.as_bytes()))) | |
186 | Ok(Self(object_str.to_string())) | |
187 | } | |
188 | } | |
189 | ||
190 | impl ToString for AnyObject { | |
191 | fn to_string(&self) -> String { | |
192 | self.0.to_string() | |
169 | 193 | } |
170 | 194 | } |
171 | 195 | |
172 | 196 | #[derive(Clone, Debug, Serialize, Deserialize)] |
173 | pub struct AnyOperation(Vec<u8>); | |
197 | #[serde(transparent)] | |
198 | #[repr(transparent)] | |
199 | pub struct AnyOperation(pub Value); | |
174 | 200 | |
175 | 201 | impl<O: GiteratedObject> GiteratedOperation<O> for AnyOperation { |
176 | 202 | type Success = Vec<u8>; |
177 | 203 | |
178 | 204 | type Failure = Vec<u8>; |
179 | 205 | } |
206 | ||
207 | impl<'b, O: GiteratedObject + Clone + Debug, B: ObjectBackend> Object<'b, O, B> { | |
208 | pub async fn get<V: GiteratedObjectValue<Object = O> + Send + Debug>( | |
209 | &mut self, | |
210 | ) -> Result<V, OperationError<GetValueError>> { | |
211 | self.request(GetValue { | |
212 | value_name: V::value_name().to_string(), | |
213 | _marker: PhantomData, | |
214 | }) | |
215 | .await | |
216 | } | |
217 | ||
218 | pub async fn get_setting<S: Setting + Send + Clone + Debug>( | |
219 | &mut self, | |
220 | ) -> Result<S, OperationError<GetSettingError>> { | |
221 | self.request(GetSetting { | |
222 | setting_name: S::name().to_string(), | |
223 | _marker: PhantomData, | |
224 | }) | |
225 | .await | |
226 | } | |
227 | ||
228 | pub async fn set_setting<S: Setting + Send + Clone + Debug>( | |
229 | &mut self, | |
230 | setting: S, | |
231 | ) -> Result<(), OperationError<SetSettingError>> { | |
232 | self.request(SetSetting { | |
233 | setting_name: S::name().to_string(), | |
234 | value: setting, | |
235 | }) | |
236 | .await | |
237 | } | |
238 | ||
239 | pub async fn request<R: GiteratedOperation<O> + Debug>( | |
240 | &mut self, | |
241 | request: R, | |
242 | ) -> Result<R::Success, OperationError<R::Failure>> { | |
243 | self.backend | |
244 | .object_operation(self.inner.clone(), request) | |
245 | .await | |
246 | } | |
247 | } |
giterated-models/src/operation/repository.rs
@@ -1,7 +1,7 @@ | ||
1 | 1 | use serde::{Deserialize, Serialize}; |
2 | 2 | |
3 | 3 | use crate::{ |
4 | error::RepositoryError, | |
4 | error::{OperationError, RepositoryError}, | |
5 | 5 | model::repository::{IssueLabel, Repository, RepositoryIssue, RepositoryTreeEntry}, |
6 | 6 | }; |
7 | 7 | |
@@ -78,24 +78,32 @@ impl GiteratedOperation<Repository> for RepositoryFileInspectRequest { | ||
78 | 78 | } |
79 | 79 | |
80 | 80 | impl<B: ObjectBackend + std::fmt::Debug> Object<'_, Repository, B> { |
81 | pub async fn issues_count(&mut self) -> Result<u64, RepositoryError> { | |
81 | pub async fn issues_count(&mut self) -> Result<u64, OperationError<RepositoryError>> { | |
82 | 82 | self.request::<RepositoryIssuesCountRequest>(RepositoryIssuesCountRequest) |
83 | .await | |
83 | 84 | } |
84 | 85 | |
85 | pub async fn issue_labels(&mut self) -> Result<Vec<IssueLabel>, RepositoryError> { | |
86 | pub async fn issue_labels( | |
87 | &mut self, | |
88 | ) -> Result<Vec<IssueLabel>, OperationError<RepositoryError>> { | |
86 | 89 | self.request::<RepositoryIssueLabelsRequest>(RepositoryIssueLabelsRequest) |
90 | .await | |
87 | 91 | } |
88 | 92 | |
89 | pub async fn issues(&mut self) -> Result<Vec<RepositoryIssue>, RepositoryError> { | |
93 | pub async fn issues( | |
94 | &mut self, | |
95 | ) -> Result<Vec<RepositoryIssue>, OperationError<RepositoryError>> { | |
90 | 96 | self.request::<RepositoryIssuesRequest>(RepositoryIssuesRequest) |
97 | .await | |
91 | 98 | } |
92 | 99 | |
93 | 100 | pub async fn inspect_files( |
94 | 101 | &mut self, |
95 | 102 | entry: &RepositoryTreeEntry, |
96 | ) -> Result<Vec<RepositoryTreeEntry>, RepositoryError> { | |
103 | ) -> Result<Vec<RepositoryTreeEntry>, OperationError<RepositoryError>> { | |
97 | 104 | self.request::<RepositoryFileInspectRequest>(RepositoryFileInspectRequest { |
98 | 105 | path: entry.clone(), |
99 | 106 | }) |
107 | .await | |
100 | 108 | } |
101 | 109 | } |
giterated-models/src/operation/user.rs
@@ -1,7 +1,7 @@ | ||
1 | 1 | use serde::{Deserialize, Serialize}; |
2 | 2 | |
3 | 3 | use crate::{ |
4 | error::UserError, | |
4 | error::{OperationError, UserError}, | |
5 | 5 | model::{instance::Instance, repository::Repository, user::User}, |
6 | 6 | }; |
7 | 7 | |
@@ -22,10 +22,11 @@ impl<B: ObjectBackend + std::fmt::Debug> Object<'_, User, B> { | ||
22 | 22 | pub async fn repositories( |
23 | 23 | &mut self, |
24 | 24 | instance: &Instance, |
25 | ) -> Result<Vec<Repository>, UserError> { | |
25 | ) -> Result<Vec<Repository>, OperationError<UserError>> { | |
26 | 26 | self.request::<UserRepositoriesRequest>(UserRepositoriesRequest { |
27 | 27 | instance: instance.clone(), |
28 | 28 | user: self.inner.clone(), |
29 | 29 | }) |
30 | .await | |
30 | 31 | } |
31 | 32 | } |
giterated-models/src/values/mod.rs
@@ -1,3 +1,79 @@ | ||
1 | use std::{fmt::Debug, marker::PhantomData}; | |
2 | ||
3 | use serde::{de::DeserializeOwned, Deserialize, Serialize}; | |
4 | use serde_json::Value; | |
5 | use thiserror::Error; | |
6 | ||
7 | use crate::{ | |
8 | model::settings::Setting, | |
9 | operation::{GiteratedObject, GiteratedObjectValue, GiteratedOperation}, | |
10 | }; | |
11 | ||
1 | 12 | pub mod instance; |
2 | 13 | pub mod repository; |
3 | 14 | pub mod user; |
15 | ||
16 | // #[derive(Serialize, Deserialize)] | |
17 | // pub struct GetRequest<V: GiteratedObjectValue> { | |
18 | // value_name: String, | |
19 | // _marker: PhantomData<V>, | |
20 | // } | |
21 | ||
22 | // impl<O: GiteratedObject, V: GiteratedObjectValue<Object = O> + Send> GiteratedOperation<O> | |
23 | // for GetRequest<V> | |
24 | // { | |
25 | // type Success = V; | |
26 | ||
27 | // type Failure = GetValueError; | |
28 | // } | |
29 | ||
30 | // #[derive(Error, Debug, Serialize, Deserialize)] | |
31 | // pub enum GetValueError {} | |
32 | ||
33 | #[derive(Serialize, Deserialize, Debug, Clone)] | |
34 | pub struct GetSetting<S: Setting + std::fmt::Debug + Clone> { | |
35 | pub setting_name: String, | |
36 | pub _marker: PhantomData<S>, | |
37 | } | |
38 | ||
39 | impl<O: GiteratedObject, S: Setting + Send + DeserializeOwned + Debug + Clone> GiteratedOperation<O> | |
40 | for GetSetting<S> | |
41 | { | |
42 | type Success = S; | |
43 | ||
44 | type Failure = GetSettingError; | |
45 | } | |
46 | ||
47 | #[derive(Error, Debug, Serialize, Deserialize)] | |
48 | pub enum GetSettingError {} | |
49 | #[derive(Serialize, Deserialize, Debug, Clone)] | |
50 | #[serde(bound(deserialize = "S: Setting"))] | |
51 | pub struct SetSetting<S: Setting> { | |
52 | pub setting_name: String, | |
53 | pub value: S, | |
54 | } | |
55 | ||
56 | impl<O: GiteratedObject, S: Setting + Send> GiteratedOperation<O> for SetSetting<S> { | |
57 | type Success = (); | |
58 | ||
59 | type Failure = SetSettingError; | |
60 | } | |
61 | ||
62 | #[derive(Error, Debug, Serialize, Deserialize)] | |
63 | pub enum SetSettingError {} | |
64 | ||
65 | #[derive(Debug, Clone, Deserialize, Serialize)] | |
66 | #[serde(transparent)] | |
67 | pub struct AnyValue<O> { | |
68 | value: Value, | |
69 | #[serde(skip)] | |
70 | _marker: PhantomData<O>, | |
71 | } | |
72 | ||
73 | impl<O: GiteratedObject> GiteratedObjectValue for AnyValue<O> { | |
74 | type Object = O; | |
75 | ||
76 | fn value_name() -> &'static str { | |
77 | todo!() | |
78 | } | |
79 | } |