1313use crate :: db:: relational_db:: RelationalDB ;
1414use crate :: host:: module_host:: WeakModuleHost ;
1515use crate :: host:: FunctionArgs ;
16+ use bytes:: Bytes ;
1617use spacetimedb_datastore:: execution_context:: Workload ;
17- use spacetimedb_datastore:: system_tables:: { StOutboundMsgRow , ST_OUTBOUND_MSG_ID } ;
18+ use spacetimedb_datastore:: system_tables:: { st_inbound_msg_result_status , StOutboundMsgRow , ST_OUTBOUND_MSG_ID } ;
1819use spacetimedb_datastore:: traits:: IsolationLevel ;
1920use spacetimedb_lib:: { AlgebraicValue , Identity , ProductValue } ;
2021use spacetimedb_primitives:: { ColId , TableId } ;
@@ -130,7 +131,7 @@ impl TargetState {
130131/// Outcome of a delivery attempt.
131132enum DeliveryOutcome {
132133 /// Reducer succeeded (HTTP 200).
133- Success ,
134+ Success ( Bytes ) ,
134135 /// Reducer ran but returned Err (HTTP 422).
135136 ReducerError ( String ) ,
136137 /// Budget exceeded (HTTP 402).
@@ -211,14 +212,13 @@ async fn run_idc_loop(
211212}
212213
213214/// Decode the delivery outcome into `(result_status, result_payload)` for recording.
214- fn outcome_to_result ( outcome : & DeliveryOutcome ) -> ( u8 , String ) {
215- use spacetimedb_datastore:: system_tables:: st_inbound_msg_result_status;
215+ fn outcome_to_result ( outcome : & DeliveryOutcome ) -> ( u8 , Bytes ) {
216216 match outcome {
217- DeliveryOutcome :: Success => ( st_inbound_msg_result_status:: SUCCESS , String :: new ( ) ) ,
218- DeliveryOutcome :: ReducerError ( msg) => ( st_inbound_msg_result_status:: REDUCER_ERROR , msg. clone ( ) ) ,
217+ DeliveryOutcome :: Success ( payload ) => ( st_inbound_msg_result_status:: SUCCESS , payload . clone ( ) ) ,
218+ DeliveryOutcome :: ReducerError ( msg) => ( st_inbound_msg_result_status:: REDUCER_ERROR , Bytes :: from ( msg. clone ( ) ) ) ,
219219 DeliveryOutcome :: BudgetExceeded => (
220220 st_inbound_msg_result_status:: REDUCER_ERROR ,
221- "budget exceeded" . to_string ( ) ,
221+ Bytes :: from ( "budget exceeded" . to_string ( ) ) ,
222222 ) ,
223223 DeliveryOutcome :: TransportError ( _) => unreachable ! ( "transport errors never finalize" ) ,
224224 }
@@ -232,8 +232,8 @@ async fn finalize_message(
232232 db : & RelationalDB ,
233233 module_host : & WeakModuleHost ,
234234 msg : & PendingMessage ,
235- _result_status : u8 ,
236- result_payload : String ,
235+ result_status : u8 ,
236+ result_payload : Bytes ,
237237) {
238238 // Call the on_result reducer if configured.
239239 if let Some ( on_result_reducer) = & msg. on_result_reducer {
@@ -247,23 +247,37 @@ async fn finalize_message(
247247 return ;
248248 } ;
249249
250- // Encode `(request_row: OutboxRow, result: Result<(), String>)` as BSATN args.
251- let result = if result_payload. is_empty ( ) {
252- Ok :: < ( ) , String > ( ( ) )
253- } else {
254- Err :: < ( ) , String > ( result_payload)
255- } ;
256250 let mut args_bytes = Vec :: new ( ) ;
257- if let Err ( e) = spacetimedb_sats:: bsatn:: to_writer ( & mut args_bytes, & msg. request_row )
258- . and_then ( |_| spacetimedb_sats:: bsatn:: to_writer ( & mut args_bytes, & result) )
259- {
251+ if let Err ( e) = spacetimedb_sats:: bsatn:: to_writer ( & mut args_bytes, & msg. request_row ) {
260252 log:: error!(
261253 "idc_actor: failed to encode on_result args for msg_id={}: {e}" ,
262254 msg. msg_id
263255 ) ;
264256 delete_message ( db, msg. msg_id ) ;
265257 return ;
266258 }
259+ match result_status {
260+ st_inbound_msg_result_status:: SUCCESS => {
261+ args_bytes. push ( 0 ) ;
262+ args_bytes. extend_from_slice ( & result_payload) ;
263+ }
264+ st_inbound_msg_result_status:: REDUCER_ERROR => {
265+ let err = String :: from_utf8_lossy ( & result_payload) . into_owned ( ) ;
266+ if let Err ( e) = spacetimedb_sats:: bsatn:: to_writer ( & mut args_bytes, & Err :: < ( ) , String > ( err) ) {
267+ log:: error!(
268+ "idc_actor: failed to encode on_result error args for msg_id={}: {e}" ,
269+ msg. msg_id
270+ ) ;
271+ delete_message ( db, msg. msg_id ) ;
272+ return ;
273+ }
274+ }
275+ status => {
276+ log:: error!( "idc_actor: unexpected result status {status} for msg_id={}" , msg. msg_id) ;
277+ delete_message ( db, msg. msg_id ) ;
278+ return ;
279+ }
280+ }
267281
268282 let caller_identity = Identity :: ZERO ; // system call
269283 let result = host
@@ -452,7 +466,7 @@ async fn attempt_delivery(client: &reqwest::Client, config: &IdcActorConfig, msg
452466 let status = resp. status ( ) ;
453467 if status. is_success ( ) {
454468 // HTTP 200: reducer committed successfully.
455- DeliveryOutcome :: Success
469+ DeliveryOutcome :: Success ( resp . bytes ( ) . await . unwrap_or_default ( ) )
456470 } else if status. as_u16 ( ) == 422 {
457471 // HTTP 422: reducer ran but returned Err(...).
458472 let body = resp. text ( ) . await . unwrap_or_default ( ) ;
0 commit comments