feat(billing): implement tenant subscription entitlements system (milestones 0-6)
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
use serde_json::Value as JsonValue;
|
||||
use std::time::Duration;
|
||||
|
||||
#[allow(unreachable_code)]
|
||||
pub async fn execute_decide_program(
|
||||
state: &JsonValue,
|
||||
command: &JsonValue,
|
||||
@@ -28,6 +29,7 @@ pub async fn execute_decide_program(
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unreachable_code)]
|
||||
pub async fn execute_apply_program(
|
||||
state: &JsonValue,
|
||||
event: &JsonValue,
|
||||
@@ -60,11 +62,10 @@ async fn execute_decide_v8(
|
||||
state: &JsonValue,
|
||||
command: &JsonValue,
|
||||
program: &str,
|
||||
gas_limit: u64,
|
||||
_gas_limit: u64,
|
||||
timeout: Duration,
|
||||
) -> Result<Vec<JsonValue>, crate::types::AggregateError> {
|
||||
use std::sync::Arc;
|
||||
use v8::{Array, Context, Function, HandleScope, Isolate, Object, Scope, Script};
|
||||
use v8::{Context, ContextScope, Function, HandleScope, Isolate, Script};
|
||||
|
||||
let state_str = serde_json::to_string(state).map_err(|e| {
|
||||
crate::types::AggregateError::DecideError(format!("State serialization: {}", e))
|
||||
@@ -73,47 +74,45 @@ async fn execute_decide_v8(
|
||||
crate::types::AggregateError::DecideError(format!("Command serialization: {}", e))
|
||||
})?;
|
||||
|
||||
let program_owned = program.to_string();
|
||||
let result = tokio::task::spawn_blocking(move || {
|
||||
let isolate = &mut Isolate::new(v8::CreateParams::default());
|
||||
|
||||
let scope = &mut HandleScope::new(isolate);
|
||||
let context = Context::new(scope);
|
||||
let context = Context::new(scope, v8::ContextOptions::default());
|
||||
let scope = &mut ContextScope::new(scope, context);
|
||||
|
||||
let source =
|
||||
v8::String::new(scope, program).ok_or_else(|| "Failed to create program string")?;
|
||||
v8::String::new(scope, &program_owned).ok_or("Failed to create program string")?;
|
||||
|
||||
let script =
|
||||
Script::compile(scope, source, None).ok_or_else(|| "Failed to compile program")?;
|
||||
let script = Script::compile(scope, source, None).ok_or("Failed to compile program")?;
|
||||
|
||||
script.run(scope).ok_or_else(|| "Failed to run program")?;
|
||||
script.run(scope).ok_or("Failed to run program")?;
|
||||
|
||||
let global = context.global(scope);
|
||||
let decide_name =
|
||||
v8::String::new(scope, "decide").ok_or_else(|| "Failed to create decide string")?;
|
||||
v8::String::new(scope, "decide").ok_or("Failed to create decide string")?;
|
||||
|
||||
let decide_fn = global
|
||||
.get(scope, decide_name.into())
|
||||
.and_then(|v| v8::Local::<Function>::try_from(v).ok())
|
||||
.ok_or_else(|| "decide function not found")?;
|
||||
.ok_or("decide function not found")?;
|
||||
|
||||
let state_json = v8::String::new(scope, &state_str)
|
||||
.ok_or_else(|| "Failed to create state JSON string")?;
|
||||
let state_obj =
|
||||
v8::json::parse(scope, state_json).ok_or_else(|| "Failed to parse state JSON")?;
|
||||
let state_json =
|
||||
v8::String::new(scope, &state_str).ok_or("Failed to create state JSON string")?;
|
||||
let state_obj = v8::json::parse(scope, state_json).ok_or("Failed to parse state JSON")?;
|
||||
|
||||
let command_json = v8::String::new(scope, &command_str)
|
||||
.ok_or_else(|| "Failed to create command JSON string")?;
|
||||
let command_json =
|
||||
v8::String::new(scope, &command_str).ok_or("Failed to create command JSON string")?;
|
||||
let command_obj =
|
||||
v8::json::parse(scope, command_json).ok_or_else(|| "Failed to parse command JSON")?;
|
||||
v8::json::parse(scope, command_json).ok_or("Failed to parse command JSON")?;
|
||||
|
||||
let args: [v8::Local<v8::Value>; 2] = [state_obj.into(), command_obj.into()];
|
||||
let args: [v8::Local<v8::Value>; 2] = [state_obj, command_obj];
|
||||
let result = decide_fn
|
||||
.call(scope, global.into(), &args)
|
||||
.ok_or_else(|| "decide function call failed")?;
|
||||
.ok_or("decide function call failed")?;
|
||||
|
||||
let result_json =
|
||||
v8::json::stringify(scope, result).ok_or_else(|| "Failed to stringify result")?;
|
||||
let result_json = v8::json::stringify(scope, result).ok_or("Failed to stringify result")?;
|
||||
let result_str = result_json.to_rust_string_lossy(scope);
|
||||
|
||||
let events: Vec<JsonValue> = serde_json::from_str(&result_str)
|
||||
@@ -155,47 +154,43 @@ async fn execute_apply_v8(
|
||||
|
||||
let _ = gas_limit;
|
||||
|
||||
let program_owned = program.to_string();
|
||||
let result = tokio::task::spawn_blocking(move || {
|
||||
let isolate = &mut Isolate::new(v8::CreateParams::default());
|
||||
|
||||
let scope = &mut HandleScope::new(isolate);
|
||||
let context = Context::new(scope);
|
||||
let context = Context::new(scope, v8::ContextOptions::default());
|
||||
let scope = &mut ContextScope::new(scope, context);
|
||||
|
||||
let source =
|
||||
v8::String::new(scope, program).ok_or_else(|| "Failed to create program string")?;
|
||||
v8::String::new(scope, &program_owned).ok_or("Failed to create program string")?;
|
||||
|
||||
let script =
|
||||
Script::compile(scope, source, None).ok_or_else(|| "Failed to compile program")?;
|
||||
let script = Script::compile(scope, source, None).ok_or("Failed to compile program")?;
|
||||
|
||||
script.run(scope).ok_or_else(|| "Failed to run program")?;
|
||||
script.run(scope).ok_or("Failed to run program")?;
|
||||
|
||||
let global = context.global(scope);
|
||||
let apply_name =
|
||||
v8::String::new(scope, "apply").ok_or_else(|| "Failed to create apply string")?;
|
||||
let apply_name = v8::String::new(scope, "apply").ok_or("Failed to create apply string")?;
|
||||
|
||||
let apply_fn = global
|
||||
.get(scope, apply_name.into())
|
||||
.and_then(|v| v8::Local::<Function>::try_from(v).ok())
|
||||
.ok_or_else(|| "apply function not found")?;
|
||||
.ok_or("apply function not found")?;
|
||||
|
||||
let state_json = v8::String::new(scope, &state_str)
|
||||
.ok_or_else(|| "Failed to create state JSON string")?;
|
||||
let state_obj =
|
||||
v8::json::parse(scope, state_json).ok_or_else(|| "Failed to parse state JSON")?;
|
||||
let state_json =
|
||||
v8::String::new(scope, &state_str).ok_or("Failed to create state JSON string")?;
|
||||
let state_obj = v8::json::parse(scope, state_json).ok_or("Failed to parse state JSON")?;
|
||||
|
||||
let event_json = v8::String::new(scope, &event_str)
|
||||
.ok_or_else(|| "Failed to create event JSON string")?;
|
||||
let event_obj =
|
||||
v8::json::parse(scope, event_json).ok_or_else(|| "Failed to parse event JSON")?;
|
||||
let event_json =
|
||||
v8::String::new(scope, &event_str).ok_or("Failed to create event JSON string")?;
|
||||
let event_obj = v8::json::parse(scope, event_json).ok_or("Failed to parse event JSON")?;
|
||||
|
||||
let args: [v8::Local<v8::Value>; 2] = [state_obj.into(), event_obj.into()];
|
||||
let args: [v8::Local<v8::Value>; 2] = [state_obj, event_obj];
|
||||
let result = apply_fn
|
||||
.call(scope, global.into(), &args)
|
||||
.ok_or_else(|| "apply function call failed")?;
|
||||
.ok_or("apply function call failed")?;
|
||||
|
||||
let result_json =
|
||||
v8::json::stringify(scope, result).ok_or_else(|| "Failed to stringify result")?;
|
||||
let result_json = v8::json::stringify(scope, result).ok_or("Failed to stringify result")?;
|
||||
let result_str = result_json.to_rust_string_lossy(scope);
|
||||
|
||||
let new_state: JsonValue = serde_json::from_str(&result_str)
|
||||
@@ -250,6 +245,7 @@ async fn execute_apply_wasm(
|
||||
mod tests {
|
||||
use super::*;
|
||||
use serde_json::json;
|
||||
use std::time::Duration;
|
||||
|
||||
#[tokio::test]
|
||||
async fn no_runtime_returns_error() {
|
||||
@@ -257,7 +253,7 @@ mod tests {
|
||||
{
|
||||
let state = json!({});
|
||||
let command = json!({});
|
||||
let result =
|
||||
let result: Result<Vec<JsonValue>, crate::types::AggregateError> =
|
||||
execute_decide_program(&state, &command, "program", 1000, Duration::from_secs(1))
|
||||
.await;
|
||||
assert!(result.is_err());
|
||||
|
||||
Reference in New Issue
Block a user