implement auth macros
This commit is contained in:
parent
8c88695953
commit
aa4712b8af
22
Cargo.lock
generated
22
Cargo.lock
generated
@ -140,16 +140,6 @@ dependencies = [
|
||||
"syn 2.0.101",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "authorization"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"heromodels",
|
||||
"heromodels_core",
|
||||
"rhai",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.4.0"
|
||||
@ -1653,6 +1643,16 @@ version = "0.4.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
||||
|
||||
[[package]]
|
||||
name = "macros"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"heromodels",
|
||||
"heromodels_core",
|
||||
"rhai",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matchers"
|
||||
version = "0.1.0"
|
||||
@ -2378,11 +2378,11 @@ dependencies = [
|
||||
name = "rhailib_dsl"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"authorization",
|
||||
"chrono",
|
||||
"heromodels",
|
||||
"heromodels-derive",
|
||||
"heromodels_core",
|
||||
"macros",
|
||||
"rhai",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
@ -39,6 +39,6 @@ members = [
|
||||
"src/monitor", # Added the new monitor package to workspace
|
||||
"src/repl", # Added the refactored REPL package
|
||||
"examples",
|
||||
"src/rhai_engine_ui", "src/authorization", "src/dsl",
|
||||
"src/rhai_engine_ui", "src/macros", "src/dsl",
|
||||
]
|
||||
resolver = "2" # Recommended for new workspaces
|
||||
|
@ -10,7 +10,7 @@ heromodels = { path = "../../../db/heromodels", features = ["rhai"] }
|
||||
heromodels_core = { path = "../../../db/heromodels_core" }
|
||||
chrono = "0.4"
|
||||
heromodels-derive = { path = "../../../db/heromodels-derive" }
|
||||
authorization = { path = "../authorization"}
|
||||
macros = { path = "../macros"}
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
|
||||
|
@ -34,7 +34,6 @@ fn register_example_module(engine: &mut Engine, db: Arc<OurDB>) {
|
||||
|
||||
register_authorized_get_by_id_fn!(
|
||||
module: &mut module,
|
||||
db_clone: db.clone(),
|
||||
rhai_fn_name: "get_collection",
|
||||
resource_type_str: "Collection",
|
||||
rhai_return_rust_type: heromodels::models::library::collection::Collection // Use Collection struct
|
||||
@ -53,25 +52,12 @@ fn register_example_module(engine: &mut Engine, db: Arc<OurDB>) {
|
||||
engine.register_global_module(module.into());
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
||||
fn create_alice_engine(db_dir: &str, alice_pk: &str) -> Engine {
|
||||
let mut engine = Engine::new();
|
||||
|
||||
let temp_dir = tempdir().unwrap();
|
||||
let db = Arc::new(OurDB::new(temp_dir.path(), false).expect("Failed to create DB"));
|
||||
|
||||
register_example_module(&mut engine, db.clone());
|
||||
|
||||
println!("--- Registered Functions ---");
|
||||
// The closure now returns Option<FuncMetadata> by cloning the metadata.
|
||||
// FuncMetadata is Clone and 'static, satisfying collect_fn_metadata's requirements.
|
||||
for metadata_clone in engine.collect_fn_metadata(None, |info: rhai::FuncInfo<'_>| Some(info.metadata.clone()), true) {
|
||||
if metadata_clone.name == "get_collection" {
|
||||
println!("Found get_collection function, args: {:?}", metadata_clone.param_types);
|
||||
}
|
||||
}
|
||||
println!("--------------------------");
|
||||
|
||||
|
||||
let db_path = format!("{}/{}", db_dir, alice_pk);
|
||||
let db = Arc::new(OurDB::new(&db_path, false).expect("Failed to create DB"));
|
||||
|
||||
// Populate DB using the new `create_collection` helper.
|
||||
// Ownership is no longer on the collection itself, so we don't need owner_pk here.
|
||||
let coll = Collection::new()
|
||||
@ -83,70 +69,111 @@ fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
||||
let coll1 = Collection::new()
|
||||
.title("Alice's Private Collection")
|
||||
.description("This is Alice's private collection");
|
||||
let coll2 = Collection::new()
|
||||
.title("Bob's Shared Collection")
|
||||
.description("This is Bob's shared collection");
|
||||
let coll3 = Collection::new()
|
||||
.title("General Collection")
|
||||
.description("This is a general collection");
|
||||
|
||||
db.set(&coll1).expect("Failed to set collection");
|
||||
db.set(&coll2).expect("Failed to set collection");
|
||||
db.set(&coll3).expect("Failed to set collection");
|
||||
|
||||
// Grant access based on the new model.
|
||||
grant_access(&db, "alice_pk", "Collection", coll1.id());
|
||||
grant_access(&db, "bob_pk", "Collection", coll2.id());
|
||||
grant_access(&db, "alice_pk", "Collection", coll2.id()); // Alice can also see Bob's collection.
|
||||
grant_access(&db, "general_user_pk", "Collection", coll3.id());
|
||||
grant_access(&db, "user_pk", "Collection", coll3.id());
|
||||
|
||||
register_example_module(&mut engine, db.clone());
|
||||
let mut db_config = rhai::Map::new();
|
||||
db_config.insert("DB_PATH".into(), db_dir.clone().into());
|
||||
db_config.insert("CIRCLE_PUBLIC_KEY".into(), "alice_pk".into());
|
||||
engine.set_default_tag(Dynamic::from(db_config));
|
||||
engine
|
||||
}
|
||||
|
||||
fn create_bob_engine(db_dir: &str, bob_pk: &str) -> Engine {
|
||||
let mut engine = Engine::new();
|
||||
|
||||
let db_path = format!("{}/{}", db_dir, bob_pk);
|
||||
let db = Arc::new(OurDB::new(db_path, false).expect("Failed to create DB"));
|
||||
|
||||
let coll2 = Collection::new()
|
||||
.title("Bob's Shared Collection")
|
||||
.description("This is Bob's shared collection Alice has access.");
|
||||
|
||||
db.set(&coll2).expect("Failed to set collection");
|
||||
grant_access(&db, "alice_pk", "Collection", coll2.id());
|
||||
|
||||
register_example_module(&mut engine, db.clone());
|
||||
let mut db_config = rhai::Map::new();
|
||||
db_config.insert("DB_PATH".into(), db_dir.clone().into());
|
||||
db_config.insert("CIRCLE_PUBLIC_KEY".into(), "bob_pk".into());
|
||||
engine.set_default_tag(Dynamic::from(db_config));
|
||||
engine
|
||||
}
|
||||
|
||||
fn create_user_engine(db_dir: &str, user_pk: &str) -> Engine {
|
||||
let mut engine = Engine::new();
|
||||
|
||||
let db_path = format!("{}/{}", db_dir, user_pk);
|
||||
let db = Arc::new(OurDB::new(db_path, false).expect("Failed to create DB"));
|
||||
register_example_module(&mut engine, db.clone());
|
||||
let mut db_config = rhai::Map::new();
|
||||
db_config.insert("DB_PATH".into(), db_dir.clone().into());
|
||||
db_config.insert("CIRCLE_PUBLIC_KEY".into(), "user_pk".into());
|
||||
engine.set_default_tag(Dynamic::from(db_config));
|
||||
engine
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
||||
let db_path = format!("{}/hero/db", std::env::var("HOME").unwrap());
|
||||
let alice_pk = "alice_pk";
|
||||
let bob_pk = "bob_pk";
|
||||
let user_pk = "user_pk";
|
||||
|
||||
let mut engine_alice = create_alice_engine(&db_path, alice_pk);
|
||||
let mut engine_bob = create_bob_engine(&db_path, bob_pk);
|
||||
let mut engine_user = create_user_engine(&db_path, user_pk);
|
||||
|
||||
println!("--------------------------");
|
||||
println!("--- Rhai Authorization Example ---");
|
||||
|
||||
let mut scope = Scope::new();
|
||||
|
||||
// Scenario 1: Alice accesses her own collection (Success)
|
||||
let mut db_config = rhai::Map::new();
|
||||
db_config.insert("db_path".into(), "actual/path/to/db.sqlite".into());
|
||||
engine.set_default_tag(Dynamic::from(db_config)); // Or pass via CallFnOptions
|
||||
|
||||
// Create a Dynamic value holding your DB path or a config object
|
||||
let mut db_config = rhai::Map::new();
|
||||
db_config.insert("db_path".into(), "actual/path/to/db.sqlite".into());
|
||||
db_config.insert("CALLER_PUBLIC_KEY".into(), "alice_pk".into());
|
||||
engine.set_default_tag(Dynamic::from(db_config));
|
||||
{
|
||||
let mut tag_dynamic = engine_alice.default_tag_mut().as_map_mut().unwrap();
|
||||
tag_dynamic.insert("CALLER_PUBLIC_KEY".into(), "alice_pk".into());
|
||||
}
|
||||
// engine_alice.set_default_tag(Dynamic::from(tag_dynamic.clone()));
|
||||
|
||||
println!("Alice accessing her collection 1: Success, title"); // Access field directly
|
||||
let result = engine.eval::<Option<Collection>>("get_collection(1)")?;
|
||||
let result_clone = result.clone().expect("REASON");
|
||||
let result = engine_alice.eval::<Option<Collection>>("get_collection(1)")?;
|
||||
let result_clone = result.clone().expect("Failed to retrieve collection. It might not exist or you may not have access.");
|
||||
println!("Alice accessing her collection 1: Success, title = {}", result_clone.title); // Access field directly
|
||||
assert_eq!(result_clone.id(), 1);
|
||||
|
||||
// Scenario 2: Bob tries to access Alice's collection (Failure)
|
||||
let mut db_config = rhai::Map::new();
|
||||
db_config.insert("db_path".into(), "actual/path/to/db.sqlite".into());
|
||||
db_config.insert("CALLER_PUBLIC_KEY".into(), "bob_pk".into());
|
||||
engine.set_default_tag(Dynamic::from(db_config));
|
||||
let result = engine.eval_with_scope::<Dynamic>(&mut scope, "get_collection(1)");
|
||||
println!("Bob accessing Alice's collection 1: {:?}", result);
|
||||
let result_clone = result.expect("REASON");
|
||||
println!("Bob accessing Alice's collection 1: {:?}", result_clone);
|
||||
// assert!(result_clone.is_none());
|
||||
{
|
||||
let mut tag_dynamic = engine_bob.default_tag_mut().as_map_mut().unwrap();
|
||||
tag_dynamic.insert("CALLER_PUBLIC_KEY".into(), "bob_pk".into());
|
||||
}
|
||||
let result = engine_alice.eval_with_scope::<Option<Collection>>(&mut scope, "get_collection(1)")?;
|
||||
println!("Bob accessing Alice's collection 1: Failure as expected ({:?})", result);
|
||||
assert!(result.is_none());
|
||||
|
||||
// Scenario 3: Alice accesses Bob's collection (Success)
|
||||
let mut db_config = rhai::Map::new();
|
||||
db_config.insert("db_path".into(), "actual/path/to/db.sqlite".into());
|
||||
db_config.insert("CALLER_PUBLIC_KEY".into(), "alice_pk".into());
|
||||
engine.set_default_tag(Dynamic::from(db_config));
|
||||
let result = engine.eval_with_scope::<Collection>(&mut scope, "get_collection(2)")?;
|
||||
println!("Alice accessing Bob's collection 2: Success, title = {}", result.title); // Access field directly
|
||||
assert_eq!(result.id(), 2);
|
||||
engine_bob.set_default_tag(Dynamic::from(db_config));
|
||||
let result: Option<Collection> = engine_bob.eval_with_scope::<Option<Collection>>(&mut scope, "get_collection(2)")?;
|
||||
let collection = result.expect("Alice should have access to Bob's collection");
|
||||
println!("Alice accessing Bob's collection 2: Success, title = {}", collection.title); // Access field directly
|
||||
assert_eq!(collection.id(), 2);
|
||||
|
||||
// Scenario 4: General user lists collections (Sees 1)
|
||||
let mut db_config = rhai::Map::new();
|
||||
db_config.insert("db_path".into(), "actual/path/to/db.sqlite".into());
|
||||
db_config.insert("CALLER_PUBLIC_KEY".into(), "general_user_pk".into());
|
||||
engine.set_default_tag(Dynamic::from(db_config));
|
||||
let result = engine.eval_with_scope::<RhaiCollectionArray>(&mut scope, "list_all_collections()").unwrap();
|
||||
engine_user.set_default_tag(Dynamic::from(db_config));
|
||||
let result = engine_user.eval_with_scope::<RhaiCollectionArray>(&mut scope, "list_all_collections()").unwrap();
|
||||
println!("General user listing collections: Found {}", result.0.len());
|
||||
assert_eq!(result.0.len(), 1);
|
||||
assert_eq!(result.0[0].id(), 3);
|
||||
@ -155,8 +182,8 @@ fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
||||
let mut db_config = rhai::Map::new();
|
||||
db_config.insert("db_path".into(), "actual/path/to/db.sqlite".into());
|
||||
db_config.insert("CALLER_PUBLIC_KEY".into(), "alice_pk".into());
|
||||
engine.set_default_tag(Dynamic::from(db_config));
|
||||
let collections = engine.eval_with_scope::<RhaiCollectionArray>(&mut scope, "list_all_collections()").unwrap();
|
||||
engine_alice.set_default_tag(Dynamic::from(db_config));
|
||||
let collections = engine_alice.eval_with_scope::<RhaiCollectionArray>(&mut scope, "list_all_collections()").unwrap();
|
||||
println!("Alice listing collections: Found {}", collections.0.len());
|
||||
assert_eq!(collections.0.len(), 2);
|
||||
let ids: Vec<u32> = collections.0.iter().map(|c| c.id()).collect();
|
||||
|
@ -0,0 +1,395 @@
|
||||
#![feature(prelude_import)]
|
||||
#[prelude_import]
|
||||
use std::prelude::rust_2021::*;
|
||||
#[macro_use]
|
||||
extern crate std;
|
||||
use rhai::{Engine, Module, Position, Scope, Dynamic};
|
||||
use std::sync::Arc;
|
||||
use tempfile::tempdir;
|
||||
use heromodels::db::{Db, Collection as DbCollection};
|
||||
use heromodels::{
|
||||
db::hero::OurDB, models::library::collection::Collection,
|
||||
models::library::rhai::RhaiCollectionArray, models::access::access::Access,
|
||||
};
|
||||
use rhailib_dsl::{register_authorized_get_by_id_fn, register_authorized_list_fn};
|
||||
use rhai::{FuncRegistration, EvalAltResult};
|
||||
fn grant_access(db: &Arc<OurDB>, user_pk: &str, resource_type: &str, resource_id: u32) {
|
||||
let access_record = Access::new()
|
||||
.circle_pk(user_pk.to_string())
|
||||
.object_type(resource_type.to_string())
|
||||
.object_id(resource_id)
|
||||
.contact_id(0)
|
||||
.group_id(0);
|
||||
db.set(&access_record).expect("Failed to set access record");
|
||||
}
|
||||
fn register_example_module(engine: &mut Engine, db: Arc<OurDB>) {
|
||||
let mut module = Module::new();
|
||||
FuncRegistration::new("get_collection")
|
||||
.set_into_module(
|
||||
&mut module,
|
||||
move |
|
||||
context: rhai::NativeCallContext,
|
||||
id_val: i64,
|
||||
| -> Result<
|
||||
Option<heromodels::models::library::collection::Collection>,
|
||||
Box<EvalAltResult>,
|
||||
> {
|
||||
let actual_id: u32 = ::macros::id_from_i64_to_u32(id_val)?;
|
||||
let tag_map = context
|
||||
.tag()
|
||||
.and_then(|tag| tag.read_lock::<rhai::Map>())
|
||||
.ok_or_else(|| Box::new(
|
||||
EvalAltResult::ErrorRuntime(
|
||||
"Context tag must be a Map.".into(),
|
||||
context.position(),
|
||||
),
|
||||
))?;
|
||||
let pk_dynamic = tag_map
|
||||
.get("CALLER_PUBLIC_KEY")
|
||||
.ok_or_else(|| Box::new(
|
||||
EvalAltResult::ErrorRuntime(
|
||||
"'CALLER_PUBLIC_KEY' not found in context tag Map.".into(),
|
||||
context.position(),
|
||||
),
|
||||
))?;
|
||||
let circle_pk = tag_map
|
||||
.get("CIRCLE_PUBLIC_KEY")
|
||||
.ok_or_else(|| Box::new(
|
||||
EvalAltResult::ErrorRuntime(
|
||||
"'CIRCLE_PUBLIC_KEY' not found in context tag Map.".into(),
|
||||
context.position(),
|
||||
),
|
||||
))?;
|
||||
let circle_pk = circle_pk.clone().into_string()?;
|
||||
let db_path = ::alloc::__export::must_use({
|
||||
let res = ::alloc::fmt::format(
|
||||
format_args!("~/hero/{0}", circle_pk),
|
||||
);
|
||||
res
|
||||
});
|
||||
let db = Arc::new(
|
||||
OurDB::new(db_path, false).expect("Failed to create DB"),
|
||||
);
|
||||
let caller_pk_str = pk_dynamic.clone().into_string()?;
|
||||
{
|
||||
::std::io::_print(
|
||||
format_args!(
|
||||
"Checking access for public key: {0}\n",
|
||||
caller_pk_str,
|
||||
),
|
||||
);
|
||||
};
|
||||
if circle_pk != caller_pk_str {
|
||||
let has_access = heromodels::models::access::access::can_access_resource(
|
||||
db.clone(),
|
||||
&caller_pk_str,
|
||||
actual_id,
|
||||
"Collection",
|
||||
);
|
||||
if !has_access {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
let result = db
|
||||
.get_by_id(actual_id)
|
||||
.map_err(|e| {
|
||||
Box::new(
|
||||
EvalAltResult::ErrorRuntime(
|
||||
::alloc::__export::must_use({
|
||||
let res = ::alloc::fmt::format(
|
||||
format_args!(
|
||||
"Database error fetching {0}: {1:?}",
|
||||
"Collection",
|
||||
e,
|
||||
),
|
||||
);
|
||||
res
|
||||
})
|
||||
.into(),
|
||||
context.position(),
|
||||
),
|
||||
)
|
||||
})?;
|
||||
Ok(result)
|
||||
},
|
||||
);
|
||||
let db_instance_auth_outer = db.clone().clone();
|
||||
let db_instance_fetch = db.clone().clone();
|
||||
FuncRegistration::new("list_all_collections")
|
||||
.set_into_module(
|
||||
&mut module,
|
||||
move |
|
||||
context: rhai::NativeCallContext,
|
||||
| -> Result<
|
||||
heromodels::models::library::rhai::RhaiCollectionArray,
|
||||
Box<EvalAltResult>,
|
||||
> {
|
||||
let tag_map = context
|
||||
.tag()
|
||||
.and_then(|tag| tag.read_lock::<rhai::Map>())
|
||||
.ok_or_else(|| Box::new(
|
||||
EvalAltResult::ErrorRuntime(
|
||||
"Context tag must be a Map.".into(),
|
||||
context.position(),
|
||||
),
|
||||
))?;
|
||||
let pk_dynamic = tag_map
|
||||
.get("CALLER_PUBLIC_KEY")
|
||||
.ok_or_else(|| Box::new(
|
||||
EvalAltResult::ErrorRuntime(
|
||||
"'CALLER_PUBLIC_KEY' not found in context tag Map.".into(),
|
||||
context.position(),
|
||||
),
|
||||
))?;
|
||||
let caller_pk_str = pk_dynamic.clone().into_string()?;
|
||||
let all_items: Vec<
|
||||
heromodels::models::library::collection::Collection,
|
||||
> = db_instance_fetch
|
||||
.collection::<heromodels::models::library::collection::Collection>()
|
||||
.map_err(|e| Box::new(
|
||||
EvalAltResult::ErrorRuntime(
|
||||
::alloc::__export::must_use({
|
||||
let res = ::alloc::fmt::format(format_args!("{0:?}", e));
|
||||
res
|
||||
})
|
||||
.into(),
|
||||
Position::NONE,
|
||||
),
|
||||
))?
|
||||
.get_all()
|
||||
.map_err(|e| Box::new(
|
||||
EvalAltResult::ErrorRuntime(
|
||||
::alloc::__export::must_use({
|
||||
let res = ::alloc::fmt::format(format_args!("{0:?}", e));
|
||||
res
|
||||
})
|
||||
.into(),
|
||||
Position::NONE,
|
||||
),
|
||||
))?;
|
||||
let authorized_items: Vec<
|
||||
heromodels::models::library::collection::Collection,
|
||||
> = all_items
|
||||
.into_iter()
|
||||
.filter(|item| {
|
||||
let resource_id = item.id();
|
||||
heromodels::models::access::access::can_access_resource(
|
||||
db_instance_auth_outer.clone(),
|
||||
&caller_pk_str,
|
||||
resource_id,
|
||||
"Collection",
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
Ok(authorized_items.into())
|
||||
},
|
||||
);
|
||||
engine.register_global_module(module.into());
|
||||
}
|
||||
fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
||||
let mut engine = Engine::new();
|
||||
let temp_dir = tempdir().unwrap();
|
||||
let db = Arc::new(OurDB::new(temp_dir.path(), false).expect("Failed to create DB"));
|
||||
register_example_module(&mut engine, db.clone());
|
||||
{
|
||||
::std::io::_print(format_args!("--- Registered Functions ---\n"));
|
||||
};
|
||||
for metadata_clone in engine
|
||||
.collect_fn_metadata(
|
||||
None,
|
||||
|info: rhai::FuncInfo<'_>| Some(info.metadata.clone()),
|
||||
true,
|
||||
)
|
||||
{
|
||||
if metadata_clone.name == "get_collection" {
|
||||
{
|
||||
::std::io::_print(
|
||||
format_args!(
|
||||
"Found get_collection function, args: {0:?}\n",
|
||||
metadata_clone.param_types,
|
||||
),
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
{
|
||||
::std::io::_print(format_args!("--------------------------\n"));
|
||||
};
|
||||
let coll = Collection::new()
|
||||
.title("My new collection")
|
||||
.description("This is a new collection");
|
||||
db.set(&coll).expect("Failed to set collection");
|
||||
let coll1 = Collection::new()
|
||||
.title("Alice's Private Collection")
|
||||
.description("This is Alice's private collection");
|
||||
let coll2 = Collection::new()
|
||||
.title("Bob's Shared Collection")
|
||||
.description("This is Bob's shared collection");
|
||||
let coll3 = Collection::new()
|
||||
.title("General Collection")
|
||||
.description("This is a general collection");
|
||||
db.set(&coll1).expect("Failed to set collection");
|
||||
db.set(&coll2).expect("Failed to set collection");
|
||||
db.set(&coll3).expect("Failed to set collection");
|
||||
grant_access(&db, "alice_pk", "Collection", coll1.id());
|
||||
grant_access(&db, "bob_pk", "Collection", coll2.id());
|
||||
grant_access(&db, "alice_pk", "Collection", coll2.id());
|
||||
grant_access(&db, "general_user_pk", "Collection", coll3.id());
|
||||
{
|
||||
::std::io::_print(format_args!("--- Rhai Authorization Example ---\n"));
|
||||
};
|
||||
let mut scope = Scope::new();
|
||||
let mut db_config = rhai::Map::new();
|
||||
db_config.insert("db_path".into(), "actual/path/to/db.sqlite".into());
|
||||
engine.set_default_tag(Dynamic::from(db_config));
|
||||
let mut db_config = rhai::Map::new();
|
||||
db_config.insert("db_path".into(), "actual/path/to/db.sqlite".into());
|
||||
db_config.insert("CALLER_PUBLIC_KEY".into(), "alice_pk".into());
|
||||
db_config.insert("CIRCLE_PUBLIC_KEY".into(), "alice_pk".into());
|
||||
engine.set_default_tag(Dynamic::from(db_config));
|
||||
{
|
||||
::std::io::_print(
|
||||
format_args!("Alice accessing her collection 1: Success, title\n"),
|
||||
);
|
||||
};
|
||||
let result = engine.eval::<Option<Collection>>("get_collection(1)")?;
|
||||
let result_clone = result.clone().expect("REASON");
|
||||
{
|
||||
::std::io::_print(
|
||||
format_args!(
|
||||
"Alice accessing her collection 1: Success, title = {0}\n",
|
||||
result_clone.title,
|
||||
),
|
||||
);
|
||||
};
|
||||
match (&result_clone.id(), &1) {
|
||||
(left_val, right_val) => {
|
||||
if !(*left_val == *right_val) {
|
||||
let kind = ::core::panicking::AssertKind::Eq;
|
||||
::core::panicking::assert_failed(
|
||||
kind,
|
||||
&*left_val,
|
||||
&*right_val,
|
||||
::core::option::Option::None,
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
let mut db_config = rhai::Map::new();
|
||||
db_config.insert("db_path".into(), "actual/path/to/db.sqlite".into());
|
||||
db_config.insert("CALLER_PUBLIC_KEY".into(), "bob_pk".into());
|
||||
db_config.insert("CIRCLE_PUBLIC_KEY".into(), "alice_pk".into());
|
||||
engine.set_default_tag(Dynamic::from(db_config));
|
||||
let result = engine
|
||||
.eval_with_scope::<Option<Collection>>(&mut scope, "get_collection(1)")?;
|
||||
{
|
||||
::std::io::_print(
|
||||
format_args!(
|
||||
"Bob accessing Alice\'s collection 1: Failure as expected ({0:?})\n",
|
||||
result,
|
||||
),
|
||||
);
|
||||
};
|
||||
if !result.is_none() {
|
||||
::core::panicking::panic("assertion failed: result.is_none()")
|
||||
}
|
||||
let mut db_config = rhai::Map::new();
|
||||
db_config.insert("db_path".into(), "actual/path/to/db.sqlite".into());
|
||||
db_config.insert("CALLER_PUBLIC_KEY".into(), "alice_pk".into());
|
||||
db_config.insert("CIRCLE_PUBLIC_KEY".into(), "bob_pk".into());
|
||||
engine.set_default_tag(Dynamic::from(db_config));
|
||||
let result: Option<Collection> = engine
|
||||
.eval_with_scope::<Option<Collection>>(&mut scope, "get_collection(2)")?;
|
||||
let collection = result.expect("Alice should have access to Bob's collection");
|
||||
{
|
||||
::std::io::_print(
|
||||
format_args!(
|
||||
"Alice accessing Bob\'s collection 2: Success, title = {0}\n",
|
||||
collection.title,
|
||||
),
|
||||
);
|
||||
};
|
||||
match (&collection.id(), &2) {
|
||||
(left_val, right_val) => {
|
||||
if !(*left_val == *right_val) {
|
||||
let kind = ::core::panicking::AssertKind::Eq;
|
||||
::core::panicking::assert_failed(
|
||||
kind,
|
||||
&*left_val,
|
||||
&*right_val,
|
||||
::core::option::Option::None,
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
let mut db_config = rhai::Map::new();
|
||||
db_config.insert("db_path".into(), "actual/path/to/db.sqlite".into());
|
||||
db_config.insert("CALLER_PUBLIC_KEY".into(), "general_user_pk".into());
|
||||
engine.set_default_tag(Dynamic::from(db_config));
|
||||
let result = engine
|
||||
.eval_with_scope::<RhaiCollectionArray>(&mut scope, "list_all_collections()")
|
||||
.unwrap();
|
||||
{
|
||||
::std::io::_print(
|
||||
format_args!("General user listing collections: Found {0}\n", result.0.len()),
|
||||
);
|
||||
};
|
||||
match (&result.0.len(), &1) {
|
||||
(left_val, right_val) => {
|
||||
if !(*left_val == *right_val) {
|
||||
let kind = ::core::panicking::AssertKind::Eq;
|
||||
::core::panicking::assert_failed(
|
||||
kind,
|
||||
&*left_val,
|
||||
&*right_val,
|
||||
::core::option::Option::None,
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
match (&result.0[0].id(), &3) {
|
||||
(left_val, right_val) => {
|
||||
if !(*left_val == *right_val) {
|
||||
let kind = ::core::panicking::AssertKind::Eq;
|
||||
::core::panicking::assert_failed(
|
||||
kind,
|
||||
&*left_val,
|
||||
&*right_val,
|
||||
::core::option::Option::None,
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
let mut db_config = rhai::Map::new();
|
||||
db_config.insert("db_path".into(), "actual/path/to/db.sqlite".into());
|
||||
db_config.insert("CALLER_PUBLIC_KEY".into(), "alice_pk".into());
|
||||
engine.set_default_tag(Dynamic::from(db_config));
|
||||
let collections = engine
|
||||
.eval_with_scope::<RhaiCollectionArray>(&mut scope, "list_all_collections()")
|
||||
.unwrap();
|
||||
{
|
||||
::std::io::_print(
|
||||
format_args!("Alice listing collections: Found {0}\n", collections.0.len()),
|
||||
);
|
||||
};
|
||||
match (&collections.0.len(), &2) {
|
||||
(left_val, right_val) => {
|
||||
if !(*left_val == *right_val) {
|
||||
let kind = ::core::panicking::AssertKind::Eq;
|
||||
::core::panicking::assert_failed(
|
||||
kind,
|
||||
&*left_val,
|
||||
&*right_val,
|
||||
::core::option::Option::None,
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
let ids: Vec<u32> = collections.0.iter().map(|c| c.id()).collect();
|
||||
if !(ids.contains(&1) && ids.contains(&2)) {
|
||||
::core::panicking::panic(
|
||||
"assertion failed: ids.contains(&1) && ids.contains(&2)",
|
||||
)
|
||||
}
|
||||
Ok(())
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
pub mod library;
|
||||
pub mod access;
|
||||
|
||||
pub use authorization::register_authorized_get_by_id_fn;
|
||||
pub use authorization::register_authorized_list_fn;
|
||||
pub use authorization::id_from_i64_to_u32;
|
||||
pub use macros::register_authorized_get_by_id_fn;
|
||||
pub use macros::register_authorized_list_fn;
|
||||
pub use macros::id_from_i64_to_u32;
|
@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "authorization"
|
||||
name = "macros"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
191
src/macros/examples/access_control.rs
Normal file
191
src/macros/examples/access_control.rs
Normal file
@ -0,0 +1,191 @@
|
||||
use macros::{register_authorized_get_by_id_fn, register_authorized_list_fn};
|
||||
use rhai::{Engine, Module, Position, Scope, Dynamic};
|
||||
use std::sync::Arc;
|
||||
|
||||
// Import DB traits with an alias for the Collection trait to avoid naming conflicts.
|
||||
// Import DB traits from heromodels::db as suggested by compiler errors.
|
||||
use heromodels::db::{Db, Collection as DbCollection};
|
||||
use heromodels::{
|
||||
db::hero::OurDB,
|
||||
models::library::collection::Collection, // Actual data model for single items
|
||||
models::library::rhai::RhaiCollectionArray, // Wrapper for arrays of collections
|
||||
models::access::access::Access,
|
||||
};
|
||||
|
||||
use rhai::{FuncRegistration, EvalAltResult}; // For macro expansion
|
||||
|
||||
// Rewritten to match the new `Access` model structure.
|
||||
fn grant_access(db: &Arc<OurDB>, user_pk: &str, resource_type: &str, resource_id: u32) {
|
||||
let access_record = Access::new()
|
||||
.circle_pk(user_pk.to_string())
|
||||
.object_type(resource_type.to_string())
|
||||
.object_id(resource_id)
|
||||
.contact_id(0)
|
||||
.group_id(0);
|
||||
|
||||
db.set(&access_record).expect("Failed to set access record");
|
||||
}
|
||||
|
||||
// No changes needed here, but it relies on the new imports to compile.
|
||||
fn register_example_module(engine: &mut Engine, db: Arc<OurDB>) {
|
||||
let mut module = Module::new();
|
||||
|
||||
register_authorized_get_by_id_fn!(
|
||||
module: &mut module,
|
||||
rhai_fn_name: "get_collection",
|
||||
resource_type_str: "Collection",
|
||||
rhai_return_rust_type: heromodels::models::library::collection::Collection // Use Collection struct
|
||||
);
|
||||
|
||||
register_authorized_list_fn!(
|
||||
module: &mut module,
|
||||
db_clone: db.clone(),
|
||||
rhai_fn_name: "list_all_collections",
|
||||
resource_type_str: "Collection",
|
||||
rhai_return_rust_type: heromodels::models::library::collection::Collection, // Use Collection struct
|
||||
item_id_accessor: id, // Assumes Collection has an id() method that returns u32
|
||||
rhai_return_wrapper_type: heromodels::models::library::rhai::RhaiCollectionArray // Wrapper type for Rhai
|
||||
);
|
||||
|
||||
engine.register_global_module(module.into());
|
||||
}
|
||||
|
||||
fn create_alice_engine(db_dir: &str, alice_pk: &str) -> Engine {
|
||||
let mut engine = Engine::new();
|
||||
|
||||
let db_path = format!("{}/{}", db_dir, alice_pk);
|
||||
let db = Arc::new(OurDB::new(&db_path, false).expect("Failed to create DB"));
|
||||
|
||||
// Populate DB using the new `create_collection` helper.
|
||||
// Ownership is no longer on the collection itself, so we don't need owner_pk here.
|
||||
let coll = Collection::new()
|
||||
.title("My new collection")
|
||||
.description("This is a new collection");
|
||||
|
||||
db.set(&coll).expect("Failed to set collection");
|
||||
|
||||
let coll1 = Collection::new()
|
||||
.title("Alice's Private Collection")
|
||||
.description("This is Alice's private collection");
|
||||
let coll3 = Collection::new()
|
||||
.title("General Collection")
|
||||
.description("This is a general collection");
|
||||
|
||||
db.set(&coll1).expect("Failed to set collection");
|
||||
db.set(&coll3).expect("Failed to set collection");
|
||||
|
||||
// Grant access based on the new model.
|
||||
grant_access(&db, "alice_pk", "Collection", coll1.id());
|
||||
grant_access(&db, "user_pk", "Collection", coll3.id());
|
||||
|
||||
register_example_module(&mut engine, db.clone());
|
||||
let mut db_config = rhai::Map::new();
|
||||
db_config.insert("DB_PATH".into(), db_dir.clone().into());
|
||||
db_config.insert("CIRCLE_PUBLIC_KEY".into(), "alice_pk".into());
|
||||
engine.set_default_tag(Dynamic::from(db_config));
|
||||
engine
|
||||
}
|
||||
|
||||
fn create_bob_engine(db_dir: &str, bob_pk: &str) -> Engine {
|
||||
let mut engine = Engine::new();
|
||||
|
||||
let db_path = format!("{}/{}", db_dir, bob_pk);
|
||||
let db = Arc::new(OurDB::new(db_path, false).expect("Failed to create DB"));
|
||||
|
||||
let coll2 = Collection::new()
|
||||
.title("Bob's Shared Collection")
|
||||
.description("This is Bob's shared collection Alice has access.");
|
||||
|
||||
db.set(&coll2).expect("Failed to set collection");
|
||||
grant_access(&db, "alice_pk", "Collection", coll2.id());
|
||||
|
||||
register_example_module(&mut engine, db.clone());
|
||||
let mut db_config = rhai::Map::new();
|
||||
db_config.insert("DB_PATH".into(), db_dir.clone().into());
|
||||
db_config.insert("CIRCLE_PUBLIC_KEY".into(), "bob_pk".into());
|
||||
engine.set_default_tag(Dynamic::from(db_config));
|
||||
engine
|
||||
}
|
||||
|
||||
fn create_user_engine(db_dir: &str, user_pk: &str) -> Engine {
|
||||
let mut engine = Engine::new();
|
||||
|
||||
let db_path = format!("{}/{}", db_dir, user_pk);
|
||||
let db = Arc::new(OurDB::new(db_path, false).expect("Failed to create DB"));
|
||||
register_example_module(&mut engine, db.clone());
|
||||
let mut db_config = rhai::Map::new();
|
||||
db_config.insert("DB_PATH".into(), db_dir.clone().into());
|
||||
db_config.insert("CIRCLE_PUBLIC_KEY".into(), "user_pk".into());
|
||||
engine.set_default_tag(Dynamic::from(db_config));
|
||||
engine
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
||||
let db_path = format!("{}/hero/db", std::env::var("HOME").unwrap());
|
||||
let alice_pk = "alice_pk";
|
||||
let bob_pk = "bob_pk";
|
||||
let user_pk = "user_pk";
|
||||
|
||||
let mut engine_alice = create_alice_engine(&db_path, alice_pk);
|
||||
let mut engine_bob = create_bob_engine(&db_path, bob_pk);
|
||||
let mut engine_user = create_user_engine(&db_path, user_pk);
|
||||
|
||||
println!("--------------------------");
|
||||
println!("--- Rhai Authorization Example ---");
|
||||
|
||||
let mut scope = Scope::new();
|
||||
|
||||
// Create a Dynamic value holding your DB path or a config object
|
||||
{
|
||||
let mut tag_dynamic = engine_alice.default_tag_mut().as_map_mut().unwrap();
|
||||
tag_dynamic.insert("CALLER_PUBLIC_KEY".into(), "alice_pk".into());
|
||||
}
|
||||
// engine_alice.set_default_tag(Dynamic::from(tag_dynamic.clone()));
|
||||
|
||||
println!("Alice accessing her collection 1: Success, title"); // Access field directly
|
||||
let result = engine_alice.eval::<Option<Collection>>("get_collection(1)")?;
|
||||
let result_clone = result.clone().expect("Failed to retrieve collection. It might not exist or you may not have access.");
|
||||
println!("Alice accessing her collection 1: Success, title = {}", result_clone.title); // Access field directly
|
||||
assert_eq!(result_clone.id(), 1);
|
||||
|
||||
// Scenario 2: Bob tries to access Alice's collection (Failure)
|
||||
{
|
||||
let mut tag_dynamic = engine_bob.default_tag_mut().as_map_mut().unwrap();
|
||||
tag_dynamic.insert("CALLER_PUBLIC_KEY".into(), "bob_pk".into());
|
||||
}
|
||||
let result = engine_alice.eval_with_scope::<Option<Collection>>(&mut scope, "get_collection(1)")?;
|
||||
println!("Bob accessing Alice's collection 1: Failure as expected ({:?})", result);
|
||||
assert!(result.is_none());
|
||||
|
||||
// Scenario 3: Alice accesses Bob's collection (Success)
|
||||
let mut db_config = rhai::Map::new();
|
||||
db_config.insert("CALLER_PUBLIC_KEY".into(), "alice_pk".into());
|
||||
engine_bob.set_default_tag(Dynamic::from(db_config));
|
||||
let result: Option<Collection> = engine_bob.eval_with_scope::<Option<Collection>>(&mut scope, "get_collection(2)")?;
|
||||
let collection = result.expect("Alice should have access to Bob's collection");
|
||||
println!("Alice accessing Bob's collection 2: Success, title = {}", collection.title); // Access field directly
|
||||
assert_eq!(collection.id(), 2);
|
||||
|
||||
// Scenario 4: General user lists collections (Sees 1)
|
||||
let mut db_config = rhai::Map::new();
|
||||
db_config.insert("db_path".into(), "actual/path/to/db.sqlite".into());
|
||||
db_config.insert("CALLER_PUBLIC_KEY".into(), "general_user_pk".into());
|
||||
engine_user.set_default_tag(Dynamic::from(db_config));
|
||||
let result = engine_user.eval_with_scope::<RhaiCollectionArray>(&mut scope, "list_all_collections()").unwrap();
|
||||
println!("General user listing collections: Found {}", result.0.len());
|
||||
assert_eq!(result.0.len(), 1);
|
||||
assert_eq!(result.0[0].id(), 3);
|
||||
|
||||
// Scenario 5: Alice lists collections (Sees 2)
|
||||
let mut db_config = rhai::Map::new();
|
||||
db_config.insert("db_path".into(), "actual/path/to/db.sqlite".into());
|
||||
db_config.insert("CALLER_PUBLIC_KEY".into(), "alice_pk".into());
|
||||
engine_alice.set_default_tag(Dynamic::from(db_config));
|
||||
let collections = engine_alice.eval_with_scope::<RhaiCollectionArray>(&mut scope, "list_all_collections()").unwrap();
|
||||
println!("Alice listing collections: Found {}", collections.0.len());
|
||||
assert_eq!(collections.0.len(), 2);
|
||||
let ids: Vec<u32> = collections.0.iter().map(|c| c.id()).collect();
|
||||
assert!(ids.contains(&1) && ids.contains(&2));
|
||||
|
||||
Ok(())
|
||||
}
|
@ -14,9 +14,7 @@
|
||||
//! 2. The macros internally use `can_access_resource` for authorization checks.
|
||||
//! 3. Ensure `CALLER_PUBLIC_KEY` is set in the Rhai engine's scope before calling authorized functions.
|
||||
|
||||
use heromodels::models::access::access::can_access_resource;
|
||||
use heromodels_core::Model;
|
||||
use rhai::{EvalAltResult, NativeCallContext, Position};
|
||||
use rhai::{EvalAltResult, Position, FuncRegistration};
|
||||
use std::convert::TryFrom;
|
||||
|
||||
/// Extracts the `CALLER_PUBLIC_KEY` string constant from the Rhai `NativeCallContext`.
|
||||
@ -78,14 +76,10 @@ pub fn id_from_i64_to_u32(id_i64: i64) -> Result<u32, Box<EvalAltResult>> {
|
||||
macro_rules! register_authorized_get_by_id_fn {
|
||||
(
|
||||
module: $module:expr,
|
||||
db_clone: $db_clone:expr, // Cloned Arc<OurDB> for database access
|
||||
rhai_fn_name: $rhai_fn_name:expr, // String literal for the Rhai function name (e.g., "get_collection")
|
||||
resource_type_str: $resource_type_str:expr, // String literal for the resource type (e.g., "Collection")
|
||||
rhai_return_rust_type: $rhai_return_rust_type:ty // Rust type of the resource returned (e.g., `RhaiCollection`)
|
||||
) => {
|
||||
let db_instance_auth = $db_clone.clone();
|
||||
let db_instance_fetch = $db_clone.clone();
|
||||
|
||||
FuncRegistration::new($rhai_fn_name).set_into_module(
|
||||
$module,
|
||||
move |context: rhai::NativeCallContext, id_val: i64| -> Result<Option<$rhai_return_rust_type>, Box<EvalAltResult>> {
|
||||
@ -100,26 +94,59 @@ macro_rules! register_authorized_get_by_id_fn {
|
||||
let pk_dynamic = tag_map.get("CALLER_PUBLIC_KEY")
|
||||
.ok_or_else(|| Box::new(EvalAltResult::ErrorRuntime("'CALLER_PUBLIC_KEY' not found in context tag Map.".into(), context.position())))?;
|
||||
|
||||
let db_path = tag_map.get("DB_PATH")
|
||||
.ok_or_else(|| Box::new(EvalAltResult::ErrorRuntime("'DB_PATH' not found in context tag Map.".into(), context.position())))?;
|
||||
|
||||
let db_path = db_path.clone().into_string()?;
|
||||
|
||||
println!("DB Path: {}", db_path);
|
||||
|
||||
let circle_pk = tag_map.get("CIRCLE_PUBLIC_KEY")
|
||||
.ok_or_else(|| Box::new(EvalAltResult::ErrorRuntime("'CIRCLE_PUBLIC_KEY' not found in context tag Map.".into(), context.position())))?;
|
||||
|
||||
let circle_pk = circle_pk.clone().into_string()?;
|
||||
|
||||
let db_path = format!("{}/{}", db_path, circle_pk);
|
||||
let db = Arc::new(OurDB::new(db_path, false).expect("Failed to create DB"));
|
||||
|
||||
let caller_pk_str = pk_dynamic.clone().into_string()?;
|
||||
|
||||
// Use the standalone can_access_resource function from heromodels
|
||||
let has_access = heromodels::models::access::access::can_access_resource(
|
||||
db_instance_auth.clone(),
|
||||
&caller_pk_str,
|
||||
actual_id,
|
||||
$resource_type_str,
|
||||
);
|
||||
println!("Checking access for public key: {}", caller_pk_str);
|
||||
if circle_pk != caller_pk_str {
|
||||
// Use the standalone can_access_resource function from heromodels
|
||||
let has_access = heromodels::models::access::access::can_access_resource(
|
||||
db.clone(),
|
||||
&caller_pk_str,
|
||||
actual_id,
|
||||
$resource_type_str,
|
||||
);
|
||||
|
||||
if !has_access {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
|
||||
let all_items: Vec<$rhai_return_rust_type> = db
|
||||
.collection::<$rhai_return_rust_type>()
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(format!("{:?}", e).into(), Position::NONE)))?
|
||||
.get_all()
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(format!("{:?}", e).into(), Position::NONE)))?;
|
||||
|
||||
let result = db_instance_fetch.get_by_id(actual_id).map_err(|e| {
|
||||
for item in all_items {
|
||||
println!("{} with ID: {}", $resource_type_str, item.id());
|
||||
}
|
||||
println!("Fetching {} with ID: {}", $resource_type_str, actual_id);
|
||||
|
||||
|
||||
|
||||
let result = db.get_by_id(actual_id).map_err(|e| {
|
||||
println!("Database error fetching {} with ID: {}", $resource_type_str, actual_id);
|
||||
Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Database error fetching {}: {:?}", $resource_type_str, e).into(),
|
||||
context.position(),
|
||||
))
|
||||
})?;
|
||||
println!("Database fetched");
|
||||
Ok(result)
|
||||
},
|
||||
);
|
||||
@ -194,4 +221,4 @@ macro_rules! register_authorized_list_fn {
|
||||
},
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
use chrono::Utc;
|
||||
use log::{debug, error, info};
|
||||
use redis::AsyncCommands;
|
||||
use rhai::{Engine, Scope};
|
||||
use rhai::{Dynamic, Engine, Scope};
|
||||
use rhai_client::RhaiTaskDetails; // Import for constructing the reply message
|
||||
use serde_json;
|
||||
use std::collections::HashMap;
|
||||
@ -44,7 +44,8 @@ async fn update_task_status_in_redis(
|
||||
pub fn spawn_rhai_worker(
|
||||
_circle_id: u32, // For logging or specific logic if needed in the future
|
||||
circle_public_key: String,
|
||||
engine: Engine,
|
||||
db_path: String,
|
||||
mut engine: Engine,
|
||||
redis_url: String,
|
||||
mut shutdown_rx: mpsc::Receiver<()>, // Add shutdown receiver
|
||||
preserve_tasks: bool, // Flag to control task cleanup
|
||||
@ -86,12 +87,12 @@ pub fn spawn_rhai_worker(
|
||||
tokio::select! {
|
||||
// Listen for shutdown signal
|
||||
_ = shutdown_rx.recv() => {
|
||||
info!("Worker for Circle Public Key '{}': Shutdown signal received. Terminating loop.", circle_public_key);
|
||||
info!("Worker for Circle Public Key '{}': Shutdown signal received. Terminating loop.", circle_public_key.clone());
|
||||
break;
|
||||
}
|
||||
// Listen for tasks from Redis
|
||||
blpop_result = redis_conn.blpop(&blpop_keys, BLPOP_TIMEOUT_SECONDS as f64) => {
|
||||
debug!("Worker for Circle Public Key '{}': Attempting BLPOP on queue: {}", circle_public_key, queue_key);
|
||||
debug!("Worker for Circle Public Key '{}': Attempting BLPOP on queue: {}", circle_public_key.clone(), queue_key);
|
||||
let response: Option<(String, String)> = match blpop_result {
|
||||
Ok(resp) => resp,
|
||||
Err(e) => {
|
||||
@ -127,23 +128,19 @@ pub fn spawn_rhai_worker(
|
||||
debug!("Worker for Circle Public Key '{}', Task {}: Status updated to 'processing'.", circle_public_key, task_id);
|
||||
}
|
||||
|
||||
let mut scope = Scope::new();
|
||||
scope.push_constant("CIRCLE_PUBLIC_KEY", circle_public_key.clone());
|
||||
debug!("Worker for Circle Public Key '{}', Task {}: Injected CIRCLE_PUBLIC_KEY into scope.", circle_public_key, task_id);
|
||||
|
||||
if let Some(public_key) = public_key_opt.as_deref() {
|
||||
if !public_key.is_empty() {
|
||||
scope.push_constant("CALLER_PUBLIC_KEY", public_key.to_string());
|
||||
debug!("Worker for Circle Public Key '{}', Task {}: Injected CALLER_PUBLIC_KEY into scope.", circle_public_key, task_id);
|
||||
}
|
||||
}
|
||||
let mut db_config = rhai::Map::new();
|
||||
db_config.insert("DB_PATH".into(), db_path.clone().into());
|
||||
db_config.insert("CALLER_PUBLIC_KEY".into(), public_key_opt.unwrap_or_default().into());
|
||||
db_config.insert("CIRCLE_PUBLIC_KEY".into(), circle_public_key.clone().into());
|
||||
engine.set_default_tag(Dynamic::from(db_config)); // Or pass via CallFnOptions
|
||||
|
||||
debug!("Worker for Circle Public Key '{}', Task {}: Evaluating script with Rhai engine.", circle_public_key, task_id);
|
||||
|
||||
let mut final_status = "error".to_string(); // Default to error
|
||||
let mut final_output: Option<String> = None;
|
||||
let mut final_error_msg: Option<String> = None;
|
||||
|
||||
match engine.eval_with_scope::<rhai::Dynamic>(&mut scope, &script_content) {
|
||||
match engine.eval::<rhai::Dynamic>(&script_content) {
|
||||
Ok(result) => {
|
||||
let output_str = if result.is::<String>() {
|
||||
// If the result is a string, we can unwrap it directly.
|
||||
@ -194,7 +191,7 @@ pub fn spawn_rhai_worker(
|
||||
created_at, // Original creation time
|
||||
updated_at: Utc::now(), // Time of this final update/reply
|
||||
// reply_to_queue is no longer a field
|
||||
public_key: public_key_opt,
|
||||
public_key: public_key_opt.clone(),
|
||||
};
|
||||
match serde_json::to_string(&reply_details) {
|
||||
Ok(reply_json) => {
|
||||
|
Loading…
Reference in New Issue
Block a user