@@ -105,6 +105,8 @@ pub enum ClientMessage<Args> {
105105 /// Remove a subscription to a SQL query that was added with SubscribeSingle.
106106 Unsubscribe ( Unsubscribe ) ,
107107 UnsubscribeMulti ( UnsubscribeMulti ) ,
108+ /// Request a procedure run.
109+ CallProcedure ( CallProcedure < Args > ) ,
108110}
109111
110112impl < Args > ClientMessage < Args > {
@@ -127,6 +129,17 @@ impl<Args> ClientMessage<Args> {
127129 ClientMessage :: Subscribe ( x) => ClientMessage :: Subscribe ( x) ,
128130 ClientMessage :: SubscribeMulti ( x) => ClientMessage :: SubscribeMulti ( x) ,
129131 ClientMessage :: UnsubscribeMulti ( x) => ClientMessage :: UnsubscribeMulti ( x) ,
132+ ClientMessage :: CallProcedure ( CallProcedure {
133+ procedure,
134+ args,
135+ request_id,
136+ flags,
137+ } ) => ClientMessage :: CallProcedure ( CallProcedure {
138+ procedure,
139+ args : f ( args) ,
140+ request_id,
141+ flags,
142+ } ) ,
130143 }
131144 }
132145}
@@ -292,6 +305,40 @@ pub struct OneOffQuery {
292305 pub query_string : Box < str > ,
293306}
294307
308+ #[ derive( SpacetimeType ) ]
309+ #[ sats( crate = spacetimedb_lib) ]
310+ /// Request a procedure run.
311+ ///
312+ /// Parametric over the argument type to enable [`ClientMessage::map_args`].
313+ pub struct CallProcedure < Args > {
314+ /// The name of the procedure to call.
315+ pub procedure : Box < str > ,
316+ /// The arguments to the procedure.
317+ ///
318+ /// In the wire format, this will be a [`Bytes`], BSATN or JSON encoded according to the reducer's argument schema
319+ /// and the enclosing message format.
320+ pub args : Args ,
321+ /// An identifier for a client request.
322+ ///
323+ /// The server will include the same ID in the response [`ProcedureResult`].
324+ pub request_id : u32 ,
325+ /// Reserved space for future extensions.
326+ pub flags : CallProcedureFlags ,
327+ }
328+
329+ #[ derive( Clone , Copy , Default , PartialEq , Eq ) ]
330+ pub enum CallProcedureFlags {
331+ #[ default]
332+ Default ,
333+ }
334+
335+ impl_st ! ( [ ] CallProcedureFlags , AlgebraicType :: U8 ) ;
336+ impl_serialize ! ( [ ] CallProcedureFlags , ( self , ser) => ser. serialize_u8( * self as u8 ) ) ;
337+ impl_deserialize ! ( [ ] CallProcedureFlags , de => match de. deserialize_u8( ) ? {
338+ 0 => Ok ( Self :: Default ) ,
339+ x => Err ( D :: Error :: custom( format_args!( "invalid call procedure flag {x}" ) ) ) ,
340+ } ) ;
341+
295342/// The tag recognized by the host and SDKs to mean no compression of a [`ServerMessage`].
296343pub const SERVER_MSG_COMPRESSION_TAG_NONE : u8 = 0 ;
297344
@@ -326,6 +373,8 @@ pub enum ServerMessage<F: WebsocketFormat> {
326373 SubscribeMultiApplied ( SubscribeMultiApplied < F > ) ,
327374 /// Sent in response to an `UnsubscribeMulti` message. This contains the matching rows.
328375 UnsubscribeMultiApplied ( UnsubscribeMultiApplied < F > ) ,
376+ /// Sent in response to a [`CallProcedure`] message. This contains the return value.
377+ ProcedureResult ( ProcedureResult < F > ) ,
329378}
330379
331380/// The matching rows of a subscription query.
@@ -705,6 +754,48 @@ pub struct OneOffTable<F: WebsocketFormat> {
705754 pub rows : F :: List ,
706755}
707756
757+ /// The result of running a procedure,
758+ /// including the return value of the procedure on success.
759+ ///
760+ /// Sent in response to a [`CallProcedure`] message.
761+ #[ derive( SpacetimeType , Debug ) ]
762+ #[ sats( crate = spacetimedb_lib) ]
763+ pub struct ProcedureResult < F : WebsocketFormat > {
764+ /// The status of the procedure run.
765+ ///
766+ /// Contains the return value if successful, or the error message if not.
767+ pub status : ProcedureStatus < F > ,
768+ /// The time when the reducer started.
769+ ///
770+ /// Note that [`Timestamp`] serializes as `i64` nanoseconds since the Unix epoch.
771+ pub timestamp : Timestamp ,
772+ /// The time the procedure took to run.
773+ pub total_host_execution_duration : TimeDuration ,
774+ /// The same same client-provided identifier as in the original [`ProcedureCall`] request.
775+ ///
776+ /// Clients use this to correlate the response with the original request.
777+ pub request_id : u32 ,
778+ }
779+
780+ /// The status of a procedure call,
781+ /// including the return value on success.
782+ #[ derive( SpacetimeType , Debug ) ]
783+ #[ sats( crate = spacetimedb_lib) ]
784+ pub enum ProcedureStatus < F : WebsocketFormat > {
785+ /// The procedure ran and returned the enclosed value.
786+ ///
787+ /// All user error handling happens within here;
788+ /// the returned value may be a `Result` or `Option`,
789+ /// or any other type to which the user may ascribe arbitrary meaning.
790+ Returned ( F :: Single ) ,
791+ /// The reducer was interrupted due to insufficient energy/funds.
792+ ///
793+ /// The procedure may have performed some observable side effects before being interrupted.
794+ OutOfEnergy ,
795+ /// The call failed in the host, e.g. due to a type error or unknown procedure name.
796+ InternalError ( String ) ,
797+ }
798+
708799/// Used whenever different formats need to coexist.
709800#[ derive( Debug , Clone ) ]
710801pub enum FormatSwitch < B , J > {
0 commit comments