@@ -5,16 +5,19 @@ use self::error::{
55} ;
66use self :: ser:: serialize_to_js;
77use self :: string:: { str_from_ident, IntoJsString } ;
8- use self :: syscall:: { call_call_reducer, call_describe_module, get_hooks, resolve_sys_module, FnRet , HookFunctions } ;
8+ use self :: syscall:: {
9+ call_call_reducer, call_call_view, call_call_view_anon, call_describe_module, get_hooks, resolve_sys_module, FnRet ,
10+ HookFunctions ,
11+ } ;
912use super :: module_common:: { build_common_module_from_raw, run_describer, ModuleCommon } ;
1013use super :: module_host:: { CallProcedureParams , CallReducerParams , Module , ModuleInfo , ModuleRuntime } ;
1114use super :: UpdateDatabaseResult ;
1215use crate :: host:: instance_env:: { ChunkPool , InstanceEnv } ;
13- use crate :: host:: module_host:: Instance ;
16+ use crate :: host:: module_host:: { CallViewParams , Instance , ViewCallResult } ;
1417use crate :: host:: v8:: error:: { ErrorOrException , ExceptionThrown } ;
1518use crate :: host:: wasm_common:: instrumentation:: CallTimes ;
1619use crate :: host:: wasm_common:: module_host_actor:: {
17- DescribeError , ExecutionStats , ExecutionTimings , InstanceCommon , ReducerExecuteResult ,
20+ DescribeError , ExecutionStats , ExecutionTimings , InstanceCommon , ReducerExecuteResult , ViewExecuteResult ,
1821} ;
1922use crate :: host:: wasm_common:: { RowIters , TimingSpanSet } ;
2023use crate :: host:: { ReducerCallResult , Scheduler } ;
@@ -25,7 +28,7 @@ use anyhow::Context as _;
2528use core:: str;
2629use itertools:: Either ;
2730use spacetimedb_client_api_messages:: energy:: FunctionBudget ;
28- use spacetimedb_datastore:: locking_tx_datastore:: { FuncCallType , MutTxId } ;
31+ use spacetimedb_datastore:: locking_tx_datastore:: { FuncCallType , MutTxId , ViewCall } ;
2932use spacetimedb_datastore:: traits:: Program ;
3033use spacetimedb_lib:: { RawModuleDef , Timestamp } ;
3134use spacetimedb_schema:: auto_migrate:: MigrationPolicy ;
@@ -243,6 +246,7 @@ pub struct JsInstance {
243246 request_tx : SyncSender < JsWorkerRequest > ,
244247 update_response_rx : Receiver < anyhow:: Result < UpdateDatabaseResult > > ,
245248 call_reducer_response_rx : Receiver < ( ReducerCallResult , bool ) > ,
249+ call_view_response_rx : Receiver < ( ViewCallResult , bool ) > ,
246250 trapped : bool ,
247251}
248252
@@ -297,6 +301,24 @@ impl JsInstance {
297301 ) -> Result < super :: ProcedureCallResult , super :: ProcedureCallError > {
298302 todo ! ( "JS/TS module procedure support" )
299303 }
304+
305+ pub fn call_view ( & mut self , tx : MutTxId , params : CallViewParams ) -> ViewCallResult {
306+ // Send the request.
307+ let request = JsWorkerRequest :: CallView { tx, params } ;
308+ self . request_tx
309+ . send ( request)
310+ . expect ( "worker's `request_rx` should be live as `JsInstance::drop` hasn't happened" ) ;
311+
312+ // Wait for the response.
313+ let ( response, trapped) = self
314+ . call_view_response_rx
315+ . recv ( )
316+ . expect ( "worker's `call_view_response_tx` should be live as `JsInstance::drop` hasn't happened" ) ;
317+
318+ self . trapped = trapped;
319+
320+ response
321+ }
300322}
301323
302324/// A request for the worker in [`spawn_instance_worker`].
@@ -315,6 +337,8 @@ enum JsWorkerRequest {
315337 tx : Option < MutTxId > ,
316338 params : CallReducerParams ,
317339 } ,
340+ /// See [`JsInstance::call_view`].
341+ CallView { tx : MutTxId , params : CallViewParams } ,
318342}
319343
320344/// Performs some of the startup work of [`spawn_instance_worker`].
@@ -376,6 +400,8 @@ fn spawn_instance_worker(
376400 let ( update_response_tx, update_response_rx) = mpsc:: sync_channel ( 0 ) ;
377401 // The Worker --ReducerCallResult-> Instance channel:
378402 let ( call_reducer_response_tx, call_reducer_response_rx) = mpsc:: sync_channel ( 0 ) ;
403+ // The Worker --ViewCallResult-> Instance channel:
404+ let ( call_view_response_tx, call_view_response_rx) = mpsc:: sync_channel ( 0 ) ;
379405
380406 // This one-shot channel is used for initial startup error handling within the thread.
381407 let ( result_tx, result_rx) = oneshot:: channel ( ) ;
@@ -449,6 +475,13 @@ fn spawn_instance_worker(
449475 unreachable ! ( "should have receiver for `call_reducer` response, {e}" ) ;
450476 }
451477 }
478+ JsWorkerRequest :: CallView { tx, params } => {
479+ let res = call_view ( & mut instance_common, replica_ctx, scope, & hooks, tx, params) ;
480+
481+ if let Err ( e) = call_view_response_tx. send ( res) {
482+ unreachable ! ( "should have receiver for `call_view` response, {e}" ) ;
483+ }
484+ }
452485 }
453486 }
454487 } ) ;
@@ -460,6 +493,7 @@ fn spawn_instance_worker(
460493 request_tx,
461494 update_response_rx,
462495 call_reducer_response_rx,
496+ call_view_response_rx,
463497 trapped : false ,
464498 } ;
465499 ( opt_mc, inst)
@@ -655,6 +689,43 @@ fn call_reducer<'scope>(
655689 ( res, trapped)
656690}
657691
692+ fn call_view < ' scope > (
693+ instance_common : & mut InstanceCommon ,
694+ replica_ctx : & ReplicaContext ,
695+ scope : & mut PinScope < ' scope , ' _ > ,
696+ hooks : & HookFunctions < ' _ > ,
697+ tx : MutTxId ,
698+ params : CallViewParams ,
699+ ) -> ( ViewCallResult , bool ) {
700+ let mut trapped = false ;
701+
702+ let is_anonymous = params. is_anonymous ;
703+ let ( res, _) = instance_common. call_view_with_tx (
704+ replica_ctx,
705+ tx,
706+ params,
707+ move |a, b, c| log_traceback ( replica_ctx, a, b, c) ,
708+ |tx, op, budget| {
709+ let func = FuncCallType :: View ( if is_anonymous {
710+ ViewCall :: anonymous ( op. db_id , op. args . get_bsatn ( ) . clone ( ) )
711+ } else {
712+ ViewCall :: with_identity ( * op. caller_identity , op. db_id , op. args . get_bsatn ( ) . clone ( ) )
713+ } ) ;
714+ let ( tx, stats, call_result) =
715+ common_call ( scope, tx, op. name , op. timestamp , budget, func, & mut trapped, |scope| {
716+ Ok ( if is_anonymous {
717+ call_call_view_anon ( scope, hooks, op. into ( ) ) ?
718+ } else {
719+ call_call_view ( scope, hooks, op) ?
720+ } )
721+ } ) ;
722+ ( tx, ViewExecuteResult { stats, call_result } )
723+ } ,
724+ ) ;
725+
726+ ( res, trapped)
727+ }
728+
658729/// Extracts the raw module def by running the registered `__describe_module__` hook.
659730fn extract_description < ' scope > (
660731 scope : & mut PinScope < ' scope , ' _ > ,
0 commit comments