Skip to content

Commit 12efbd1

Browse files
committed
Scope plugins to drives #73
1 parent a96fd2a commit 12efbd1

File tree

6 files changed

+232
-53
lines changed

6 files changed

+232
-53
lines changed

lib/src/class_extender.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,19 @@ pub type ResourceGetHandler = Arc<
2929
pub type CommitHandler =
3030
Arc<dyn for<'a> Fn(CommitExtenderContext<'a>) -> BoxFuture<'a, AtomicResult<()>> + Send + Sync>;
3131

32+
#[derive(Clone, Debug)]
33+
pub enum ClassExtenderScope {
34+
Global,
35+
Drive(String),
36+
}
37+
3238
#[derive(Clone)]
3339
pub struct ClassExtender {
3440
pub classes: Vec<String>,
3541
pub on_resource_get: Option<ResourceGetHandler>,
3642
pub before_commit: Option<CommitHandler>,
3743
pub after_commit: Option<CommitHandler>,
44+
pub scope: ClassExtenderScope,
3845
}
3946

4047
impl ClassExtender {
@@ -66,4 +73,44 @@ impl ClassExtender {
6673
{
6774
Arc::new(handler)
6875
}
76+
77+
/// Checks if the resource is within the scope of the extender.
78+
/// To prevent unnecessary database lookups, the cached root can be supplied.
79+
/// Returns a tuple of (is_in_scope, cached_root).
80+
pub async fn check_scope(
81+
&self,
82+
resource: &Resource,
83+
store: &Db,
84+
cached_root: Option<String>,
85+
) -> AtomicResult<(bool, Option<String>)> {
86+
match &self.scope {
87+
ClassExtenderScope::Drive(scope) => {
88+
// If the resource is the scope itself we can just return true.
89+
if resource.get_subject().clone() == scope.clone() {
90+
return Ok((true, Some(resource.get_subject().clone())));
91+
}
92+
93+
// Find the root parent of the resource or use the cached root.
94+
let rs = if let Some(rs) = &cached_root {
95+
rs.clone()
96+
} else {
97+
let parents = resource.get_parent_tree(store).await?;
98+
let Some(root) = parents.last() else {
99+
return Ok((false, None));
100+
};
101+
102+
root.get_subject().clone()
103+
};
104+
105+
if rs != *scope {
106+
return Ok((false, Some(rs)));
107+
}
108+
109+
return Ok((true, Some(rs)));
110+
}
111+
ClassExtenderScope::Global => {
112+
return Ok((true, cached_root));
113+
}
114+
}
115+
}
69116
}

lib/src/collections.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Collections are dynamic resources that refer to multiple resources.
22
//! They are constructed using a [Query]
3-
use crate::class_extender::{ClassExtender, GetExtenderContext};
3+
use crate::class_extender::{ClassExtender, ClassExtenderScope, GetExtenderContext};
44
use crate::{
55
agents::ForAgent,
66
errors::AtomicResult,
@@ -25,6 +25,7 @@ pub fn get_collection_class_extender() -> ClassExtender {
2525
})),
2626
before_commit: None,
2727
after_commit: None,
28+
scope: ClassExtenderScope::Global,
2829
}
2930
}
3031

lib/src/db.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,10 +731,22 @@ impl Storelike for Db {
731731

732732
let mut transaction = Transaction::new();
733733

734+
let mut root_subject: Option<String> = None;
735+
734736
// BEFORE APPLY COMMIT HANDLERS
735737
if let Some(resource_new) = &commit_response.resource_new {
736738
for extender in self.class_extenders.iter() {
737739
if extender.resource_has_extender(resource_new)? {
740+
let (is_in_scope, cached_root) = extender
741+
.check_scope(&resource_new, self, root_subject)
742+
.await?;
743+
744+
root_subject = cached_root;
745+
746+
if !is_in_scope {
747+
continue;
748+
}
749+
738750
let Some(handler) = extender.before_commit.as_ref() else {
739751
continue;
740752
};
@@ -799,6 +811,16 @@ impl Storelike for Db {
799811
if let Some(resource_new) = &commit_response.resource_new {
800812
for extender in self.class_extenders.iter() {
801813
if extender.resource_has_extender(resource_new)? {
814+
let (is_in_scope, cached_root) = extender
815+
.check_scope(&resource_new, self, root_subject)
816+
.await?;
817+
818+
root_subject = cached_root;
819+
820+
if !is_in_scope {
821+
continue;
822+
}
823+
802824
use crate::class_extender::CommitExtenderContext;
803825

804826
let Some(handler) = extender.after_commit.as_ref() else {
@@ -886,9 +908,20 @@ impl Storelike for Db {
886908

887909
let _explanation = crate::hierarchy::check_read(self, &resource, for_agent).await?;
888910

911+
let mut root_subject: Option<String> = None;
912+
889913
// If a certain class needs to be extended, add it to this match statement
890914
for extender in self.class_extenders.iter() {
891915
if extender.resource_has_extender(&resource)? {
916+
let (is_in_scope, cached_root) =
917+
extender.check_scope(&resource, self, root_subject).await?;
918+
919+
root_subject = cached_root;
920+
921+
if !is_in_scope {
922+
continue;
923+
}
924+
892925
if skip_dynamic {
893926
// This lets clients know that the resource may have dynamic properties that are currently not included
894927
resource

server/src/plugins/chatroom.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ They list a bunch of Messages.
55
*/
66

77
use atomic_lib::{
8-
class_extender::{BoxFuture, ClassExtender, CommitExtenderContext, GetExtenderContext},
8+
class_extender::{
9+
BoxFuture, ClassExtender, ClassExtenderScope, CommitExtenderContext, GetExtenderContext,
10+
},
911
commit::{CommitBuilder, CommitOpts},
1012
errors::AtomicResult,
1113
storelike::{Query, QueryResult, ResourceResponse},
@@ -149,6 +151,7 @@ pub fn build_chatroom_extender() -> ClassExtender {
149151
on_resource_get: Some(ClassExtender::wrap_get_handler(construct_chatroom)),
150152
before_commit: None,
151153
after_commit: None,
154+
scope: ClassExtenderScope::Global,
152155
}
153156
}
154157

@@ -160,5 +163,6 @@ pub fn build_message_extender() -> ClassExtender {
160163
after_commit: Some(ClassExtender::wrap_commit_handler(
161164
after_apply_commit_message,
162165
)),
166+
scope: ClassExtenderScope::Global,
163167
}
164168
}

server/src/plugins/invite.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use atomic_lib::{
22
agents::Agent,
3-
class_extender::{BoxFuture, ClassExtender, CommitExtenderContext, GetExtenderContext},
3+
class_extender::{
4+
BoxFuture, ClassExtender, ClassExtenderScope, CommitExtenderContext, GetExtenderContext,
5+
},
46
errors::AtomicResult,
57
hierarchy,
68
storelike::ResourceResponse,
@@ -200,5 +202,6 @@ pub fn build_invite_extender() -> ClassExtender {
200202
on_resource_get: Some(ClassExtender::wrap_get_handler(construct_invite_redirect)),
201203
before_commit: Some(ClassExtender::wrap_commit_handler(before_apply_commit)),
202204
after_commit: None,
205+
scope: ClassExtenderScope::Global,
203206
}
204207
}

0 commit comments

Comments
 (0)