@@ -3,12 +3,12 @@ use std::time::Duration;
33use std:: { collections:: HashMap , sync:: Arc } ;
44
55use neon:: prelude:: * ;
6- use tonic:: metadata:: MetadataKey ;
6+ use tonic:: metadata:: { BinaryMetadataValue , MetadataKey } ;
77
88use temporal_sdk_core:: { ClientOptions as CoreClientOptions , CoreRuntime , RetryClient } ;
99
1010use bridge_macros:: { TryFromJs , js_function} ;
11- use temporal_client:: { ClientInitError , ConfiguredClient , TemporalServiceClientWithMetrics } ;
11+ use temporal_client:: { ClientInitError , ConfiguredClient , TemporalServiceClient } ;
1212
1313use crate :: runtime:: Runtime ;
1414use crate :: { helpers:: * , runtime:: RuntimeExt as _} ;
@@ -38,7 +38,7 @@ pub fn init(cx: &mut neon::prelude::ModuleContext) -> neon::prelude::NeonResult<
3838 Ok ( ( ) )
3939}
4040
41- type CoreClient = RetryClient < ConfiguredClient < TemporalServiceClientWithMetrics > > ;
41+ type CoreClient = RetryClient < ConfiguredClient < TemporalServiceClient > > ;
4242
4343pub struct Client {
4444 // These fields are pub because they are accessed from Worker::new
@@ -61,6 +61,10 @@ pub fn client_new(
6161
6262 let core_client = match res {
6363 Ok ( core_client) => core_client,
64+ Err ( ClientInitError :: InvalidHeaders ( e) ) => Err ( BridgeError :: TypeError {
65+ message : format ! ( "Invalid metadata key: {e}" ) ,
66+ field : None ,
67+ } ) ?,
6468 Err ( ClientInitError :: SystemInfoCallError ( e) ) => Err ( BridgeError :: TransportError (
6569 format ! ( "Failed to call GetSystemInfo: {e}" ) ,
6670 ) ) ?,
@@ -84,13 +88,27 @@ pub fn client_new(
8488#[ js_function]
8589pub fn client_update_headers (
8690 client : OpaqueInboundHandle < Client > ,
87- headers : HashMap < String , String > ,
91+ headers : HashMap < String , MetadataValue > ,
8892) -> BridgeResult < ( ) > {
93+ let ( ascii_headers, bin_headers) = config:: partition_headers ( Some ( headers) ) ;
94+ client
95+ . borrow ( ) ?
96+ . core_client
97+ . get_client ( )
98+ . set_headers ( ascii_headers. unwrap_or_default ( ) )
99+ . map_err ( |err| BridgeError :: TypeError {
100+ message : format ! ( "Invalid metadata key: {err}" ) ,
101+ field : None ,
102+ } ) ?;
89103 client
90104 . borrow ( ) ?
91105 . core_client
92106 . get_client ( )
93- . set_headers ( headers) ;
107+ . set_binary_headers ( bin_headers. unwrap_or_default ( ) )
108+ . map_err ( |err| BridgeError :: TypeError {
109+ message : format ! ( "Invalid metadata key: {err}" ) ,
110+ field : None ,
111+ } ) ?;
94112 Ok ( ( ) )
95113}
96114
@@ -122,10 +140,16 @@ pub struct RpcCall {
122140 pub rpc : String ,
123141 pub req : Vec < u8 > ,
124142 pub retry : bool ,
125- pub metadata : HashMap < String , String > ,
143+ pub metadata : HashMap < String , MetadataValue > ,
126144 pub timeout : Option < Duration > ,
127145}
128146
147+ #[ derive( Debug , Clone , TryFromJs ) ]
148+ pub enum MetadataValue {
149+ Ascii { value : String } ,
150+ Binary { value : Vec < u8 > } ,
151+ }
152+
129153/// Send a request to the Workflow Service using the provided Client
130154#[ js_function]
131155pub fn client_send_workflow_service_request (
@@ -576,16 +600,29 @@ fn rpc_req<P: prost::Message + Default>(call: RpcCall) -> BridgeResult<tonic::Re
576600
577601 let mut req = tonic:: Request :: new ( proto) ;
578602 for ( k, v) in call. metadata {
579- req. metadata_mut ( ) . insert (
580- MetadataKey :: from_str ( k. as_str ( ) ) . map_err ( |err| BridgeError :: TypeError {
581- field : None ,
582- message : format ! ( "Invalid metadata key: {err}" ) ,
583- } ) ?,
584- v. parse ( ) . map_err ( |err| BridgeError :: TypeError {
585- field : None ,
586- message : format ! ( "Invalid metadata value: {err}" ) ,
587- } ) ?,
588- ) ;
603+ match v {
604+ MetadataValue :: Ascii { value : v } => {
605+ req. metadata_mut ( ) . insert (
606+ MetadataKey :: from_str ( k. as_str ( ) ) . map_err ( |err| BridgeError :: TypeError {
607+ field : None ,
608+ message : format ! ( "Invalid metadata key: {err}" ) ,
609+ } ) ?,
610+ v. parse ( ) . map_err ( |err| BridgeError :: TypeError {
611+ field : None ,
612+ message : format ! ( "Invalid metadata value: {err}" ) ,
613+ } ) ?,
614+ ) ;
615+ }
616+ MetadataValue :: Binary { value : v } => {
617+ req. metadata_mut ( ) . insert_bin (
618+ MetadataKey :: from_str ( k. as_str ( ) ) . map_err ( |err| BridgeError :: TypeError {
619+ field : None ,
620+ message : format ! ( "Invalid metadata key: {err}" ) ,
621+ } ) ?,
622+ BinaryMetadataValue :: from_bytes ( & v) ,
623+ ) ;
624+ }
625+ }
589626 }
590627
591628 if let Some ( timeout) = call. timeout {
@@ -620,7 +657,7 @@ mod config {
620657
621658 use bridge_macros:: TryFromJs ;
622659
623- use crate :: helpers:: * ;
660+ use crate :: { client :: MetadataValue , helpers:: * } ;
624661
625662 #[ derive( Debug , Clone , TryFromJs ) ]
626663 pub ( super ) struct ClientOptions {
@@ -629,7 +666,7 @@ mod config {
629666 client_version : String ,
630667 tls : Option < TlsConfig > ,
631668 http_connect_proxy : Option < HttpConnectProxy > ,
632- headers : Option < HashMap < String , String > > ,
669+ headers : Option < HashMap < String , MetadataValue > > ,
633670 api_key : Option < String > ,
634671 disable_error_code_metric_tags : bool ,
635672 }
@@ -669,13 +706,16 @@ mod config {
669706 builder. tls_cfg ( tls. into ( ) ) ;
670707 }
671708
709+ let ( ascii_headers, bin_headers) = partition_headers ( self . headers ) ;
710+
672711 let client_options = builder
673712 . target_url ( self . target_url )
674713 . client_name ( self . client_name )
675714 . client_version ( self . client_version )
676715 // tls_cfg -- above
677716 . http_connect_proxy ( self . http_connect_proxy . map ( Into :: into) )
678- . headers ( self . headers )
717+ . headers ( ascii_headers)
718+ . binary_headers ( bin_headers)
679719 . api_key ( self . api_key )
680720 . disable_error_code_metric_tags ( self . disable_error_code_metric_tags )
681721 // identity -- skipped: will be set on worker
@@ -711,4 +751,31 @@ mod config {
711751 }
712752 }
713753 }
754+
755+ pub ( super ) fn partition_headers (
756+ headers : Option < HashMap < String , MetadataValue > > ,
757+ ) -> (
758+ Option < HashMap < String , String > > ,
759+ Option < HashMap < String , Vec < u8 > > > ,
760+ ) {
761+ let Some ( headers) = headers else {
762+ return ( None , None ) ;
763+ } ;
764+ let mut ascii_headers = HashMap :: default ( ) ;
765+ let mut bin_headers = HashMap :: default ( ) ;
766+ for ( k, v) in headers {
767+ match v {
768+ MetadataValue :: Ascii { value : v } => {
769+ ascii_headers. insert ( k, v) ;
770+ }
771+ MetadataValue :: Binary { value : v } => {
772+ bin_headers. insert ( k, v) ;
773+ }
774+ }
775+ }
776+ (
777+ ( !ascii_headers. is_empty ( ) ) . then_some ( ascii_headers) ,
778+ ( !bin_headers. is_empty ( ) ) . then_some ( bin_headers) ,
779+ )
780+ }
714781}
0 commit comments