1+ use std:: time:: Duration ;
2+
13use crate :: CLIENT_NOT_FOUND_ERROR_MSG ;
24use crate :: admin:: FluvioAdminJS ;
35use crate :: consumer:: PartitionConsumerJS ;
46use crate :: producer:: TopicProducerJS ;
57use crate :: error:: FluvioErrorJS ;
68
9+ use fluvio:: TopicProducerConfig ;
10+ use fluvio:: Compression ;
11+ use fluvio:: TopicProducerConfigBuilder ;
12+ use node_bindgen:: core:: JSValue ;
713use tracing:: debug;
814
915use fluvio:: Fluvio ;
@@ -14,6 +20,9 @@ use node_bindgen::core::NjError;
1420use node_bindgen:: core:: val:: JsEnv ;
1521use node_bindgen:: sys:: napi_value;
1622use node_bindgen:: core:: JSClass ;
23+ use node_bindgen:: core:: val:: JsObject ;
24+
25+ use crate :: optional_property;
1726
1827impl From < Fluvio > for FluvioJS {
1928 fn from ( inner : Fluvio ) -> Self {
@@ -82,4 +91,83 @@ impl FluvioJS {
8291 Err ( FluvioErrorJS :: new ( CLIENT_NOT_FOUND_ERROR_MSG . to_owned ( ) ) )
8392 }
8493 }
94+
95+ #[ node_bindgen]
96+ async fn topic_producer_with_config (
97+ & mut self ,
98+ topic : String ,
99+ config : TopicProducerConfigWrapper ,
100+ ) -> Result < TopicProducerJS , FluvioErrorJS > {
101+ let config = config. inner ;
102+
103+ if let Some ( client) = & mut self . inner {
104+ Ok ( TopicProducerJS :: from (
105+ client. topic_producer_with_config ( topic, config) . await ?,
106+ ) )
107+ } else {
108+ Err ( FluvioErrorJS :: new ( CLIENT_NOT_FOUND_ERROR_MSG . to_owned ( ) ) )
109+ }
110+ }
111+ }
112+
113+ pub struct TopicProducerConfigWrapper {
114+ pub inner : TopicProducerConfig ,
115+ }
116+
117+ impl JSValue < ' _ > for TopicProducerConfigWrapper {
118+ fn convert_to_rust ( env : & JsEnv , js_value : napi_value ) -> Result < Self , NjError > {
119+ debug ! ( "converting topic producer config from JS" ) ;
120+ if let Ok ( js_obj) = env. convert_to_rust :: < JsObject > ( js_value) {
121+ let mut builder = TopicProducerConfigBuilder :: default ( ) ;
122+
123+ // Extract compression if provided
124+ if let Some ( compression_str) = optional_property ! ( "compression" , String , js_obj) {
125+ let compression = match compression_str. as_str ( ) {
126+ "none" => Compression :: None ,
127+ "gzip" => Compression :: Gzip ,
128+ "snappy" => Compression :: Snappy ,
129+ "lz4" => Compression :: Lz4 ,
130+ "zstd" => Compression :: Zstd ,
131+ _ => {
132+ return Err ( NjError :: Other ( format ! (
133+ "Invalid compression type: {}" ,
134+ compression_str
135+ ) ) )
136+ }
137+ } ;
138+ builder. compression ( compression) ;
139+ }
140+
141+ // Extract max_request_size if provided
142+ if let Some ( max_request_size) = optional_property ! ( "maxRequestSize" , i64 , js_obj) {
143+ builder. max_request_size ( max_request_size as usize ) ;
144+ }
145+
146+ // Extract batch_size if provided
147+ if let Some ( batch_size) = optional_property ! ( "batchSize" , i64 , js_obj) {
148+ builder. batch_size ( batch_size as usize ) ;
149+ }
150+
151+ // Extract batch_queue_size if provided
152+ if let Some ( batch_queue_size) = optional_property ! ( "batchQueueSize" , i64 , js_obj) {
153+ builder. batch_queue_size ( batch_queue_size as usize ) ;
154+ }
155+
156+ // Extract linger if provided (in milliseconds)
157+ if let Some ( linger_ms) = optional_property ! ( "lingerMs" , i64 , js_obj) {
158+ builder. linger ( Duration :: from_millis ( linger_ms as u64 ) ) ;
159+ }
160+
161+ // Build the config
162+ match builder. build ( ) {
163+ Ok ( config) => Ok ( Self { inner : config } ) ,
164+ Err ( err) => Err ( NjError :: Other ( format ! (
165+ "Failed to build TopicProducerConfig: {}" ,
166+ err
167+ ) ) ) ,
168+ }
169+ } else {
170+ Err ( NjError :: Other ( "parameter must be a JSON object" . to_owned ( ) ) )
171+ }
172+ }
85173}
0 commit comments