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

ambee/giterated

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

Giterated Stack `ObjectValue` and `Setting` refactor.

This refactor adds value and setting update events, as well as value getters. Additionally, the stack is now the owner of the ability to write settings into storage. This is accomplished with the `MetadataProvider` trait. This sets up the ground work for push federation, cache, and basically everything else. commit 7befc583cb3e0c6719506c550ed66ac76293413c Author: Amber <[email protected]> Date: Fri Sep 29 15:46:48 2023 -0500 Finish value and settings refactor in the stack. commit 3ac09994a0caafd1a0b95d9a781c7f202f20e75b Author: Amber <[email protected]> Date: Fri Sep 29 09:46:32 2023 -0500 Add set_setting handling back in commit 84fd31e3eae85d98fa68a28b333dbb32cde3bdb8 Author: Amber <[email protected]> Date: Wed Sep 27 06:36:31 2023 -0500 Remove some allocations from meta types commit 16c310ce3680c4a14ed35083b6a230aaecd43152 Author: Amber <[email protected]> Date: Wed Sep 27 05:35:03 2023 -0500 Add cargo metadata commit eb2520a20001bac7b21c6c3d34f62db32f0ada80 Author: Amber <[email protected]> Date: Wed Sep 27 05:26:27 2023 -0500 Refactor setting and value management to use the unified stack. Allows for tight management, inspection, and eventing of setting and value management. commit 901fe103da0fce4b40f33b0a8b64404049ae03cf Author: Amber <[email protected]> Date: Wed Sep 27 02:38:33 2023 -0500 Set up ground work for value / settings refactor

Amber - ⁨2⁩ years ago

parent: tbd commit: ⁨c377e4d

Showing ⁨⁨19⁩ changed files⁩ with ⁨⁨832⁩ insertions⁩ and ⁨⁨391⁩ deletions⁩

Cargo.lock

