diff --git a/crates/client-api/src/routes/database.rs b/crates/client-api/src/routes/database.rs index f871e1e9d5d..18128b79e17 100644 --- a/crates/client-api/src/routes/database.rs +++ b/crates/client-api/src/routes/database.rs @@ -223,19 +223,20 @@ fn assert_content_type_json(content_type: headers::ContentType) -> axum::respons } } -fn reducer_outcome_response(owner_identity: &Identity, reducer: &str, outcome: ReducerOutcome) -> (StatusCode, String) { +fn reducer_outcome_response( + owner_identity: &Identity, + reducer: &str, + outcome: ReducerOutcome, +) -> (StatusCode, Box) { match outcome { - ReducerOutcome::Committed => (StatusCode::OK, "".to_owned()), + ReducerOutcome::Committed => (StatusCode::OK, "".into()), ReducerOutcome::Failed(errmsg) => { // TODO: different status code? this is what cloudflare uses, sorta - (StatusCode::from_u16(530).unwrap(), errmsg) + (StatusCode::from_u16(530).unwrap(), *errmsg) } ReducerOutcome::BudgetExceeded => { log::warn!("Node's energy budget exceeded for identity: {owner_identity} while executing {reducer}"); - ( - StatusCode::PAYMENT_REQUIRED, - "Module energy budget exhausted.".to_owned(), - ) + (StatusCode::PAYMENT_REQUIRED, "Module energy budget exhausted.".into()) } } } diff --git a/crates/core/src/host/host_controller.rs b/crates/core/src/host/host_controller.rs index 46678071acf..bf7fe461a62 100644 --- a/crates/core/src/host/host_controller.rs +++ b/crates/core/src/host/host_controller.rs @@ -156,7 +156,7 @@ impl From for Result<(), anyhow::Error> { #[derive(Clone, Debug)] pub enum ReducerOutcome { Committed, - Failed(String), + Failed(Box>), BudgetExceeded, } @@ -178,7 +178,7 @@ impl From<&EventStatus> for ReducerOutcome { fn from(status: &EventStatus) -> Self { match &status { EventStatus::Committed(_) => ReducerOutcome::Committed, - EventStatus::Failed(e) => ReducerOutcome::Failed(e.clone()), + EventStatus::Failed(e) => ReducerOutcome::Failed(Box::new((&**e).into())), EventStatus::OutOfEnergy => ReducerOutcome::BudgetExceeded, } } diff --git a/crates/core/src/host/module_host.rs b/crates/core/src/host/module_host.rs index 5d819caa2a3..012883b84d2 100644 --- a/crates/core/src/host/module_host.rs +++ b/crates/core/src/host/module_host.rs @@ -578,7 +578,7 @@ pub fn call_identity_connected( // If the reducer returned an error or couldn't run due to insufficient energy, // abort the connection: the module code has decided it doesn't want this client. - ReducerOutcome::Failed(message) => Err(ClientConnectedError::Rejected(message)), + ReducerOutcome::Failed(message) => Err(ClientConnectedError::Rejected(*message)), ReducerOutcome::BudgetExceeded => Err(ClientConnectedError::OutOfEnergy), } } else { @@ -966,7 +966,7 @@ pub enum ClientConnectedError { #[error("Failed to insert `st_client` row for module without client_connected reducer: {0}")] DBError(#[from] Box), #[error("Connection rejected by `client_connected` reducer: {0}")] - Rejected(String), + Rejected(Box), #[error("Insufficient energy balance to run `client_connected` reducer")] OutOfEnergy, } diff --git a/crates/core/src/host/v8/mod.rs b/crates/core/src/host/v8/mod.rs index 730fd7a4e12..0abf9203163 100644 --- a/crates/core/src/host/v8/mod.rs +++ b/crates/core/src/host/v8/mod.rs @@ -43,6 +43,7 @@ use spacetimedb_datastore::locking_tx_datastore::FuncCallType; use spacetimedb_datastore::traits::Program; use spacetimedb_lib::{ConnectionId, Identity, RawModuleDef, Timestamp}; use spacetimedb_schema::auto_migrate::MigrationPolicy; +use spacetimedb_table::static_assert_size; use std::sync::{Arc, LazyLock}; use std::time::Instant; use tokio::sync::oneshot; @@ -368,11 +369,13 @@ impl JsInstance { self: Box, program: Program, ) -> (anyhow::Result>, Box) { - self.send_recv( - JsWorkerReply::into_init_database, - JsWorkerRequest::InitDatabase(program), - ) - .await + let (ret, inst) = self + .send_recv( + JsWorkerReply::into_init_database, + JsWorkerRequest::InitDatabase(program), + ) + .await; + (*ret, inst) } pub async fn call_procedure(self: Box, params: CallProcedureParams) -> (CallProcedureReturn, Box) { @@ -421,10 +424,12 @@ enum JsWorkerReply { CallIdentityConnected(Result<(), ClientConnectedError>), CallIdentityDisconnected(Result<(), ReducerCallError>), DisconnectClient(Result<(), ReducerCallError>), - InitDatabase(anyhow::Result>), + InitDatabase(Box>>), CallScheduledFunction(CallScheduledFunctionResult), } +static_assert_size!(JsWorkerReply, 48); + /// A request for the worker in [`spawn_instance_worker`]. // We care about optimizing for `CallReducer` as it happens frequently, // so we don't want to box anything in it. @@ -646,7 +651,7 @@ fn spawn_instance_worker( JsWorkerRequest::InitDatabase(program) => { let (res, trapped): (Result, anyhow::Error>, bool) = init_database(replica_ctx, &module_common.info().module_def, program, call_reducer); - reply("init_database", InitDatabase(res), trapped); + reply("init_database", InitDatabase(Box::new(res)), trapped); } JsWorkerRequest::CallScheduledFunction(params, rt) => { let _guard = rt.enter();