View file
@@ -746,7 +746,7 @@ dependencies = [
746 746
747 747 [[package]]
748 748 name = "giterated-daemon"
749 version = "0.0.6"
749 version = "0.1.0"
750 750 dependencies = [
751 751 "aes-gcm",
752 752 "anyhow",

giterated-daemon/Cargo.toml

View file
@@ -1,7 +1,14 @@
1 1 [package]
2 2 name = "giterated-daemon"
3 version = "0.0.6"
3 version = "0.1.0"
4 authors = ["Amber Kowalski"]
4 5 edition = "2021"
6 rust-version = "1.70.0"
7 description = "Giterated's Data Models"
8 homepage = "https://giterated.dev/ambee/giterated"
9 repository = "https://giterated.dev/ambee/giterated"
10 license = "MIT OR Apache-2.0"
11 keywords = ["giterated"]
5 12
6 13 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 14

giterated-daemon/src/backend/git.rs

View file
@@ -5,21 +5,21 @@ use git2::BranchType;
5 5 use giterated_models::instance::{Instance, RepositoryCreateRequest};
6 6
7 7 use giterated_models::repository::{
8 AccessList, Commit, DefaultBranch, Description, IssueLabel, LatestCommit, Repository,
9 RepositoryBranch, RepositoryBranchesRequest, RepositoryChunkLine,
10 RepositoryCommitBeforeRequest, RepositoryCommitFromIdRequest, RepositoryDiff,
11 RepositoryDiffFile, RepositoryDiffFileChunk, RepositoryDiffFileInfo, RepositoryDiffFileStatus,
12 RepositoryDiffPatchRequest, RepositoryDiffRequest, RepositoryFile, RepositoryFileFromIdRequest,
8 AccessList, Commit, DefaultBranch, Description, IssueLabel, Repository, RepositoryBranch,
9 RepositoryBranchesRequest, RepositoryChunkLine, RepositoryCommitBeforeRequest,
10 RepositoryCommitFromIdRequest, RepositoryDiff, RepositoryDiffFile, RepositoryDiffFileChunk,
11 RepositoryDiffFileInfo, RepositoryDiffFileStatus, RepositoryDiffPatchRequest,
12 RepositoryDiffRequest, RepositoryFile, RepositoryFileFromIdRequest,
13 13 RepositoryFileFromPathRequest, RepositoryFileInspectRequest, RepositoryIssue,
14 14 RepositoryIssueLabelsRequest, RepositoryIssuesCountRequest, RepositoryIssuesRequest,
15 15 RepositoryLastCommitOfFileRequest, RepositoryObjectType, RepositoryStatistics,
16 16 RepositoryStatisticsRequest, RepositoryTreeEntry, RepositoryVisibility, Visibility,
17 17 };
18 use giterated_models::settings::{AnySetting, Setting};
19 use giterated_models::user::{User, UserParseError};
20 use giterated_models::value::{AnyValue, GiteratedObjectValue};
21 use giterated_stack::AuthenticatedUser;
22 use serde_json::Value;
18
19 use giterated_models::user::User;
20
21 use giterated_stack::{AuthenticatedUser, GiteratedStack};
22
23 23 use sqlx::PgPool;
24 24 use std::ops::Deref;
25 25 use std::{
@@ -27,9 +27,9 @@ use std::{
27 27 sync::Arc,
28 28 };
29 29 use thiserror::Error;
30 use tokio::sync::Mutex;
30 use tokio::sync::OnceCell;
31 31
32 use super::{IssuesBackend, MetadataBackend, RepositoryBackend};
32 use super::{IssuesBackend, RepositoryBackend};
33 33
34 34 // TODO: Handle this
35 35 //region database structures
@@ -52,7 +52,7 @@ impl GitRepository {
52 52 &self,
53 53 our_instance: &Instance,
54 54 user: &Option<AuthenticatedUser>,
55 settings: &Arc<Mutex<dyn MetadataBackend + Send>>,
55 stack: &GiteratedStack,
56 56 ) -> bool {
57 57 if matches!(self.visibility, RepositoryVisibility::Public) {
58 58 return true;
@@ -70,32 +70,20 @@ impl GitRepository {
70 70 }
71 71
72 72 if matches!(self.visibility, RepositoryVisibility::Private) {
73 // Check if the user can view
74 let mut settings = settings.lock().await;
75
76 let access_list = settings
77 .repository_get(
78 &Repository {
79 owner: self.owner_user.clone(),
80 name: self.name.clone(),
81 instance: our_instance.clone(),
82 },
83 AccessList::name(),
84 )
85 .await;
86
87 let access_list: AccessList = match access_list {
88 Ok(list) => serde_json::from_value(list.0).unwrap(),
89 Err(_) => {
90 return false;
91 }
92 };
73 // Check if the user can view\
74 let access_list = stack
75 .new_get_setting::<_, AccessList>(&Repository {
76 owner: self.owner_user.clone(),
77 name: self.name.clone(),
78 instance: our_instance.clone(),
79 })
80 .await
81 .unwrap();
93 82
94 83 access_list
95 84 .0
96 85 .iter()
97 .find(|access_list_user| *access_list_user == user.deref())
98 .is_some()
86 .any(|access_list_user| access_list_user == user.deref())
99 87 } else {
100 88 false
101 89 }
@@ -165,7 +153,7 @@ pub struct GitBackend {
165 153 pub pg_pool: PgPool,
166 154 pub repository_folder: String,
167 155 pub instance: Instance,
168 pub settings_provider: Arc<Mutex<dyn MetadataBackend + Send>>,
156 pub stack: Arc<OnceCell<Arc<GiteratedStack>>>,
169 157 }
170 158
171 159 impl GitBackend {
@@ -173,13 +161,15 @@ impl GitBackend {
173 161 pg_pool: &PgPool,
174 162 repository_folder: &str,
175 163 instance: impl ToOwned<Owned = Instance>,
176 settings_provider: Arc<Mutex<dyn MetadataBackend + Send>>,
164 stack: Arc<OnceCell<Arc<GiteratedStack>>>,
177 165 ) -> Self {
166 let instance = instance.to_owned();
167
178 168 Self {
179 169 pg_pool: pg_pool.clone(),
180 170 repository_folder: repository_folder.to_string(),
181 instance: instance.to_owned(),
182 settings_provider,
171 instance,
172 stack,
183 173 }
184 174 }
185 175
@@ -256,7 +246,7 @@ impl GitBackend {
256 246 .can_user_view_repository(
257 247 &self.instance,
258 248 &Some(requester.clone()),
259 &self.settings_provider,
249 self.stack.get().unwrap(),
260 250 )
261 251 .await
262 252 {
@@ -276,7 +266,7 @@ impl GitBackend {
276 266
277 267 match repository.open_git2_repository(&self.repository_folder) {
278 268 Ok(git) => Ok(git),
279 Err(err) => return Err(err),
269 Err(err) => Err(err),
280 270 }
281 271 }
282 272
@@ -368,10 +358,9 @@ impl GitBackend {
368 358 match git.find_branch(rev.as_ref().unwrap(), BranchType::Local) {
369 359 Ok(branch) => tree_id = branch.get().target(),
370 360 Err(_) => {
371 return Err(Box::new(GitBackendError::RefNotFound(
372 rev.unwrap().to_string(),
373 ))
374 .into())
361 return Err(
362 Box::new(GitBackendError::RefNotFound(rev.unwrap().to_string())).into(),
363 )
375 364 }
376 365 }
377 366 }
@@ -381,10 +370,7 @@ impl GitBackend {
381 370 }
382 371
383 372 /// Gets the last commit in a rev
384 pub fn get_last_commit_in_rev(
385 git: &git2::Repository,
386 rev: &str,
387 ) -> anyhow::Result<Commit> {
373 pub fn get_last_commit_in_rev(git: &git2::Repository, rev: &str) -> anyhow::Result<Commit> {
388 374 let oid = Self::get_oid_from_reference(git, Some(rev))?;
389 375
390 376 // Walk through the repository commit graph starting at our rev
@@ -392,11 +378,12 @@ impl GitBackend {
392 378 revwalk.set_sorting(git2::Sort::TIME)?;
393 379 revwalk.push(oid)?;
394 380
395 if let Some(commit_oid) = revwalk.next() {
396 if let Ok(commit_oid) = commit_oid {
397 if let Ok(commit) = git.find_commit(commit_oid).map_err(|_| GitBackendError::CommitNotFound(commit_oid.to_string())) {
398 return Ok(Commit::from(commit));
399 }
381 if let Some(Ok(commit_oid)) = revwalk.next() {
382 if let Ok(commit) = git
383 .find_commit(commit_oid)
384 .map_err(|_| GitBackendError::CommitNotFound(commit_oid.to_string()))
385 {
386 return Ok(Commit::from(commit));
400 387 }
401 388 }
402 389
@@ -416,7 +403,7 @@ impl RepositoryBackend for GitBackend {
416 403 .await
417 404 {
418 405 Ok(repository
419 .can_user_view_repository(&self.instance, requester, &self.settings_provider)
406 .can_user_view_repository(&self.instance, requester, self.stack.get().unwrap())
420 407 .await)
421 408 } else {
422 409 Ok(false)
@@ -468,45 +455,29 @@ impl RepositoryBackend for GitBackend {
468 455 request.owner.instance, request.owner.username, request.name
469 456 );
470 457
458 let stack = self.stack.get().unwrap();
459
471 460 let repository = Repository {
472 461 owner: request.owner.clone(),
473 462 name: request.name.clone(),
474 463 instance: request.instance.as_ref().unwrap_or(&self.instance).clone(),
475 464 };
476 465
477 let mut settings_backend = self.settings_provider.lock().await;
478 settings_backend
479 .repository_write(
466 stack
467 .write_setting(
480 468 &repository,
481 Description::name(),
482 AnySetting(
483 serde_json::to_value(Description(
484 request.description.clone().unwrap_or_default(),
485 ))
486 .unwrap(),
487 ),
469 Description(request.description.clone().unwrap_or_default()),
488 470 )
489 471 .await
490 472 .unwrap();
491 settings_backend
492 .repository_write(
493 &repository,
494 Visibility::name(),
495 AnySetting(
496 serde_json::to_value(Visibility(request.visibility.clone())).unwrap(),
497 ),
498 )
473
474 stack
475 .write_setting(&repository, Visibility(request.visibility.clone()))
499 476 .await
500 477 .unwrap();
501 settings_backend
502 .repository_write(
503 &repository,
504 DefaultBranch::name(),
505 AnySetting(
506 serde_json::to_value(DefaultBranch(request.default_branch.clone()))
507 .unwrap(),
508 ),
509 )
478
479 stack
480 .write_setting(&repository, DefaultBranch(request.default_branch.clone()))
510 481 .await
511 482 .unwrap();
512 483
@@ -526,49 +497,6 @@ impl RepositoryBackend for GitBackend {
526 497 }
527 498 }
528 499
529 async fn get_value(
530 &mut self,
531 repository: &Repository,
532 name: &str,
533 ) -> Result<AnyValue<Repository>, Error> {
534 Ok(unsafe {
535 if name == Description::value_name() {
536 AnyValue::from_raw(self.get_setting(repository, Description::name()).await?.0)
537 } else if name == Visibility::value_name() {
538 AnyValue::from_raw(self.get_setting(repository, Visibility::name()).await?.0)
539 } else if name == DefaultBranch::value_name() {
540 AnyValue::from_raw(self.get_setting(repository, DefaultBranch::name()).await?.0)
541 } else if name == LatestCommit::value_name() {
542 AnyValue::from_raw(serde_json::to_value(LatestCommit(None)).unwrap())
543 } else {
544 return Err(UserParseError.into());
545 }
546 })
547 }
548
549 async fn get_setting(
550 &mut self,
551 repository: &Repository,
552 name: &str,
553 ) -> Result<AnySetting, Error> {
554 let mut provider = self.settings_provider.lock().await;
555
556 Ok(provider.repository_get(repository, name).await?)
557 }
558
559 async fn write_setting(
560 &mut self,
561 repository: &Repository,
562 name: &str,
563 setting: &Value,
564 ) -> Result<(), Error> {
565 let mut provider = self.settings_provider.lock().await;
566
567 provider
568 .repository_write(repository, name, AnySetting(setting.clone()))
569 .await
570 }
571
572 500 async fn repository_file_inspect(
573 501 &mut self,
574 502 requester: &Option<AuthenticatedUser>,
@@ -579,7 +507,7 @@ impl RepositoryBackend for GitBackend {
579 507 .open_repository_and_check_permissions(&repository.owner, &repository.name, requester)
580 508 .await?;
581 509
582 let tree_id = Self::get_oid_from_reference(&git, request.rev.as_ref().map(|s| s.as_str()))?;
510 let tree_id = Self::get_oid_from_reference(&git, request.rev.as_deref())?;
583 511
584 512 // unwrap might be dangerous?
585 513 // Get the commit from the oid
@@ -701,7 +629,7 @@ impl RepositoryBackend for GitBackend {
701 629 .open_repository_and_check_permissions(&repository.owner, &repository.name, requester)
702 630 .await?;
703 631
704 let tree_id = Self::get_oid_from_reference(&git, request.rev.as_ref().map(|s| s.as_str()))?;
632 let tree_id = Self::get_oid_from_reference(&git, request.rev.as_deref())?;
705 633
706 634 // unwrap might be dangerous?
707 635 // Get the commit from the oid
@@ -796,7 +724,7 @@ impl RepositoryBackend for GitBackend {
796 724 .open_repository_and_check_permissions(&repository.owner, &repository.name, requester)
797 725 .await?;
798 726
799 let tree_id = Self::get_oid_from_reference(&git, request.rev.as_ref().map(|s| s.as_str()))?;
727 let tree_id = Self::get_oid_from_reference(&git, request.rev.as_deref())?;
800 728
801 729 // unwrap might be dangerous?
802 730 // Get the commit from the oid
@@ -842,12 +770,17 @@ impl RepositoryBackend for GitBackend {
842 770 };
843 771
844 772 // TODO: Non UTF-8?
845 let commit = GitBackend::get_last_commit_in_rev(&git, branch.0.get().name().unwrap()).ok();
773 let commit =
774 GitBackend::get_last_commit_in_rev(&git, branch.0.get().name().unwrap()).ok();
846 775
847 776 // TODO: Implement stale with configurable age
848 let mut stale = false;
849
850 branches.push(RepositoryBranch {name:name.to_string(), stale, last_commit: commit })
777 let stale = false;
778
779 branches.push(RepositoryBranch {
780 name: name.to_string(),
781 stale,
782 last_commit: commit,
783 })
851 784 }
852 785
853 786 Ok(branches)
@@ -1072,12 +1005,10 @@ impl RepositoryBackend for GitBackend {
1072 1005 revwalk.set_sorting(git2::Sort::TIME)?;
1073 1006 revwalk.push(commit.id())?;
1074 1007
1075 if let Some(next) = revwalk.next() {
1076 if let Ok(before_commit_oid) = next {
1077 // Find the commit using the parsed oid
1078 if let Ok(before_commit) = git.find_commit(before_commit_oid) {
1079 return Ok(Commit::from(before_commit));
1080 }
1008 if let Some(Ok(before_commit_oid)) = revwalk.next() {
1009 // Find the commit using the parsed oid
1010 if let Ok(before_commit) = git.find_commit(before_commit_oid) {
1011 return Ok(Commit::from(before_commit));
1081 1012 }
1082 1013 }
1083 1014

giterated-daemon/src/backend/mod.rs

View file
@@ -96,18 +96,6 @@ pub trait RepositoryBackend {
96 96 repository: &Repository,
97 97 request: &RepositoryBranchesRequest,
98 98 ) -> Result<Vec<RepositoryBranch>, Error>;
99 async fn get_value(
100 &mut self,
101 user: &Repository,
102 name: &str,
103 ) -> Result<AnyValue<Repository>, Error>;
104 async fn get_setting(&mut self, user: &Repository, name: &str) -> Result<AnySetting, Error>;
105 async fn write_setting(
106 &mut self,
107 repository: &Repository,
108 name: &str,
109 setting: &Value,
110 ) -> Result<(), Error>;
111 99 async fn exists(
112 100 &mut self,
113 101 requester: &Option<AuthenticatedUser>,

giterated-daemon/src/backend/settings.rs

View file
@@ -1,15 +1,20 @@
1 use std::sync::Arc;
2
1 3 use anyhow::Error;
2 4
3 5 use giterated_models::repository::Repository;
4 6 use giterated_models::settings::AnySetting;
5 7 use giterated_models::user::User;
6 8
9 use giterated_stack::GiteratedStack;
7 10 use sqlx::PgPool;
11 use tokio::sync::OnceCell;
8 12
9 13 use super::MetadataBackend;
10 14
11 15 pub struct DatabaseSettings {
12 16 pub pg_pool: PgPool,
17 pub stack: Arc<OnceCell<Arc<GiteratedStack>>>,
13 18 }
14 19
15 20 #[async_trait::async_trait]
@@ -75,7 +80,7 @@ impl MetadataBackend for DatabaseSettings {
75 80
76 81 #[allow(unused)]
77 82 #[derive(Debug, sqlx::FromRow)]
78 struct UserSettingRow {
83 pub struct UserSettingRow {
79 84 pub username: String,
80 85 pub name: String,
81 86 pub value: String,
@@ -83,7 +88,7 @@ struct UserSettingRow {
83 88
84 89 #[allow(unused)]
85 90 #[derive(Debug, sqlx::FromRow)]
86 struct RepositorySettingRow {
91 pub struct RepositorySettingRow {
87 92 pub repository: String,
88 93 pub name: String,
89 94 pub value: String,

giterated-daemon/src/backend/user.rs

View file
@@ -240,7 +240,7 @@ impl AuthBackend for UserAuth {
240 240 username: user.username,
241 241 instance: self.this_instance.clone(),
242 242 },
243 &source,
243 source,
244 244 )
245 245 .await;
246 246

giterated-daemon/src/connection/wrapper.rs

View file
@@ -102,7 +102,7 @@ pub async fn connection_wrapper(
102 102 signature,
103 103 } = source
104 104 {
105 let public_key = key_cache.get(&instance).await.unwrap();
105 let public_key = key_cache.get(instance).await.unwrap();
106 106 let public_key = RsaPublicKey::from_pkcs1_pem(&public_key).unwrap();
107 107 let verifying_key = VerifyingKey::<Sha256>::new(public_key);
108 108
@@ -130,7 +130,7 @@ pub async fn connection_wrapper(
130 130 for source in &message.source {
131 131 if let AuthenticationSource::User { user, token } = source {
132 132 // Get token
133 let public_key = key_cache.get(&verified_instance).await.unwrap();
133 let public_key = key_cache.get(verified_instance).await.unwrap();
134 134
135 135 let token: TokenData<UserTokenMetadata> = jsonwebtoken::decode(
136 136 token.as_ref(),

giterated-daemon/src/database_backend/handler.rs

View file
@@ -444,44 +444,6 @@ pub fn repository_commit_before(
444 444 .boxed_local()
445 445 }
446 446
447 pub fn repository_get_value(
448 object: &Repository,
449 operation: GetValueTyped<AnyValue<Repository>>,
450 state: DatabaseBackend,
451 ) -> LocalBoxFuture<'static, Result<AnyValue<Repository>, OperationError<GetValueError>>> {
452 let object = object.clone();
453
454 async move {
455 let mut repository_backend = state.repository_backend.lock().await;
456 let value = repository_backend
457 .get_value(&object, &operation.value_name)
458 .await
459 .as_internal_error()?;
460
461 Ok(value)
462 }
463 .boxed_local()
464 }
465
466 pub fn repository_get_setting(
467 object: &Repository,
468 operation: GetSetting,
469 state: DatabaseBackend,
470 ) -> LocalBoxFuture<'static, Result<Value, OperationError<GetSettingError>>> {
471 let object = object.clone();
472
473 async move {
474 let mut repository_backend = state.repository_backend.lock().await;
475 let value = repository_backend
476 .get_setting(&object, &operation.setting_name)
477 .await
478 .as_internal_error()?;
479
480 Ok(value.0)
481 }
482 .boxed_local()
483 }
484
485 447 pub fn instance_authentication_request(
486 448 object: &Instance,
487 449 operation: AuthenticationTokenRequest,
@@ -534,121 +496,106 @@ pub fn instance_create_repository_request(
534 496
535 497 pub fn user_get_value_display_name(
536 498 object: &User,
537 operation: GetValueTyped<DisplayName>,
538 state: DatabaseBackend,
539 // _requester: AuthorizedUser,
499 _operation: GetValueTyped<DisplayName>,
500 _state: DatabaseBackend,
501 stack: Arc<GiteratedStack>, // _requester: AuthorizedUser,
540 502 ) -> LocalBoxFuture<'static, Result<DisplayName, OperationError<GetValueError>>> {
541 503 let object = object.clone();
542 504
543 505 async move {
544 let mut backend = state.user_backend.lock().await;
545
546 let raw_value = backend
547 .get_value(&object, &operation.value_name)
506 stack
507 .new_get_setting::<_, DisplayName>(&object)
548 508 .await
549 .as_internal_error()?;
550
551 Ok(serde_json::from_value(raw_value.into_inner()).as_internal_error()?)
509 .as_internal_error()
552 510 }
553 511 .boxed_local()
554 512 }
555 513
556 514 pub fn user_get_value_bio(
557 515 object: &User,
558 operation: GetValueTyped<Bio>,
559 state: DatabaseBackend,
516 _operation: GetValueTyped<Bio>,
517 _state: DatabaseBackend,
518 stack: Arc<GiteratedStack>,
560 519 ) -> LocalBoxFuture<'static, Result<Bio, OperationError<GetValueError>>> {
561 520 let object = object.clone();
562 521
563 522 async move {
564 let mut backend = state.user_backend.lock().await;
565
566 let raw_value = backend
567 .get_value(&object, &operation.value_name)
523 stack
524 .new_get_setting::<_, Bio>(&object)
568 525 .await
569 .as_internal_error()?;
570
571 Ok(serde_json::from_value(raw_value.into_inner()).as_internal_error()?)
526 .as_internal_error()
572 527 }
573 528 .boxed_local()
574 529 }
575 530
576 531 pub fn repository_get_value_description(
577 532 object: &Repository,
578 operation: GetValueTyped<Description>,
579 state: DatabaseBackend,
533 _operation: GetValueTyped<Description>,
534 _state: DatabaseBackend,
535 stack: Arc<GiteratedStack>,
580 536 ) -> LocalBoxFuture<'static, Result<Description, OperationError<GetValueError>>> {
581 537 let object = object.clone();
582 538
583 539 async move {
584 let mut backend = state.repository_backend.lock().await;
585
586 let raw_value = backend
587 .get_value(&object, &operation.value_name)
540 stack
541 .new_get_setting::<_, Description>(&object)
588 542 .await
589 .as_internal_error()?;
590
591 Ok(serde_json::from_value(raw_value.into_inner()).as_internal_error()?)
543 .as_internal_error()
592 544 }
593 545 .boxed_local()
594 546 }
595 547
596 548 pub fn repository_get_value_visibility(
597 549 object: &Repository,
598 operation: GetValueTyped<Visibility>,
599 state: DatabaseBackend,
550 _operation: GetValueTyped<Visibility>,
551 _state: DatabaseBackend,
552 stack: Arc<GiteratedStack>,
600 553 ) -> LocalBoxFuture<'static, Result<Visibility, OperationError<GetValueError>>> {
601 554 let object = object.clone();
602 555
603 556 async move {
604 let mut backend = state.repository_backend.lock().await;
605
606 let raw_value = backend
607 .get_value(&object, &operation.value_name)
557 stack
558 .new_get_setting::<_, Visibility>(&object)
608 559 .await
609 .as_internal_error()?;
610
611 Ok(serde_json::from_value(raw_value.into_inner()).as_internal_error()?)
560 .as_internal_error()
612 561 }
613 562 .boxed_local()
614 563 }
615 564
616 565 pub fn repository_get_default_branch(
617 566 object: &Repository,
618 operation: GetValueTyped<DefaultBranch>,
619 state: DatabaseBackend,
567 _operation: GetValueTyped<DefaultBranch>,
568 _state: DatabaseBackend,
569 stack: Arc<GiteratedStack>,
620 570 ) -> LocalBoxFuture<'static, Result<DefaultBranch, OperationError<GetValueError>>> {
621 571 let object = object.clone();
622 572
623 573 async move {
624 let mut backend = state.repository_backend.lock().await;
625
626 let raw_value = backend
627 .get_value(&object, &operation.value_name)
574 stack
575 .new_get_setting::<_, DefaultBranch>(&object)
628 576 .await
629 .as_internal_error()?;
630
631 Ok(serde_json::from_value(raw_value.into_inner()).as_internal_error()?)
577 .as_internal_error()
632 578 }
633 579 .boxed_local()
634 580 }
635 581
636 582 pub fn repository_get_latest_commit(
637 583 object: &Repository,
638 operation: GetValueTyped<LatestCommit>,
584 _operation: GetValueTyped<LatestCommit>,
639 585 state: DatabaseBackend,
586 _stack: Arc<GiteratedStack>,
640 587 ) -> LocalBoxFuture<'static, Result<LatestCommit, OperationError<GetValueError>>> {
641 let object = object.clone();
588 let _object = object.clone();
642 589
643 590 async move {
644 let mut backend = state.repository_backend.lock().await;
591 let _backend = state.repository_backend.lock().await;
645 592
646 let raw_value = backend
647 .get_value(&object, &operation.value_name)
648 .await
649 .as_internal_error()?;
593 // stack
594 // .new_get_setting::<_, LatestCommit>(&*object)
595 // .await
596 // .as_internal_error()
650 597
651 Ok(serde_json::from_value(raw_value.into_inner()).as_internal_error()?)
598 todo!()
652 599 }
653 600 .boxed_local()
654 601 }

giterated-daemon/src/database_backend/mod.rs

View file
@@ -1,8 +1,10 @@
1 1 pub mod handler;
2 2 pub mod updates;
3 3
4 use std::any::Any;
4 5 use std::sync::Arc;
5 6
7 use anyhow::Context;
6 8 use giterated_models::error::OperationError;
7 9 use giterated_models::instance::Instance;
8 10 use giterated_models::object::{GiteratedObject, Object, ObjectRequestError};
@@ -10,11 +12,15 @@ use giterated_models::object_backend::ObjectBackend;
10 12 use giterated_models::operation::GiteratedOperation;
11 13 use giterated_models::repository::{DefaultBranch, Description, Repository, Visibility};
12 14 use giterated_models::user::{Bio, DisplayName, User};
13 use giterated_stack::StackOperationState;
14 use giterated_stack::SubstackBuilder;
15 use giterated_stack::provider::MetadataProvider;
16 use giterated_stack::{GiteratedStack, ObjectMeta, SubstackBuilder};
17 use giterated_stack::{SettingMeta, StackOperationState};
18 use serde_json::Value;
19 use sqlx::PgPool;
15 20 use std::fmt::Debug;
16 use tokio::sync::Mutex;
21 use tokio::sync::{Mutex, OnceCell};
17 22
23 use crate::backend::settings::{RepositorySettingRow, UserSettingRow};
18 24 use crate::backend::{RepositoryBackend, UserBackend};
19 25
20 26 use self::handler::{
@@ -22,9 +28,9 @@ use self::handler::{
22 28 instance_registration_request, repository_commit_before, repository_commit_by_id,
23 29 repository_diff, repository_diff_patch, repository_file_from_id, repository_file_from_path,
24 30 repository_get_branches, repository_get_default_branch, repository_get_latest_commit,
25 repository_get_setting, repository_get_statistics, repository_get_value_description,
26 repository_get_value_visibility, repository_info, repository_last_commit_of_file,
27 user_get_repositories, user_get_setting, user_get_value_bio, user_get_value_display_name,
31 repository_get_statistics, repository_get_value_description, repository_get_value_visibility,
32 repository_info, repository_last_commit_of_file, user_get_repositories, user_get_value_bio,
33 user_get_value_display_name,
28 34 };
29 35
30 36 #[derive(Clone, Debug)]
@@ -57,8 +63,10 @@ impl ObjectBackend<StackOperationState> for Foobackend {
57 63 #[allow(unused)]
58 64 pub struct DatabaseBackend {
59 65 pub(self) our_instance: Instance,
66 pub(self) pool: PgPool,
60 67 pub(self) user_backend: Arc<Mutex<dyn UserBackend + Send>>,
61 68 pub(self) repository_backend: Arc<Mutex<dyn RepositoryBackend + Send>>,
69 pub stack: Arc<OnceCell<Arc<GiteratedStack>>>,
62 70 }
63 71
64 72 impl DatabaseBackend {
@@ -66,30 +74,36 @@ impl DatabaseBackend {
66 74 instance: Instance,
67 75 user_backend: Arc<Mutex<dyn UserBackend + Send>>,
68 76 repository_backend: Arc<Mutex<dyn RepositoryBackend + Send>>,
77 pool: PgPool,
78 stack: Arc<OnceCell<Arc<GiteratedStack>>>,
69 79 ) -> Self {
70 80 Self {
71 81 our_instance: instance,
72 82 user_backend,
73 83 repository_backend,
84 pool,
85 stack,
74 86 }
75 87 }
76 88
77 89 pub fn into_substack(self) -> SubstackBuilder<Self> {
78 let mut builder = SubstackBuilder::<Self>::new(self);
90 let mut builder = SubstackBuilder::<Self>::new(self.clone());
91
92 builder.object_metadata_provider(Box::new(self));
79 93
80 94 builder
81 95 .object::<Repository>()
82 .object_settings(repository_get_setting)
83 96 .object::<User>()
84 .object_settings(user_get_setting)
85 97 .object::<Instance>();
86 98
99 // Register value settings, which are settings that directly correspond to
100 // value types.
87 101 builder
88 .setting::<DisplayName>()
89 .setting::<Bio>()
90 .setting::<Description>()
91 .setting::<Visibility>()
92 .setting::<DefaultBranch>();
102 .value_setting::<User, DisplayName>()
103 .value_setting::<User, Bio>()
104 .value_setting::<Repository, Description>()
105 .value_setting::<Repository, Visibility>()
106 .value_setting::<Repository, DefaultBranch>();
93 107
94 108 builder
95 109 .value(user_get_value_bio)
@@ -124,3 +138,74 @@ impl Debug for DatabaseBackend {
124 138 f.debug_struct("DatabaseBackend").finish()
125 139 }
126 140 }
141
142 #[async_trait::async_trait]
143 impl MetadataProvider for DatabaseBackend {
144 fn provides_for(&self, object: &dyn Any) -> bool {
145 object.is::<Instance>() || object.is::<Repository>() || object.is::<User>()
146 }
147
148 async fn write(
149 &self,
150 object: &(dyn Any + Send + Sync),
151 _object_meta: &ObjectMeta,
152 setting: &(dyn Any + Send + Sync),
153 setting_meta: &SettingMeta,
154 ) -> Result<(), anyhow::Error> {
155 if let Some(repository) = object.downcast_ref::<Repository>() {
156 sqlx::query!("INSERT INTO repository_settings VALUES ($1, $2, $3) ON CONFLICT (repository, name) DO UPDATE SET value = $3",
157 repository.to_string(), setting_meta.name, serde_json::to_string(&(setting_meta.serialize)(setting).unwrap())?)
158 .execute(&self.pool).await?;
159
160 Ok(())
161 } else if let Some(user) = object.downcast_ref::<User>() {
162 sqlx::query!("INSERT INTO user_settings VALUES ($1, $2, $3) ON CONFLICT (username, name) DO UPDATE SET value = $3",
163 user.username, setting_meta.name, serde_json::to_string(&(setting_meta.serialize)(setting).unwrap())?)
164 .execute(&self.pool).await?;
165
166 Ok(())
167 } else {
168 unreachable!()
169 }
170 }
171
172 async fn read(
173 &self,
174 object: &(dyn Any + Send + Sync),
175 _object_meta: &ObjectMeta,
176 setting_meta: &SettingMeta,
177 ) -> Result<Value, anyhow::Error> {
178 if let Some(repository) = object.downcast_ref::<Repository>() {
179 let row = sqlx::query_as!(
180 RepositorySettingRow,
181 "SELECT * FROM repository_settings WHERE repository = $1 AND name = $2",
182 repository.to_string(),
183 setting_meta.name
184 )
185 .fetch_one(&self.pool)
186 .await?;
187
188 let setting =
189 serde_json::from_str(&row.value).context("deserializing setting from database")?;
190
191 Ok(setting)
192 } else if let Some(user) = object.downcast_ref::<User>() {
193 info!("User for {}", setting_meta.name);
194 let row = sqlx::query_as!(
195 UserSettingRow,
196 "SELECT * FROM user_settings WHERE username = $1 AND name = $2",
197 user.username,
198 setting_meta.name
199 )
200 .fetch_one(&self.pool)
201 .await?;
202
203 let setting =
204 serde_json::from_str(&row.value).context("deserializing setting from database")?;
205
206 Ok(setting)
207 } else {
208 unreachable!()
209 }
210 }
211 }

giterated-daemon/src/database_backend/updates.rs

View file
@@ -1,15 +1,12 @@
1 1 use futures_util::{future::BoxFuture, FutureExt};
2 2 use giterated_models::{
3 repository::{DefaultBranch, Description, Repository},
4 settings::{AnySetting, Setting},
5 update::ValueUpdate,
3 repository::{Description, Repository},
4 settings::AnySetting,
6 5 user::User,
7 value::{AnyValue, GiteratedObjectValue},
6 value::AnyValue,
8 7 };
9 8 use giterated_stack::{AuthorizedUser, StackOperationState};
10 9
11 use super::DatabaseBackend;
12
13 10 pub fn user_set_value(
14 11 _object: User,
15 12 _value_name: String,
@@ -54,34 +51,26 @@ pub fn repository_set_description(
54 51 async { Ok(()) }.boxed()
55 52 }
56 53
57 pub fn repository_set_default_branch(
58 object: Repository,
59 default_branch: DefaultBranch,
60 // Ensure user is authorized for this request
61 _user: AuthorizedUser,
62 backend: DatabaseBackend,
63 ) -> BoxFuture<'static, Result<(), ()>> {
64 async move {
65 let mut repository_backend = backend.repository_backend.lock().await;
54 // pub fn repository_set_default_branch(
55 // object: Repository,
56 // default_branch: DefaultBranch,
57 // // Ensure user is authorized for this request
58 // _user: AuthorizedUser,
59 // backend: DatabaseBackend,
60 // stack: Arc<GiteratedStack>,
61 // ) -> BoxFuture<'static, Result<(), ()>> {
62 // async move {
63 // stack.write_setting(&object, &default_branch).await.unwrap();
66 64
67 repository_backend
68 .write_setting(
69 &object,
70 DefaultBranch::name(),
71 &serde_json::to_value(default_branch.clone()).unwrap(),
72 )
73 .await
74 .unwrap();
65 // let _set_value = ValueUpdate {
66 // object: object.to_string(),
67 // value_name: DefaultBranch::value_name().to_owned(),
68 // value: unsafe { AnyValue::from_raw(serde_json::to_value(default_branch).unwrap()) },
69 // };
75 70
76 let _set_value = ValueUpdate {
77 object: object.to_string(),
78 value_name: DefaultBranch::value_name().to_owned(),
79 value: unsafe { AnyValue::from_raw(serde_json::to_value(default_branch).unwrap()) },
80 };
81
82 // Submit value update back to the daemon
83 // state.value_update(set_value);
84 Ok(())
85 }
86 .boxed()
87 }
71 // // Submit value update back to the daemon
72 // // state.value_update(set_value);
73 // Ok(())
74 // }
75 // .boxed()
76 // }

giterated-daemon/src/keys.rs

View file
@@ -12,7 +12,7 @@ pub struct PublicKeyCache {
12 12 impl PublicKeyCache {
13 13 pub async fn get(&mut self, instance: &Instance) -> Result<String, Error> {
14 14 if let Some(key) = self.keys.get(instance) {
15 return Ok(key.clone());
15 Ok(key.clone())
16 16 } else {
17 17 let key = reqwest::get(format!("https://{}/.giterated/pubkey.pem", instance))
18 18 .await?

giterated-daemon/src/main.rs

View file
@@ -19,7 +19,7 @@ use tokio::{
19 19 fs::File,
20 20 io::{AsyncRead, AsyncReadExt, AsyncWrite},
21 21 net::{TcpListener, TcpStream},
22 sync::Mutex,
22 sync::{Mutex, OnceCell},
23 23 };
24 24 use tokio_tungstenite::{accept_async, WebSocketStream};
25 25 use tokio_util::task::LocalPoolHandle;
@@ -53,8 +53,11 @@ async fn main() -> Result<(), Error> {
53 53 sqlx::migrate!().run(&db_pool).await?;
54 54 info!("Connected");
55 55
56 let stack_cell = Arc::new(OnceCell::default());
57
56 58 let settings = Arc::new(Mutex::new(DatabaseSettings {
57 59 pg_pool: db_pool.clone(),
60 stack: stack_cell.clone(),
58 61 }));
59 62
60 63 let repository_backend: Arc<Mutex<dyn RepositoryBackend + Send>> =
@@ -67,7 +70,7 @@ async fn main() -> Result<(), Error> {
67 70 ),
68 71 instance: Instance::from_str(config["giterated"]["instance"].as_str().unwrap())
69 72 .unwrap(),
70 settings_provider: settings.clone(),
73 stack: stack_cell.clone(),
71 74 }));
72 75
73 76 let token_granter = Arc::new(Mutex::new(AuthenticationTokenGranter {
@@ -88,6 +91,8 @@ async fn main() -> Result<(), Error> {
88 91 Instance::from_str(config["giterated"]["instance"].as_str().unwrap()).unwrap(),
89 92 user_backend.clone(),
90 93 repository_backend.clone(),
94 db_pool.clone(),
95 stack_cell.clone(),
91 96 );
92 97
93 98 let mut runtime = GiteratedStack::default();
@@ -97,6 +102,10 @@ async fn main() -> Result<(), Error> {
97 102
98 103 let runtime = Arc::new(runtime);
99 104
105 stack_cell
106 .set(runtime.clone())
107 .expect("failed to store global daemon stack");
108
100 109 let operation_state = {
101 110 StackOperationState {
102 111 our_instance: Instance::from_str(config["giterated"]["instance"].as_str().unwrap())

giterated-models/Cargo.toml

View file
@@ -1,7 +1,17 @@
1 1 [package]
2 2 name = "giterated-models"
3 3 version = "0.1.0"
4 authors = ["Amber Kowalski"]
4 5 edition = "2021"
6 rust-version = "1.70.0"
7 description = "Giterated's Data Models"
8 homepage = "https://giterated.dev/ambee/giterated"
9 repository = "https://giterated.dev/ambee/giterated"
10 license = "MIT OR Apache-2.0"
11 keywords = ["giterated"]
12
13 # Leave until MVP
14 publish = false
5 15
6 16 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 17

giterated-stack/Cargo.toml

View file
@@ -1,7 +1,17 @@
1 1 [package]
2 2 name = "giterated-stack"
3 3 version = "0.1.0"
4 authors = ["Amber Kowalski"]
4 5 edition = "2021"
6 rust-version = "1.70.0"
7 description = "Giterated's Unified Stack"
8 homepage = "https://giterated.dev/ambee/giterated"
9 repository = "https://giterated.dev/ambee/giterated"
10 license = "MPL-2.0"
11 keywords = ["giterated"]
12
13 # Leave until MVP
14 publish = false
5 15
6 16 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 17

giterated-stack/src/handler.rs

View file
@@ -1,6 +1,5 @@
1 1 use std::{any::Any, collections::HashMap, sync::Arc};
2 2
3 use anyhow::Context;
4 3 use futures_util::FutureExt;
5 4 use giterated_models::{
6 5 authenticated::AuthenticatedPayload,
@@ -16,11 +15,13 @@ use giterated_models::{
16 15 value::{AnyValue, GetValue, GetValueTyped, GiteratedObjectValue},
17 16 };
18 17
18 use serde::{Deserialize, Serialize};
19 19 use tracing::trace;
20 20
21 21 use crate::{
22 GiteratedOperationHandler, ObjectMeta, ObjectOperationPair, ObjectValuePair, OperationMeta,
23 OperationWrapper, SettingMeta, StackOperationState, ValueMeta,
22 provider::MetadataProvider, GiteratedOperationHandler, MissingValue, ObjectMeta,
23 ObjectOperationPair, ObjectSettingPair, ObjectValuePair, OperationMeta, OperationWrapper,
24 SettingMeta, SettingUpdate, StackOperationState, ValueMeta,
24 25 };
25 26
26 27 /// Temporary name for the next generation of Giterated stack
@@ -29,13 +30,25 @@ pub struct GiteratedStack {
29 30 operation_handlers: HashMap<ObjectOperationPair, HandlerTree>,
30 31 value_getters: HashMap<ObjectValuePair, OperationWrapper>,
31 32 setting_getters: HashMap<String, OperationWrapper>,
33 value_change: HashMap<ObjectValuePair, OperationWrapper>,
34 setting_change: HashMap<ObjectSettingPair, OperationWrapper>,
35 metadata_providers: Vec<Box<dyn MetadataProvider>>,
32 36 metadata: RuntimeMetadata,
33 37 }
34 38
39 impl Debug for GiteratedStack {
40 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
41 f.debug_struct("GiteratedStack").finish()
42 }
43 }
44
45 #[derive(Clone)]
46 pub struct ValueChangeEvent(Arc<dyn Any + Send + Sync>);
47
35 48 impl GiteratedStack {
36 49 pub fn merge_builder<S: GiteratedStackState>(
37 50 &mut self,
38 builder: SubstackBuilder<S>,
51 mut builder: SubstackBuilder<S>,
39 52 ) -> &mut Self {
40 53 for (target, handler) in builder.operation_handlers {
41 54 let tree = self.get_or_create_tree(&target);
@@ -51,11 +64,162 @@ impl GiteratedStack {
51 64 assert!(self.setting_getters.insert(target, handler).is_none());
52 65 }
53 66
67 for (target, handler) in builder.value_change {
68 self.value_change.insert(target, handler);
69 }
70
71 for (target, handler) in builder.setting_change {
72 self.setting_change.insert(target, handler);
73 }
74
75 self.metadata_providers
76 .append(&mut builder.metadata_providers);
77
54 78 self.metadata.append(builder.metadata);
55 79
56 80 self
57 81 }
58 82
83 pub async fn value_update<O, V>(
84 &self,
85 object: O,
86 new_value: V,
87 operation_state: &StackOperationState,
88 ) where
89 O: GiteratedObject + 'static,
90 V: GiteratedObjectValue<Object = O> + 'static,
91 {
92 trace!("value updated {}::{}", O::object_name(), V::value_name());
93 let target = ObjectValuePair::from_types::<O, V>();
94
95 if let Some(handler) = self.value_change.get(&target) {
96 // TODO
97 let _ = handler
98 .handle(
99 &(Box::new(object) as _),
100 &(Box::new(ValueChangedShim { new_value }) as _),
101 operation_state,
102 )
103 .await;
104 }
105 }
106
107 pub async fn setting_update<O, S>(
108 &self,
109 object: O,
110 new_setting: S,
111 operation_state: &StackOperationState,
112 ) where
113 O: GiteratedObject + 'static,
114 S: Setting + 'static,
115 {
116 trace!("setting updated {}::{}", O::object_name(), S::name());
117 let target = ObjectSettingPair::from_types::<O, S>();
118
119 if let Some(handler) = self.setting_change.get(&target) {
120 let _ = handler
121 .handle(
122 &(Box::new(object) as _),
123 &(Box::new(SettingUpdate(new_setting)) as _),
124 operation_state,
125 )
126 .await;
127 }
128 }
129
130 pub async fn new_object<O>(&self, _new_object: &O, _operation_state: &StackOperationState)
131 where
132 O: GiteratedObject,
133 {
134 // TODO
135 }
136
137 /// Writes a setting for the specified object.
138 pub async fn write_setting<O, S>(
139 &self,
140 object: &O,
141 setting: S,
142 ) -> Result<(), OperationError<()>>
143 where
144 O: GiteratedObject + 'static,
145 S: Setting + 'static + Clone,
146 {
147 for provider in self.metadata_providers.iter() {
148 if provider.provides_for(object as &dyn Any) {
149 let setting_meta = self
150 .metadata
151 .settings
152 .get(&ObjectSettingPair {
153 object_kind: O::object_name().to_string(),
154 setting_name: S::name().to_string(),
155 })
156 .ok_or_else(|| OperationError::Unhandled)?;
157
158 let object_meta = self
159 .metadata
160 .objects
161 .get(O::object_name())
162 .ok_or_else(|| OperationError::Unhandled)?;
163
164 let result = provider
165 .write(object, object_meta, &setting, setting_meta)
166 .await
167 .as_internal_error_with_context(format!("writing setting {}", S::name()));
168
169 return result;
170 }
171 }
172
173 Err(OperationError::Unhandled)
174 }
175
176 /// Gets a setting for the specified object.
177 pub async fn new_get_setting<O, S>(&self, object: &O) -> Result<S, OperationError<MissingValue>>
178 where
179 O: GiteratedObject + 'static,
180 S: Setting + 'static,
181 {
182 for provider in self.metadata_providers.iter() {
183 if provider.provides_for(object as &dyn Any) {
184 trace!(
185 "Resolving setting {} for object {} from provider.",
186 S::name(),
187 O::object_name()
188 );
189
190 let setting_meta = self
191 .metadata
192 .settings
193 .get(&ObjectSettingPair {
194 object_kind: O::object_name().to_string(),
195 setting_name: S::name().to_string(),
196 })
197 .ok_or_else(|| OperationError::Unhandled)?;
198
199 let object_meta = self
200 .metadata
201 .objects
202 .get(O::object_name())
203 .ok_or_else(|| OperationError::Unhandled)?;
204
205 let value = provider
206 .read(object, object_meta, setting_meta)
207 .await
208 .as_internal_error_with_context(format!("getting setting {}", S::name()))?;
209
210 return serde_json::from_value(value)
211 .as_internal_error_with_context("deserializing setting");
212 }
213 }
214 trace!(
215 "No provider registered for setting {} and object {}",
216 S::name(),
217 O::object_name()
218 );
219
220 Err(OperationError::Unhandled)
221 }
222
59 223 fn get_or_create_tree(&mut self, target: &ObjectOperationPair) -> &mut HandlerTree {
60 224 if self.operation_handlers.contains_key(target) {
61 225 self.operation_handlers.get_mut(target).unwrap()
@@ -68,16 +232,11 @@ impl GiteratedStack {
68 232 }
69 233 }
70 234
235 #[derive(Default)]
71 236 pub struct HandlerTree {
72 237 elements: Vec<OperationWrapper>,
73 238 }
74 239
75 impl Default for HandlerTree {
76 fn default() -> Self {
77 Self { elements: vec![] }
78 }
79 }
80
81 240 impl HandlerTree {
82 241 pub fn push(&mut self, handler: OperationWrapper) {
83 242 self.elements.push(handler);
@@ -90,7 +249,7 @@ impl HandlerTree {
90 249 operation_state: &StackOperationState,
91 250 ) -> Result<Box<dyn Any + 'static>, OperationError<Box<dyn Any + 'static>>> {
92 251 for handler in self.elements.iter() {
93 match handler.handle(object, &operation, operation_state).await {
252 match handler.handle(object, operation, operation_state).await {
94 253 Ok(success) => return Ok(success),
95 254 Err(err) => match err {
96 255 OperationError::Operation(failure) => {
@@ -114,7 +273,7 @@ struct RuntimeMetadata {
114 273 objects: HashMap<String, ObjectMeta>,
115 274 operations: HashMap<ObjectOperationPair, OperationMeta>,
116 275 values: HashMap<ObjectValuePair, ValueMeta>,
117 settings: HashMap<String, SettingMeta>,
276 settings: HashMap<ObjectSettingPair, SettingMeta>,
118 277 }
119 278
120 279 /// Defines a type that is a valid Giterated runtime state.
@@ -130,6 +289,10 @@ pub struct SubstackBuilder<S: GiteratedStackState> {
130 289 value_getters: HashMap<ObjectValuePair, OperationWrapper>,
131 290 setting_getters: HashMap<String, OperationWrapper>,
132 291 metadata: RuntimeMetadata,
292 value_change: HashMap<ObjectValuePair, OperationWrapper>,
293 metadata_providers: Vec<Box<dyn MetadataProvider>>,
294 setting_change: HashMap<ObjectSettingPair, OperationWrapper>,
295
133 296 state: S,
134 297 }
135 298
@@ -140,6 +303,9 @@ impl<S: GiteratedStackState + 'static> SubstackBuilder<S> {
140 303 value_getters: Default::default(),
141 304 setting_getters: Default::default(),
142 305 metadata: Default::default(),
306 value_change: Default::default(),
307 metadata_providers: Default::default(),
308 setting_change: Default::default(),
143 309 state,
144 310 }
145 311 }
@@ -210,8 +376,51 @@ impl<S: GiteratedStackState + 'static> SubstackBuilder<S> {
210 376 ///
211 377 /// # Type Registration
212 378 /// This will register the provided setting type.
213 pub fn setting<T: Setting + 'static>(&mut self) -> &mut Self {
214 self.metadata.register_setting::<T>();
379 pub fn setting<O: GiteratedObject + 'static, T: Setting + 'static>(&mut self) -> &mut Self {
380 self.metadata.register_setting::<O, T>();
381
382 self
383 }
384
385 /// Register a [`GiteratedObjectValue`] that is also a [`Setting`], which
386 /// allows for automatic value updates.
387 pub fn value_setting<
388 O: GiteratedObject + 'static + Clone,
389 T: GiteratedObjectValue<Object = O> + Setting + 'static + Clone,
390 >(
391 &mut self,
392 ) -> &mut Self {
393 self.metadata.register_setting::<O, T>();
394 self.metadata.register_value::<O, T>();
395
396 self.setting_change.insert(
397 ObjectSettingPair {
398 object_kind: O::object_name().to_string(),
399 setting_name: T::name().to_string(),
400 },
401 OperationWrapper::new(
402 move |object: &O,
403 setting: SettingUpdate<T>,
404 _state: (),
405 operation_state: StackOperationState,
406 stack: Arc<GiteratedStack>| {
407 trace!(
408 "value setting updated {}::{}",
409 O::object_name(),
410 T::value_name()
411 );
412 let object = object.clone();
413 async move {
414 stack
415 .value_update(object, setting.0, &operation_state)
416 .await;
417 Ok(())
418 }
419 .boxed_local()
420 },
421 (),
422 ),
423 );
215 424
216 425 self
217 426 }
@@ -242,7 +451,7 @@ impl<S: GiteratedStackState + 'static> SubstackBuilder<S> {
242 451 _state: S,
243 452 operation_state: StackOperationState,
244 453 stack: Arc<GiteratedStack>| {
245 let stack = stack.clone();
454 let stack = stack;
246 455 let object_name = handler_object_name;
247 456 let value_name = handler_value_name;
248 457 let object = object.clone();
@@ -310,6 +519,42 @@ impl<S: GiteratedStackState + 'static> SubstackBuilder<S> {
310 519
311 520 self
312 521 }
522
523 pub fn value_change<O, A, F, V>(&mut self, handler: F) -> &mut Self
524 where
525 O: GiteratedObject + 'static,
526 F: GiteratedOperationHandler<A, O, ValueChangedShim<V>, S> + Clone + 'static + Send + Sync,
527 V: GiteratedObjectValue<Object = O> + Clone + 'static,
528 {
529 let object_name = handler.object_name().to_string();
530
531 let wrapped = OperationWrapper::new(handler, self.state.clone());
532
533 assert!(self.setting_getters.insert(object_name, wrapped).is_none());
534
535 self
536 }
537
538 pub fn object_metadata_provider(&mut self, provider: Box<dyn MetadataProvider>) -> &mut Self {
539 self.metadata_providers.push(provider);
540
541 self
542 }
543 }
544
545 #[derive(Serialize, Deserialize, Clone)]
546 pub struct ValueChangedShim<V> {
547 new_value: V,
548 }
549
550 impl<O, V> GiteratedOperation<O> for ValueChangedShim<V>
551 where
552 O: GiteratedObject,
553 V: GiteratedObjectValue<Object = O>,
554 {
555 type Success = V;
556
557 type Failure = MissingValue;
313 558 }
314 559
315 560 impl RuntimeMetadata {
@@ -338,8 +583,8 @@ impl RuntimeMetadata {
338 583 .operations
339 584 .insert(
340 585 ObjectOperationPair {
341 object_name: object_name.clone(),
342 operation_name: operation_name.clone(),
586 object_name: object_name,
587 operation_name: operation_name,
343 588 },
344 589 OperationMeta::new::<O, D>(),
345 590 )
@@ -372,8 +617,8 @@ impl RuntimeMetadata {
372 617 .values
373 618 .insert(
374 619 ObjectValuePair {
375 object_kind: object_name.clone(),
376 value_kind: value_name.clone(),
620 object_kind: object_name,
621 value_kind: value_name,
377 622 },
378 623 ValueMeta::new::<V>(),
379 624 )
@@ -393,12 +638,16 @@ impl RuntimeMetadata {
393 638 }
394 639 }
395 640
396 fn register_setting<S: Setting + 'static>(&mut self) {
397 let setting_name = S::name().to_string();
398
641 fn register_setting<O: GiteratedObject + 'static, S: Setting + 'static>(&mut self) {
399 642 if self
400 643 .settings
401 .insert(setting_name.clone(), SettingMeta::new::<S>())
644 .insert(
645 ObjectSettingPair {
646 object_kind: O::object_name().to_string(),
647 setting_name: S::name().to_string(),
648 },
649 SettingMeta::new::<O, S>(),
650 )
402 651 .is_some()
403 652 {
404 653 trace!(
@@ -479,7 +728,10 @@ impl GiteratedStack {
479 728 let setting_meta = self
480 729 .metadata
481 730 .settings
482 .get(&operation.setting_name)
731 .get(&ObjectSettingPair {
732 object_kind: object_type.clone(),
733 setting_name: operation.setting_name.clone(),
734 })
483 735 .ok_or_else(|| OperationError::Unhandled)?;
484 736 let raw_result = self
485 737 .get_setting(object, object_type.clone(), operation, operation_state)
@@ -487,7 +739,7 @@ impl GiteratedStack {
487 739 return match raw_result {
488 740 Ok(success) => {
489 741 // Success is the setting type, serialize it
490 let serialized = (setting_meta.serialize)(success).unwrap();
742 let serialized = (setting_meta.serialize)(&(*success)).unwrap();
491 743
492 744 Ok(serde_json::to_vec(&serialized).unwrap())
493 745 }
@@ -507,6 +759,79 @@ impl GiteratedStack {
507 759 OperationError::Unhandled => OperationError::Unhandled,
508 760 }),
509 761 };
762 } else if message.operation == "set_setting" {
763 let operation: SetSetting = serde_json::from_slice(&message.payload.0).unwrap();
764
765 trace!(
766 "Handling network {}::set_setting for {}",
767 object_type,
768 operation.setting_name
769 );
770
771 let setting_meta = self
772 .metadata
773 .settings
774 .get(&ObjectSettingPair {
775 object_kind: object_type.clone(),
776 setting_name: operation.setting_name.clone(),
777 })
778 .unwrap();
779
780 let setting = (setting_meta.deserialize)(operation.value.0)
781 .as_internal_error_with_context(format!(
782 "deserializing setting {} for object {}",
783 operation.setting_name, object_type
784 ))?;
785
786 trace!(
787 "Deserialized setting {} for object {}",
788 operation.setting_name,
789 object_type,
790 );
791
792 for provider in self.metadata_providers.iter() {
793 if provider.provides_for(object.as_ref()) {
794 trace!(
795 "Resolved setting provider for setting {} for object {}",
796 operation.setting_name,
797 object_type,
798 );
799
800 let object_meta = self
801 .metadata
802 .objects
803 .get(&object_type)
804 .ok_or_else(|| OperationError::Unhandled)?;
805
806 let raw_result = provider
807 .write(&(*object), object_meta, &(*setting), setting_meta)
808 .await;
809
810 return match raw_result {
811 Ok(_) => {
812 (setting_meta.setting_updated)(
813 object,
814 setting,
815 operation_state.runtime.clone(),
816 operation_state,
817 )
818 .await;
819
820 Ok(serde_json::to_vec(&()).unwrap())
821 }
822 Err(e) => Err(OperationError::Internal(e.context(format!(
823 "writing object {} setting {}",
824 object_type, operation.setting_name
825 )))),
826 };
827 }
828
829 trace!(
830 "Failed to resolve setting provider for setting {} for object {}",
831 operation.setting_name,
832 object_type,
833 );
834 }
510 835 }
511 836
512 837 let target = ObjectOperationPair {
@@ -606,7 +931,7 @@ impl GiteratedStack {
606 931 }
607 932
608 933 return match getter
609 .handle(&(object), &((value_meta.typed_get)()), &operation_state)
934 .handle(&(object), &((value_meta.typed_get)()), operation_state)
610 935 .await
611 936 {
612 937 Ok(success) => {
@@ -656,10 +981,46 @@ impl GiteratedStack {
656 981
657 982 pub async fn network_set_setting(
658 983 &self,
659 _operation: SetSetting,
660 _operation_state: &StackOperationState,
984 object: Box<dyn Any + Send + Sync>,
985 object_kind: String,
986 operation: SetSetting,
987 operation_state: &StackOperationState,
661 988 ) -> Result<Vec<u8>, OperationError<Vec<u8>>> {
662 todo!()
989 trace!(
990 "Handling network {}::set_setting for {}",
991 object_kind,
992 operation.setting_name
993 );
994
995 let target = ObjectSettingPair {
996 object_kind: object_kind.clone(),
997 setting_name: operation.setting_name.clone(),
998 };
999
1000 let handler = self.setting_change.get(&target).unwrap();
1001
1002 let raw_result = handler
1003 .handle(&object, &(Box::new(operation) as _), operation_state)
1004 .await;
1005
1006 match raw_result {
1007 Ok(_) => {
1008 // Serialize success, which is the value type itself
1009 let serialized = serde_json::to_vec(&()).as_internal_error()?;
1010
1011 Ok(serialized)
1012 }
1013 Err(err) => Err(match err {
1014 OperationError::Operation(failure) => {
1015 // Failure is sourced from GetValue operation, but this is hardcoded for now
1016 let failure: GetValueError = *failure.downcast().unwrap();
1017
1018 OperationError::Operation(serde_json::to_vec(&failure).as_internal_error()?)
1019 }
1020 OperationError::Internal(internal) => OperationError::Internal(internal),
1021 OperationError::Unhandled => OperationError::Unhandled,
1022 }),
1023 }
663 1024 }
664 1025 }
665 1026
@@ -712,7 +1073,7 @@ impl ObjectBackend<StackOperationState> for Arc<GiteratedStack> {
712 1073 }
713 1074
714 1075 return match getter
715 .handle(&(object), &((value_meta.typed_get)()), &operation_state)
1076 .handle(&(object), &((value_meta.typed_get)()), operation_state)
716 1077 .await
717 1078 {
718 1079 Ok(success) => Ok(*success.downcast().unwrap()),

giterated-stack/src/lib.rs

View file
@@ -1,7 +1,9 @@
1 1 mod handler;
2 2 mod meta;
3 pub mod provider;
3 4 pub use handler::{GiteratedStack, GiteratedStackState, *};
4 5 pub use meta::*;
6 use serde::{de::DeserializeOwned, Deserialize, Serialize};
5 7 pub mod state;
6 8 pub mod update;
7 9
@@ -18,9 +20,9 @@ use giterated_models::{
18 20 object_backend::ObjectBackend,
19 21 operation::GiteratedOperation,
20 22 repository::{AccessList, Repository},
21 settings::{GetSetting, SetSetting},
23 settings::{GetSetting, SetSetting, Setting},
22 24 user::User,
23 value::GetValue,
25 value::{GetValue, GiteratedObjectValue},
24 26 };
25 27
26 28 #[derive(Clone, Debug, Hash, Eq, PartialEq)]
@@ -29,12 +31,46 @@ struct ObjectOperationPair {
29 31 pub operation_name: String,
30 32 }
31 33
34 impl ObjectOperationPair {
35 #[allow(unused)]
36 pub fn from_types<O: GiteratedObject, D: GiteratedOperation<O>>() -> Self {
37 Self {
38 object_name: O::object_name().to_string(),
39 operation_name: D::operation_name().to_string(),
40 }
41 }
42 }
43
32 44 #[derive(Clone, Debug, Hash, Eq, PartialEq)]
33 45 pub struct ObjectValuePair {
34 46 pub object_kind: String,
35 47 pub value_kind: String,
36 48 }
37 49
50 impl ObjectValuePair {
51 pub fn from_types<O: GiteratedObject, D: GiteratedObjectValue<Object = O>>() -> Self {
52 Self {
53 object_kind: O::object_name().to_string(),
54 value_kind: D::value_name().to_string(),
55 }
56 }
57 }
58
59 #[derive(Clone, Debug, Hash, Eq, PartialEq)]
60 pub struct ObjectSettingPair {
61 pub object_kind: String,
62 pub setting_name: String,
63 }
64
65 impl ObjectSettingPair {
66 pub fn from_types<O: GiteratedObject, S: Setting>() -> Self {
67 Self {
68 object_kind: O::object_name().to_string(),
69 setting_name: S::name().to_string(),
70 }
71 }
72 }
73
38 74 #[async_trait::async_trait(?Send)]
39 75 pub trait GiteratedOperationHandler<
40 76 L,
@@ -359,7 +395,7 @@ impl<O: GiteratedObject, D: GiteratedOperation<O>> FromOperationState<O, D>
359 395 }
360 396 }
361 397
362 #[derive(Debug, thiserror::Error)]
398 #[derive(Debug, thiserror::Error, Serialize, Deserialize)]
363 399 #[error("missing value")]
364 400 pub struct MissingValue;
365 401
@@ -374,10 +410,7 @@ impl<O: GiteratedObject, D: GiteratedOperation<O> + Send + Sync> FromOperationSt
374 410 _operation: &D,
375 411 state: &StackOperationState,
376 412 ) -> Result<AuthenticatedUser, ExtractorError<MissingValue>> {
377 state
378 .user
379 .clone()
380 .ok_or_else(|| ExtractorError(MissingValue))
413 state.user.clone().ok_or(ExtractorError(MissingValue))
381 414 }
382 415 }
383 416
@@ -392,10 +425,7 @@ impl<O: GiteratedObject, D: GiteratedOperation<O> + Send + Sync> FromOperationSt
392 425 _operation: &D,
393 426 state: &StackOperationState,
394 427 ) -> Result<AuthenticatedInstance, ExtractorError<MissingValue>> {
395 state
396 .instance
397 .clone()
398 .ok_or_else(|| ExtractorError(MissingValue))
428 state.instance.clone().ok_or(ExtractorError(MissingValue))
399 429 }
400 430 }
401 431
@@ -460,7 +490,7 @@ impl AuthorizedOperation<User> for SetSetting {
460 490 authorize_for: &User,
461 491 operation_state: &StackOperationState,
462 492 ) -> Result<bool, ExtractorError<MissingValue>> {
463 let authenticated_user = operation_state.user.as_ref().ok_or_else(|| MissingValue)?;
493 let authenticated_user = operation_state.user.as_ref().ok_or(MissingValue)?;
464 494
465 495 Ok(authorize_for == authenticated_user.deref())
466 496 }
@@ -475,7 +505,7 @@ impl AuthorizedOperation<User> for GetSetting {
475 505 authorize_for: &User,
476 506 operation_state: &StackOperationState,
477 507 ) -> Result<bool, ExtractorError<MissingValue>> {
478 let authenticated_user = operation_state.user.as_ref().ok_or_else(|| MissingValue)?;
508 let authenticated_user = operation_state.user.as_ref().ok_or(MissingValue)?;
479 509
480 510 Ok(authorize_for == authenticated_user.deref())
481 511 }
@@ -499,18 +529,17 @@ impl AuthorizedOperation<Repository> for SetSetting {
499 529 .runtime
500 530 .get_object::<Repository>(&authorize_for.to_string(), operation_state)
501 531 .await
502 .map_err(|err| anyhow::Error::from(err))?;
532 .map_err(anyhow::Error::from)?;
503 533
504 534 let access_list = object
505 535 .get_setting::<AccessList>(operation_state)
506 536 .await
507 .map_err(|err| anyhow::Error::from(err))?;
537 .map_err(anyhow::Error::from)?;
508 538
509 539 if access_list
510 540 .0
511 541 .iter()
512 .find(|user| *user == authenticated_user.deref())
513 .is_some()
542 .any(|user| user == authenticated_user.deref())
514 543 {
515 544 Ok(true)
516 545 } else {
@@ -537,18 +566,17 @@ impl AuthorizedOperation<Repository> for GetSetting {
537 566 .runtime
538 567 .get_object::<Repository>(&authorize_for.to_string(), operation_state)
539 568 .await
540 .map_err(|err| anyhow::Error::from(err))?;
569 .map_err(anyhow::Error::from)?;
541 570
542 571 let access_list = object
543 572 .get_setting::<AccessList>(operation_state)
544 573 .await
545 .map_err(|err| anyhow::Error::from(err))?;
574 .map_err(anyhow::Error::from)?;
546 575
547 576 if access_list
548 577 .0
549 578 .iter()
550 .find(|user| *user == authenticated_user.deref())
551 .is_some()
579 .any(|user| user == authenticated_user.deref())
552 580 {
553 581 Ok(true)
554 582 } else {
@@ -710,3 +738,18 @@ impl Deref for AuthenticatedUser {
710 738 &self.0
711 739 }
712 740 }
741
742 #[derive(Clone, Debug, Serialize, Deserialize)]
743 #[serde(transparent)]
744 #[serde(bound(deserialize = "S: DeserializeOwned"))]
745 pub struct SettingUpdate<S: Setting + Serialize + DeserializeOwned>(pub S);
746
747 impl<O, S> GiteratedOperation<O> for SettingUpdate<S>
748 where
749 O: GiteratedObject,
750 S: Setting + Serialize + DeserializeOwned,
751 {
752 type Success = ();
753
754 type Failure = ();
755 }

giterated-stack/src/meta/mod.rs

View file
@@ -1,5 +1,6 @@
1 use std::{any::Any, str::FromStr};
1 use std::{any::Any, str::FromStr, sync::Arc};
2 2
3 use futures_util::{future::LocalBoxFuture, FutureExt};
3 4 use giterated_models::{
4 5 object::GiteratedObject,
5 6 operation::GiteratedOperation,
@@ -8,13 +9,14 @@ use giterated_models::{
8 9 };
9 10 use serde_json::Value;
10 11
12 use crate::{GiteratedStack, StackOperationState};
13
11 14 pub struct ValueMeta {
12 15 pub name: String,
13 pub deserialize: Box<dyn Fn(&[u8]) -> Result<Box<dyn Any>, serde_json::Error> + Send + Sync>,
14 pub serialize:
15 Box<dyn Fn(Box<dyn Any + Send + Sync>) -> Result<Vec<u8>, serde_json::Error> + Send + Sync>,
16 pub typed_get: Box<dyn Fn() -> Box<dyn Any + Send + Sync> + Send + Sync>,
17 pub is_get_value_typed: Box<dyn Fn(&Box<dyn Any + Send + Sync>) -> bool + Send + Sync>,
16 pub deserialize: fn(&[u8]) -> Result<Box<dyn Any>, serde_json::Error>,
17 pub serialize: fn(Box<dyn Any + Send + Sync>) -> Result<Vec<u8>, serde_json::Error>,
18 pub typed_get: fn() -> Box<dyn Any + Send + Sync>,
19 pub is_get_value_typed: fn(&Box<dyn Any + Send + Sync>) -> bool,
18 20 }
19 21
20 22 pub trait IntoValueMeta {
@@ -31,13 +33,13 @@ impl<O: GiteratedObject, V: GiteratedObjectValue<Object = O> + 'static> IntoValu
31 33 }
32 34
33 35 fn deserialize(buffer: &[u8]) -> Result<Box<dyn Any>, serde_json::Error> {
34 Ok(Box::new(serde_json::from_slice(&buffer)?))
36 Ok(Box::new(serde_json::from_slice(buffer)?))
35 37 }
36 38
37 39 fn serialize(value: Box<dyn Any + Send + Sync>) -> Result<Vec<u8>, serde_json::Error> {
38 40 let value = value.downcast::<V>().unwrap();
39 41
40 Ok(serde_json::to_vec(&*value)?)
42 serde_json::to_vec(&*value)
41 43 }
42 44
43 45 fn typed_get() -> Box<dyn Any + Send + Sync> {
@@ -56,10 +58,10 @@ impl ValueMeta {
56 58 pub fn new<I: IntoValueMeta + 'static>() -> Self {
57 59 Self {
58 60 name: I::name(),
59 deserialize: Box::new(I::deserialize) as _,
60 serialize: Box::new(I::serialize) as _,
61 typed_get: Box::new(I::typed_get) as _,
62 is_get_value_typed: Box::new(I::is_get_value_typed) as _,
61 deserialize: I::deserialize,
62 serialize: I::serialize,
63 typed_get: I::typed_get,
64 is_get_value_typed: I::is_get_value_typed,
63 65 }
64 66 }
65 67 }
@@ -67,13 +69,10 @@ impl ValueMeta {
67 69 pub struct OperationMeta {
68 70 pub name: String,
69 71 pub object_kind: String,
70 pub deserialize:
71 Box<dyn Fn(&[u8]) -> Result<Box<dyn Any + Send + Sync>, serde_json::Error> + Send + Sync>,
72 pub any_is_same: Box<dyn Fn(&dyn Any) -> bool + Send + Sync>,
73 pub serialize_success:
74 Box<dyn Fn(Box<dyn Any>) -> Result<Vec<u8>, serde_json::Error> + Send + Sync>,
75 pub serialize_error:
76 Box<dyn Fn(Box<dyn Any>) -> Result<Vec<u8>, serde_json::Error> + Send + Sync>,
72 pub deserialize: fn(&[u8]) -> Result<Box<dyn Any + Send + Sync>, serde_json::Error>,
73 pub any_is_same: fn(&dyn Any) -> bool,
74 pub serialize_success: fn(Box<dyn Any>) -> Result<Vec<u8>, serde_json::Error>,
75 pub serialize_error: fn(Box<dyn Any>) -> Result<Vec<u8>, serde_json::Error>,
77 76 }
78 77
79 78 pub trait IntoOperationMeta<O> {
@@ -118,11 +117,11 @@ impl OperationMeta {
118 117 pub fn new<O: GiteratedObject + 'static, I: IntoOperationMeta<O> + 'static>() -> Self {
119 118 Self {
120 119 name: I::name(),
121 deserialize: Box::new(I::deserialize) as _,
122 serialize_success: Box::new(I::serialize_success) as _,
123 serialize_error: Box::new(I::serialize_failure) as _,
120 deserialize: I::deserialize,
121 serialize_success: I::serialize_success,
122 serialize_error: I::serialize_failure,
124 123 object_kind: O::object_name().to_string(),
125 any_is_same: Box::new(I::any_is_same) as _,
124 any_is_same: I::any_is_same,
126 125 }
127 126 }
128 127 }
@@ -130,7 +129,7 @@ impl OperationMeta {
130 129 pub struct ObjectMeta {
131 130 pub name: String,
132 131 pub from_str: Box<dyn Fn(&str) -> Result<Box<dyn Any + Send + Sync>, ()> + Send + Sync>,
133 pub any_is_same: Box<dyn Fn(&dyn Any) -> bool + Send + Sync>,
132 pub any_is_same: fn(&dyn Any) -> bool,
134 133 }
135 134
136 135 pub trait IntoObjectMeta: FromStr {
@@ -157,44 +156,74 @@ impl ObjectMeta {
157 156
158 157 Ok(Box::new(object) as Box<dyn Any + Send + Sync>)
159 158 }),
160 any_is_same: Box::new(I::any_is_same) as _,
159 any_is_same: I::any_is_same,
161 160 }
162 161 }
163 162 }
164 163
165 164 pub struct SettingMeta {
166 165 pub name: String,
167 pub deserialize: Box<dyn Fn(&[u8]) -> Result<Box<dyn Any>, serde_json::Error> + Send + Sync>,
168 pub serialize:
169 Box<dyn Fn(Box<dyn Any + Send + Sync>) -> Result<Value, serde_json::Error> + Send + Sync>,
166 pub deserialize: fn(Value) -> Result<Box<dyn Any + Send + Sync>, serde_json::Error>,
167 pub serialize: fn(&(dyn Any + Send + Sync)) -> Result<Value, serde_json::Error>,
168 pub setting_updated: for<'fut> fn(
169 Box<dyn Any + Send + Sync>,
170 Box<dyn Any + Send + Sync>,
171 Arc<GiteratedStack>,
172 &StackOperationState,
173 ) -> LocalBoxFuture<'_, ()>,
170 174 }
171 175
172 pub trait IntoSettingMeta {
176 pub trait IntoSettingMeta<O> {
173 177 fn name() -> String;
174 fn deserialize(buffer: &[u8]) -> Result<Box<dyn Any>, serde_json::Error>;
175 fn serialize(setting: Box<dyn Any + Send + Sync>) -> Result<Value, serde_json::Error>;
178 fn deserialize(value: Value) -> Result<Box<dyn Any + Send + Sync>, serde_json::Error>;
179 fn serialize(setting: &(dyn Any + Send + Sync)) -> Result<Value, serde_json::Error>;
180 fn setting_updated(
181 object: Box<dyn Any + Send + Sync>,
182 setting: Box<dyn Any + Send + Sync>,
183 stack: Arc<GiteratedStack>,
184 operation_state: &StackOperationState,
185 ) -> LocalBoxFuture<'_, ()>;
176 186 }
177 187
178 impl<S: Setting> IntoSettingMeta for S {
188 impl<O: GiteratedObject + 'static, S: Setting + 'static> IntoSettingMeta<O> for S {
179 189 fn name() -> String {
180 190 S::name().to_string()
181 191 }
182 192
183 fn deserialize(buffer: &[u8]) -> Result<Box<dyn Any>, serde_json::Error> {
184 Ok(Box::new(serde_json::from_slice(buffer)?))
193 fn deserialize(value: Value) -> Result<Box<dyn Any + Send + Sync>, serde_json::Error> {
194 Ok(Box::new(serde_json::from_value::<S>(value)?))
195 }
196
197 fn serialize(setting: &(dyn Any + Send + Sync)) -> Result<Value, serde_json::Error> {
198 serde_json::to_value(setting.downcast_ref::<S>().unwrap())
185 199 }
186 200
187 fn serialize(setting: Box<dyn Any + Send + Sync>) -> Result<Value, serde_json::Error> {
188 Ok(*setting.downcast::<Value>().unwrap())
201 fn setting_updated(
202 object: Box<dyn Any + Send + Sync>,
203 setting: Box<dyn Any + Send + Sync>,
204 stack: Arc<GiteratedStack>,
205 operation_state: &StackOperationState,
206 ) -> LocalBoxFuture<'_, ()> {
207 async move {
208 stack
209 .setting_update(
210 *object.downcast::<O>().unwrap(),
211 *setting.downcast::<S>().unwrap(),
212 operation_state,
213 )
214 .await
215 }
216 .boxed_local()
189 217 }
190 218 }
191 219
192 220 impl SettingMeta {
193 pub fn new<I: IntoSettingMeta + 'static>() -> Self {
221 pub fn new<O: GiteratedObject, I: IntoSettingMeta<O> + 'static>() -> Self {
194 222 Self {
195 223 name: I::name(),
196 deserialize: Box::new(I::deserialize) as _,
197 serialize: Box::new(I::serialize) as _,
224 deserialize: I::deserialize,
225 serialize: I::serialize,
226 setting_updated: I::setting_updated,
198 227 }
199 228 }
200 229 }

giterated-stack/src/provider/metadata.rs

View file
@@ -0,0 +1,25 @@
1 use std::any::Any;
2
3 use anyhow::Error;
4
5 use serde_json::Value;
6
7 use crate::{ObjectMeta, SettingMeta};
8
9 #[async_trait::async_trait]
10 pub trait MetadataProvider: Send + Sync + 'static {
11 fn provides_for(&self, object: &dyn Any) -> bool;
12 async fn write(
13 &self,
14 object: &(dyn Any + Send + Sync),
15 object_meta: &ObjectMeta,
16 setting: &(dyn Any + Send + Sync),
17 setting_meta: &SettingMeta,
18 ) -> Result<(), Error>;
19 async fn read(
20 &self,
21 object: &(dyn Any + Send + Sync),
22 object_meta: &ObjectMeta,
23 setting_meta: &SettingMeta,
24 ) -> Result<Value, Error>;
25 }

giterated-stack/src/provider/mod.rs

View file
@@ -0,0 +1,2 @@
1 mod metadata;
2 pub use metadata::MetadataProvider;