openiap_clib/
lib.rs

1// #![warn(missing_docs)]
2//! FFI bindings for the OpenIAP client library.
3//! used by the OpenIAP client library for other programming languages to interact with the client library.
4//! For now, nodejs, python and dotnet 6
5use openiap_client::protos::{
6    AggregateRequest, CountRequest, DistinctRequest, DownloadRequest, Envelope, InsertOneRequest,
7    QueryRequest, SigninRequest, UploadRequest, WatchEvent, WatchRequest,
8};
9use openiap_client::{Client, ClientEvent, CreateCollectionRequest, CreateIndexRequest, DeleteManyRequest, DeleteOneRequest, DeleteWorkitemRequest, DropCollectionRequest, DropIndexRequest, GetIndexesRequest, InsertManyRequest, InsertOrUpdateOneRequest, PopWorkitemRequest, PushWorkitemRequest, QueueEvent, QueueMessageRequest, RegisterExchangeRequest, RegisterQueueRequest, Timestamp, UpdateOneRequest, UpdateWorkitemRequest, Workitem, WorkitemFile};
10
11#[cfg(all(test, not(windows)))]
12mod tests;
13
14use std::collections::{HashMap, VecDeque};
15use std::ffi::CStr;
16use std::ffi::CString;
17use std::os::raw::c_char;
18use std::sync::Mutex;
19use std::vec;
20// use tokio::runtime::Runtime;
21use tracing::{debug, info, trace};
22
23mod safe_wrappers;
24use safe_wrappers::{c_char_to_str, safe_wrapper};
25
26use lazy_static::lazy_static;
27lazy_static! {
28    // TODO: Add max size for the queues
29    static ref WATCH_EVENTS: std::sync::Mutex<HashMap<String, VecDeque<WatchEvent>>> = {
30        let m = HashMap::new();
31        Mutex::new(m)
32    };
33    static ref QUEUE_EVENTS: std::sync::Mutex<HashMap<String, VecDeque<QueueEvent>>> = {
34        let m = HashMap::new();
35        Mutex::new(m)
36    };
37    static ref CLIENT_EVENTS: std::sync::Mutex<HashMap<String, VecDeque<ClientEvent>>> = {
38        let m = HashMap::new();
39        Mutex::new(m)
40    };
41
42}
43/// A wrapper for the client library.
44/// This struct is used to hold the client instance and the runtime instance.
45#[repr(C)]
46pub struct ClientWrapper {
47    success: bool,
48    error: *const c_char,
49    client: Option<Client>
50}
51/// WatchEventWrapper is a wrapper for the WatchEvent struct.
52#[repr(C)]
53#[derive(Debug, Clone)]
54pub struct WatchEventWrapper {
55    id: *const c_char,
56    operation: *const c_char,
57    document: *const c_char,
58    request_id: i32,
59}
60impl Default for WatchEventWrapper {
61    fn default() -> Self { 
62        WatchEventWrapper {
63            id: std::ptr::null(),
64            operation: std::ptr::null(),
65            document: std::ptr::null(),
66            request_id: 0,
67        }
68     }
69}
70#[repr(C)]
71pub struct UserWrapper {
72    id: *const c_char,
73    name: *const c_char,
74    username: *const c_char,
75    email: *const c_char,
76    roles: *const *const c_char,
77    roles_len: i32,
78}
79
80/// Return currentlly signed in user
81#[no_mangle]
82#[tracing::instrument(skip_all)]
83pub extern "C" fn client_user(
84    client: *mut ClientWrapper
85) -> *const UserWrapper {
86    let client_wrapper = match safe_wrapper(client) {
87        Some(client) => client,
88        None => {
89            return std::ptr::null();
90        }
91    };
92    let b = client_wrapper.client.clone().unwrap();
93    let user = b.get_user();
94    match user {
95        None => {
96            return std::ptr::null();
97        }
98        Some(user) => {
99            // Immediately leak each CString for each role, casting to *const c_char.
100            let role_ptrs: Vec<*const c_char> = user.roles.iter()
101            .map(|role| {
102                CString::new(role.name.clone())
103                    .unwrap()
104                    .into_raw() as *const c_char  // Cast here to get *const c_char
105            })
106            .collect();
107
108            // Leak the boxed slice that holds the role pointers.
109            let roles_len = role_ptrs.len();  // Use the length of the vector
110            let roles_buf = role_ptrs.into_boxed_slice();
111            let roles_ptr = Box::into_raw(roles_buf) as *const *const c_char;
112
113            let response = UserWrapper {
114                id: CString::new(user.id).unwrap().into_raw(),
115                name: CString::new(user.name).unwrap().into_raw(),
116                username: CString::new(user.username).unwrap().into_raw(),
117                email: CString::new(user.email).unwrap().into_raw(),
118                roles: roles_ptr,
119                roles_len: roles_len as i32,
120            };
121            return Box::into_raw(Box::new(response)) as *mut UserWrapper;
122        }
123    }
124}
125/// Free the user wrapper
126#[no_mangle]
127#[tracing::instrument(skip_all)]
128pub extern "C" fn free_user(user: *mut UserWrapper) {
129    if user.is_null() {
130        return;
131    }
132    unsafe {
133        if !(*user).id.is_null() {
134            let _ = CString::from_raw((*user).id as *mut c_char);
135        }
136        if !(*user).name.is_null() {
137            let _ = CString::from_raw((*user).name as *mut c_char);
138        }
139        if !(*user).username.is_null() {
140            let _ = CString::from_raw((*user).username as *mut c_char);
141        }
142        if !(*user).email.is_null() {
143            let _ = CString::from_raw((*user).email as *mut c_char);
144        }
145        if !(*user).roles.is_null() {
146            let roles = (*user).roles;
147            let mut i = 0;
148            while !roles.offset(i).is_null() {
149                let _ = CString::from_raw(roles.offset(i) as *mut c_char);
150                i += 1;
151            }
152        }
153        let _ = Box::from_raw(user);
154    }
155}
156
157/// QueryRequestWrapper is a wrapper for the QuQueryResponseWrappereryRequest struct.
158#[repr(C)]
159pub struct QueryRequestWrapper {
160    collectionname: *const c_char,
161    query: *const c_char,
162    projection: *const c_char,
163    orderby: *const c_char,
164    queryas: *const c_char,
165    explain: bool,
166    skip: i32,
167    top: i32,
168    request_id: i32,
169}
170/// QueryResponseWrapper is a wrapper for the QueryResponse struct.
171#[repr(C)]
172pub struct QueryResponseWrapper {
173    success: bool,
174    results: *const c_char,
175    error: *const c_char,
176    request_id: i32,
177}
178// run query syncronously
179#[no_mangle]
180#[tracing::instrument(skip_all)]
181pub extern "C" fn query(
182    client: *mut ClientWrapper,
183    options: *mut QueryRequestWrapper,
184) -> *mut QueryResponseWrapper {
185    let options = match safe_wrapper(options) {
186        Some(options) => options,
187        None => {
188            let error_msg = CString::new("Invalid options").unwrap().into_raw();
189            let response = QueryResponseWrapper {
190                success: false,
191                results: std::ptr::null(),
192                error: error_msg,
193                request_id: 0,
194            };
195            return Box::into_raw(Box::new(response));
196        }
197    };
198    let client_wrapper = match safe_wrapper(client) {
199        Some(client) => client,
200        None => {
201            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
202            let response = QueryResponseWrapper {
203                success: false,
204                results: std::ptr::null(),
205                error: error_msg,
206                request_id: options.request_id,
207            };
208            return Box::into_raw(Box::new(response));
209        }
210    };
211    let request = QueryRequest {
212        collectionname: c_char_to_str(options.collectionname),
213        query: c_char_to_str(options.query),
214        projection: c_char_to_str(options.projection),
215        orderby: c_char_to_str(options.orderby),
216        queryas: c_char_to_str(options.queryas),
217        explain: options.explain,
218        skip: options.skip,
219        top: options.top
220    };
221    if client_wrapper.client.is_none() {
222        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
223        let response = QueryResponseWrapper {
224            success: false,
225            results: std::ptr::null(),
226            error: error_msg,
227            request_id: options.request_id,
228        };
229        return Box::into_raw(Box::new(response));
230    }
231    let client = client_wrapper.client.clone().unwrap();
232
233    let result = tokio::task::block_in_place(|| {
234        let handle = client.get_runtime_handle();
235        handle.block_on(client.query(request))
236    });
237    Box::into_raw(Box::new(match result {
238        Ok(data) => {
239            let results: *const c_char = CString::new(data.results).unwrap().into_raw();
240            QueryResponseWrapper {
241                success: true,
242                results,
243                error: std::ptr::null(),
244                request_id: options.request_id,
245            }
246        }
247        Err(e) => {
248            let error_msg = CString::new(format!("Query failed: {:?}", e))
249                .unwrap()
250                .into_raw();
251            QueryResponseWrapper {
252                success: false,
253                results: std::ptr::null(),
254                error: error_msg,
255                request_id: options.request_id,
256            }
257        }
258    }))
259}
260/// QueryCallback is a callback function for the query_async function.
261type QueryCallback = extern "C" fn(wrapper: *mut QueryResponseWrapper);
262// run query asyncronously
263#[no_mangle]
264#[tracing::instrument(skip_all)]
265pub extern "C" fn query_async(
266    client: *mut ClientWrapper,
267    options: *mut QueryRequestWrapper,
268    callback: QueryCallback,
269) {
270    debug!("Rust: query_async");
271    let options = match safe_wrapper(options) {
272        Some(options) => options,
273        None => {
274            let error_msg = CString::new("Invalid options").unwrap().into_raw();
275            let response = QueryResponseWrapper {
276                success: false,
277                results: std::ptr::null(),
278                error: error_msg,
279                request_id: 0,
280            };
281            return callback(Box::into_raw(Box::new(response)));
282        }
283    };
284    let client_wrapper = match safe_wrapper(client) {
285        Some(client) => client,
286        None => {
287            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
288            let response = QueryResponseWrapper {
289                success: false,
290                results: std::ptr::null(),
291                error: error_msg,
292                request_id: options.request_id,
293            };
294            return callback(Box::into_raw(Box::new(response)));
295        }
296    };
297    let client = client_wrapper.client.clone();
298    let collectionname = c_char_to_str(options.collectionname);
299    let query = c_char_to_str(options.query);
300    let projection = c_char_to_str(options.projection);
301    let orderby = c_char_to_str(options.orderby);
302    let queryas = c_char_to_str(options.queryas);
303    let explain = options.explain;
304    let skip = options.skip;
305    let top = options.top;
306    debug!("Rust: query_async: collectionname: {}, query: {}, projection: {}, orderby: {}, queryas: {}, explain: {}, skip: {}, top: {}", collectionname, query, projection, orderby, queryas, explain, skip, top);
307
308    let request = QueryRequest {
309        collectionname: collectionname.to_string(),
310        query: query.to_string(),
311        projection: projection.to_string(),
312        orderby: orderby.to_string(),
313        queryas: queryas.to_string(),
314        explain,
315        skip,
316        top
317    };    
318    if client.is_none() {
319        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
320        let response = QueryResponseWrapper {
321            success: false,
322            results: std::ptr::null(),
323            error: error_msg,
324            request_id: options.request_id,
325        };
326        return callback(Box::into_raw(Box::new(response)));
327    }
328
329    debug!("Rust: runtime.spawn");
330    let client = client.unwrap();
331    let handle = client.get_runtime_handle();
332    let request_id = options.request_id;
333    // tokio::spawn(async move {
334    let _guard = handle.enter();
335    handle.spawn(async move {
336        debug!("Rust: client.query");
337        let result = client.query(request).await;
338
339        let response = match result {
340            Ok(data) => {
341                let results: *const c_char = CString::new(data.results).unwrap().into_raw();
342                QueryResponseWrapper {
343                    success: true,
344                    results,
345                    error: std::ptr::null(),
346                    request_id: request_id,
347                }
348            }
349            Err(e) => {
350                let error_msg = CString::new(format!("Query failed: {:?}", e))
351                    .unwrap()
352                    .into_raw();
353                QueryResponseWrapper {
354                    success: false,
355                    results: std::ptr::null(),
356                    error: error_msg,
357                    request_id: request_id,
358                }
359            }
360        };
361        debug!("Rust: callback response");
362        callback(Box::into_raw(Box::new(response)));
363    });
364}
365#[no_mangle]
366#[tracing::instrument(skip_all)]
367pub extern "C" fn free_query_response(response: *mut QueryResponseWrapper) {
368    if response.is_null() {
369        return;
370    }
371    unsafe {
372        if !(*response).error.is_null() {
373            let _ = CString::from_raw((*response).error as *mut c_char);
374        }
375        if !(*response).results.is_null() {
376            let _ = CString::from_raw((*response).results as *mut c_char);
377        }
378        let _ = Box::from_raw(response);
379    }
380}
381
382
383#[no_mangle]
384#[tracing::instrument(skip_all)]
385pub extern "C" fn enable_tracing(rust_log: *const c_char, tracing: *const c_char) {
386    let rust_log = c_char_to_str(rust_log);
387    let rust_log = rust_log.to_string();
388    let tracing = c_char_to_str(tracing);
389    let tracing = tracing.to_string();
390    openiap_client::enable_tracing(&rust_log, &tracing);
391}
392#[no_mangle]
393#[tracing::instrument(skip_all)]
394pub extern "C" fn disable_tracing() {
395    openiap_client::disable_tracing();
396}
397
398
399fn free<T>(ptr: *mut T) {
400    if ptr.is_null() {
401        return;
402    }
403    unsafe {
404        let _ = Box::from_raw(ptr);
405    }
406}
407
408#[no_mangle]
409pub extern "C" fn create_client() -> *mut ClientWrapper {
410    let client = Client::new();
411    trace!("create_client");
412    Box::into_raw(Box::new(ClientWrapper {
413        client: Some(client),
414        success: true,
415        error: std::ptr::null(),
416    }))    
417}
418/// A wrapper for the client library.
419/// This struct is used to hold the client instance and the runtime instance.
420#[repr(C)]
421pub struct ConnectResponseWrapper {
422    success: bool,
423    error: *const c_char,
424    request_id: i32,
425}
426#[no_mangle]
427pub extern "C" fn client_connect(client_wrap: *mut ClientWrapper, server_address: *const c_char) -> *mut ConnectResponseWrapper {
428    let server_address = c_char_to_str(server_address);
429    trace!("server_address = {:?}", server_address);
430    let client = match safe_wrapper( client_wrap ) {
431        Some( wrap ) => wrap.client.clone().unwrap(),
432        None => {
433            Client::new()
434        }
435    };
436    trace!("connect::begin");
437    let res: Result<(), openiap_client::OpenIAPError> = client.connect(&server_address);
438    trace!("connect::complete");
439    if res.is_err() {
440        let e = res.err().unwrap();
441        debug!("error_msg = {:?}", format!("Connection failed: {:?}", e));
442        let error_msg = CString::new(format!("Connection failed: {:?}", e))
443            .unwrap()
444            .into_raw();
445        
446        let result = Box::into_raw(Box::new(ConnectResponseWrapper {
447            success: false,
448            error: error_msg,
449            request_id: 0,
450        }));
451        debug!("connect::complete error result address: {:?}", result);
452        return result;
453    }
454    let result = Box::into_raw(Box::new(ConnectResponseWrapper {
455        success: true,
456        error: std::ptr::null(),
457        request_id: 0,
458    }));
459    trace!("connect::complete result address: {:?}", result);
460    result
461}
462type ConnectCallback = extern "C" fn(wrapper: *mut ConnectResponseWrapper);
463#[no_mangle]
464#[tracing::instrument(skip_all)]
465pub extern "C" fn connect_async(client: *mut ClientWrapper, server_address: *const c_char, request_id: i32, callback: ConnectCallback) {
466    debug!("connect_async");
467    let server_address = c_char_to_str(server_address);
468    debug!("server_address = {:?}", server_address);
469
470    let client = match safe_wrapper( client ) {
471        Some( wrap ) => wrap.client.clone().unwrap(),
472        None => {
473            Client::new()
474        }
475    };
476
477    trace!("Spawn the async task");
478    let client_result: Result<(), openiap_client::OpenIAPError> = client.connect(&server_address);
479    let handle = client.get_runtime_handle();
480    handle.spawn(async move {
481        let wrapper = if client_result.is_ok() {
482            Box::into_raw(Box::new(ConnectResponseWrapper {
483                success: true,
484                error: std::ptr::null(),
485                request_id,
486            }))
487        } else {
488            let e = client_result.err().unwrap();
489            let error_msg = CString::new(format!("Connection failed: {:?}", e))
490                .unwrap()
491                .into_raw();
492            Box::into_raw(Box::new(ConnectResponseWrapper {
493                success: false,
494                error: error_msg,
495                request_id,
496            }))
497        };
498        trace!("Client::Calling callback with result");
499        callback(wrapper);
500    });
501}
502#[no_mangle]
503pub extern "C" fn client_set_agent_name(client_wrap: *mut ClientWrapper, agent_name: *const c_char) {
504    let agent_name = c_char_to_str(agent_name);
505    debug!("set_agent_name = {:?}", agent_name);
506    let client = match safe_wrapper( client_wrap ) {
507        Some( wrap ) => wrap.client.clone().unwrap(),
508        None => {
509            Client::new()
510        }
511    };
512    client.set_agent_name(&agent_name);
513}
514#[no_mangle]
515pub extern "C" fn client_set_agent_version(client_wrap: *mut ClientWrapper, agent_version: *const c_char) {
516    let agent_version = c_char_to_str(agent_version);
517    debug!("set_agent_version = {:?}", agent_version);
518    let client = match safe_wrapper( client_wrap ) {
519        Some( wrap ) => wrap.client.clone().unwrap(),
520        None => {
521            Client::new()
522        }
523    };
524    client.set_agent_version(&agent_version);
525}
526#[no_mangle]
527#[tracing::instrument(skip_all)]
528pub extern "C" fn free_connect_response(response: *mut ConnectResponseWrapper) {
529    free(response);
530}
531
532#[no_mangle]
533#[tracing::instrument(skip_all)]
534pub extern "C" fn client_disconnect(client_wrap: *mut ClientWrapper) {
535    let client = match safe_wrapper( client_wrap ) {
536        Some( wrap ) => wrap.client.clone().unwrap(),
537        None => {
538            Client::new()
539        }
540    };
541    client.disconnect();
542}
543#[no_mangle]
544#[tracing::instrument(skip_all)]
545pub extern "C" fn free_client(response: *mut ClientWrapper) {
546    if response.is_null() {
547        debug!("free_client: response is null");
548        return;
549    }
550    unsafe {
551        let response_ref: &ClientWrapper = match safe_wrapper(response) {
552            Some(response) => response,
553            None => {
554                debug!("free_client: response is not valid");
555                return;
556            }
557        };
558        if !response_ref.error.is_null() {
559            let error_cstr = CStr::from_ptr(response_ref.error);
560            if let Ok(error_str) = error_cstr.to_str() {
561                debug!("free_client: error = {}", error_str);
562            } else {
563                debug!("free_client: error = <invalid UTF-8>");
564            }
565        }
566
567        if let Some(client) = &response_ref.client {
568            // let client_clone = client.clone();
569            client.disconnect();
570
571            let handle = client.get_runtime_handle();
572            // Ensure that the runtime properly shuts down after the block_on call
573            handle.spawn(async move {
574                {
575                    // let inner = client_clone.inner.lock().await;
576                    let inner = client.inner.lock().await;
577                    let mut queries = inner.queries.lock().await;
578
579                    // Cancel pending requests
580                    for (id, response_tx) in queries.drain() {
581                        debug!("free_client: canceling request with id: {:?}", id);
582                        let _ = response_tx.send(Envelope {
583                            command: "cancelled".to_string(),
584                            ..Default::default()
585                        });
586                    }
587
588                    // debug!("free_client: released queries lock");
589                } // Ensure locks are dropped before proceeding
590
591                {
592                    let inner = client.inner.lock().await;
593                    let mut streams = inner.streams.lock().await;
594                    let stream_keys = streams.keys().cloned().collect::<Vec<String>>();
595                    stream_keys.iter().for_each(|k| {
596                        debug!("free_client: client inner state: stream: {:?}", k);
597                        streams.remove(k.clone().as_str());
598                    });
599                    // debug!("free_client: released streams lock");
600                } // Ensure locks are dropped before proceeding
601            });
602        }
603        // Free the client
604        // let _client_wrapper: Box<ClientWrapper> = Box::from_raw(response);
605        // debug!("free_client 5");
606    }
607    debug!("free_client::complete");
608}
609
610#[repr(C)]
611pub struct SigninRequestWrapper {
612    username: *const c_char,
613    password: *const c_char,
614    jwt: *const c_char,
615    agent: *const c_char,
616    version: *const c_char,
617    longtoken: bool,
618    validateonly: bool,
619    ping: bool,
620    request_id: i32
621}
622#[repr(C)]
623pub struct SigninResponseWrapper {
624    success: bool,
625    jwt: *const c_char,
626    error: *const c_char,
627    request_id: i32
628}
629
630#[no_mangle]
631#[tracing::instrument(skip_all)]
632pub extern "C" fn signin(
633    client: *mut ClientWrapper,
634    options: *mut SigninRequestWrapper,
635) -> *mut SigninResponseWrapper {
636    let options = match safe_wrapper( options ) {
637        Some( options ) => options,
638        None => {
639            let error_msg = CString::new("Invalid options").unwrap().into_raw();
640            let response = SigninResponseWrapper {
641                success: false,
642                jwt: std::ptr::null(),
643                error: error_msg,
644                request_id: 0,
645            };
646            return Box::into_raw(Box::new(response));
647        }
648    };
649    let client_wrapper: &mut ClientWrapper = match safe_wrapper( client ) {
650        Some( client ) => client,
651        None => {
652            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
653            let response = SigninResponseWrapper {
654                success: false,
655                jwt: std::ptr::null(),
656                error: error_msg,
657                request_id: options.request_id,
658            };
659            return Box::into_raw(Box::new(response));
660        }
661    };
662    let client = client_wrapper.client.clone();
663
664    let request = SigninRequest {
665        username: c_char_to_str(options.username),
666        password: c_char_to_str(options.password),
667        jwt: c_char_to_str(options.jwt),
668        agent: c_char_to_str(options.agent),
669        version: c_char_to_str(options.version),
670        longtoken: options.longtoken,
671        ping: options.ping,
672        validateonly: options.validateonly
673    };
674
675    if client.is_none() {
676        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
677        let response = SigninResponseWrapper {
678            success: false,
679            jwt: std::ptr::null(),
680            error: error_msg,
681            request_id: options.request_id,
682        };
683        return Box::into_raw(Box::new(response));
684    }
685    let client = client.unwrap();
686    let result = tokio::task::block_in_place(|| {
687        let handle = client.get_runtime_handle();
688        handle.block_on(client.signin(request))
689    });
690
691    let response = match result {
692        Ok(data) => {
693            let jwt = CString::new(data.jwt).unwrap().into_raw();
694            SigninResponseWrapper {
695                success: true,
696                jwt,
697                error: std::ptr::null(),
698                request_id: options.request_id,
699            }
700        }
701        Err(e) => {
702            let error_msg = CString::new(format!("Signin failed: {:?}", e))
703                .unwrap()
704                .into_raw();
705            SigninResponseWrapper {
706                success: false,
707                jwt: std::ptr::null(),
708                error: error_msg,
709                request_id: options.request_id,
710            }
711        }
712    };
713
714    Box::into_raw(Box::new(response))
715}
716
717type SigninCallback = extern "C" fn(wrapper: *mut SigninResponseWrapper);
718#[no_mangle]
719#[tracing::instrument(skip_all)]
720pub extern "C" fn signin_async(
721    client: *mut ClientWrapper,
722    options: *mut SigninRequestWrapper,
723    callback: SigninCallback,
724) {
725    let options = match safe_wrapper(options ) {
726        Some( options ) => options,
727        None => {
728            let error_msg = CString::new("Invalid options").unwrap().into_raw();
729            let response = SigninResponseWrapper {
730                success: false,
731                jwt: std::ptr::null(),
732                error: error_msg,
733                request_id: 0,
734            };
735            return callback(Box::into_raw(Box::new(response)));
736        }
737    };
738    let client_wrapper = match safe_wrapper(client) {
739        Some( client ) => client,
740        None => {
741            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
742            let response = SigninResponseWrapper {
743                success: false,
744                jwt: std::ptr::null(),
745                error: error_msg,
746                request_id: options.request_id,
747            };
748            return callback(Box::into_raw(Box::new(response)));
749        }
750    };
751    let client = client_wrapper.client.clone();
752
753    let request = SigninRequest {
754        username: c_char_to_str(options.username),
755        password: c_char_to_str(options.password),
756        jwt: c_char_to_str(options.jwt),
757        agent: c_char_to_str(options.agent),
758        version: c_char_to_str(options.version),
759        longtoken: options.longtoken,
760        ping: options.ping,
761        validateonly: options.validateonly
762    };
763
764    if client.is_none() {
765        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
766        let response = SigninResponseWrapper {
767            success: false,
768            jwt: std::ptr::null(),
769            error: error_msg,
770            request_id: options.request_id,
771        };
772        return callback(Box::into_raw(Box::new(response)));
773    }
774    let client = client.unwrap();
775    let handle = client.get_runtime_handle();
776    let request_id = options.request_id;
777    handle.spawn(async move {
778        // let result = client_clone.unwrap().signin(request).await;
779        let result = client.signin(request).await;
780
781        let response = match result {
782            Ok(data) => {
783                let jwt = CString::new(data.jwt).unwrap().into_raw();
784                Box::new(SigninResponseWrapper {
785                    success: true,
786                    jwt,
787                    error: std::ptr::null(),
788                    request_id
789                })
790            }
791            Err(e) => {
792                let error_msg = CString::new(format!("Signin failed: {:?}", e))
793                    .unwrap()
794                    .into_raw();
795                Box::new(SigninResponseWrapper {
796                    success: false,
797                    jwt: std::ptr::null(),
798                    error: error_msg,
799                    request_id
800                })
801            }
802        };
803
804        callback(Box::into_raw(response));
805    });
806
807    // Keep the main thread alive for a short time to ensure the async task completes
808    std::thread::sleep(std::time::Duration::from_secs(2));
809}
810
811#[no_mangle]
812#[tracing::instrument(skip_all)]
813pub extern "C" fn free_signin_response(response: *mut SigninResponseWrapper) {
814    if response.is_null() {
815        return;
816    }
817    unsafe {
818        if !(*response).error.is_null() {
819            let _ = CString::from_raw((*response).error as *mut c_char);
820        }
821        if !(*response).jwt.is_null() {
822            let _ = CString::from_raw((*response).jwt as *mut c_char);
823        }
824        let _ = Box::from_raw(response);
825    }
826}
827
828#[repr(C)]
829pub struct ListCollectionsResponseWrapper {
830    success: bool,
831    results: *const c_char,
832    error: *const c_char,
833    request_id: i32,
834}
835#[no_mangle]
836#[tracing::instrument(skip_all)]
837pub extern "C" fn list_collections(
838    client: *mut ClientWrapper,
839    includehist: bool,
840) -> *mut ListCollectionsResponseWrapper {
841    let client_wrapper = match safe_wrapper(client) {
842        Some(client) => client,
843        None => {
844            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
845            let response = ListCollectionsResponseWrapper {
846                success: false,
847                results: std::ptr::null(),
848                error: error_msg,
849                request_id: 0,
850            };
851            return Box::into_raw(Box::new(response));
852        }
853    };
854    let client = client_wrapper.client.clone();
855    if client.is_none() {
856        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
857        let response = ListCollectionsResponseWrapper {
858            success: false,
859            results: std::ptr::null(),
860            error: error_msg,
861            request_id: 0,
862        };
863        return Box::into_raw(Box::new(response));
864    }
865    let client = client.unwrap();
866    let result = tokio::task::block_in_place(|| {
867        let handle = client.get_runtime_handle();
868        handle.block_on(client.list_collections(includehist))
869    });
870
871    let response = match result {
872        Ok(data) => {
873            let results = CString::new(data).unwrap().into_raw();
874            ListCollectionsResponseWrapper {
875                success: true,
876                results,
877                error: std::ptr::null(),
878                request_id: 0,                
879            }
880        }
881        Err(e) => {
882            let error_msg = CString::new(format!("List collections failed: {:?}", e))
883                .unwrap()
884                .into_raw();
885            ListCollectionsResponseWrapper {
886                success: false,
887                results: std::ptr::null(),
888                error: error_msg,
889                request_id: 0,
890            }
891        }
892    };
893
894    Box::into_raw(Box::new(response))
895}
896type ListCollectionsCallback = extern "C" fn(wrapper: *mut ListCollectionsResponseWrapper);
897#[no_mangle]
898#[tracing::instrument(skip_all)]
899pub extern "C" fn list_collections_async(
900    client: *mut ClientWrapper,
901    includehist: bool,
902    request_id: i32,
903    callback: ListCollectionsCallback,
904) {
905    let client_wrapper = match safe_wrapper(client) {
906        Some(client) => client,
907        None => {
908            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
909            let response = ListCollectionsResponseWrapper {
910                success: false,
911                results: std::ptr::null(),
912                error: error_msg,
913                request_id: request_id,
914            };
915            return callback(Box::into_raw(Box::new(response)));
916        }
917    };
918    let client = client_wrapper.client.clone();
919    if client.is_none() {
920        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
921        let response = ListCollectionsResponseWrapper {
922            success: false,
923            results: std::ptr::null(),
924            error: error_msg,
925            request_id: request_id,
926        };
927        return callback(Box::into_raw(Box::new(response)));
928    }
929    let client = client.unwrap();
930    let handle = client.get_runtime_handle();
931    handle.spawn(async move {
932        let result = client.list_collections(includehist).await;
933
934        let response = match result {
935            Ok(data) => {
936                let results = CString::new(data).unwrap().into_raw();
937                ListCollectionsResponseWrapper {
938                    success: true,
939                    results,
940                    error: std::ptr::null(),
941                    request_id: request_id,
942                }
943            }
944            Err(e) => {
945                let error_msg = CString::new(format!("List collections failed: {:?}", e))
946                    .unwrap()
947                    .into_raw();
948                ListCollectionsResponseWrapper {
949                    success: false,
950                    results: std::ptr::null(),
951                    error: error_msg,
952                    request_id: request_id,
953                }
954            }
955        };
956
957        callback(Box::into_raw(Box::new(response)));
958    });
959}
960#[no_mangle]
961#[tracing::instrument(skip_all)]
962pub extern "C" fn free_list_collections_response(response: *mut ListCollectionsResponseWrapper) {
963    if response.is_null() {
964        return;
965    }
966    unsafe {
967        if !(*response).error.is_null() {
968            let _ = CString::from_raw((*response).error as *mut c_char);
969        }
970        if !(*response).results.is_null() {
971            let _ = CString::from_raw((*response).results as *mut c_char);
972        }
973        let _ = Box::from_raw(response);
974    }
975}
976
977#[repr(C)]
978pub struct ColCollationWrapper {
979    locale: *const c_char,
980    case_level: bool,
981    case_first: *const c_char,
982    strength: i32,
983    numeric_ordering: bool,
984    alternate: *const c_char,
985    max_variable: *const c_char,
986    backwards: bool,
987}
988#[repr(C)]
989pub struct ColTimeseriesWrapper {
990    time_field: *const c_char,
991    meta_field: *const c_char,
992    granularity: *const c_char,
993}
994#[repr(C)]
995pub struct CreateCollectionRequestWrapper {
996    collectionname: *const c_char,
997    collation: *mut ColCollationWrapper,
998    timeseries: *mut ColTimeseriesWrapper,
999    expire_after_seconds: i32,
1000    change_stream_pre_and_post_images: bool,
1001    capped: bool,
1002    max: i32,
1003    size: i32,
1004    request_id: i32,
1005}
1006#[repr(C)]
1007pub struct CreateCollectionResponseWrapper {
1008    success: bool,
1009    error: *const c_char,
1010    request_id: i32,
1011}
1012#[no_mangle]
1013#[tracing::instrument(skip_all)]
1014pub extern "C" fn create_collection(
1015    client: *mut ClientWrapper,
1016    options: *mut CreateCollectionRequestWrapper,
1017) -> *mut CreateCollectionResponseWrapper {
1018    let options = match safe_wrapper(options) {
1019        Some(options) => options,
1020        None => {
1021            let error_msg = CString::new("Invalid options").unwrap().into_raw();
1022            let response = CreateCollectionResponseWrapper {
1023                success: false,
1024                error: error_msg,
1025                request_id: 0,
1026            };
1027            return Box::into_raw(Box::new(response));
1028        }
1029    };
1030    let client_wrapper = match safe_wrapper(client) {
1031        Some(client) => client,
1032        None => {
1033            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
1034            let response = CreateCollectionResponseWrapper {
1035                success: false,
1036                error: error_msg,
1037                request_id: options.request_id,
1038            };
1039            return Box::into_raw(Box::new(response));
1040        }
1041    };
1042    let client = client_wrapper.client.clone();
1043    let request = CreateCollectionRequest {
1044        collectionname: c_char_to_str(options.collectionname),
1045        collation: match safe_wrapper(options.collation) {
1046            Some(collation) => {
1047                Some(openiap_client::protos::ColCollation {
1048                    locale: c_char_to_str(collation.locale),
1049                    case_level: collation.case_level,
1050                    case_first: c_char_to_str(collation.case_first),
1051                    strength: collation.strength,
1052                    numeric_ordering: collation.numeric_ordering,
1053                    alternate: c_char_to_str(collation.alternate),
1054                    max_variable: c_char_to_str(collation.max_variable),
1055                    backwards: collation.backwards,
1056                })
1057            }
1058            None => None,
1059        },
1060        timeseries: match safe_wrapper(options.timeseries) {
1061            Some(timeseries) => {
1062                Some(openiap_client::protos::ColTimeseries {
1063                    time_field: c_char_to_str(timeseries.time_field),
1064                    meta_field: c_char_to_str(timeseries.meta_field),
1065                    granularity: c_char_to_str(timeseries.granularity),
1066                })
1067            }
1068            None => None,
1069        },
1070        expire_after_seconds: options.expire_after_seconds,
1071        change_stream_pre_and_post_images: options.change_stream_pre_and_post_images,
1072        capped: options.capped,
1073        max: options.max,
1074        size: options.size,
1075    };
1076    if client.is_none() {
1077        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
1078        let response = CreateCollectionResponseWrapper {
1079            success: false,
1080            error: error_msg,
1081            request_id: options.request_id,
1082        };
1083        return Box::into_raw(Box::new(response));
1084    }
1085    let client = client.unwrap();
1086    let result = tokio::task::block_in_place(|| {
1087        let handle = client.get_runtime_handle();
1088        handle.block_on(client.create_collection(request))
1089    });
1090
1091    let response = match result {
1092        Ok(_) => {
1093            CreateCollectionResponseWrapper {
1094                success: true,
1095                error: std::ptr::null(),
1096                request_id: options.request_id,
1097            }
1098        }
1099        Err(e) => {
1100            let error_msg = CString::new(format!("Create collection failed: {:?}", e))
1101                .unwrap()
1102                .into_raw();
1103            CreateCollectionResponseWrapper {
1104                success: false,
1105                error: error_msg,
1106                request_id: options.request_id,
1107            }
1108        }
1109    };
1110    Box::into_raw(Box::new(response))
1111}
1112type CreateCollectionCallback = extern "C" fn(wrapper: *mut CreateCollectionResponseWrapper);
1113#[no_mangle]
1114#[tracing::instrument(skip_all)]
1115pub extern "C" fn create_collection_async(
1116    client: *mut ClientWrapper,
1117    options: *mut CreateCollectionRequestWrapper,
1118    callback: CreateCollectionCallback,
1119) {
1120    let options = match safe_wrapper(options) {
1121        Some(options) => options,
1122        None => {
1123            let error_msg = CString::new("Invalid options").unwrap().into_raw();
1124            let response = CreateCollectionResponseWrapper {
1125                success: false,
1126                error: error_msg,
1127                request_id: 0,
1128            };
1129            return callback(Box::into_raw(Box::new(response)));
1130        }
1131    };
1132    let client_wrapper = match safe_wrapper(client) {
1133        Some(client) => client,
1134        None => {
1135            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
1136            let response = CreateCollectionResponseWrapper {
1137                success: false,
1138                error: error_msg,
1139                request_id: options.request_id,
1140            };
1141            return callback(Box::into_raw(Box::new(response)));
1142        }
1143    };
1144    let client = client_wrapper.client.clone();
1145    let request = CreateCollectionRequest {
1146        collectionname: c_char_to_str(options.collectionname),
1147        collation: match safe_wrapper(options.collation) {
1148            Some(collation) => {
1149                Some(openiap_client::protos::ColCollation {
1150                    locale: c_char_to_str(collation.locale),
1151                    case_level: collation.case_level,
1152                    case_first: c_char_to_str(collation.case_first),
1153                    strength: collation.strength,
1154                    numeric_ordering: collation.numeric_ordering,
1155                    alternate: c_char_to_str(collation.alternate),
1156                    max_variable: c_char_to_str(collation.max_variable),
1157                    backwards: collation.backwards,
1158                })
1159            }
1160            None => None,
1161        },
1162        timeseries: match safe_wrapper(options.timeseries) {
1163            Some(timeseries) => {
1164                Some(openiap_client::protos::ColTimeseries {
1165                    time_field: c_char_to_str(timeseries.time_field),
1166                    meta_field: c_char_to_str(timeseries.meta_field),
1167                    granularity: c_char_to_str(timeseries.granularity),
1168                })
1169            }
1170            None => None,
1171        },
1172        expire_after_seconds: options.expire_after_seconds,
1173        change_stream_pre_and_post_images: options.change_stream_pre_and_post_images,
1174        capped: options.capped,
1175        max: options.max,
1176        size: options.size,
1177    };
1178    if client.is_none() {
1179        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
1180        let response = CreateCollectionResponseWrapper {
1181            success: false,
1182            error: error_msg,
1183            request_id: options.request_id,
1184        };
1185        return callback(Box::into_raw(Box::new(response)));
1186    }
1187    let client = client.unwrap();
1188    let handle = client.get_runtime_handle();
1189    let request_id = options.request_id;
1190    handle.spawn(async move {
1191        let result = client.create_collection(request).await;
1192
1193        let response = match result {
1194            Ok(_) => {
1195                CreateCollectionResponseWrapper {
1196                    success: true,
1197                    error: std::ptr::null(),
1198                    request_id
1199                }
1200            }
1201            Err(e) => {
1202                let error_msg = CString::new(format!("Create collection failed: {:?}", e))
1203                    .unwrap()
1204                    .into_raw();
1205                CreateCollectionResponseWrapper {
1206                    success: false,
1207                    error: error_msg,
1208                    request_id
1209                }
1210            }
1211        };
1212
1213        callback(Box::into_raw(Box::new(response)));
1214    });
1215}
1216#[no_mangle]
1217#[tracing::instrument(skip_all)]
1218pub extern "C" fn free_create_collection_response(response: *mut CreateCollectionResponseWrapper) {
1219    if response.is_null() {
1220        return;
1221    }
1222    unsafe {
1223        if !(*response).error.is_null() {
1224            let _ = CString::from_raw((*response).error as *mut c_char);
1225        }
1226        let _ = Box::from_raw(response);
1227    }
1228}
1229
1230#[repr(C)]
1231pub struct DropCollectionResponseWrapper {
1232    success: bool,
1233    error: *const c_char,
1234    request_id: i32,
1235}
1236#[no_mangle]
1237#[tracing::instrument(skip_all)]
1238pub extern "C" fn drop_collection(
1239    client: *mut ClientWrapper,
1240    collectionname: *const c_char,
1241) -> *mut DropCollectionResponseWrapper {
1242    let client_wrapper = match safe_wrapper(client) {
1243        Some(client) => client,
1244        None => {
1245            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
1246            let response = DropCollectionResponseWrapper {
1247                success: false,
1248                error: error_msg,
1249                request_id: 0,
1250            };
1251            return Box::into_raw(Box::new(response));
1252        }
1253    };
1254    let client = client_wrapper.client.clone();
1255    let request = DropCollectionRequest {
1256        collectionname: c_char_to_str(collectionname),
1257    };
1258    if client.is_none() {
1259        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
1260        let response = DropCollectionResponseWrapper {
1261            success: false,
1262            error: error_msg,
1263            request_id: 0,
1264        };
1265        return Box::into_raw(Box::new(response));
1266    }
1267    let client = client.unwrap();
1268    let result = tokio::task::block_in_place(|| {
1269        let handle = client.get_runtime_handle();
1270        handle.block_on(client.drop_collection(request))
1271    });
1272
1273    let response = match result {
1274        Ok(_) => {
1275            DropCollectionResponseWrapper {
1276                success: true,
1277                error: std::ptr::null(),
1278                request_id: 0,
1279            }
1280        }
1281        Err(e) => {
1282            let error_msg = CString::new(format!("Drop collection failed: {:?}", e))
1283                .unwrap()
1284                .into_raw();
1285            DropCollectionResponseWrapper {
1286                success: false,
1287                error: error_msg,
1288                request_id: 0,
1289            }
1290        }
1291    };
1292
1293    Box::into_raw(Box::new(response))
1294}
1295type DropCollectionCallback = extern "C" fn(wrapper: *mut DropCollectionResponseWrapper);
1296#[no_mangle]
1297#[tracing::instrument(skip_all)]
1298pub extern "C" fn drop_collection_async(
1299    client: *mut ClientWrapper,
1300    collectionname: *const c_char,
1301    request_id: i32,
1302    callback: DropCollectionCallback,
1303) {
1304    let client_wrapper = match safe_wrapper(client) {
1305        Some(client) => client,
1306        None => {
1307            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
1308            let response = DropCollectionResponseWrapper {
1309                success: false,
1310                error: error_msg,
1311                request_id: request_id,
1312            };
1313            return callback(Box::into_raw(Box::new(response)));
1314        }
1315    };
1316    let client = client_wrapper.client.clone();
1317    let request = DropCollectionRequest {
1318        collectionname: c_char_to_str(collectionname),
1319    };
1320    if client.is_none() {
1321        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
1322        let response = DropCollectionResponseWrapper {
1323            success: false,
1324            error: error_msg,
1325            request_id,
1326        };
1327        return callback(Box::into_raw(Box::new(response)));
1328    }
1329    let client = client.unwrap();
1330    let handle = client.get_runtime_handle();
1331    handle.spawn(async move {
1332        let result = client.drop_collection(request).await;
1333
1334        let response = match result {
1335            Ok(_) => {
1336                DropCollectionResponseWrapper {
1337                    success: true,
1338                    error: std::ptr::null(),
1339                    request_id,
1340                }
1341            }
1342            Err(e) => {
1343                let error_msg = CString::new(format!("Drop collection failed: {:?}", e))
1344                    .unwrap()
1345                    .into_raw();
1346                DropCollectionResponseWrapper {
1347                    success: false,
1348                    error: error_msg,
1349                    request_id,
1350                }
1351            }
1352        };
1353
1354        callback(Box::into_raw(Box::new(response)));
1355    });
1356}
1357#[no_mangle]
1358#[tracing::instrument(skip_all)]
1359pub extern "C" fn free_drop_collection_response(response: *mut DropCollectionResponseWrapper) {
1360    if response.is_null() {
1361        return;
1362    }
1363    unsafe {
1364        if !(*response).error.is_null() {
1365            let _ = CString::from_raw((*response).error as *mut c_char);
1366        }
1367        let _ = Box::from_raw(response);
1368    }
1369}
1370
1371#[repr(C)]
1372pub struct GetIndexesResponseWrapper {
1373    success: bool,
1374    results: *const c_char,
1375    error: *const c_char,
1376    request_id: i32,
1377}
1378#[no_mangle]
1379#[tracing::instrument(skip_all)]
1380pub extern "C" fn get_indexes(
1381    client: *mut ClientWrapper,
1382    collectionname: *const c_char,
1383) -> *mut GetIndexesResponseWrapper {
1384    let client_wrapper = match safe_wrapper(client) {
1385        Some(client) => client,
1386        None => {
1387            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
1388            let response = GetIndexesResponseWrapper {
1389                success: false,
1390                results: std::ptr::null(),
1391                error: error_msg,
1392                request_id: 0,
1393            };
1394            return Box::into_raw(Box::new(response));
1395        }
1396    };
1397    let client = client_wrapper.client.clone();
1398    let request = GetIndexesRequest {
1399        collectionname: c_char_to_str(collectionname),
1400    };
1401    if client.is_none() {
1402        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
1403        let response = GetIndexesResponseWrapper {
1404            success: false,
1405            results: std::ptr::null(),
1406            error: error_msg,
1407            request_id: 0,
1408        };
1409        return Box::into_raw(Box::new(response));
1410    }
1411    let client = client.unwrap();
1412    let result = tokio::task::block_in_place(|| {
1413        let handle = client.get_runtime_handle();
1414        handle.block_on(client.get_indexes(request))
1415    });
1416
1417    let response = match result {
1418        Ok(data) => {
1419            let results = CString::new(data).unwrap().into_raw();
1420            GetIndexesResponseWrapper {
1421                success: true,
1422                results,
1423                error: std::ptr::null(),
1424                request_id: 0,
1425            }
1426        }
1427        Err(e) => {
1428            let error_msg = CString::new(format!("Get indexes failed: {:?}", e))
1429                .unwrap()
1430                .into_raw();
1431            GetIndexesResponseWrapper {
1432                success: false,
1433                results: std::ptr::null(),
1434                error: error_msg,
1435                request_id: 0,
1436            }
1437        }
1438    };
1439
1440    Box::into_raw(Box::new(response))
1441}
1442type GetIndexesCallback = extern "C" fn(wrapper: *mut GetIndexesResponseWrapper);
1443#[no_mangle]
1444#[tracing::instrument(skip_all)]
1445pub extern "C" fn get_indexes_async(
1446    client: *mut ClientWrapper,
1447    collectionname: *const c_char,
1448    request_id: i32,
1449    callback: GetIndexesCallback,
1450)  {
1451    let client_wrapper = match safe_wrapper(client) {
1452        Some(client) => client,
1453        None => {
1454            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
1455            let response = GetIndexesResponseWrapper {
1456                success: false,
1457                results: std::ptr::null(),
1458                error: error_msg,
1459                request_id,
1460            };
1461            return callback(Box::into_raw(Box::new(response)));
1462        }
1463    };
1464    let client = client_wrapper.client.clone();
1465    let request = GetIndexesRequest {
1466        collectionname: c_char_to_str(collectionname),
1467    };
1468    if client.is_none() {
1469        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
1470        let response = GetIndexesResponseWrapper {
1471            success: false,
1472            results: std::ptr::null(),
1473            error: error_msg,
1474            request_id,
1475        };
1476        return callback(Box::into_raw(Box::new(response)));
1477    }
1478    let client = client.unwrap();
1479    let handle = client.get_runtime_handle();
1480    handle.spawn(async move {
1481        let result = client.get_indexes(request).await;
1482
1483        let response = match result {
1484            Ok(data) => {
1485                let results = CString::new(data).unwrap().into_raw();
1486                GetIndexesResponseWrapper {
1487                    success: true,
1488                    results,
1489                    error: std::ptr::null(),
1490                    request_id,
1491                }
1492            }
1493            Err(e) => {
1494                let error_msg = CString::new(format!("Get indexes failed: {:?}", e))
1495                    .unwrap()
1496                    .into_raw();
1497                GetIndexesResponseWrapper {
1498                    success: false,
1499                    results: std::ptr::null(),
1500                    error: error_msg,
1501                    request_id,
1502                }
1503            }
1504        };
1505
1506        callback(Box::into_raw(Box::new(response)));
1507    });
1508
1509}
1510#[no_mangle]
1511#[tracing::instrument(skip_all)]
1512pub extern "C" fn free_get_indexes_response(response: *mut GetIndexesResponseWrapper) {
1513    if response.is_null() {
1514        return;
1515    }
1516    unsafe {
1517        if !(*response).error.is_null() {
1518            let _ = CString::from_raw((*response).error as *mut c_char);
1519        }
1520        if !(*response).results.is_null() {
1521            let _ = CString::from_raw((*response).results as *mut c_char);
1522        }
1523        let _ = Box::from_raw(response);
1524    }
1525}
1526
1527#[repr(C)]
1528pub struct CreateIndexRequestWrapper {
1529    collectionname: *const c_char,
1530    index: *const c_char,
1531    options: *const c_char,
1532    name: *const c_char,
1533    request_id: i32,
1534}
1535#[repr(C)]
1536pub struct CreateIndexResponseWrapper {
1537    success: bool,
1538    error: *const c_char,
1539    request_id: i32,
1540}
1541#[no_mangle]
1542#[tracing::instrument(skip_all)]
1543pub extern "C" fn create_index(
1544    client: *mut ClientWrapper,
1545    options: *mut CreateIndexRequestWrapper,
1546) -> *mut CreateIndexResponseWrapper {
1547    let options = match safe_wrapper(options) {
1548        Some(options) => options,
1549        None => {
1550            let error_msg = CString::new("Invalid options").unwrap().into_raw();
1551            let response = CreateIndexResponseWrapper {
1552                success: false,
1553                error: error_msg,
1554                request_id: 0,
1555            };
1556            return Box::into_raw(Box::new(response));
1557        }
1558    };
1559    let client_wrapper = match safe_wrapper(client) {
1560        Some(client) => client,
1561        None => {
1562            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
1563            let response = CreateIndexResponseWrapper {
1564                success: false,
1565                error: error_msg,
1566                request_id: options.request_id,
1567            };
1568            return Box::into_raw(Box::new(response));
1569        }
1570    };
1571    let client = client_wrapper.client.clone();
1572    let request = CreateIndexRequest {
1573        collectionname: c_char_to_str(options.collectionname),
1574        index: c_char_to_str(options.index),
1575        options: c_char_to_str(options.options),
1576        name: c_char_to_str(options.name),
1577    };
1578    if client.is_none() {
1579        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
1580        let response = CreateIndexResponseWrapper {
1581            success: false,
1582            error: error_msg,
1583            request_id: options.request_id,
1584        };
1585        return Box::into_raw(Box::new(response));
1586    }
1587    let client = client.unwrap();
1588    let result = tokio::task::block_in_place(|| {
1589        let handle = client.get_runtime_handle();
1590        handle.block_on(client.create_index(request))
1591    });
1592
1593    let response = match result {
1594        Ok(_) => {
1595            CreateIndexResponseWrapper {
1596                success: true,
1597                error: std::ptr::null(),
1598                request_id: options.request_id,
1599            }
1600        }
1601        Err(e) => {
1602            let error_msg = CString::new(format!("Create index failed: {:?}", e))
1603                .unwrap()
1604                .into_raw();
1605            CreateIndexResponseWrapper {
1606                success: false,
1607                error: error_msg,
1608                request_id: options.request_id,
1609            }
1610        }
1611    };
1612
1613    Box::into_raw(Box::new(response))
1614}
1615type CreateIndexCallback = extern "C" fn(wrapper: *mut CreateIndexResponseWrapper);
1616#[no_mangle]
1617#[tracing::instrument(skip_all)]
1618pub extern "C" fn create_index_async(
1619    client: *mut ClientWrapper,
1620    options: *mut CreateIndexRequestWrapper,
1621    callback: CreateIndexCallback,
1622) {
1623    let options = match safe_wrapper(options) {
1624        Some(options) => options,
1625        None => {
1626            let error_msg = CString::new("Invalid options").unwrap().into_raw();
1627            let response = CreateIndexResponseWrapper {
1628                success: false,
1629                error: error_msg,
1630                request_id: 0,
1631            };
1632            return callback(Box::into_raw(Box::new(response)));
1633        }
1634    };
1635    let client_wrapper = match safe_wrapper(client) {
1636        Some(client) => client,
1637        None => {
1638            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
1639            let response = CreateIndexResponseWrapper {
1640                success: false,
1641                error: error_msg,
1642                request_id: options.request_id,
1643            };
1644            return callback(Box::into_raw(Box::new(response)));
1645        }
1646    };
1647    let client = client_wrapper.client.clone();
1648    let request = CreateIndexRequest {
1649        collectionname: c_char_to_str(options.collectionname),
1650        index: c_char_to_str(options.index),
1651        options: c_char_to_str(options.options),
1652        name: c_char_to_str(options.name),
1653    };
1654    if client.is_none() {
1655        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
1656        let response = CreateIndexResponseWrapper {
1657            success: false,
1658            error: error_msg,
1659            request_id: options.request_id,
1660        };
1661        return callback(Box::into_raw(Box::new(response)));
1662    }
1663    let client = client.unwrap();
1664    let handle = client.get_runtime_handle();
1665    let request_id = options.request_id;
1666    handle.spawn(async move {
1667        let result = client.create_index(request).await;
1668
1669        let response = match result {
1670            Ok(_) => {
1671                CreateIndexResponseWrapper {
1672                    success: true,
1673                    error: std::ptr::null(),
1674                    request_id
1675                }
1676            }
1677            Err(e) => {
1678                let error_msg = CString::new(format!("Create index failed: {:?}", e))
1679                    .unwrap()
1680                    .into_raw();
1681                CreateIndexResponseWrapper {
1682                    success: false,
1683                    error: error_msg,
1684                    request_id
1685                }
1686            }
1687        };
1688
1689        callback(Box::into_raw(Box::new(response)));
1690    });
1691}
1692#[no_mangle]
1693#[tracing::instrument(skip_all)]
1694pub extern "C" fn free_create_index_response(response: *mut CreateIndexResponseWrapper) {
1695    if response.is_null() {
1696        return;
1697    }
1698    unsafe {
1699        if !(*response).error.is_null() {
1700            let _ = CString::from_raw((*response).error as *mut c_char);
1701        }
1702        let _ = Box::from_raw(response);
1703    }
1704}
1705
1706#[repr(C)]
1707pub struct DropIndexResponseWrapper {
1708    success: bool,
1709    error: *const c_char,
1710    request_id: i32,
1711}
1712#[no_mangle]
1713#[tracing::instrument(skip_all)]
1714pub extern "C" fn drop_index(
1715    client: *mut ClientWrapper,
1716    collectionname: *const c_char,
1717    name: *const c_char,
1718) -> *mut DropIndexResponseWrapper {
1719    let client_wrapper = match safe_wrapper(client) {
1720        Some(client) => client,
1721        None => {
1722            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
1723            let response = DropIndexResponseWrapper {
1724                success: false,
1725                error: error_msg,
1726                request_id: 0,
1727            };
1728            return Box::into_raw(Box::new(response));
1729        }
1730    };
1731    let client = client_wrapper.client.clone();
1732    let request = DropIndexRequest {
1733        collectionname: c_char_to_str(collectionname),
1734        name: c_char_to_str(name),
1735    };
1736    if client.is_none() {
1737        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
1738        let response = DropIndexResponseWrapper {
1739            success: false,
1740            error: error_msg,
1741            request_id: 0,
1742        };
1743        return Box::into_raw(Box::new(response));
1744    }
1745    let client = client.unwrap();
1746    let result = tokio::task::block_in_place(|| {
1747        let handle = client.get_runtime_handle();
1748        handle.block_on(client.drop_index(request))
1749    });
1750
1751    let response = match result {
1752        Ok(_) => {
1753            DropIndexResponseWrapper {
1754                success: true,
1755                error: std::ptr::null(),
1756                request_id: 0,
1757            }
1758        }
1759        Err(e) => {
1760            let error_msg = CString::new(format!("Drop index failed: {:?}", e))
1761                .unwrap()
1762                .into_raw();
1763            DropIndexResponseWrapper {
1764                success: false,
1765                error: error_msg,
1766                request_id: 0,
1767            }
1768        }
1769    };
1770
1771    Box::into_raw(Box::new(response))
1772}
1773type DropIndexCallback = extern "C" fn(wrapper: *mut DropIndexResponseWrapper);
1774#[no_mangle]
1775#[tracing::instrument(skip_all)]
1776pub extern "C" fn drop_index_async(
1777    client: *mut ClientWrapper,
1778    collectionname: *const c_char,
1779    name: *const c_char,
1780    request_id: i32,
1781    callback: DropIndexCallback,
1782) {
1783    let client_wrapper = match safe_wrapper(client) {
1784        Some(client) => client,
1785        None => {
1786            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
1787            let response = DropIndexResponseWrapper {
1788                success: false,
1789                error: error_msg,
1790                request_id
1791            };
1792            return callback(Box::into_raw(Box::new(response)));
1793        }
1794    };
1795    let client = client_wrapper.client.clone();
1796    let request = DropIndexRequest {
1797        collectionname: c_char_to_str(collectionname),
1798        name: c_char_to_str(name),
1799    };
1800    if client.is_none() {
1801        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
1802        let response = DropIndexResponseWrapper {
1803            success: false,
1804            error: error_msg,
1805            request_id
1806        };
1807        return callback(Box::into_raw(Box::new(response)));
1808    }
1809    let client = client.unwrap();
1810    let handle = client.get_runtime_handle();
1811    handle.spawn(async move {
1812        let result = client.drop_index(request).await;
1813
1814        let response = match result {
1815            Ok(_) => {
1816                DropIndexResponseWrapper {
1817                    success: true,
1818                    error: std::ptr::null(),
1819                    request_id
1820                }
1821            }
1822            Err(e) => {
1823                let error_msg = CString::new(format!("Drop index failed: {:?}", e))
1824                    .unwrap()
1825                    .into_raw();
1826                DropIndexResponseWrapper {
1827                    success: false,
1828                    error: error_msg,
1829                    request_id
1830                }
1831            }
1832        };
1833
1834        callback(Box::into_raw(Box::new(response)));
1835    });
1836}
1837#[no_mangle]
1838#[tracing::instrument(skip_all)]
1839pub extern "C" fn free_drop_index_response(response: *mut DropIndexResponseWrapper) {
1840    if response.is_null() {
1841        return;        
1842    }
1843    unsafe {
1844        if !(*response).error.is_null() {
1845            let _ = CString::from_raw((*response).error as *mut c_char);
1846        }
1847        let _ = Box::from_raw(response);
1848    }
1849}
1850
1851#[repr(C)]
1852pub struct AggregateRequestWrapper {
1853    collectionname: *const c_char,
1854    aggregates: *const c_char,
1855    queryas: *const c_char,
1856    hint: *const c_char,
1857    explain: bool,
1858    request_id: i32
1859}
1860#[repr(C)]
1861pub struct AggregateResponseWrapper {
1862    success: bool,
1863    results: *const c_char,
1864    error: *const c_char,
1865    request_id: i32
1866}
1867#[no_mangle]
1868#[tracing::instrument(skip_all)]
1869pub extern "C" fn aggregate(
1870    client: *mut ClientWrapper,
1871    options: *mut AggregateRequestWrapper,
1872) -> *mut AggregateResponseWrapper {
1873    let options = match safe_wrapper(options) {
1874        Some(options) => options,
1875        None => {
1876            let error_msg = CString::new("Invalid options").unwrap().into_raw();
1877            let response = AggregateResponseWrapper {
1878                success: false,
1879                results: std::ptr::null(),
1880                error: error_msg,
1881                request_id: 0,
1882            };
1883            return Box::into_raw(Box::new(response));
1884        }
1885    };
1886    let client_wrapper = match safe_wrapper(client ) {
1887        Some(client) => client,
1888        None => {
1889            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
1890            let response = AggregateResponseWrapper {
1891                success: false,
1892                results: std::ptr::null(),
1893                error: error_msg,
1894                request_id: options.request_id,
1895            };
1896            return Box::into_raw(Box::new(response));
1897        }
1898    };
1899    let client = client_wrapper.client.clone();
1900    let request = AggregateRequest {
1901        collectionname: c_char_to_str(options.collectionname),
1902        aggregates: c_char_to_str(options.aggregates),
1903        queryas: c_char_to_str(options.queryas),
1904        hint: c_char_to_str(options.hint),
1905        explain: options.explain
1906    };
1907    if client.is_none() {
1908        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
1909        let response = AggregateResponseWrapper {
1910            success: false,
1911            results: std::ptr::null(),
1912            error: error_msg,
1913            request_id: options.request_id,
1914        };
1915        return Box::into_raw(Box::new(response));
1916    }
1917    let client = client.unwrap();
1918    let result = tokio::task::block_in_place(|| {
1919        let handle = client.get_runtime_handle();
1920        handle.block_on(client.aggregate(request))
1921    });
1922
1923    let response = match result {
1924        Ok(data) => {
1925            let results = CString::new(data.results).unwrap().into_raw();
1926            AggregateResponseWrapper {
1927                success: true,
1928                results,
1929                error: std::ptr::null(),
1930                request_id: options.request_id,
1931            }
1932        }
1933        Err(e) => {
1934            let error_msg = CString::new(format!("Aggregate failed: {:?}", e))
1935                .unwrap()
1936                .into_raw();
1937            AggregateResponseWrapper {
1938                success: false,
1939                results: std::ptr::null(),
1940                error: error_msg,
1941                request_id: options.request_id,
1942            }
1943        }
1944    };
1945
1946    Box::into_raw(Box::new(response))
1947}
1948
1949type AggregateCallback = extern "C" fn(wrapper: *mut AggregateResponseWrapper);
1950#[no_mangle]
1951#[tracing::instrument(skip_all)]
1952pub extern "C" fn aggregate_async(
1953    client: *mut ClientWrapper,
1954    options: *mut AggregateRequestWrapper,
1955    callback: AggregateCallback,
1956) {
1957    debug!("Rust: aggregate_async");
1958    let options = match safe_wrapper(options ) {
1959        Some( options ) => options,
1960        None => {
1961            let error_msg = CString::new("Invalid options").unwrap().into_raw();
1962            let response = AggregateResponseWrapper {
1963                success: false,
1964                results: std::ptr::null(),
1965                error: error_msg,
1966                request_id: 0,
1967            };
1968            return callback(Box::into_raw(Box::new(response)));
1969        }
1970    };
1971    let client_wrapper = match safe_wrapper(client) {
1972        Some( client ) => client,
1973        None => {
1974            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
1975            let response = AggregateResponseWrapper {
1976                success: false,
1977                results: std::ptr::null(),
1978                error: error_msg,
1979                request_id: options.request_id,
1980            };
1981            return callback(Box::into_raw(Box::new(response)));
1982        }
1983    };
1984    let client = client_wrapper.client.clone();
1985    let request = AggregateRequest {
1986        collectionname: c_char_to_str(options.collectionname),
1987        aggregates: c_char_to_str(options.aggregates),
1988        queryas: c_char_to_str(options.queryas),
1989        hint: c_char_to_str(options.hint),
1990        explain: options.explain
1991    };
1992    if client.is_none() {
1993        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
1994        let response = AggregateResponseWrapper {
1995            success: false,
1996            results: std::ptr::null(),
1997            error: error_msg,
1998            request_id: options.request_id,
1999        };
2000        return callback(Box::into_raw(Box::new(response)));
2001    }
2002
2003    let client = client.unwrap();
2004    let handle = client.get_runtime_handle();
2005    let request_id = options.request_id;
2006    debug!("Rust: runtime.spawn");
2007    handle.spawn(async move {
2008        debug!("Rust: client.aggregate");
2009        let result = client.aggregate(request).await;
2010        let response = match result {
2011            Ok(data) => {
2012                let results = CString::new(data.results).unwrap().into_raw();
2013                AggregateResponseWrapper {
2014                    success: true,
2015                    results,
2016                    error: std::ptr::null(),
2017                    request_id,
2018                }
2019            }
2020            Err(e) => {
2021                let error_msg = CString::new(format!("Aggregate failed: {:?}", e))
2022                    .unwrap()
2023                    .into_raw();
2024                AggregateResponseWrapper {
2025                    success: false,
2026                    results: std::ptr::null(),
2027                    error: error_msg,
2028                    request_id,
2029                }
2030            }
2031        };
2032        debug!("Rust: callback response");
2033        callback(Box::into_raw(Box::new(response)));
2034    });
2035}
2036#[no_mangle]
2037#[tracing::instrument(skip_all)]
2038pub extern "C" fn free_aggregate_response(response: *mut AggregateResponseWrapper) {
2039    if response.is_null() {
2040        return;
2041    }
2042    unsafe {
2043        if !(*response).error.is_null() {
2044            let _ = CString::from_raw((*response).error as *mut c_char);
2045        }
2046        if !(*response).results.is_null() {
2047            let _ = CString::from_raw((*response).results as *mut c_char);
2048        }
2049        let _ = Box::from_raw(response);
2050    }
2051}
2052
2053#[repr(C)]
2054pub struct CountRequestWrapper {
2055    collectionname: *const c_char,
2056    query: *const c_char,
2057    queryas: *const c_char,
2058    explain: bool,
2059    request_id: i32
2060}
2061#[repr(C)]
2062pub struct CountResponseWrapper {
2063    success: bool,
2064    result: i32,
2065    error: *const c_char,
2066    request_id: i32
2067}
2068#[no_mangle]
2069#[tracing::instrument(skip_all)]
2070pub extern "C" fn count(
2071    client: *mut ClientWrapper,
2072    options: *mut CountRequestWrapper,
2073) -> *mut CountResponseWrapper {
2074    let options = match safe_wrapper(options) {
2075        Some(options) => options,
2076        None => {
2077            let error_msg = CString::new("Invalid options").unwrap().into_raw();
2078            let response = CountResponseWrapper {
2079                success: false,
2080                result: 0,
2081                error: error_msg,
2082                request_id: 0,
2083            };
2084            return Box::into_raw(Box::new(response));
2085        }
2086    };
2087    let client_wrapper = match safe_wrapper(client) {
2088        Some(client) => client,
2089        None => {
2090            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
2091            let response = CountResponseWrapper {
2092                success: false,
2093                result: 0,
2094                error: error_msg,
2095                request_id: options.request_id,
2096            };
2097            return Box::into_raw(Box::new(response));
2098        }
2099    };
2100    let client = client_wrapper.client.clone();
2101    let request = CountRequest {
2102        collectionname: c_char_to_str(options.collectionname),
2103        query: c_char_to_str(options.query),
2104        queryas: c_char_to_str(options.queryas),
2105        explain: options.explain
2106    };
2107    if client.is_none() {
2108        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
2109        let response = CountResponseWrapper {
2110            success: false,
2111            result: 0,
2112            error: error_msg,
2113            request_id: options.request_id,
2114        };
2115        return Box::into_raw(Box::new(response));
2116    }
2117
2118    let client = client.unwrap();
2119    let result = tokio::task::block_in_place(|| {
2120        let handle = client.get_runtime_handle();
2121        handle.block_on(client.count(request))
2122    });
2123
2124    let response = match result {
2125        Ok(data) => {
2126            let result = data.result;
2127            CountResponseWrapper {
2128                success: true,
2129                result,
2130                error: std::ptr::null(),
2131                request_id: options.request_id,
2132            }
2133        }
2134        Err(e) => {
2135            let error_msg = CString::new(format!("Count failed: {:?}", e))
2136                .unwrap()
2137                .into_raw();
2138            CountResponseWrapper {
2139                success: false,
2140                result: 0,
2141                error: error_msg,
2142                request_id: options.request_id,
2143            }
2144        }
2145    };
2146
2147    Box::into_raw(Box::new(response))
2148}
2149
2150type CountCallback = extern "C" fn(wrapper: *mut CountResponseWrapper);
2151#[no_mangle]
2152#[tracing::instrument(skip_all)]
2153pub extern "C" fn count_async(
2154    client: *mut ClientWrapper,
2155    options: *mut CountRequestWrapper,
2156    callback: CountCallback,
2157) {
2158    let options = match safe_wrapper(options) {
2159        Some(options) => options,
2160        None => {
2161            let error_msg = CString::new("Invalid options").unwrap().into_raw();
2162            let response = CountResponseWrapper {
2163                success: false,
2164                result: 0,
2165                error: error_msg,
2166                request_id: 0,
2167            };
2168            return callback(Box::into_raw(Box::new(response)));
2169        }
2170    };
2171    let client_wrapper = match safe_wrapper(client) {
2172        Some(client) => client,
2173        None => {
2174            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
2175            let response = CountResponseWrapper {
2176                success: false,
2177                result: 0,
2178                error: error_msg,
2179                request_id: options.request_id,
2180            };
2181            return callback(Box::into_raw(Box::new(response)));
2182        }
2183    };
2184    let client = client_wrapper.client.clone();
2185    let request = CountRequest {
2186        collectionname: c_char_to_str(options.collectionname),
2187        query: c_char_to_str(options.query),
2188        queryas: c_char_to_str(options.queryas),
2189        explain: options.explain
2190    };
2191    if client.is_none() {
2192        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
2193        let response = CountResponseWrapper {
2194            success: false,
2195            result: 0,
2196            error: error_msg,
2197            request_id: options.request_id,
2198        };
2199        return callback(Box::into_raw(Box::new(response)));
2200    }
2201    let client = client.unwrap();
2202    let handle = client.get_runtime_handle();
2203    let request_id = options.request_id;
2204    handle.spawn(async move {
2205        let result = client.count(request).await;
2206        let response = match result {
2207            Ok(data) => {
2208                let result = data.result;
2209                CountResponseWrapper {
2210                    success: true,
2211                    result,
2212                    error: std::ptr::null(),
2213                    request_id,
2214                }
2215            }
2216            Err(e) => {
2217                let error_msg = CString::new(format!("Count failed: {:?}", e))
2218                    .unwrap()
2219                    .into_raw();
2220                CountResponseWrapper {
2221                    success: false,
2222                    result: 0,
2223                    error: error_msg,
2224                    request_id,
2225                }
2226            }
2227        };
2228
2229        callback(Box::into_raw(Box::new(response)));
2230    });
2231}
2232#[no_mangle]
2233#[tracing::instrument(skip_all)]
2234pub extern "C" fn free_count_response(response: *mut CountResponseWrapper) {
2235    if response.is_null() {
2236        return;
2237    }
2238    unsafe {
2239        if !(*response).error.is_null() {
2240            let _ = CString::from_raw((*response).error as *mut c_char);
2241        }
2242        let _ = Box::from_raw(response);
2243    }
2244}
2245
2246#[repr(C)]
2247pub struct DistinctRequestWrapper {
2248    collectionname: *const c_char,
2249    field: *const c_char,
2250    query: *const c_char,
2251    queryas: *const c_char,
2252    explain: bool,
2253    request_id: i32
2254}
2255#[repr(C)]
2256pub struct DistinctResponseWrapper {
2257    success: bool,
2258    // results: *const c_char,
2259    results: *mut *const c_char,
2260    error: *const c_char,
2261    results_len: i32,
2262    request_id: i32
2263}
2264#[no_mangle]
2265#[tracing::instrument(skip_all)]
2266pub extern "C" fn distinct(
2267    client: *mut ClientWrapper,
2268    options: *mut DistinctRequestWrapper,
2269) -> *mut DistinctResponseWrapper {
2270    let options = match safe_wrapper(options) {
2271        Some(options) => options,
2272        None => {
2273            let error_msg = CString::new("Invalid options").unwrap().into_raw();
2274            let response = DistinctResponseWrapper {
2275                success: false,
2276                results: std::ptr::null_mut(),
2277                error: error_msg,
2278                results_len: 0,
2279                request_id: 0,
2280            };
2281            return Box::into_raw(Box::new(response));
2282        }
2283    };
2284    let client_wrapper = match safe_wrapper(client) {
2285        Some(client) => client,
2286        None => {
2287            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
2288            let response = DistinctResponseWrapper {
2289                success: false,
2290                results: std::ptr::null_mut(),
2291                error: error_msg,
2292                results_len: 0,
2293                request_id: options.request_id,
2294            };
2295            return Box::into_raw(Box::new(response));
2296        }
2297    };
2298    let client = client_wrapper.client.clone();
2299    let request = DistinctRequest {
2300        collectionname: c_char_to_str(options.collectionname),
2301        field: c_char_to_str(options.field),
2302        query: c_char_to_str(options.query),
2303        queryas: c_char_to_str(options.queryas),
2304        explain: options.explain,
2305        ..Default::default()
2306    };
2307    if client.is_none() {
2308        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
2309        let response = DistinctResponseWrapper {
2310            success: false,
2311            results: std::ptr::null_mut(),
2312            error: error_msg,
2313            results_len: 0,
2314            request_id: options.request_id,
2315        };
2316        return Box::into_raw(Box::new(response));
2317    }
2318    let client = client.unwrap();
2319    let result = tokio::task::block_in_place(|| {
2320        let handle = client.get_runtime_handle();
2321        handle.block_on( client.distinct(request))
2322    });
2323
2324    let response = match result {
2325        Ok(data) => {
2326            let results_cstrings: Vec<CString> = data
2327                .results
2328                .iter()
2329                .map(|s| CString::new(s.as_str()).unwrap())
2330                .collect();
2331            let results_ptrs: Vec<*const c_char> =
2332                results_cstrings.iter().map(|s| s.as_ptr()).collect();
2333            let results_array =
2334                Box::into_raw(results_ptrs.clone().into_boxed_slice()) as *mut *const c_char;
2335
2336            std::mem::forget(results_cstrings);
2337
2338            DistinctResponseWrapper {
2339                success: true,
2340                results: results_array,
2341                error: std::ptr::null(),
2342                results_len: data.results.len().try_into().unwrap(),
2343                request_id: options.request_id,
2344            }
2345        }
2346        Err(e) => {
2347            let error_msg = CString::new(format!("Distinct failed: {:?}", e))
2348                .unwrap()
2349                .into_raw();
2350            DistinctResponseWrapper {
2351                success: false,
2352                results: std::ptr::null_mut(),
2353                error: error_msg,
2354                results_len: 0,
2355                request_id: options.request_id,
2356            }
2357        }
2358    };
2359
2360    Box::into_raw(Box::new(response))
2361}
2362
2363type DistinctCallback = extern "C" fn(wrapper: *mut DistinctResponseWrapper);
2364#[no_mangle]
2365#[tracing::instrument(skip_all)]
2366pub extern "C" fn distinct_async(
2367    client: *mut ClientWrapper,
2368    options: *mut DistinctRequestWrapper,
2369    callback: DistinctCallback,
2370) {
2371    let options = match safe_wrapper(options) {
2372        Some(options) => options,
2373        None => {
2374            let error_msg = CString::new("Invalid options").unwrap().into_raw();
2375            let response = DistinctResponseWrapper {
2376                success: false,
2377                results: std::ptr::null_mut(),
2378                error: error_msg,
2379                results_len: 0,
2380                request_id: 0,
2381            };
2382            return callback(Box::into_raw(Box::new(response)));
2383        }
2384    };
2385    let client_wrapper = match safe_wrapper(client) {
2386        Some(client) => client,
2387        None => {
2388            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
2389            let response = DistinctResponseWrapper {
2390                success: false,
2391                results: std::ptr::null_mut(),
2392                error: error_msg,
2393                results_len: 0,
2394                request_id: options.request_id,
2395            };
2396            return callback(Box::into_raw(Box::new(response)));
2397        }
2398    };
2399    let client = client_wrapper.client.clone();
2400    let request = DistinctRequest {
2401        collectionname: c_char_to_str(options.collectionname),
2402        field: c_char_to_str(options.field),
2403        query: c_char_to_str(options.query),
2404        queryas: c_char_to_str(options.queryas),
2405        explain: options.explain,
2406        ..Default::default()
2407    };
2408    if client.is_none() {
2409        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
2410        let response = DistinctResponseWrapper {
2411            success: false,
2412            results: std::ptr::null_mut(),
2413            error: error_msg,
2414            results_len: 0,
2415            request_id: options.request_id,
2416        };
2417        return callback(Box::into_raw(Box::new(response)));
2418    }
2419    let client = client.unwrap();
2420    let handle = client.get_runtime_handle();
2421    let request_id = options.request_id;
2422    handle.spawn(async move {
2423        let result = client.distinct(request).await;
2424        let response = match result {
2425            Ok(data) => {
2426                let results_cstrings: Vec<CString> = data
2427                    .results
2428                    .iter()
2429                    .map(|s| CString::new(s.as_str()).unwrap())
2430                    .collect();
2431                let results_ptrs: Vec<*const c_char> =
2432                    results_cstrings.iter().map(|s| s.as_ptr()).collect();
2433                let results_array =
2434                    Box::into_raw(results_ptrs.clone().into_boxed_slice()) as *mut *const c_char;
2435
2436                std::mem::forget(results_cstrings);
2437
2438                debug!("Rust: results_array: {:?}", results_array);
2439                for (i, ptr) in results_ptrs.iter().enumerate() {
2440                    debug!("Rust: results_ptrs[{}]: {:?}: {:?}", i, ptr, unsafe {
2441                        CStr::from_ptr(*ptr).to_str().unwrap()
2442                    });
2443                }
2444
2445                DistinctResponseWrapper {
2446                    success: true,
2447                    results: results_array,
2448                    error: std::ptr::null(),
2449                    results_len: data.results.len().try_into().unwrap(),
2450                    request_id,
2451                }
2452            }
2453            Err(e) => {
2454                let error_msg = CString::new(format!("Distinct failed: {:?}", e))
2455                    .unwrap()
2456                    .into_raw();
2457                DistinctResponseWrapper {
2458                    success: false,
2459                    results: std::ptr::null_mut(),
2460                    error: error_msg,
2461                    results_len: 0,
2462                    request_id,
2463                }
2464            }
2465        };
2466
2467        callback(Box::into_raw(Box::new(response)));
2468    });
2469}
2470#[no_mangle]
2471#[tracing::instrument(skip_all)]
2472pub extern "C" fn free_distinct_response(response: *mut DistinctResponseWrapper) {
2473    if response.is_null() {
2474        return;
2475    }
2476    unsafe {
2477        if !(*response).results.is_null() {
2478            for i in 0..(*response).results_len {
2479                let c_str_ptr = *(*response).results.add(i as usize);
2480                if !c_str_ptr.is_null() {
2481                    let _ = CString::from_raw(c_str_ptr as *mut c_char); // Free the C string
2482                }
2483            }
2484            let _ = Box::from_raw((*response).results);
2485        }
2486
2487        if !(*response).error.is_null() {
2488            let _ = CString::from_raw((*response).error as *mut c_char);
2489        }
2490        let _ = Box::from_raw(response);
2491    }
2492}
2493#[repr(C)]
2494pub struct InsertOneRequestWrapper {
2495    collectionname: *const c_char,
2496    item: *const c_char,
2497    w: i32,
2498    j: bool,
2499    request_id: i32
2500}
2501#[repr(C)]
2502pub struct InsertOneResponseWrapper {
2503    success: bool,
2504    result: *const c_char,
2505    error: *const c_char,
2506    request_id: i32
2507}
2508#[no_mangle]
2509#[tracing::instrument(skip_all)]
2510pub extern "C" fn insert_one(
2511    client: *mut ClientWrapper,
2512    options: *mut InsertOneRequestWrapper,
2513) -> *mut InsertOneResponseWrapper {
2514    let options = match safe_wrapper(options) {
2515        Some(options) => options,
2516        None => {
2517            let error_msg = CString::new("Invalid options").unwrap().into_raw();
2518            let response = InsertOneResponseWrapper {
2519                success: false,
2520                result: std::ptr::null(),
2521                error: error_msg,
2522                request_id: 0,
2523            };
2524            return Box::into_raw(Box::new(response));
2525        }
2526    };
2527    let client_wrapper = match safe_wrapper(client) {
2528        Some(client) => client,
2529        None => {
2530            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
2531            let response = InsertOneResponseWrapper {
2532                success: false,
2533                result: std::ptr::null(),
2534                error: error_msg,
2535                request_id: options.request_id,
2536            };
2537            return Box::into_raw(Box::new(response));
2538        }
2539    };
2540    let client = client_wrapper.client.clone();
2541    let request = InsertOneRequest {
2542        collectionname: c_char_to_str(options.collectionname),
2543        item: c_char_to_str(options.item),
2544        w: options.w,
2545        j: options.j,
2546    };
2547    if client.is_none() {
2548        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
2549        let response = InsertOneResponseWrapper {
2550            success: false,
2551            result: std::ptr::null(),
2552            error: error_msg,
2553            request_id: options.request_id,
2554        };
2555        return Box::into_raw(Box::new(response));
2556    }
2557    let client = client.unwrap();
2558    let result = tokio::task::block_in_place(|| {
2559        let handle = client.get_runtime_handle();
2560        handle.block_on( client.insert_one(request))
2561    });
2562
2563    let response = match result {
2564        Ok(data) => {
2565            let result = CString::new(data.result).unwrap().into_raw();
2566            InsertOneResponseWrapper {
2567                success: true,
2568                result,
2569                error: std::ptr::null(),
2570                request_id: options.request_id,
2571            }
2572        }
2573        Err(e) => {
2574            let error_msg = CString::new(format!("InsertOne failed: {:?}", e))
2575                .unwrap()
2576                .into_raw();
2577            InsertOneResponseWrapper {
2578                success: false,
2579                result: std::ptr::null(),
2580                error: error_msg,
2581                request_id: options.request_id,
2582            }
2583        }
2584    };
2585
2586    Box::into_raw(Box::new(response))
2587}
2588
2589type InsertOneCallback = extern "C" fn(wrapper: *mut InsertOneResponseWrapper);
2590#[no_mangle]
2591#[tracing::instrument(skip_all)]
2592pub extern "C" fn insert_one_async(
2593    client: *mut ClientWrapper,
2594    options: *mut InsertOneRequestWrapper,
2595    callback: InsertOneCallback,
2596) {
2597    let options = match safe_wrapper(options) {
2598        Some(options) => options,
2599        None => {
2600            let error_msg = CString::new("Invalid options").unwrap().into_raw();
2601            let response = InsertOneResponseWrapper {
2602                success: false,
2603                result: std::ptr::null(),
2604                error: error_msg,
2605                request_id: 0,
2606            };
2607            return callback(Box::into_raw(Box::new(response)));
2608        }
2609    };
2610    let client_wrapper = match safe_wrapper(client) {
2611        Some(client) => client,
2612        None => {
2613            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
2614            let response = InsertOneResponseWrapper {
2615                success: false,
2616                result: std::ptr::null(),
2617                error: error_msg,
2618                request_id: options.request_id,
2619            };
2620            return callback(Box::into_raw(Box::new(response)));
2621        }
2622    };
2623    let client = client_wrapper.client.clone();
2624    let request = InsertOneRequest {
2625        collectionname: c_char_to_str(options.collectionname),
2626        item: c_char_to_str(options.item),
2627        w: options.w,
2628        j: options.j,
2629    };
2630    if client.is_none() {
2631        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
2632        let response = InsertOneResponseWrapper {
2633            success: false,
2634            result: std::ptr::null(),
2635            error: error_msg,
2636            request_id: options.request_id,
2637        };
2638        return callback(Box::into_raw(Box::new(response)));
2639    }
2640
2641    let client = client.unwrap();
2642    let handle = client.get_runtime_handle();
2643    let request_id = options.request_id;
2644    handle.spawn(async move {
2645        let result = client.insert_one(request).await;
2646        let response = match result {
2647            Ok(data) => {
2648                let result = CString::new(data.result).unwrap().into_raw();
2649                InsertOneResponseWrapper {
2650                    success: true,
2651                    result,
2652                    error: std::ptr::null(),
2653                    request_id,
2654                }
2655            }
2656            Err(e) => {
2657                let error_msg = CString::new(format!("InsertOne failed: {:?}", e))
2658                    .unwrap()
2659                    .into_raw();
2660                InsertOneResponseWrapper {
2661                    success: false,
2662                    result: std::ptr::null(),
2663                    error: error_msg,
2664                    request_id, 
2665                }
2666            }
2667        };
2668
2669        callback(Box::into_raw(Box::new(response)));
2670    });
2671}
2672#[no_mangle]
2673#[tracing::instrument(skip_all)]
2674pub extern "C" fn free_insert_one_response(response: *mut InsertOneResponseWrapper) {
2675    if response.is_null() {
2676        return;
2677    }
2678    unsafe {
2679        if !(*response).error.is_null() {
2680            let _ = CString::from_raw((*response).error as *mut c_char);
2681        }
2682        if !(*response).result.is_null() {
2683            let _ = CString::from_raw((*response).result as *mut c_char);
2684        }
2685        let _ = Box::from_raw(response);
2686    }
2687}
2688#[repr(C)]
2689pub struct InsertManyRequestWrapper {
2690    collectionname: *const c_char,
2691    items: *const c_char,
2692    w: i32,
2693    j: bool,
2694    skipresults: bool,
2695    request_id: i32
2696}
2697#[repr(C)]
2698pub struct InsertManyResponseWrapper {
2699    success: bool,
2700    results: *const c_char,
2701    error: *const c_char,
2702    request_id: i32,
2703}
2704#[no_mangle]
2705#[tracing::instrument(skip_all)]
2706pub extern "C" fn insert_many(
2707    client: *mut ClientWrapper,
2708    options: *mut InsertManyRequestWrapper,
2709) -> *mut InsertManyResponseWrapper {
2710    let options = match safe_wrapper(options) {
2711        Some(options) => options,
2712        None => {
2713            let error_msg = CString::new("Invalid options").unwrap().into_raw();
2714            let response = InsertManyResponseWrapper {
2715                success: false,
2716                results: std::ptr::null(),
2717                error: error_msg,
2718                request_id: 0,
2719            };
2720            return Box::into_raw(Box::new(response));
2721        }
2722    };
2723    let client_wrapper = match safe_wrapper(client) {
2724        Some(client) => client,
2725        None => {
2726            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
2727            let response = InsertManyResponseWrapper {
2728                success: false,
2729                results: std::ptr::null(),
2730                error: error_msg,
2731                request_id: options.request_id,
2732            };
2733            return Box::into_raw(Box::new(response));
2734        }
2735    };
2736    let client = client_wrapper.client.clone();
2737    let request = InsertManyRequest {
2738        collectionname: c_char_to_str(options.collectionname),
2739        items: c_char_to_str(options.items),
2740        w: options.w,
2741        j: options.j,
2742        skipresults: options.skipresults
2743    };
2744    if client.is_none() {
2745        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
2746        let response = InsertManyResponseWrapper {
2747            success: false,
2748            results: std::ptr::null(),
2749            error: error_msg,
2750            request_id: options.request_id,
2751        };
2752        return Box::into_raw(Box::new(response));
2753    }
2754    let client = client.unwrap();
2755    let result = tokio::task::block_in_place(|| {
2756        let handle = client.get_runtime_handle();
2757        handle.block_on( client.insert_many(request))
2758    });
2759
2760    let response = match result {
2761        Ok(data) => {
2762            let results = CString::new(data.results).unwrap().into_raw();
2763            InsertManyResponseWrapper {
2764                success: true,
2765                results,
2766                error: std::ptr::null(),
2767                request_id: options.request_id,
2768            }
2769        }
2770        Err(e) => {
2771            let error_msg = CString::new(format!("InsertMany failed: {:?}", e))
2772                .unwrap()
2773                .into_raw();
2774            InsertManyResponseWrapper {
2775                success: false,
2776                results: std::ptr::null(),
2777                error: error_msg,
2778                request_id: options.request_id,
2779            }
2780        }
2781    };
2782
2783    Box::into_raw(Box::new(response))
2784}
2785
2786type InsertManyCallback = extern "C" fn(wrapper: *mut InsertManyResponseWrapper);
2787#[no_mangle]
2788#[tracing::instrument(skip_all)]
2789pub extern "C" fn insert_many_async(
2790    client: *mut ClientWrapper,
2791    options: *mut InsertManyRequestWrapper,
2792    callback: InsertManyCallback,
2793) {
2794    let options = match safe_wrapper(options) {
2795        Some(options) => options,
2796        None => {
2797            let error_msg = CString::new("Invalid options").unwrap().into_raw();
2798            let response = InsertManyResponseWrapper {
2799                success: false,
2800                results: std::ptr::null(),
2801                error: error_msg,
2802                request_id: 0,
2803            };
2804            return callback(Box::into_raw(Box::new(response)));
2805        }
2806    };
2807    let client_wrapper = match safe_wrapper(client) {
2808        Some(client) => client,
2809        None => {
2810            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
2811            let response = InsertManyResponseWrapper {
2812                success: false,
2813                results: std::ptr::null(),
2814                error: error_msg,
2815                request_id: options.request_id,
2816            };
2817            return callback(Box::into_raw(Box::new(response)));
2818        }
2819    };
2820    let client = client_wrapper.client.clone();
2821    let request = InsertManyRequest {
2822        collectionname: c_char_to_str(options.collectionname),
2823        items: c_char_to_str(options.items),
2824        w: options.w,
2825        j: options.j,
2826        skipresults: options.skipresults
2827    };
2828    if client.is_none() {
2829        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
2830        let response = InsertManyResponseWrapper {
2831            success: false,
2832            results: std::ptr::null(),
2833            error: error_msg,
2834            request_id: options.request_id,
2835        };
2836        return callback(Box::into_raw(Box::new(response)));
2837    }
2838
2839    let client = client.unwrap();
2840    let handle = client.get_runtime_handle();
2841    let request_id = options.request_id;
2842    handle.spawn(async move {
2843        let result = client.insert_many(request).await;
2844        let response = match result {
2845            Ok(data) => {
2846                let results = CString::new(data.results.clone()).unwrap().into_raw();
2847                InsertManyResponseWrapper {
2848                    success: true,
2849                    results,
2850                    error: std::ptr::null(),
2851                    request_id,
2852                }
2853            }
2854            Err(e) => {
2855                let error_msg = CString::new(format!("InsertMany failed: {:?}", e))
2856                    .unwrap()
2857                    .into_raw();
2858                InsertManyResponseWrapper {
2859                    success: false,
2860                    results: std::ptr::null(),
2861                    error: error_msg,
2862                    request_id,
2863                }
2864            }
2865        };
2866
2867        callback(Box::into_raw(Box::new(response)));
2868    });
2869}
2870
2871#[no_mangle]
2872#[tracing::instrument(skip_all)]
2873pub extern "C" fn free_insert_many_response(response: *mut InsertManyResponseWrapper) {
2874    if response.is_null() {
2875        return;
2876    }
2877    unsafe {
2878        if !(*response).results.is_null() {
2879            let _ = CString::from_raw((*response).results as *mut c_char);
2880        }
2881        let _ = Box::from_raw(response);
2882    }
2883}
2884
2885#[repr(C)]
2886pub struct UpdateOneRequestWrapper {
2887    collectionname: *const c_char,
2888    item: *const c_char,
2889    w: i32,
2890    j: bool,
2891    request_id: i32
2892}
2893#[repr(C)]
2894pub struct UpdateOneResponseWrapper {
2895    success: bool,
2896    result: *const c_char,
2897    error: *const c_char,
2898    request_id: i32
2899}
2900#[no_mangle]
2901#[tracing::instrument(skip_all)]
2902pub extern "C" fn update_one(
2903    client: *mut ClientWrapper,
2904    options: *mut UpdateOneRequestWrapper,
2905) -> *mut UpdateOneResponseWrapper {
2906    let options = match safe_wrapper(options) {
2907        Some(options) => options,
2908        None => {
2909            let error_msg = CString::new("Invalid options").unwrap().into_raw();
2910            let response = UpdateOneResponseWrapper {
2911                success: false,
2912                result: std::ptr::null(),
2913                error: error_msg,
2914                request_id: 0,
2915            };
2916            return Box::into_raw(Box::new(response));
2917        }
2918    };
2919    let client_wrapper = match safe_wrapper(client) {
2920        Some(client) => client,
2921        None => {
2922            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
2923            let response = UpdateOneResponseWrapper {
2924                success: false,
2925                result: std::ptr::null(),
2926                error: error_msg,
2927                request_id: options.request_id,
2928            };
2929            return Box::into_raw(Box::new(response));
2930        }
2931    };
2932    let client = client_wrapper.client.clone();
2933    let request = UpdateOneRequest {
2934        collectionname: c_char_to_str(options.collectionname),
2935        item: c_char_to_str(options.item),
2936        w: options.w,
2937        j: options.j
2938    };
2939    if client.is_none() {
2940        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
2941        let response = UpdateOneResponseWrapper {
2942            success: false,
2943            result: std::ptr::null(),
2944            error: error_msg,
2945            request_id: options.request_id,
2946        };
2947        return Box::into_raw(Box::new(response));
2948    }
2949    let client = client.unwrap();
2950    let result = tokio::task::block_in_place(|| {
2951        let handle = client.get_runtime_handle();
2952        handle.block_on( client.update_one(request))
2953    });
2954
2955    let response = match result {
2956        Ok(data) => {
2957            let result = CString::new(data.result).unwrap().into_raw();
2958            UpdateOneResponseWrapper {
2959                success: true,
2960                result,
2961                error: std::ptr::null(),
2962                request_id: options.request_id,
2963            }
2964        }
2965        Err(e) => {
2966            let error_msg = CString::new(format!("UpdateOne failed: {:?}", e))
2967                .unwrap()
2968                .into_raw();
2969            UpdateOneResponseWrapper {
2970                success: false,
2971                result: std::ptr::null(),
2972                error: error_msg,
2973                request_id: options.request_id,
2974            }
2975        }
2976    };
2977
2978    Box::into_raw(Box::new(response))
2979}
2980
2981type UpdateOneCallback = extern "C" fn(wrapper: *mut UpdateOneResponseWrapper);
2982#[no_mangle]
2983#[tracing::instrument(skip_all)]
2984pub extern "C" fn update_one_async(
2985    client: *mut ClientWrapper,
2986    options: *mut UpdateOneRequestWrapper,
2987    callback: UpdateOneCallback,
2988) {
2989    let options = match safe_wrapper(options) {
2990        Some(options) => options,
2991        None => {
2992            let error_msg = CString::new("Invalid options").unwrap().into_raw();
2993            let response = UpdateOneResponseWrapper {
2994                success: false,
2995                result: std::ptr::null(),
2996                error: error_msg,
2997                request_id: 0,
2998            };
2999            return callback(Box::into_raw(Box::new(response)));
3000        }
3001    };
3002    let client_wrapper = match safe_wrapper(client) {
3003        Some(client) => client,
3004        None => {
3005            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
3006            let response = UpdateOneResponseWrapper {
3007                success: false,
3008                result: std::ptr::null(),
3009                error: error_msg,
3010                request_id: options.request_id,
3011            };
3012            return callback(Box::into_raw(Box::new(response)));
3013        }
3014    };
3015    let client = client_wrapper.client.clone();
3016    let request = UpdateOneRequest {
3017        collectionname: c_char_to_str(options.collectionname),
3018        item: c_char_to_str(options.item),
3019        w: options.w,
3020        j: options.j
3021    };
3022    if client.is_none() {
3023        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
3024        let response = UpdateOneResponseWrapper {
3025            success: false,
3026            result: std::ptr::null(),
3027            error: error_msg,
3028            request_id: options.request_id,
3029        };
3030        return callback(Box::into_raw(Box::new(response)));
3031    }
3032
3033    let client = client.unwrap();
3034    let handle = client.get_runtime_handle();
3035    let request_id = options.request_id;
3036    handle.spawn(async move {
3037        let result = client.update_one(request).await;
3038        let response = match result {
3039            Ok(data) => {
3040                let result = CString::new(data.result).unwrap().into_raw();
3041                UpdateOneResponseWrapper {
3042                    success: true,
3043                    result,
3044                    error: std::ptr::null(),
3045                    request_id,
3046                }
3047            }
3048            Err(e) => {
3049                let error_msg = CString::new(format!("UpdateOne failed: {:?}", e))
3050                    .unwrap()
3051                    .into_raw();
3052                UpdateOneResponseWrapper {
3053                    success: false,
3054                    result: std::ptr::null(),
3055                    error: error_msg,
3056                    request_id,
3057                }
3058            }
3059        };
3060
3061        callback(Box::into_raw(Box::new(response)));
3062    });
3063}
3064
3065#[no_mangle]
3066#[tracing::instrument(skip_all)]
3067pub extern "C" fn free_update_one_response(response: *mut UpdateOneResponseWrapper) {
3068    if response.is_null() {
3069        return;
3070    }
3071    unsafe {
3072        if !(*response).error.is_null() {
3073            let _ = CString::from_raw((*response).error as *mut c_char);
3074        }
3075        if !(*response).result.is_null() {
3076            let _ = CString::from_raw((*response).result as *mut c_char);
3077        }
3078        let _ = Box::from_raw(response);
3079    }
3080}
3081
3082#[repr(C)]
3083pub struct InsertOrUpdateOneRequestWrapper {
3084    collectionname: *const c_char,
3085    uniqeness: *const c_char, 
3086    item: *const c_char,
3087    w: i32,
3088    j: bool,
3089    request_id: i32
3090}
3091#[repr(C)]
3092pub struct InsertOrUpdateOneResponseWrapper {
3093    success: bool,
3094    result: *const c_char,
3095    error: *const c_char,
3096    request_id: i32
3097}
3098#[no_mangle]
3099#[tracing::instrument(skip_all)]
3100pub extern "C" fn insert_or_update_one(
3101    client: *mut ClientWrapper,
3102    options: *mut InsertOrUpdateOneRequestWrapper,
3103) -> *mut InsertOrUpdateOneResponseWrapper {
3104    let options = match safe_wrapper(options) {
3105        Some(options) => options,
3106        None => {
3107            let error_msg = CString::new("Invalid options").unwrap().into_raw();
3108            let response = InsertOrUpdateOneResponseWrapper {
3109                success: false,
3110                result: std::ptr::null(),
3111                error: error_msg,
3112                request_id: 0,
3113            };
3114            return Box::into_raw(Box::new(response));
3115        }
3116    };
3117    let client_wrapper = match safe_wrapper(client) {
3118        Some(client) => client,
3119        None => {
3120            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
3121            let response = InsertOrUpdateOneResponseWrapper {
3122                success: false,
3123                result: std::ptr::null(),
3124                error: error_msg,
3125                request_id: options.request_id,
3126            };
3127            return Box::into_raw(Box::new(response));
3128        }
3129    };
3130    let client = client_wrapper.client.clone();
3131    debug!("Rust: insert_or_update_one create request");
3132
3133    trace!("Rust: parse collectionname");
3134    let collectionname = c_char_to_str(options.collectionname);
3135    trace!("Rust: parse uniqeness");
3136    let uniqeness = c_char_to_str(options.uniqeness);
3137    trace!("Rust: parse item");
3138    let item = c_char_to_str(options.item);
3139    trace!("Rust: parse w");
3140    let w = options.w;
3141    trace!("Rust: parse j");
3142    let j = options.j;
3143    let request = InsertOrUpdateOneRequest {
3144        collectionname,
3145        uniqeness,
3146        item,
3147        w,
3148        j
3149    };
3150    if client.is_none() {
3151        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
3152        let response = InsertOrUpdateOneResponseWrapper {
3153            success: false,
3154            result: std::ptr::null(),
3155            error: error_msg,
3156            request_id: options.request_id,
3157        };
3158        return Box::into_raw(Box::new(response));
3159    }
3160    let client = client.unwrap();
3161    debug!("Rust: run insert_or_update_one in runtime");
3162    let result = tokio::task::block_in_place(|| {
3163        let handle = client.get_runtime_handle();
3164        handle.block_on( client.insert_or_update_one(request))
3165    });
3166
3167    let response = match result {
3168        Ok(data) => {
3169            let result = CString::new(data).unwrap().into_raw();
3170            InsertOrUpdateOneResponseWrapper {
3171                success: true,
3172                result,
3173                error: std::ptr::null(),
3174                request_id: options.request_id,
3175            }
3176        }
3177        Err(e) => {
3178            let error_msg = CString::new(format!("InsertOrUpdateOne failed: {:?}", e))
3179                .unwrap()
3180                .into_raw();
3181            InsertOrUpdateOneResponseWrapper {
3182                success: false,
3183                result: std::ptr::null(),
3184                error: error_msg,
3185                request_id: options.request_id,
3186            }
3187        }
3188    };
3189
3190    Box::into_raw(Box::new(response))
3191}
3192
3193type InsertOrUpdateOneCallback = extern "C" fn(wrapper: *mut InsertOrUpdateOneResponseWrapper);
3194#[no_mangle]
3195#[tracing::instrument(skip_all)]
3196pub extern "C" fn insert_or_update_one_async(
3197    client: *mut ClientWrapper,
3198    options: *mut InsertOrUpdateOneRequestWrapper,
3199    callback: InsertOrUpdateOneCallback,
3200) {
3201    let options = match safe_wrapper(options) {
3202        Some(options) => options,
3203        None => {
3204            let error_msg = CString::new("Invalid options").unwrap().into_raw();
3205            let response = InsertOrUpdateOneResponseWrapper {
3206                success: false,
3207                result: std::ptr::null(),
3208                error: error_msg,
3209                request_id: 0,
3210            };
3211            return callback(Box::into_raw(Box::new(response)));
3212        }
3213    };
3214    let client_wrapper = match safe_wrapper(client) {
3215        Some(client) => client,
3216        None => {
3217            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
3218            let response = InsertOrUpdateOneResponseWrapper {
3219                success: false,
3220                result: std::ptr::null(),
3221                error: error_msg,
3222                request_id: options.request_id,
3223            };
3224            return callback(Box::into_raw(Box::new(response)));
3225        }
3226    };
3227    let client = client_wrapper.client.clone();
3228    debug!("Rust: insert_or_update_one_async create request");
3229    let request = InsertOrUpdateOneRequest {
3230        collectionname: c_char_to_str(options.collectionname),
3231        uniqeness: c_char_to_str(options.uniqeness),
3232        item: c_char_to_str(options.item),
3233        w: options.w,
3234        j: options.j
3235    };
3236    if client.is_none() {
3237        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
3238        let response = InsertOrUpdateOneResponseWrapper {
3239            success: false,
3240            result: std::ptr::null(),
3241            error: error_msg,
3242            request_id: options.request_id,
3243        };
3244        return callback(Box::into_raw(Box::new(response)));
3245    }
3246    let client = client.unwrap();
3247    let handle = client.get_runtime_handle();
3248    let request_id = options.request_id;
3249    handle.spawn(async move {
3250        let result = client.insert_or_update_one(request).await;
3251
3252        let response = match result {
3253            Ok(data) => {
3254                let result = CString::new(data).unwrap().into_raw();
3255                InsertOrUpdateOneResponseWrapper {
3256                    success: true,
3257                    result,
3258                    error: std::ptr::null(),
3259                    request_id,
3260                }
3261            }
3262            Err(e) => {
3263                let error_msg = CString::new(format!("InsertOrUpdateOne failed: {:?}", e))
3264                    .unwrap()
3265                    .into_raw();
3266                InsertOrUpdateOneResponseWrapper {
3267                    success: false,
3268                    result: std::ptr::null(),
3269                    error: error_msg,
3270                    request_id,
3271                }
3272            }
3273        };
3274
3275        callback(Box::into_raw(Box::new(response)));
3276    });
3277}
3278#[no_mangle]
3279#[tracing::instrument(skip_all)]
3280pub extern "C" fn free_insert_or_update_one_response(response: *mut InsertOrUpdateOneResponseWrapper) {
3281    if response.is_null() {
3282        return;
3283    }
3284    unsafe {
3285        if !(*response).error.is_null() {
3286            let _ = CString::from_raw((*response).error as *mut c_char);
3287        }
3288        if !(*response).result.is_null() {
3289            let _ = CString::from_raw((*response).result as *mut c_char);
3290        }
3291        let _ = Box::from_raw(response);
3292    }
3293}
3294
3295#[repr(C)]
3296pub struct DeleteOneRequestWrapper {
3297    collectionname: *const c_char,
3298    id: *const c_char,
3299    recursive: bool,
3300    request_id: i32
3301}
3302#[repr(C)]
3303pub struct DeleteOneResponseWrapper {
3304    success: bool,
3305    affectedrows: i32,
3306    error: *const c_char,
3307    request_id: i32
3308}
3309#[no_mangle]
3310#[tracing::instrument(skip_all)]
3311pub extern "C" fn delete_one(
3312    client: *mut ClientWrapper,
3313    options: *mut DeleteOneRequestWrapper,
3314) -> *mut DeleteOneResponseWrapper {
3315    let options = match safe_wrapper(options) {
3316        Some(options) => options,
3317        None => {
3318            let error_msg = CString::new("Invalid options").unwrap().into_raw();
3319            let response = DeleteOneResponseWrapper {
3320                success: false,
3321                affectedrows: 0,
3322                error: error_msg,
3323                request_id: 0,
3324            };
3325            return Box::into_raw(Box::new(response));
3326        }
3327    };
3328    let client_wrapper = match safe_wrapper(client) {
3329        Some(client) => client,
3330        None => {
3331            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
3332            let response = DeleteOneResponseWrapper {
3333                success: false,
3334                affectedrows: 0,
3335                error: error_msg,
3336                request_id: options.request_id,
3337            };
3338            return Box::into_raw(Box::new(response));
3339        }
3340    };
3341    let client = client_wrapper.client.clone();
3342    let request = DeleteOneRequest {
3343        collectionname: c_char_to_str(options.collectionname),
3344        id: c_char_to_str(options.id),
3345        recursive: options.recursive
3346    };
3347    if client.is_none() {
3348        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
3349        let response = DeleteOneResponseWrapper {
3350            success: false,
3351            affectedrows: 0,
3352            error: error_msg,
3353            request_id: options.request_id,
3354        };
3355        return Box::into_raw(Box::new(response));
3356    }
3357    let client = client.unwrap();
3358    let result = tokio::task::block_in_place(|| {
3359        let handle = client.get_runtime_handle();
3360        handle.block_on( client.delete_one(request))
3361    });
3362
3363    let response = match result {
3364        Ok(data) => {
3365            let affectedrows = data;
3366            DeleteOneResponseWrapper {
3367                success: true,
3368                affectedrows,
3369                error: std::ptr::null(),
3370                request_id: options.request_id,
3371            }
3372        }
3373        Err(e) => {
3374            let error_msg = CString::new(format!("DeleteOne failed: {:?}", e))
3375                .unwrap()
3376                .into_raw();
3377            DeleteOneResponseWrapper {
3378                success: false,
3379                affectedrows: 0,
3380                error: error_msg,
3381                request_id: options.request_id,
3382            }
3383        }
3384    };
3385
3386    Box::into_raw(Box::new(response))
3387}
3388type DeleteOneCallback = extern "C" fn(wrapper: *mut DeleteOneResponseWrapper);
3389#[no_mangle]
3390#[tracing::instrument(skip_all)]
3391pub extern "C" fn delete_one_async(
3392    client: *mut ClientWrapper,
3393    options: *mut DeleteOneRequestWrapper,
3394    callback: DeleteOneCallback,
3395) {
3396    let options = match safe_wrapper(options) {
3397        Some(options) => options,
3398        None => {
3399            let error_msg = CString::new("Invalid options").unwrap().into_raw();
3400            let response = DeleteOneResponseWrapper {
3401                success: false,
3402                affectedrows: 0,
3403                error: error_msg,
3404                request_id: 0,
3405            };
3406            return callback(Box::into_raw(Box::new(response)));
3407        }
3408    };
3409    let client_wrapper = match safe_wrapper(client) {
3410        Some(client) => client,
3411        None => {
3412            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
3413            let response = DeleteOneResponseWrapper {
3414                success: false,
3415                affectedrows: 0,
3416                error: error_msg,
3417                request_id: options.request_id,
3418            };
3419            return callback(Box::into_raw(Box::new(response)));
3420        }
3421    };
3422    let client = client_wrapper.client.clone();
3423    let request = DeleteOneRequest {
3424        collectionname: c_char_to_str(options.collectionname),
3425        id: c_char_to_str(options.id),
3426        recursive: options.recursive
3427    };
3428    if client.is_none() {
3429        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
3430        let response = DeleteOneResponseWrapper {
3431            success: false,
3432            affectedrows: 0,
3433            error: error_msg,
3434            request_id: options.request_id,
3435        };
3436        return callback(Box::into_raw(Box::new(response)));
3437    }
3438
3439    let client = client.unwrap();
3440    let handle = client.get_runtime_handle();
3441    let request_id = options.request_id;
3442    handle.spawn(async move {
3443        let result = client.delete_one(request).await;
3444        let response = match result {
3445            Ok(data) => {
3446                let affectedrows = data;
3447                DeleteOneResponseWrapper {
3448                    success: true,
3449                    affectedrows,
3450                    error: std::ptr::null(),
3451                    request_id,
3452                }
3453            }
3454            Err(e) => {
3455                let error_msg = CString::new(format!("DeleteOne failed: {:?}", e))
3456                    .unwrap()
3457                    .into_raw();
3458                DeleteOneResponseWrapper {
3459                    success: false,
3460                    affectedrows: 0,
3461                    error: error_msg,
3462                    request_id,
3463                }
3464            }
3465        };
3466
3467        callback(Box::into_raw(Box::new(response)));
3468    });
3469}
3470#[no_mangle]
3471#[tracing::instrument(skip_all)]
3472pub extern "C" fn free_delete_one_response(response: *mut DeleteOneResponseWrapper) {
3473    if response.is_null() {
3474        return;
3475    }
3476    unsafe {
3477        if !(*response).error.is_null() {
3478            let _ = CString::from_raw((*response).error as *mut c_char);
3479        }
3480        let _ = Box::from_raw(response);
3481    }
3482}
3483
3484#[repr(C)]
3485pub struct DeleteManyRequestWrapper {
3486    collectionname: *const c_char,
3487    query: *const c_char,
3488    recursive: bool,
3489    ids: *const *const c_char,
3490    request_id: i32
3491}
3492#[repr(C)]
3493pub struct DeleteManyResponseWrapper {
3494    success: bool,
3495    affectedrows: i32,
3496    error: *const c_char,
3497    request_id: i32
3498}
3499#[no_mangle]
3500#[tracing::instrument(skip_all)]
3501pub extern "C" fn delete_many(
3502    client: *mut ClientWrapper,
3503    options: *mut DeleteManyRequestWrapper,
3504) -> *mut DeleteManyResponseWrapper {
3505    let options = match safe_wrapper(options) {
3506        Some(options) => options,
3507        None => {
3508            let error_msg = CString::new("Invalid options").unwrap().into_raw();
3509            let response = DeleteManyResponseWrapper {
3510                success: false,
3511                affectedrows: 0,
3512                error: error_msg,
3513                request_id: 0,
3514            };
3515            return Box::into_raw(Box::new(response));
3516        }
3517    };
3518    let client_wrapper = match safe_wrapper(client) {
3519        Some(client) => client,
3520        None => {
3521            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
3522            let response = DeleteManyResponseWrapper {
3523                success: false,
3524                affectedrows: 0,
3525                error: error_msg,
3526                request_id: options.request_id,
3527            };
3528            return Box::into_raw(Box::new(response));
3529        }
3530    };
3531    let client = client_wrapper.client.clone();
3532    let request = DeleteManyRequest {
3533        collectionname: c_char_to_str(options.collectionname),
3534        query: c_char_to_str(options.query),
3535        recursive: options.recursive,
3536        ids: {
3537            let mut ids = vec![];
3538            if !options.ids.is_null() {
3539                let mut i = 0;
3540                loop {
3541                    let id = unsafe { *options.ids.add(i) };
3542                    if id.is_null() {
3543                        break;
3544                    }
3545                    ids.push(c_char_to_str(id));
3546                    i += 1;
3547                }
3548            }
3549            ids
3550        }
3551    };
3552    if client.is_none() {
3553        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
3554        let response = DeleteManyResponseWrapper {
3555            success: false,
3556            affectedrows: 0,
3557            error: error_msg,
3558            request_id: options.request_id,
3559        };
3560        return Box::into_raw(Box::new(response));
3561    }
3562    let client = client.unwrap();
3563    let result = tokio::task::block_in_place(|| {
3564        let handle = client.get_runtime_handle();
3565        handle.block_on( client.delete_many(request))
3566    });
3567
3568    let response = match result {
3569        Ok(data) => {
3570            let affectedrows = data;
3571            DeleteManyResponseWrapper {
3572                success: true,
3573                affectedrows,
3574                error: std::ptr::null(),
3575                request_id: options.request_id,
3576            }
3577        }
3578        Err(e) => {
3579            let error_msg = CString::new(format!("DeleteMany failed: {:?}", e))
3580                .unwrap()
3581                .into_raw();
3582            DeleteManyResponseWrapper {
3583                success: false,
3584                affectedrows: 0,
3585                error: error_msg,
3586                request_id: options.request_id,
3587            }
3588        }
3589    };
3590
3591    Box::into_raw(Box::new(response))
3592}
3593type DeleteManyCallback = extern "C" fn(wrapper: *mut DeleteManyResponseWrapper);
3594#[no_mangle]
3595#[tracing::instrument(skip_all)]
3596pub extern "C" fn delete_many_async(
3597    client: *mut ClientWrapper,
3598    options: *mut DeleteManyRequestWrapper,
3599    callback: DeleteManyCallback,
3600) {
3601    let options = match safe_wrapper(options) {
3602        Some(options) => options,
3603        None => {
3604            let error_msg = CString::new("Invalid options").unwrap().into_raw();
3605            let response = DeleteManyResponseWrapper {
3606                success: false,
3607                affectedrows: 0,
3608                error: error_msg,
3609                request_id: 0,
3610            };
3611            return callback(Box::into_raw(Box::new(response)));
3612        }
3613    };
3614    let client_wrapper = match safe_wrapper(client) {
3615        Some(client) => client,
3616        None => {
3617            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
3618            let response = DeleteManyResponseWrapper {
3619                success: false,
3620                affectedrows: 0,
3621                error: error_msg,
3622                request_id: options.request_id,
3623            };
3624            return callback(Box::into_raw(Box::new(response)));
3625        }
3626    };
3627    let client = client_wrapper.client.clone();
3628    let request = DeleteManyRequest {
3629        collectionname: c_char_to_str(options.collectionname),
3630        query: c_char_to_str(options.query),
3631        recursive: options.recursive,
3632        ids: {
3633            let mut ids = vec![];
3634            let mut i = 0;
3635            loop {
3636                let id = unsafe { *options.ids.add(i) };
3637                if id.is_null() {
3638                    break;
3639                }
3640                let id = c_char_to_str(id);
3641                ids.push(id);
3642                i += 1;
3643            }
3644            ids
3645        }
3646    };
3647    if client.is_none() {
3648        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
3649        let response = DeleteManyResponseWrapper {
3650            success: false,
3651            affectedrows: 0,
3652            error: error_msg,
3653            request_id: options.request_id,
3654        };
3655        return callback(Box::into_raw(Box::new(response)));
3656    }
3657    let client = client.unwrap();
3658    let handle = client.get_runtime_handle();
3659    let request_id = options.request_id;
3660    handle.spawn(async move {
3661        let result = client.delete_many(request).await;
3662        let response = match result {
3663            Ok(data) => {
3664                let affectedrows = data;
3665                DeleteManyResponseWrapper {
3666                    success: true,
3667                    affectedrows,
3668                    error: std::ptr::null(),
3669                    request_id,
3670                }
3671            }
3672            Err(e) => {
3673                let error_msg = CString::new(format!("DeleteMany failed: {:?}", e))
3674                    .unwrap()
3675                    .into_raw();
3676                DeleteManyResponseWrapper {
3677                    success: false,
3678                    affectedrows: 0,
3679                    error: error_msg,
3680                    request_id,
3681                }
3682            }
3683        };
3684
3685        callback(Box::into_raw(Box::new(response)));
3686    });
3687}
3688#[no_mangle]
3689#[tracing::instrument(skip_all)]
3690pub extern "C" fn free_delete_many_response(response: *mut DeleteManyResponseWrapper) {
3691    if response.is_null() {
3692        return;
3693    }
3694    unsafe {
3695        if !(*response).error.is_null() {
3696            let _ = CString::from_raw((*response).error as *mut c_char);
3697        }
3698        let _ = Box::from_raw(response);
3699    }
3700}
3701
3702#[repr(C)]
3703pub struct DownloadRequestWrapper {
3704    collectionname: *const c_char,
3705    id: *const c_char,
3706    folder: *const c_char,
3707    filename: *const c_char,
3708    request_id: i32
3709}
3710#[repr(C)]
3711pub struct DownloadResponseWrapper {
3712    success: bool,
3713    filename: *const c_char,
3714    error: *const c_char,
3715    request_id: i32
3716}
3717#[no_mangle]
3718#[tracing::instrument(skip_all)]
3719pub extern "C" fn download(
3720    client: *mut ClientWrapper,
3721    options: *mut DownloadRequestWrapper,
3722) -> *mut DownloadResponseWrapper {
3723    let options = match safe_wrapper(options) {
3724        Some(options) => options,
3725        None => {
3726            let error_msg = CString::new("Invalid options").unwrap().into_raw();
3727            let response = DownloadResponseWrapper {
3728                success: false,
3729                filename: std::ptr::null(),
3730                error: error_msg,
3731                request_id: 0,
3732            };
3733            return Box::into_raw(Box::new(response));
3734        }
3735    };
3736    let client_wrapper = match safe_wrapper(client) {
3737        Some(client) => client,
3738        None => {
3739            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
3740            let response = DownloadResponseWrapper {
3741                success: false,
3742                filename: std::ptr::null(),
3743                error: error_msg,
3744                request_id: options.request_id,
3745            };
3746            return Box::into_raw(Box::new(response));
3747        }
3748    };
3749    let client = client_wrapper.client.clone();
3750    let folder = c_char_to_str(options.folder);
3751    let filename = c_char_to_str(options.filename);
3752    let request = DownloadRequest {
3753        collectionname: c_char_to_str(options.collectionname),
3754        filename: c_char_to_str(options.filename),
3755        id: c_char_to_str(options.id)
3756    };
3757    if client.is_none() {
3758        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
3759        let response = DownloadResponseWrapper {
3760            success: false,
3761            filename: std::ptr::null(),
3762            error: error_msg,
3763            request_id: options.request_id,
3764        };
3765        return Box::into_raw(Box::new(response));
3766    }
3767    let client = client.unwrap();
3768    let result = tokio::task::block_in_place(|| {
3769        let handle = client.get_runtime_handle();
3770            handle.block_on( client.download(request, Some(&folder), Some(&filename)))
3771    });
3772
3773    let response = match result {
3774        Ok(data) => {
3775            let filename = CString::new(data.filename).unwrap().into_raw();
3776            DownloadResponseWrapper {
3777                success: true,
3778                filename,
3779                error: std::ptr::null(),
3780                request_id: options.request_id,
3781            }
3782        }
3783        Err(e) => {
3784            let error_msg = CString::new(format!("Download failed: {:?}", e))
3785                .unwrap()
3786                .into_raw();
3787            DownloadResponseWrapper {
3788                success: false,
3789                filename: std::ptr::null(),
3790                error: error_msg,
3791                request_id: options.request_id,
3792            }
3793        }
3794    };
3795
3796    Box::into_raw(Box::new(response))
3797}
3798
3799type DownloadCallback = extern "C" fn(wrapper: *mut DownloadResponseWrapper);
3800#[no_mangle]
3801#[tracing::instrument(skip_all)]
3802pub extern "C" fn download_async(
3803    client: *mut ClientWrapper,
3804    options: *mut DownloadRequestWrapper,
3805    callback: DownloadCallback,
3806) {
3807    let options = match safe_wrapper(options) {
3808        Some(options) => options,
3809        None => {
3810            let error_msg = CString::new("Invalid options").unwrap().into_raw();
3811            let response = DownloadResponseWrapper {
3812                success: false,
3813                filename: std::ptr::null(),
3814                error: error_msg,
3815                request_id: 0,
3816            };
3817            return callback(Box::into_raw(Box::new(response)));
3818        }
3819    };
3820    let client_wrapper = match safe_wrapper(client) {
3821        Some(client) => client,
3822        None => {
3823            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
3824            let response = DownloadResponseWrapper {
3825                success: false,
3826                filename: std::ptr::null(),
3827                error: error_msg,
3828                request_id: options.request_id,
3829            };
3830            return callback(Box::into_raw(Box::new(response)));
3831        }
3832    };
3833    let client = client_wrapper.client.clone();
3834    let folder = c_char_to_str(options.folder);
3835    let filename = c_char_to_str(options.filename);
3836    let request = DownloadRequest {
3837        collectionname: c_char_to_str(options.collectionname),
3838        filename: c_char_to_str(options.filename),
3839        id: c_char_to_str(options.id)
3840    };
3841    if client.is_none() {
3842        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
3843        let response = DownloadResponseWrapper {
3844            success: false,
3845            filename: std::ptr::null(),
3846            error: error_msg,
3847            request_id: options.request_id,
3848        };
3849        return callback(Box::into_raw(Box::new(response)));
3850    }
3851    let client = client.unwrap();
3852    let handle = client.get_runtime_handle();
3853    let request_id = options.request_id;
3854    handle.spawn(async move {
3855        let result = client
3856            .download(request, Some(&folder), Some(&filename))
3857            .await;
3858
3859        let response = match result {
3860            Ok(data) => {
3861                let filename = CString::new(data.filename).unwrap().into_raw();
3862                DownloadResponseWrapper {
3863                    success: true,
3864                    filename,
3865                    error: std::ptr::null(),
3866                    request_id,
3867                }
3868            }
3869            Err(e) => {
3870                let error_msg = CString::new(format!("Download failed: {:?}", e))
3871                    .unwrap()
3872                    .into_raw();
3873                DownloadResponseWrapper {
3874                    success: false,
3875                    filename: std::ptr::null(),
3876                    error: error_msg,
3877                    request_id,
3878                }
3879            }
3880        };
3881
3882        callback(Box::into_raw(Box::new(response)));
3883    });
3884}
3885#[no_mangle]
3886#[tracing::instrument(skip_all)]
3887pub extern "C" fn free_download_response(response: *mut DownloadResponseWrapper) {
3888    if response.is_null() {
3889        return;
3890    }
3891    unsafe {
3892        if !(*response).error.is_null() {
3893            let _ = CString::from_raw((*response).error as *mut c_char);
3894        }
3895        if !(*response).filename.is_null() {
3896            let _ = CString::from_raw((*response).filename as *mut c_char);
3897        }
3898        let _ = Box::from_raw(response);
3899    }
3900}
3901
3902#[repr(C)]
3903pub struct UploadRequestWrapper {
3904    filepath: *const c_char,
3905    filename: *const c_char,
3906    mimetype: *const c_char,
3907    metadata: *const c_char,
3908    collectionname: *const c_char,
3909    request_id: i32
3910}
3911#[repr(C)]
3912pub struct UploadResponseWrapper {
3913    success: bool,
3914    id: *const c_char,
3915    error: *const c_char,
3916    request_id: i32
3917}
3918#[no_mangle]
3919#[tracing::instrument(skip_all)]
3920pub extern "C" fn upload(
3921    client: *mut ClientWrapper,
3922    options: *mut UploadRequestWrapper,
3923) -> *mut UploadResponseWrapper {
3924    let options = match safe_wrapper(options) {
3925        Some(options) => options,
3926        None => {
3927            let error_msg = CString::new("Invalid options").unwrap().into_raw();
3928            let response = UploadResponseWrapper {
3929                success: false,
3930                id: std::ptr::null(),
3931                error: error_msg,
3932                request_id: 0,
3933            };
3934            return Box::into_raw(Box::new(response));
3935        }
3936    };
3937    let client_wrapper = match safe_wrapper(client) {
3938        Some(client) => client,
3939        None => {
3940            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
3941            let response = UploadResponseWrapper {
3942                success: false,
3943                id: std::ptr::null(),
3944                error: error_msg,
3945                request_id: options.request_id,
3946            };
3947            return Box::into_raw(Box::new(response));
3948        }
3949    };
3950    let client = client_wrapper.client.clone();
3951    let filepath = c_char_to_str(options.filepath);
3952    if filepath.is_empty() {
3953        let error_msg = CString::new("Filepath is required").unwrap().into_raw();
3954        let response = UploadResponseWrapper {
3955            success: false,
3956            id: std::ptr::null(),
3957            error: error_msg,
3958            request_id: options.request_id,
3959        };
3960        return Box::into_raw(Box::new(response));
3961    }
3962    let filepath = filepath.to_string();
3963    debug!("upload: filepath: {}", filepath);
3964    let filename = c_char_to_str(options.filename);
3965    if filename.is_empty() {
3966        let error_msg = CString::new("Filename is required").unwrap().into_raw();
3967        let response = UploadResponseWrapper {
3968            success: false,
3969            id: std::ptr::null(),
3970            error: error_msg,
3971            request_id: options.request_id,
3972        };
3973        return Box::into_raw(Box::new(response));
3974    }
3975
3976    let request = UploadRequest {
3977        filename: filename.to_string(),
3978        mimetype: c_char_to_str(options.mimetype),
3979        metadata: c_char_to_str(options.metadata),
3980        collectionname: c_char_to_str(options.collectionname)
3981    };
3982    if client.is_none() {
3983        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
3984        let response = UploadResponseWrapper {
3985            success: false,
3986            id: std::ptr::null(),
3987            error: error_msg,
3988            request_id: options.request_id,
3989        };
3990        return Box::into_raw(Box::new(response));
3991    }
3992    let client = client.unwrap();
3993    debug!("upload: runtime.block_on");
3994    let result = tokio::task::block_in_place(|| {
3995        // let c = client.as_mut().unwrap();
3996        // c.upload(request).await
3997        // client.as_mut().unwrap().upload(request, &filepath).await
3998        let handle = client.get_runtime_handle();
3999        handle.block_on( client.upload(request, &filepath))
4000    });
4001
4002    let response = match result {
4003        Ok(data) => {
4004            let id = CString::new(data.id).unwrap().into_raw();
4005            UploadResponseWrapper {
4006                success: true,
4007                id,
4008                error: std::ptr::null(),
4009                request_id: options.request_id,
4010            }
4011        }
4012        Err(e) => {
4013            let error_msg = CString::new(format!("Upload failed: {:?}", e))
4014                .unwrap()
4015                .into_raw();
4016            UploadResponseWrapper {
4017                success: false,
4018                id: std::ptr::null(),
4019                error: error_msg,
4020                request_id: options.request_id,
4021            }
4022        }
4023    };
4024    Box::into_raw(Box::new(response))
4025}
4026
4027type UploadCallback = extern "C" fn(wrapper: *mut UploadResponseWrapper);
4028#[no_mangle]
4029#[tracing::instrument(skip_all)]
4030pub extern "C" fn upload_async(
4031    client: *mut ClientWrapper,
4032    options: *mut UploadRequestWrapper,
4033    callback: UploadCallback,
4034) {
4035    let options = match safe_wrapper(options) {
4036        Some(options) => options,
4037        None => {
4038            let error_msg = CString::new("Invalid options").unwrap().into_raw();
4039            let response = UploadResponseWrapper {
4040                success: false,
4041                id: std::ptr::null(),
4042                error: error_msg,
4043                request_id: 0,
4044            };
4045            return callback(Box::into_raw(Box::new(response)));
4046        }
4047    };
4048    let client_wrapper = match safe_wrapper(client) {
4049        Some(client) => client,
4050        None => {
4051            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
4052            let response = UploadResponseWrapper {
4053                success: false,
4054                id: std::ptr::null(),
4055                error: error_msg,
4056                request_id: options.request_id,
4057            };
4058            return callback(Box::into_raw(Box::new(response)));
4059        }
4060    };
4061    let client = client_wrapper.client.clone();
4062    let filepath = c_char_to_str(options.filepath);
4063    if filepath.is_empty() {
4064        let error_msg = CString::new("Filepath is required").unwrap().into_raw();
4065        let response = UploadResponseWrapper {
4066            success: false,
4067            id: std::ptr::null(),
4068            error: error_msg,
4069            request_id: options.request_id,
4070        };
4071        return callback(Box::into_raw(Box::new(response)));
4072    }
4073    let filepath = filepath.to_string();
4074    debug!("upload_async: filepath: {}", filepath);
4075    let filename = c_char_to_str(options.filename);
4076    if filename.is_empty() {
4077        let error_msg = CString::new("Filename is required").unwrap().into_raw();
4078        let response = UploadResponseWrapper {
4079            success: false,
4080            id: std::ptr::null(),
4081            error: error_msg,
4082            request_id: options.request_id,
4083        };
4084        return callback(Box::into_raw(Box::new(response)));
4085    }
4086
4087    let request = UploadRequest {
4088        filename: filename.to_string(),
4089        mimetype: c_char_to_str(options.mimetype),
4090        metadata: c_char_to_str(options.metadata),
4091        collectionname: c_char_to_str(options.collectionname)
4092    };
4093    if client.is_none() {
4094        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
4095        let response = UploadResponseWrapper {
4096            success: false,
4097            id: std::ptr::null(),
4098            error: error_msg,
4099            request_id: options.request_id,
4100        };
4101        return callback(Box::into_raw(Box::new(response)));
4102    }
4103    debug!("upload_async: runtime.spawn");
4104    let client = client.unwrap();
4105    let handle = client.get_runtime_handle();
4106    let request_id = options.request_id;
4107    handle.spawn(async move {
4108        debug!("upload_async: call client.upload");
4109        let result = client.upload(request, &filepath).await;
4110
4111        debug!("upload_async: call client.upload done");
4112        let response = match result {
4113            Ok(data) => {
4114                let id = CString::new(data.id).unwrap().into_raw();
4115                UploadResponseWrapper {
4116                    success: true,
4117                    id,
4118                    error: std::ptr::null(),
4119                    request_id,
4120                }
4121            }
4122            Err(e) => {
4123                let error_msg = CString::new(format!("Upload failed: {:?}", e))
4124                    .unwrap()
4125                    .into_raw();
4126                UploadResponseWrapper {
4127                    success: false,
4128                    id: std::ptr::null(),
4129                    error: error_msg,
4130                    request_id,
4131                }
4132            }
4133        };
4134        debug!("upload_async: call callback with response");
4135        callback(Box::into_raw(Box::new(response)));
4136    });
4137}
4138#[no_mangle]
4139#[tracing::instrument(skip_all)]
4140pub extern "C" fn free_upload_response(response: *mut UploadResponseWrapper) {
4141    if response.is_null() {
4142        return;
4143    }
4144    unsafe {
4145        if !(*response).error.is_null() {
4146            let _ = CString::from_raw((*response).error as *mut c_char);
4147        }
4148        if !(*response).id.is_null() {
4149            let _ = CString::from_raw((*response).id as *mut c_char);
4150        }
4151        let _ = Box::from_raw(response);
4152    }
4153}
4154
4155#[repr(C)]
4156pub struct WatchRequestWrapper {
4157    collectionname: *const c_char,
4158    paths: *const c_char,
4159    request_id: i32
4160}
4161#[repr(C)]
4162pub struct WatchResponseWrapper {
4163    success: bool,
4164    watchid: *const c_char,
4165    error: *const c_char,
4166    request_id: i32
4167}
4168#[no_mangle]
4169#[tracing::instrument(skip_all)]
4170pub extern "C" fn watch(
4171    client: *mut ClientWrapper,
4172    options: *mut WatchRequestWrapper,
4173) -> *mut WatchResponseWrapper {
4174    let options = match safe_wrapper(options) {
4175        Some(options) => options,
4176        None => {
4177            let error_msg = CString::new("Invalid options").unwrap().into_raw();
4178            let response = WatchResponseWrapper {
4179                success: false,
4180                watchid: std::ptr::null(),
4181                error: error_msg,
4182                request_id: 0,
4183            };
4184            return Box::into_raw(Box::new(response));
4185        }
4186    };
4187    let client_wrapper = match safe_wrapper(client) {
4188        Some(client) => client,
4189        None => {
4190            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
4191            let response = WatchResponseWrapper {
4192                success: false,
4193                watchid: std::ptr::null(),
4194                error: error_msg,
4195                request_id: options.request_id,
4196            };
4197            return Box::into_raw(Box::new(response));
4198        }
4199    };
4200    let client = client_wrapper.client.clone();
4201    // let events = &client_wrapper.events;
4202    let paths = c_char_to_str(options.paths);
4203    let paths = paths.split(",").map(|s| s.to_string()).collect();
4204    let request = WatchRequest {
4205        collectionname: c_char_to_str(options.collectionname),
4206        paths,
4207    };
4208    if client.is_none() {
4209        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
4210        let response = WatchResponseWrapper {
4211            success: false,
4212            watchid: std::ptr::null(),
4213            error: error_msg,
4214            request_id: options.request_id,
4215        };
4216        return Box::into_raw(Box::new(response));
4217    }
4218    let client = client.unwrap();
4219    let request_id = options.request_id;
4220    let result = tokio::task::block_in_place(|| {
4221        let handle = client.get_runtime_handle();
4222        handle.block_on(
4223        client
4224            .watch(
4225                request,
4226                Box::new(move |event: WatchEvent| {
4227                    // convert event to json
4228                    // let event = serde_json::to_string(&event).unwrap();
4229                    // let c_event = std::ffi::CString::new(event).unwrap();
4230                    debug!("watch: event: {:?}", event);
4231                    let watchid = CString::new(event.id.clone())
4232                        .unwrap()
4233                        .into_string()
4234                        .unwrap();
4235                    let mut e = WATCH_EVENTS.lock().unwrap();
4236                    let queue = e.get_mut(&watchid);
4237                    match queue {
4238                        Some(q) => {
4239                            q.push_back(event);
4240                        }
4241                        None => {
4242                            let mut q = std::collections::VecDeque::new();
4243                            q.push_back(event);
4244                            e.insert(watchid, q);
4245                        }
4246                    }
4247                }),
4248            )
4249        )
4250    });
4251
4252    let response = match result {
4253        Ok(data) => {
4254            let id = String::from(&data);
4255            let mut events = WATCH_EVENTS.lock().unwrap();
4256            let queue = events.get_mut(&id);
4257            if queue.is_none() {
4258                let q = std::collections::VecDeque::new();
4259                let k = String::from(&data);
4260                events.insert(k, q);
4261            }
4262            let watchid = CString::new(id).unwrap().into_raw();
4263            WatchResponseWrapper {
4264                success: true,
4265                watchid,
4266                error: std::ptr::null(),
4267                request_id,
4268            }
4269        }
4270        Err(e) => {
4271            let error_msg = CString::new(format!("Watch failed: {:?}", e))
4272                .unwrap()
4273                .into_raw();
4274            WatchResponseWrapper {
4275                success: false,
4276                watchid: std::ptr::null(),
4277                error: error_msg,
4278                request_id,
4279            }
4280        }
4281    };
4282
4283    Box::into_raw(Box::new(response))
4284}
4285#[no_mangle]
4286#[tracing::instrument(skip_all)]
4287pub extern "C" fn next_watch_event (
4288    watchid: *const c_char,
4289) -> *mut WatchEventWrapper {
4290    trace!("unwrap watchid");
4291    let watchid = c_char_to_str(watchid);
4292    trace!("watchid {:}", watchid);
4293    let watchid = watchid.to_string();
4294    trace!("unwrap events");
4295    let mut e = WATCH_EVENTS.lock().unwrap();
4296    trace!("get queue");
4297    let queue = e.get_mut(&watchid);
4298    match queue {
4299        Some(q) => {
4300            match q.pop_front() {
4301                Some(event) => {
4302                    debug!("got event");
4303                    let id = CString::new(event.id).unwrap().into_raw();
4304                    let operation = CString::new(event.operation).unwrap().into_raw();
4305                    let document = CString::new(event.document).unwrap().into_raw();
4306                    let event = Box::new(WatchEventWrapper {
4307                        id,
4308                        operation,
4309                        document,
4310                        request_id: 0
4311                    });
4312                    Box::into_raw(event)
4313                }
4314                None => {
4315                    trace!("No event");
4316                    Box::into_raw(Box::new(WatchEventWrapper::default())) 
4317                },
4318            }
4319        },
4320        None => {
4321            debug!("Queue for {:} not found", watchid);
4322            Box::into_raw(Box::new(WatchEventWrapper::default())) 
4323        },
4324    }
4325}
4326#[no_mangle]
4327#[tracing::instrument(skip_all)]
4328pub extern "C" fn free_watch_event(response: *mut WatchEventWrapper) {
4329    if response.is_null() {
4330        return;
4331    }
4332    unsafe {
4333        if !(*response).id.is_null() {
4334            let _ = CString::from_raw((*response).id as *mut c_char);
4335        }
4336        if !(*response).operation.is_null() {
4337            let _ = CString::from_raw((*response).operation as *mut c_char);
4338        }
4339        if !(*response).document.is_null() {
4340            let _ = CString::from_raw((*response).document as *mut c_char);
4341        }
4342        let _ = Box::from_raw(response);
4343    }
4344}
4345
4346type WatchEventCallback = extern "C" fn(*mut WatchEventWrapper);
4347type WatchCallback = extern "C" fn(wrapper: *mut WatchResponseWrapper);
4348#[no_mangle]
4349#[tracing::instrument(skip_all)]
4350pub extern "C" fn watch_async_async(
4351    client: *mut ClientWrapper,
4352    options: *mut WatchRequestWrapper,
4353    callback: WatchCallback,
4354    // event_callback: extern "C" fn(*mut WatchEventWrapper),
4355    event_callback: WatchEventCallback,
4356    // event_callback: extern "C" fn(*const c_char),
4357) {
4358    debug!("watch_async_async");
4359    let options = match safe_wrapper(options) {
4360        Some(options) => options,
4361        None => {
4362            let error_msg = CString::new("Invalid options").unwrap().into_raw();
4363            let response = WatchResponseWrapper {
4364                success: false,
4365                watchid: std::ptr::null(),
4366                error: error_msg,
4367                request_id: 0,
4368            };
4369            return callback(Box::into_raw(Box::new(response)));
4370        }
4371    };
4372    let client_wrapper = match safe_wrapper(client) {
4373        Some(client) => client,
4374        None => {
4375            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
4376            let response = WatchResponseWrapper {
4377                success: false,
4378                watchid: std::ptr::null(),
4379                error: error_msg,
4380                request_id: options.request_id,
4381            };
4382            return callback(Box::into_raw(Box::new(response)));
4383        }
4384    };
4385    let client = client_wrapper.client.clone();
4386    let paths = c_char_to_str(options.paths);
4387    let paths = paths.split(",").map(|s| s.to_string()).collect();
4388    let request = WatchRequest {
4389        collectionname: c_char_to_str(options.collectionname),
4390        paths,
4391    };
4392    if client.is_none() {
4393        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
4394        let response = WatchResponseWrapper {
4395            success: false,
4396            watchid: std::ptr::null(),
4397            error: error_msg,
4398            request_id: options.request_id,
4399        };
4400        return callback(Box::into_raw(Box::new(response)));
4401    }
4402    debug!("watch_async: runtime.spawn");
4403    let client = client.unwrap();
4404    let handle = client.get_runtime_handle();
4405    let request_id = options.request_id;
4406    handle.spawn(async move {
4407        debug!("watch_async: call client.watch");
4408        let result = client
4409            .watch(
4410                request,
4411                Box::new(move |_event: WatchEvent| {
4412                    debug!("watch_async: spawn new task, to call event_callback");
4413                    trace!("watch_async: call event_callback");
4414                    let id = CString::new(_event.id).unwrap().into_raw();
4415                    let operation = CString::new(_event.operation).unwrap().into_raw();
4416                    let document = CString::new(_event.document).unwrap().into_raw();
4417                    let event = Box::into_raw(Box::new(WatchEventWrapper {
4418                        id,
4419                        operation,
4420                        document,
4421                        request_id
4422                    }));
4423
4424                    event_callback(event);
4425                }),
4426            )
4427            .await;
4428
4429        let response = match result {
4430            Ok(data) => {
4431                let watchid = CString::new(data).unwrap().into_raw();
4432                WatchResponseWrapper {
4433                    success: true,
4434                    watchid,
4435                    error: std::ptr::null(),
4436                    request_id,
4437                }
4438            }
4439            Err(e) => {
4440                let error_msg = CString::new(format!("Watch failed: {:?}", e))
4441                    .unwrap()
4442                    .into_raw();
4443                WatchResponseWrapper {
4444                    success: false,
4445                    watchid: std::ptr::null(),
4446                    error: error_msg,
4447                    request_id,
4448                }
4449            }
4450        };
4451
4452        debug!("watch_async: call callback with response");
4453        callback(Box::into_raw(Box::new(response)));
4454    });
4455}
4456
4457#[no_mangle]
4458#[tracing::instrument(skip_all)]
4459pub extern "C" fn free_watch_response(response: *mut WatchResponseWrapper) {
4460    if response.is_null() {
4461        return;
4462    }
4463    unsafe {
4464        if !(*response).error.is_null() {
4465            let _ = CString::from_raw((*response).error as *mut c_char);
4466        }
4467        if !(*response).watchid.is_null() {
4468            let _ = CString::from_raw((*response).watchid as *mut c_char);
4469        }
4470        let _ = Box::from_raw(response);
4471    }
4472}
4473
4474#[repr(C)]
4475pub struct UnWatchResponseWrapper {
4476    success: bool,
4477    error: *const c_char,
4478    request_id: i32
4479}
4480#[no_mangle]
4481#[tracing::instrument(skip_all)]
4482pub extern "C" fn unwatch(
4483    client: *mut ClientWrapper,
4484    watchid: *const c_char
4485) -> *mut UnWatchResponseWrapper {
4486    let client_wrapper = match safe_wrapper(client) {
4487        Some(client) => client,
4488        None => {
4489            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
4490            let response = UnWatchResponseWrapper {
4491                success: false,
4492                error: error_msg,
4493                request_id: 0,
4494            };
4495            return Box::into_raw(Box::new(response));
4496        }
4497    };
4498    let client = client_wrapper.client.clone();
4499    let watchid = c_char_to_str(watchid);
4500    if watchid.is_empty() {
4501        let error_msg = CString::new("Watchid is required").unwrap().into_raw();
4502        let response = UnWatchResponseWrapper {
4503            success: false,
4504            error: error_msg,
4505            request_id: 0,
4506        };
4507        return Box::into_raw(Box::new(response));
4508    }
4509    if client.is_none() {
4510        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
4511        let response = UnWatchResponseWrapper {
4512            success: false,
4513            error: error_msg,
4514            request_id: 0
4515        };
4516        return Box::into_raw(Box::new(response));
4517    }
4518    let client = client.unwrap();
4519    trace!("watchid: {:?}", watchid);
4520    let result = tokio::task::block_in_place(|| {
4521        let handle = client.get_runtime_handle();
4522        handle.block_on( client.unwatch(&watchid))
4523    });
4524    trace!("completed, parsing result");
4525    match result {
4526        Ok(_) => {
4527            let response = UnWatchResponseWrapper {
4528                success: true,
4529                error: std::ptr::null(),
4530                request_id: 0
4531            };
4532            debug!("Unwatch success");
4533            Box::into_raw(Box::new(response))
4534        }
4535        Err(e) => {
4536            let error_msg = CString::new(format!("Unwatch failed: {:?}", e))
4537                .unwrap()
4538                .into_raw();
4539            debug!("Unwatch failed: {:?}", error_msg);
4540            let response = UnWatchResponseWrapper {
4541                success: false,
4542                error: error_msg,
4543                request_id: 0
4544            };
4545            Box::into_raw(Box::new(response))
4546        }
4547    }    
4548}
4549#[no_mangle]
4550#[tracing::instrument(skip_all)]
4551pub extern "C" fn unwatch_async(
4552    client: *mut ClientWrapper,
4553    watchid: *const c_char,
4554    request_id: i32,
4555    callback: extern "C" fn(*mut UnWatchResponseWrapper),
4556) {
4557    let client_wrapper = match safe_wrapper(client) {
4558        Some(client) => client,
4559        None => {
4560            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
4561            let response = UnWatchResponseWrapper {
4562                success: false,
4563                error: error_msg,
4564                request_id,
4565            };
4566            return callback(Box::into_raw(Box::new(response)));
4567        }
4568    };
4569    let client = client_wrapper.client.clone();
4570    let watchid = c_char_to_str(watchid);
4571    if client.is_none() {
4572        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
4573        let response = UnWatchResponseWrapper {
4574            success: false,
4575            error: error_msg,
4576            request_id,
4577        };
4578        return callback(Box::into_raw(Box::new(response)));
4579    }
4580    let client = client.unwrap();
4581    let handle = client.get_runtime_handle();
4582    handle.spawn(async move {
4583        let result = client.unwatch(&watchid).await;
4584        match result {
4585            Ok(_) => {
4586                let response = UnWatchResponseWrapper {
4587                    success: true,
4588                    error: std::ptr::null(),
4589                    request_id,
4590                };
4591                callback(Box::into_raw(Box::new(response)));
4592            }
4593            Err(e) => {
4594                let error_msg = CString::new(format!("Unwatch failed: {:?}", e))
4595                    .unwrap()
4596                    .into_raw();
4597                let response = UnWatchResponseWrapper {
4598                    success: false,
4599                    error: error_msg,
4600                    request_id,
4601                };
4602                callback(Box::into_raw(Box::new(response)));
4603            }
4604        }
4605    });
4606}
4607#[no_mangle]
4608#[tracing::instrument(skip_all)]
4609pub extern "C" fn free_unwatch_response(response: *mut UnWatchResponseWrapper) {
4610    if response.is_null() {
4611        return;
4612    }
4613    unsafe {
4614        if !(*response).error.is_null() {
4615            let _ = CString::from_raw((*response).error as *mut c_char);
4616        }
4617        let _ = Box::from_raw(response);
4618    }
4619}
4620
4621
4622#[repr(C)]
4623pub struct RegisterQueueRequestWrapper {
4624    queuename: *const c_char,
4625    request_id: i32
4626}
4627#[repr(C)]
4628pub struct RegisterQueueResponseWrapper {
4629    success: bool,
4630    queuename: *const c_char,
4631    error: *const c_char,
4632    request_id: i32
4633}
4634
4635#[no_mangle]
4636#[tracing::instrument(skip_all)]
4637pub extern "C" fn register_queue(
4638    client: *mut ClientWrapper,
4639    options: *mut RegisterQueueRequestWrapper,
4640) -> *mut RegisterQueueResponseWrapper {
4641    let options = match safe_wrapper(options) {
4642        Some(options) => options,
4643        None => {
4644            let error_msg = CString::new("Invalid options").unwrap().into_raw();
4645            let response = RegisterQueueResponseWrapper {
4646                success: false,
4647                queuename: std::ptr::null(),
4648                error: error_msg,
4649                request_id: 0,
4650            };
4651            return Box::into_raw(Box::new(response));
4652        }
4653    };
4654    let client_wrapper = match safe_wrapper(client) {
4655        Some(client) => client,
4656        None => {
4657            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
4658            let response = RegisterQueueResponseWrapper {
4659                success: false,
4660                queuename: std::ptr::null(),
4661                error: error_msg,
4662                request_id: options.request_id,
4663            };
4664            return Box::into_raw(Box::new(response));
4665        }
4666    };
4667    let client = client_wrapper.client.clone();
4668    // let events = &client_wrapper.events;
4669    let request = RegisterQueueRequest {
4670        queuename: c_char_to_str(options.queuename),
4671    };
4672    if client.is_none() {
4673        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
4674        let response = RegisterQueueResponseWrapper {
4675            success: false,
4676            queuename: std::ptr::null(),
4677            error: error_msg,
4678            request_id: options.request_id,
4679        };
4680        return Box::into_raw(Box::new(response));
4681    }
4682    let client = client.unwrap();
4683    let result = tokio::task::block_in_place(|| {
4684        let handle = client.get_runtime_handle();
4685            handle.block_on(
4686        client
4687            .register_queue(
4688                request,
4689                Box::new(move |_client, event: QueueEvent| {
4690                    trace!("queue: event: {:?}", event);
4691                    let queuename = CString::new(event.queuename.clone())
4692                        .unwrap()
4693                        .into_string()
4694                        .unwrap();
4695                    let mut e = QUEUE_EVENTS.lock().unwrap();
4696                    let queue = e.get_mut(&queuename);
4697                    match queue {
4698                        Some(q) => {
4699                            q.push_back(event);
4700                        }
4701                        None => {
4702                            let mut q = std::collections::VecDeque::new();
4703                            q.push_back(event);
4704                            e.insert(queuename, q);
4705                        }
4706                    }
4707                    None
4708                }),
4709            )
4710        )
4711    });
4712
4713    let response = match result {
4714        Ok(data) => {
4715            let id = String::from(&data);
4716            let mut events = QUEUE_EVENTS.lock().unwrap();
4717            let queue = events.get_mut(&id);
4718            if queue.is_none() {
4719                let q = std::collections::VecDeque::new();
4720                let k = String::from(&data);
4721                events.insert(k, q);
4722            }
4723            let queuename = CString::new(id).unwrap().into_raw();
4724            RegisterQueueResponseWrapper {
4725                success: true,
4726                queuename,
4727                error: std::ptr::null(),
4728                request_id: options.request_id,
4729            }
4730        }
4731        Err(e) => {
4732            let error_msg = CString::new(format!("queue failed: {:?}", e))
4733                .unwrap()
4734                .into_raw();
4735            RegisterQueueResponseWrapper {
4736                success: false,
4737                queuename: std::ptr::null(),
4738                error: error_msg,
4739                request_id: options.request_id,
4740            }
4741        }
4742    };
4743    Box::into_raw(Box::new(response))
4744}
4745
4746type QueueEventCallback = extern "C" fn(*mut QueueEventWrapper) -> *const c_char;
4747#[no_mangle]
4748#[tracing::instrument(skip_all)]
4749pub extern "C" fn register_queue_async(
4750    client: *mut ClientWrapper,
4751    options: *mut RegisterQueueRequestWrapper,
4752    event_callback: QueueEventCallback,
4753) -> *mut RegisterQueueResponseWrapper {
4754    debug!("register_queue_async");
4755    let options = match safe_wrapper(options) {
4756        Some(options) => options,
4757        None => {
4758            let error_msg = CString::new("Invalid options").unwrap().into_raw();
4759            let response = RegisterQueueResponseWrapper {
4760                success: false,
4761                queuename: std::ptr::null(),
4762                error: error_msg,
4763                request_id: 0,
4764            };
4765            return Box::into_raw(Box::new(response))
4766        }
4767    };
4768    let client_wrapper = match safe_wrapper(client) {
4769        Some(client) => client,
4770        None => {
4771            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
4772            let response = RegisterQueueResponseWrapper {
4773                success: false,
4774                queuename: std::ptr::null(),
4775                error: error_msg,
4776                request_id: options.request_id,
4777            };
4778            return Box::into_raw(Box::new(response))
4779        }
4780    };
4781    let client = client_wrapper.client.clone();
4782    let request = RegisterQueueRequest {
4783        queuename: c_char_to_str(options.queuename),
4784    };
4785    if client.is_none() {
4786        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
4787        let response = RegisterQueueResponseWrapper {
4788            success: false,
4789            queuename: std::ptr::null(),
4790            error: error_msg,
4791            request_id: options.request_id,
4792        };
4793        return Box::into_raw(Box::new(response))
4794    }
4795    let client = client.unwrap();
4796    debug!("register_queue_async: runtime.spawn");
4797    let request_id = options.request_id;
4798    let result = tokio::task::block_in_place(|| {
4799        let handle = client.get_runtime_handle();
4800        handle.block_on(
4801        client
4802            .register_queue(
4803                request,
4804                Box::new(move |_client, event: QueueEvent| {
4805                    debug!("register_queue_async: spawn new task, to call event_callback");
4806                    trace!("register_queue_async: call event_callback");
4807                    let queuename = CString::new(event.queuename).unwrap().into_raw();
4808                    let correlation_id = CString::new(event.correlation_id).unwrap().into_raw();
4809                    let replyto = CString::new(event.replyto).unwrap().into_raw();
4810                    let routingkey = CString::new(event.routingkey).unwrap().into_raw();
4811                    let exchangename = CString::new(event.exchangename).unwrap().into_raw();
4812                    let data = CString::new(event.data).unwrap().into_raw();
4813                    let event = Box::new(QueueEventWrapper {
4814                        queuename,
4815                        correlation_id,
4816                        replyto,
4817                        routingkey,
4818                        exchangename,
4819                        data,
4820                        request_id
4821                    });
4822                    let result = event_callback(Box::into_raw(event));
4823                    let result = c_char_to_str(result);
4824                    if result.is_empty() {
4825                        return None
4826                    }
4827                    let result = result.to_string();
4828                    Some(result)
4829                }),
4830            )
4831        )
4832    });
4833
4834    debug!("register_queue_async: parse result");
4835    let response = match result {
4836        Ok(data) => {
4837            let queuename = CString::new(data).unwrap().into_raw();
4838            RegisterQueueResponseWrapper {
4839                success: true,
4840                queuename,
4841                error: std::ptr::null(),
4842                request_id: options.request_id,
4843            }
4844        }
4845        Err(e) => {
4846            let error_msg = CString::new(format!("RegisterQueue failed: {:?}", e))
4847                .unwrap()
4848                .into_raw();
4849            RegisterQueueResponseWrapper {
4850                success: false,
4851                queuename: std::ptr::null(),
4852                error: error_msg,
4853                request_id: options.request_id,
4854            }
4855        }
4856    };
4857
4858    Box::into_raw(Box::new(response))
4859}
4860
4861
4862
4863#[no_mangle]
4864#[tracing::instrument(skip_all)]
4865pub extern "C" fn free_register_queue_response(response: *mut RegisterQueueResponseWrapper) {
4866    if response.is_null() {
4867        return;
4868    }
4869    unsafe {
4870        if !(*response).error.is_null() {
4871            let _ = CString::from_raw((*response).error as *mut c_char);
4872        }
4873        if !(*response).queuename.is_null() {
4874            let _ = CString::from_raw((*response).queuename as *mut c_char);
4875        }
4876        let _ = Box::from_raw(response);
4877    }
4878}
4879
4880
4881#[repr(C)]
4882pub struct RegisterExchangeRequestWrapper {
4883    exchangename: *const c_char,
4884    algorithm: *const c_char,
4885    routingkey: *const c_char,
4886    addqueue: bool,
4887    request_id: i32
4888}
4889#[repr(C)]
4890pub struct RegisterExchangeResponseWrapper {
4891    success: bool,
4892    queuename: *const c_char,
4893    error: *const c_char,
4894    request_id: i32
4895}
4896#[no_mangle]
4897#[tracing::instrument(skip_all)]
4898pub extern "C" fn register_exchange (
4899    client: *mut ClientWrapper,
4900    options: *mut RegisterExchangeRequestWrapper,
4901) -> *mut RegisterExchangeResponseWrapper {
4902    let options = match safe_wrapper(options) {
4903        Some(options) => options,
4904        None => {
4905            let error_msg = CString::new("Invalid options").unwrap().into_raw();
4906            let response = RegisterExchangeResponseWrapper {
4907                success: false,
4908                queuename: std::ptr::null(),
4909                error: error_msg,
4910                request_id: 0,
4911            };
4912            return Box::into_raw(Box::new(response));
4913        }
4914    };
4915    let client_wrapper = match safe_wrapper(client) {
4916        Some(client) => client,
4917        None => {
4918            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
4919            let response = RegisterExchangeResponseWrapper {
4920                success: false,
4921                queuename: std::ptr::null(),
4922                error: error_msg,
4923                request_id: options.request_id,
4924            };
4925            return Box::into_raw(Box::new(response));
4926        }
4927    };
4928    let client = client_wrapper.client.clone();
4929    let request = RegisterExchangeRequest {
4930        exchangename: c_char_to_str(options.exchangename),
4931        algorithm: c_char_to_str(options.algorithm),
4932        routingkey: c_char_to_str(options.routingkey),
4933        addqueue: options.addqueue,
4934    };
4935    if client.is_none() {
4936        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
4937        let response = RegisterExchangeResponseWrapper {
4938            success: false,
4939            queuename: std::ptr::null(),
4940            error: error_msg,
4941            request_id: options.request_id,
4942        };
4943        return Box::into_raw(Box::new(response));
4944    }
4945    let client = client.unwrap();
4946    let result = tokio::task::block_in_place(|| {
4947        let handle = client.get_runtime_handle();
4948            handle.block_on(
4949        client
4950            .register_exchange(request,
4951                Box::new(move |_client, event: QueueEvent| {
4952                    trace!("exchange: event: {:?}", event);
4953                    let queuename = CString::new(event.queuename.clone())
4954                        .unwrap()
4955                        .into_string()
4956                        .unwrap();
4957                    let mut e = QUEUE_EVENTS.lock().unwrap();
4958                    let queue = e.get_mut(&queuename);
4959                    match queue {
4960                        Some(q) => {
4961                            q.push_back(event);
4962                        }
4963                        None => {
4964                            let mut q = std::collections::VecDeque::new();
4965                            q.push_back(event);
4966                            e.insert(queuename, q);
4967                        }
4968                    }
4969                    None
4970                }),
4971            
4972            )
4973        )
4974    });
4975
4976    let response = match result {
4977        Ok(data) => {
4978            let queuename = CString::new(data).unwrap().into_raw();
4979            RegisterExchangeResponseWrapper {
4980                success: true,
4981                queuename,
4982                error: std::ptr::null(),
4983                request_id: options.request_id,
4984            }
4985        }
4986        Err(e) => {
4987            let error_msg = CString::new(format!("RegisterExchange failed: {:?}", e))
4988                .unwrap()
4989                .into_raw();
4990            RegisterExchangeResponseWrapper {
4991                success: false,
4992                queuename: std::ptr::null(),
4993                error: error_msg,
4994                request_id: options.request_id,
4995            }
4996        }
4997    };
4998
4999    Box::into_raw(Box::new(response))
5000}
5001type ExchangeEventCallback = extern "C" fn(*mut QueueEventWrapper);
5002#[no_mangle]
5003#[tracing::instrument(skip_all)]
5004pub extern "C" fn register_exchange_async(
5005    client: *mut ClientWrapper,
5006    options: *mut RegisterExchangeRequestWrapper,
5007    event_callback: ExchangeEventCallback,
5008) -> *mut RegisterExchangeResponseWrapper {
5009    debug!("register_exchange_async");
5010    let options = match safe_wrapper(options) {
5011        Some(options) => options,
5012        None => {
5013            let error_msg = CString::new("Invalid options").unwrap().into_raw();
5014            let response = RegisterExchangeResponseWrapper {
5015                success: false,
5016                queuename: std::ptr::null(),
5017                error: error_msg,
5018                request_id: 0,
5019            };
5020            return Box::into_raw(Box::new(response))
5021        }
5022    };
5023    let client_wrapper = match safe_wrapper(client) {
5024        Some(client) => client,
5025        None => {
5026            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
5027            let response = RegisterExchangeResponseWrapper {
5028                success: false,
5029                queuename: std::ptr::null(),
5030                error: error_msg,
5031                request_id: options.request_id,
5032            };
5033            return Box::into_raw(Box::new(response))
5034        }
5035    };
5036    let client = client_wrapper.client.clone();
5037    let request = RegisterExchangeRequest {
5038        exchangename: c_char_to_str(options.exchangename),
5039        algorithm: c_char_to_str(options.algorithm),
5040        routingkey: c_char_to_str(options.routingkey),
5041        addqueue: options.addqueue,
5042    };
5043    if client.is_none() {
5044        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
5045        let response = RegisterExchangeResponseWrapper {
5046            success: false,
5047            queuename: std::ptr::null(),
5048            error: error_msg,
5049            request_id: options.request_id,
5050        };
5051        return Box::into_raw(Box::new(response))
5052    }
5053    let client = client.unwrap();
5054    debug!("register_exchange_async: runtime.spawn");
5055    let request_id = options.request_id;
5056    let result = tokio::task::block_in_place(|| {
5057        let handle = client.get_runtime_handle();
5058            handle.block_on(
5059        client
5060            .register_exchange(request,
5061                Box::new(move |_client, event: QueueEvent| {
5062                    debug!("register_exchange_async: spawn new task, to call event_callback");
5063                    trace!("register_exchange_async: call event_callback");
5064                    let queuename = CString::new(event.queuename).unwrap().into_raw();
5065                    let correlation_id = CString::new(event.correlation_id).unwrap().into_raw();
5066                    let replyto = CString::new(event.replyto).unwrap().into_raw();
5067                    let routingkey = CString::new(event.routingkey).unwrap().into_raw();
5068                    let exchangename = CString::new(event.exchangename).unwrap().into_raw();
5069                    let data = CString::new(event.data).unwrap().into_raw();
5070                    let event = Box::new(QueueEventWrapper {
5071                        queuename,
5072                        correlation_id,
5073                        replyto,
5074                        routingkey,
5075                        exchangename,
5076                        data,
5077                        request_id
5078                    });
5079                    event_callback(Box::into_raw(event));
5080                    None
5081                }),
5082
5083            )
5084        )
5085    });
5086
5087    debug!("register_exchange_async: parse result");
5088    let response = match result {
5089        Ok(data) => {
5090            let queuename = CString::new(data).unwrap().into_raw();
5091            RegisterExchangeResponseWrapper {
5092                success: true,
5093                queuename,
5094                error: std::ptr::null(),
5095                request_id: options.request_id,
5096            }
5097        }
5098        Err(e) => {
5099            let error_msg = CString::new(format!("RegisterExchange failed: {:?}", e))
5100                .unwrap()
5101                .into_raw();
5102            RegisterExchangeResponseWrapper {
5103                success: false,
5104                queuename: std::ptr::null(),
5105                error: error_msg,
5106                request_id: options.request_id,
5107            }
5108        }
5109    };
5110    Box::into_raw(Box::new(response))
5111}
5112
5113#[no_mangle]
5114#[tracing::instrument(skip_all)]
5115pub extern "C" fn free_register_exchange_response(response: *mut RegisterExchangeResponseWrapper) {
5116    if response.is_null() {
5117        return;
5118    }
5119    unsafe {
5120        if !(*response).error.is_null() {
5121            let _ = CString::from_raw((*response).error as *mut c_char);
5122        }
5123        if !(*response).queuename.is_null() {
5124            let _ = CString::from_raw((*response).queuename as *mut c_char);
5125        }
5126        let _ = Box::from_raw(response);
5127    }
5128}
5129
5130#[repr(C)]
5131#[derive(Debug, Clone)]
5132pub struct QueueEventWrapper {
5133    queuename: *const c_char,
5134    correlation_id: *const c_char,
5135    replyto: *const c_char,
5136    routingkey: *const c_char,
5137    exchangename: *const c_char,
5138    data: *const c_char,
5139    request_id: i32,
5140}
5141impl Default for QueueEventWrapper {
5142    fn default() -> Self { 
5143        QueueEventWrapper {
5144            queuename: std::ptr::null(),
5145            correlation_id: std::ptr::null(),
5146            replyto: std::ptr::null(),
5147            routingkey: std::ptr::null(),
5148            exchangename: std::ptr::null(),
5149            data: std::ptr::null(),
5150            request_id: 0,
5151        }
5152     }
5153}
5154
5155#[no_mangle]
5156#[tracing::instrument(skip_all)]
5157pub extern "C" fn next_queue_event (
5158    queuename: *const c_char,
5159) -> *mut QueueEventWrapper {
5160    trace!("unwrap watchid");
5161    let queuename = c_char_to_str(queuename);
5162    trace!("queuename {:}", queuename);
5163    let queuename = queuename.to_string();
5164    trace!("unwrap events");
5165    let mut e = QUEUE_EVENTS.lock().unwrap();
5166    trace!("get queue");
5167    let queue = e.get_mut(&queuename);
5168    match queue {
5169        Some(q) => {
5170            match q.pop_front() {
5171                Some(event) => {
5172                    debug!("got event");
5173                    let queuename = CString::new(event.queuename).unwrap().into_raw();
5174                    let correlation_id = CString::new(event.correlation_id).unwrap().into_raw();
5175                    let replyto = CString::new(event.replyto).unwrap().into_raw();
5176                    let routingkey = CString::new(event.routingkey).unwrap().into_raw();
5177                    let exchangename = CString::new(event.exchangename).unwrap().into_raw();
5178                    let data = CString::new(event.data).unwrap().into_raw();
5179                    let event = Box::new(QueueEventWrapper {
5180                        queuename,
5181                        correlation_id,
5182                        replyto,
5183                        routingkey,
5184                        exchangename,
5185                        data,
5186                        request_id: 0
5187                    });
5188                    Box::into_raw(event)
5189                }
5190                None => {
5191                    trace!("No event");
5192                    Box::into_raw(Box::new(QueueEventWrapper::default())) 
5193                },
5194            }
5195        },
5196        None => {
5197            debug!("Queue for {:} not found", queuename);
5198            Box::into_raw(Box::new(QueueEventWrapper::default())) 
5199        },
5200    }
5201}
5202#[no_mangle]
5203#[tracing::instrument(skip_all)]
5204pub extern "C" fn free_queue_event(response: *mut QueueEventWrapper) {
5205    if response.is_null() {
5206        return;
5207    }
5208    unsafe {
5209        if !(*response).queuename.is_null() {
5210            let _ = CString::from_raw((*response).queuename as *mut c_char);
5211        }
5212        if !(*response).correlation_id.is_null() {
5213            let _ = CString::from_raw((*response).correlation_id as *mut c_char);
5214        }
5215        if !(*response).replyto.is_null() {
5216            let _ = CString::from_raw((*response).replyto as *mut c_char);
5217        }
5218        if !(*response).routingkey.is_null() {
5219            let _ = CString::from_raw((*response).routingkey as *mut c_char);
5220        }
5221        if !(*response).exchangename.is_null() {
5222            let _ = CString::from_raw((*response).exchangename as *mut c_char);
5223        }
5224        if !(*response).data.is_null() {
5225            let _ = CString::from_raw((*response).data as *mut c_char);
5226        }
5227        let _ = Box::from_raw(response);
5228    }
5229}
5230
5231#[repr(C)]
5232pub struct QueueMessageRequestWrapper {
5233    queuename: *const c_char,
5234    correlation_id: *const c_char,
5235    replyto: *const c_char,
5236    routingkey: *const c_char,
5237    exchangename: *const c_char,
5238    data: *const c_char,
5239    striptoken: bool,
5240    expiration: i32,
5241    request_id: i32,
5242}
5243#[repr(C)]
5244pub struct QueueMessageResponseWrapper {
5245    success: bool,
5246    error: *const c_char,
5247}
5248#[no_mangle]
5249#[tracing::instrument(skip_all)]
5250pub extern "C" fn queue_message(
5251    client: *mut ClientWrapper,
5252    options: *mut QueueMessageRequestWrapper,
5253) -> *mut QueueMessageResponseWrapper {
5254    let options = match safe_wrapper(options) {
5255        Some(options) => options,
5256        None => {
5257            let error_msg = CString::new("Invalid options").unwrap().into_raw();
5258            let response = QueueMessageResponseWrapper {
5259                success: false,
5260                error: error_msg,
5261            };
5262            return Box::into_raw(Box::new(response));
5263        }
5264    };
5265    let client_wrapper = match safe_wrapper(client) {
5266        Some(client) => client,
5267        None => {
5268            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
5269            let response = QueueMessageResponseWrapper {
5270                success: false,
5271                error: error_msg,
5272            };
5273            return Box::into_raw(Box::new(response));
5274        }
5275    };
5276    let client = client_wrapper.client.clone();
5277    let request = QueueMessageRequest {
5278        queuename: c_char_to_str(options.queuename),
5279        correlation_id: c_char_to_str(options.correlation_id),
5280        replyto: c_char_to_str(options.replyto),
5281        routingkey: c_char_to_str(options.routingkey),
5282        exchangename: c_char_to_str(options.exchangename),
5283        data: c_char_to_str(options.data),
5284        striptoken: options.striptoken,
5285        expiration: options.expiration,
5286    };
5287    if client.is_none() {
5288        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
5289        let response = QueueMessageResponseWrapper {
5290            success: false,
5291            error: error_msg,
5292        };
5293        return Box::into_raw(Box::new(response));
5294    }
5295    let client = client.unwrap();
5296    let result = tokio::task::block_in_place(|| {
5297        let handle = client.get_runtime_handle();
5298            handle.block_on(
5299        client
5300            .queue_message(request)
5301            )
5302    });
5303    match result {
5304        Ok(_) => {
5305            let response = QueueMessageResponseWrapper {
5306                success: true,
5307                error: std::ptr::null(),
5308            };
5309            Box::into_raw(Box::new(response))
5310        }
5311        Err(e) => {
5312            let error_msg = CString::new(format!("Queue message failed: {:?}", e))
5313                .unwrap()
5314                .into_raw();
5315            let response = QueueMessageResponseWrapper {
5316                success: false,
5317                error: error_msg,
5318            };
5319            Box::into_raw(Box::new(response))
5320        }
5321    }
5322}
5323#[no_mangle]
5324#[tracing::instrument(skip_all)]
5325pub extern "C" fn free_queue_message_response(response: *mut QueueMessageResponseWrapper) {
5326    if response.is_null() {
5327        return;
5328    }
5329    unsafe {
5330        if !(*response).error.is_null() {
5331            let _ = CString::from_raw((*response).error as *mut c_char);
5332        }
5333        let _ = Box::from_raw(response);
5334    }
5335}
5336
5337#[repr(C)]
5338pub struct UnRegisterQueueResponseWrapper {
5339    success: bool,
5340    error: *const c_char,
5341}
5342#[no_mangle]
5343#[tracing::instrument(skip_all)]
5344pub extern "C" fn unregister_queue(
5345    client: *mut ClientWrapper,
5346    queuename: *const c_char,
5347) -> *mut UnRegisterQueueResponseWrapper {
5348    let client_wrapper = match safe_wrapper(client) {
5349        Some(client) => client,
5350        None => {
5351            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
5352            let response = UnRegisterQueueResponseWrapper {
5353                success: false,
5354                error: error_msg,
5355            };
5356            return Box::into_raw(Box::new(response));
5357        }
5358    };
5359    let client = client_wrapper.client.clone();
5360    let queuename = c_char_to_str(queuename);
5361    if client.is_none() {
5362        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
5363        let response = UnRegisterQueueResponseWrapper {
5364            success: false,
5365            error: error_msg,
5366        };
5367        return Box::into_raw(Box::new(response));
5368    }
5369    let client = client.unwrap();
5370    let result = tokio::task::block_in_place(|| {
5371        let handle = client.get_runtime_handle();
5372            handle.block_on( client.unregister_queue(&queuename))
5373    });
5374    match result {
5375        Ok(_) => {
5376            let response = UnRegisterQueueResponseWrapper {
5377                success: true,
5378                error: std::ptr::null(),
5379            };
5380            Box::into_raw(Box::new(response))
5381        }
5382        Err(e) => {
5383            let error_msg = CString::new(format!("Unregister queue failed: {:?}", e))
5384                .unwrap()
5385                .into_raw();
5386            let response = UnRegisterQueueResponseWrapper {
5387                success: false,
5388                error: error_msg,
5389            };
5390            Box::into_raw(Box::new(response))
5391        }
5392    }
5393}
5394#[no_mangle]
5395#[tracing::instrument(skip_all)]
5396pub extern "C" fn free_unregister_queue_response(response: *mut UnRegisterQueueResponseWrapper) {
5397    if response.is_null() {
5398        return;
5399    }
5400    unsafe {
5401        if !(*response).error.is_null() {
5402            let _ = CString::from_raw((*response).error as *mut c_char);
5403        }
5404        let _ = Box::from_raw(response);
5405    }
5406}
5407
5408
5409
5410#[repr(C)]
5411#[derive(Debug, Clone)]
5412pub struct WorkitemFileWrapper {
5413    filename: *const c_char,
5414    id: *const c_char,
5415    compressed: bool,
5416    // file: vec::Vec<u8>,
5417}
5418impl WorkitemFileWrapper {
5419    pub fn new(filename: &str, id: &str, compressed: bool) -> Self {
5420        trace!("filename: {:?}", filename);
5421        let filename = CString::new(filename).unwrap().into_raw();
5422        trace!("filename: {:?}", filename);
5423        trace!("id: {:?}", id);
5424        let id = CString::new(id).unwrap().into_raw();
5425        trace!("id: {:?}", id);
5426        // let file: Vec<u8> = Vec::new();
5427        WorkitemFileWrapper {
5428            filename,
5429            id,
5430            // file,
5431            compressed,
5432        }
5433        // let c_filename = CString::new(filename).unwrap();
5434        // let c_id = CString::new(id).unwrap();
5435        
5436        // WorkitemFileWrapper {
5437        //     filename: c_filename.as_ptr(),
5438        //     id: c_id.as_ptr(),
5439        //     compressed,
5440        // }
5441    }
5442}
5443
5444#[repr(C)]
5445#[derive(Debug, Clone)]
5446pub struct WorkitemWrapper {
5447    id: *const c_char,
5448    name: *const c_char,
5449    payload: *const c_char,
5450    priority: i32,
5451    nextrun: u64,
5452    lastrun: u64,
5453    files: *const *const WorkitemFileWrapper,
5454    files_len: i32,
5455    state: *const c_char,
5456    wiq: *const c_char,
5457    wiqid: *const c_char,
5458    retries: i32,
5459    username: *const c_char,
5460    success_wiqid: *const c_char,
5461    failed_wiqid: *const c_char,
5462    success_wiq: *const c_char,
5463    failed_wiq: *const c_char,
5464    errormessage: *const c_char,
5465    errorsource: *const c_char,
5466    errortype: *const c_char,
5467}
5468impl WorkitemWrapper {
5469    #[tracing::instrument(skip_all)]
5470    pub fn as_workitem(&self) -> Workitem {
5471        let files_len = self.files_len;
5472        let mut files: Vec<WorkitemFile> = vec![];
5473        if files_len > 0 {
5474            let _files = unsafe { &*self.files };
5475            let _files = unsafe { std::slice::from_raw_parts(_files, files_len.try_into().unwrap()) };
5476            files = _files.iter().map(|f| {
5477                let file = unsafe { &**f };
5478                WorkitemFile {
5479                    filename: c_char_to_str(file.filename),
5480                    id: c_char_to_str(file.id),
5481                    ..Default::default()
5482                    // compressed: file.compressed,
5483                    // file: file.file.clone(),
5484                }
5485            }).collect();
5486        }
5487        trace!("nextrun: {:?}", self.nextrun);
5488        // convert self.nextrun to std::time::SystemTime
5489        let mut nextrun = Some(Timestamp::from(
5490            std::time::SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(self.nextrun)
5491        ));
5492        trace!("nextrun: {:?}", nextrun);
5493        if self.nextrun == 0 {
5494            nextrun = None;
5495        }
5496        trace!("lastrun: {:?}", self.lastrun);
5497        // convert self.lastrun to std::time::SystemTime
5498        let mut lastrun = Some(Timestamp::from(
5499            std::time::SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(self.lastrun)
5500        ));
5501        trace!("lastrun: {:?}", lastrun);
5502        if self.lastrun == 0 {
5503            lastrun = None;
5504        }    
5505        Workitem {
5506            id: c_char_to_str(self.id),
5507            name: c_char_to_str(self.name),
5508            payload: c_char_to_str(self.payload),
5509            priority: self.priority,
5510            nextrun,
5511            lastrun,
5512            files,
5513            state: c_char_to_str(self.state),
5514            wiq: c_char_to_str(self.wiq),
5515            wiqid: c_char_to_str(self.wiqid),
5516            retries: self.retries,
5517            username: c_char_to_str(self.username),
5518            success_wiqid: c_char_to_str(self.success_wiqid),
5519            failed_wiqid: c_char_to_str(self.failed_wiqid),
5520            success_wiq: c_char_to_str(self.success_wiq),
5521            failed_wiq: c_char_to_str(self.failed_wiq),
5522            errormessage: c_char_to_str(self.errormessage),
5523            errorsource: c_char_to_str(self.errorsource),
5524            errortype: c_char_to_str(self.errortype),
5525        }
5526    }
5527}
5528#[tracing::instrument(skip_all)]
5529pub fn wrap_workitem(workitem: Workitem ) -> WorkitemWrapper {
5530    trace!("parse workitem: {:?}", workitem);
5531    let id = CString::new(workitem.id).unwrap().into_raw();
5532    let name = CString::new(workitem.name).unwrap().into_raw();
5533    let payload = CString::new(workitem.payload).unwrap().into_raw();
5534    let state = CString::new(workitem.state).unwrap().into_raw();
5535    let wiq = CString::new(workitem.wiq).unwrap().into_raw();
5536    let wiqid = CString::new(workitem.wiqid).unwrap().into_raw();
5537    let username = CString::new(workitem.username).unwrap().into_raw();
5538    let success_wiqid = CString::new(workitem.success_wiqid).unwrap().into_raw();
5539    let failed_wiqid = CString::new(workitem.failed_wiqid).unwrap().into_raw();
5540    let success_wiq = CString::new(workitem.success_wiq).unwrap().into_raw();
5541    let failed_wiq = CString::new(workitem.failed_wiq).unwrap().into_raw();
5542    let errormessage = CString::new(workitem.errormessage).unwrap().into_raw();
5543    let errorsource = CString::new(workitem.errorsource).unwrap().into_raw();
5544    let errortype = CString::new(workitem.errortype).unwrap().into_raw();
5545    let mut files: Vec<*const WorkitemFileWrapper> = vec![];
5546    for f in &workitem.files {
5547        // trace!("parse workitem file: {:?}", f);
5548        // let filename = CString::new(f.filename.clone()).unwrap().into_raw();
5549        // let id = CString::new(f.id.clone()).unwrap().into_raw();
5550        // // let file: Vec<u8> = Vec::new();
5551        // let compressed = f.compressed;
5552        // let file = Box::into_raw(Box::new(WorkitemFileWrapper {
5553        //     filename,
5554        //     id,
5555        //     // file,
5556        //     compressed,
5557        // }));
5558        let file = Box::into_raw(Box::new(WorkitemFileWrapper::new(&f.filename, &f.id, f.compressed)));
5559        files.push(file);
5560    }
5561    trace!("files: {:?} at {:?}", files.len(), files);
5562    trace!("read nextrun");
5563    let nextrun = workitem.nextrun.map(|t| t.seconds as u64).unwrap_or(0);
5564    trace!("nextrun: {:?}", nextrun);
5565    let lastrun = workitem.lastrun.map(|t| t.seconds as u64).unwrap_or(0);
5566    trace!("lastrun: {:?}", lastrun);
5567    let _files = files.as_ptr();
5568    trace!("files: {:?}", files);
5569    let files_len = workitem.files.len() as i32;
5570    trace!("files_len: {:?}", files_len);
5571    let workitem = WorkitemWrapper {
5572        id,
5573        name,
5574        payload,
5575        priority: workitem.priority,
5576        nextrun,
5577        lastrun,
5578        files: _files,
5579        files_len,
5580        state,
5581        wiq,
5582        wiqid,
5583        retries: workitem.retries,
5584        username,
5585        success_wiqid,
5586        failed_wiqid,
5587        success_wiq,
5588        failed_wiq,
5589        errormessage,
5590        errorsource,
5591        errortype,
5592    };
5593    trace!("forget files");
5594    std::mem::forget(files);
5595    trace!("return workitem");
5596    workitem
5597}
5598#[repr(C)]
5599#[derive(Debug, Clone)]
5600pub struct PushWorkitemRequestWrapper {
5601    wiq: *const c_char,
5602    wiqid: *const c_char,
5603    name: *const c_char,
5604    payload: *const c_char,
5605    nextrun: u64,
5606    success_wiqid: *const c_char,
5607    failed_wiqid: *const c_char,
5608    success_wiq: *const c_char,
5609    failed_wiq: *const c_char,
5610    priority: i32,
5611    files: *const *const WorkitemFileWrapper,
5612    files_len: i32,
5613    request_id: i32
5614}
5615#[repr(C)]
5616#[derive(Debug, Clone)]
5617pub struct PushWorkitemResponseWrapper {
5618    success: bool,
5619    error: *const c_char,
5620    workitem: *const WorkitemWrapper,
5621    request_id: i32
5622}
5623#[no_mangle]
5624#[tracing::instrument(skip_all)]
5625pub extern "C" fn push_workitem(
5626    client: *mut ClientWrapper,
5627    options: *mut PushWorkitemRequestWrapper,
5628) -> *mut PushWorkitemResponseWrapper {
5629    let options = match safe_wrapper(options) {
5630        Some(options) => options,
5631        None => {
5632            let error_msg = CString::new("Invalid options").unwrap().into_raw();
5633            let response = PushWorkitemResponseWrapper {
5634                success: false,
5635                error: error_msg,
5636                workitem: std::ptr::null(),
5637                request_id: 0
5638            };
5639            return Box::into_raw(Box::new(response));
5640        }
5641    };
5642    let client_wrapper = match safe_wrapper(client) {
5643        Some(client) => client,
5644        None => {
5645            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
5646            let response = PushWorkitemResponseWrapper {
5647                success: false,
5648                error: error_msg,
5649                workitem: std::ptr::null(),
5650                request_id: options.request_id
5651            };
5652            return Box::into_raw(Box::new(response));
5653        }
5654    };
5655    let client = client_wrapper.client.clone();
5656    let files_len = options.files_len;
5657    debug!("files_len: {:?}", files_len);
5658    let mut files: Vec<WorkitemFile> = vec![];
5659    if files_len > 0 {
5660        debug!("get files of options");
5661        let _files = unsafe { &*options.files };
5662        debug!("slice files");
5663        let _files = unsafe { std::slice::from_raw_parts(_files, files_len.try_into().unwrap()) };
5664        debug!("loop files");
5665        files = _files.iter().map(|f| {
5666            debug!("process a file");
5667            let file = unsafe { &**f };
5668            debug!("create WorkitemFile instance");
5669            let filename = c_char_to_str(file.filename);
5670            trace!("filename: {:?}", filename);
5671            let id = c_char_to_str(file.id);
5672            trace!("id: {:?}", id);
5673            trace!("compressed: {:?}", file.compressed);
5674            WorkitemFile {
5675                filename,
5676                id,
5677                compressed: file.compressed,
5678                ..Default::default()
5679                // file: file.file.clone(),
5680            }
5681        }).collect();
5682    }
5683    trace!("nextrun: {:?}", options.nextrun);
5684    // convert options.nextrun to std::time::SystemTime
5685    let mut nextrun = Some(Timestamp::from(
5686        std::time::SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(options.nextrun as u64)
5687    ));
5688    trace!("nextrun: {:?}", nextrun);
5689    if options.nextrun == 0 {
5690        nextrun = None;
5691    }
5692    let request = PushWorkitemRequest {
5693        wiq: c_char_to_str(options.wiq),
5694        wiqid: c_char_to_str(options.wiqid),
5695        name: c_char_to_str(options.name),
5696        payload: c_char_to_str(options.payload),
5697        nextrun,
5698        success_wiqid: c_char_to_str(options.success_wiqid),
5699        failed_wiqid: c_char_to_str(options.failed_wiqid),
5700        success_wiq: c_char_to_str(options.success_wiq),
5701        failed_wiq: c_char_to_str(options.failed_wiq),
5702        priority: options.priority,
5703        files,
5704    };
5705    if client.is_none() {
5706        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
5707        let response = PushWorkitemResponseWrapper {
5708            success: false,
5709            error: error_msg,
5710            workitem: std::ptr::null(),
5711            request_id: options.request_id
5712        };
5713        return Box::into_raw(Box::new(response));
5714    }
5715    let client = client.unwrap();
5716    let result = tokio::task::block_in_place(|| {
5717        let handle = client.get_runtime_handle();
5718            handle.block_on(client
5719            .push_workitem(request)
5720            )
5721    });
5722
5723    match result {
5724        Ok(resp) => {
5725            Box::into_raw(Box::new(match resp.workitem {
5726                Some(workitem) => {
5727                    let workitem = wrap_workitem(workitem);
5728                    PushWorkitemResponseWrapper {
5729                        success: true,
5730                        error: std::ptr::null(),
5731                        workitem: Box::into_raw(Box::new(workitem)),
5732                        request_id: options.request_id
5733                    }
5734                }
5735                None => {
5736                    let error_msg = CString::new("Push workitem failed: workitem not found").unwrap().into_raw();
5737                    PushWorkitemResponseWrapper {
5738                        success: false,
5739                        error: error_msg,
5740                        workitem: std::ptr::null(),
5741                        request_id: options.request_id
5742                    }
5743                }
5744            }))
5745        }
5746        Err(e) => {
5747            let error_msg = CString::new(format!("Push workitem failed: {:?}", e))
5748                .unwrap()
5749                .into_raw();
5750            Box::into_raw(Box::new(PushWorkitemResponseWrapper {
5751                success: false,
5752                error: error_msg,
5753                workitem: std::ptr::null(),
5754                request_id: options.request_id
5755            }))
5756        }
5757    }
5758}
5759#[no_mangle]
5760#[tracing::instrument(skip_all)]
5761pub extern "C" fn push_workitem_async( 
5762    client: *mut ClientWrapper,
5763    options: *mut PushWorkitemRequestWrapper,
5764    callback: extern "C" fn(*mut PushWorkitemResponseWrapper),
5765) {
5766    let options = match safe_wrapper(options) {
5767        Some(options) => options,
5768        None => {
5769            let error_msg = CString::new("Invalid options").unwrap().into_raw();
5770            let response = PushWorkitemResponseWrapper {
5771                success: false,
5772                error: error_msg,
5773                workitem: std::ptr::null(),
5774                request_id: 0
5775            };
5776            return callback(Box::into_raw(Box::new(response)));
5777        }
5778    };
5779    let client_wrapper = match safe_wrapper(client) {
5780        Some(client) => client,
5781        None => {
5782            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
5783            let response = PushWorkitemResponseWrapper {
5784                success: false,
5785                error: error_msg,
5786                workitem: std::ptr::null(),
5787                request_id: options.request_id
5788            };
5789            return callback(Box::into_raw(Box::new(response)));
5790        }
5791    };
5792    let client = client_wrapper.client.clone();
5793    let files_len = options.files_len;
5794    debug!("files_len: {:?}", files_len);
5795    let mut files: Vec<WorkitemFile> = vec![];
5796    if files_len > 0 {
5797        debug!("get files of options");
5798        let _files = unsafe { &*options.files };
5799        debug!("slice files");
5800        let _files = unsafe { std::slice::from_raw_parts(_files, files_len.try_into().unwrap()) };
5801        debug!("loop files");
5802        files = _files.iter().map(|f| {
5803            debug!("process a file");
5804            let file = unsafe { &**f };
5805            debug!("create WorkitemFile instance 2");
5806            let filename = c_char_to_str(file.filename);
5807            debug!("filename: {:?}", filename);
5808            let id = c_char_to_str(file.id);
5809            debug!("id: {:?}", id);
5810            let compressed = file.compressed;
5811            debug!("compressed: {:?}", compressed); 
5812            WorkitemFile {
5813                filename: c_char_to_str(file.filename),
5814                id: c_char_to_str(file.id),
5815                compressed: file.compressed,
5816                ..Default::default()
5817                // file: file.file.clone(),
5818            }
5819        }).collect();
5820    }
5821    trace!("nextrun: {:?}", options.nextrun);
5822    // convert options.nextrun to std::time::SystemTime
5823    let mut nextrun = Some(Timestamp::from(
5824        std::time::SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(options.nextrun as u64)
5825    ));
5826    trace!("nextrun: {:?}", nextrun);
5827    if options.nextrun == 0 {
5828        nextrun = None;
5829    }
5830    let request = PushWorkitemRequest {
5831        wiq: c_char_to_str(options.wiq),
5832        wiqid: c_char_to_str(options.wiqid),
5833        name: c_char_to_str(options.name),
5834        payload: c_char_to_str(options.payload),
5835        nextrun,
5836        success_wiqid: c_char_to_str(options.success_wiqid),
5837        failed_wiqid: c_char_to_str(options.failed_wiqid),
5838        success_wiq: c_char_to_str(options.success_wiq),
5839        failed_wiq: c_char_to_str(options.failed_wiq),
5840        priority: options.priority,
5841        files,
5842    };
5843    if client.is_none() {
5844        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
5845        let response = PushWorkitemResponseWrapper {
5846            success: false,
5847            error: error_msg,
5848            workitem: std::ptr::null(),
5849            request_id: options.request_id
5850        };
5851        return callback(Box::into_raw(Box::new(response)));
5852    }
5853    let client = client.unwrap();
5854    let handle = client.get_runtime_handle();
5855    let request_id = options.request_id;
5856    handle.spawn(async move {
5857        let result = client
5858            .push_workitem(request)
5859            .await;
5860        let response = match result {
5861            Ok(resp) => {
5862                match resp.workitem {
5863                    Some(workitem) => {
5864                        let workitem = wrap_workitem(workitem);
5865                        PushWorkitemResponseWrapper {
5866                            success: true,
5867                            error: std::ptr::null(),
5868                            workitem: Box::into_raw(Box::new(workitem)),
5869                            request_id,
5870                        }
5871                    }
5872                    None => {
5873                        let error_msg = CString::new("Push workitem failed: workitem not found").unwrap().into_raw();
5874                        PushWorkitemResponseWrapper {
5875                            success: false,
5876                            error: error_msg,
5877                            workitem: std::ptr::null(),
5878                            request_id,
5879                        }
5880                    }
5881                }
5882            }
5883            Err(e) => {
5884                let error_msg = CString::new(format!("Push workitem failed: {:?}", e))
5885                    .unwrap()
5886                    .into_raw();
5887                PushWorkitemResponseWrapper {
5888                    success: false,
5889                    error: error_msg,
5890                    workitem: std::ptr::null(),
5891                    request_id,
5892                }
5893            }
5894        };
5895        let response = Box::into_raw(Box::new(response));
5896        callback(response);
5897    });
5898
5899
5900}
5901
5902#[no_mangle]
5903#[tracing::instrument(skip_all)]
5904pub extern "C" fn free_push_workitem_response(response: *mut PushWorkitemResponseWrapper) {
5905    if response.is_null() {
5906        return;
5907    }
5908    unsafe {
5909        if !(*response).error.is_null() {
5910            let _ = CString::from_raw((*response).error as *mut c_char);
5911        }
5912        if !(*response).workitem.is_null() {
5913            free_workitem((*response).workitem as *mut WorkitemWrapper);
5914        }
5915        let _ = Box::from_raw(response);
5916    }
5917}
5918
5919#[repr(C)]
5920#[derive(Debug, Clone)]
5921pub struct PopWorkitemRequestWrapper {
5922    wiq: *const c_char,
5923    wiqid: *const c_char,
5924    request_id: i32
5925    // includefiles: bool,
5926    // compressed: bool,
5927}
5928#[repr(C)]
5929#[derive(Debug, Clone)]
5930pub struct PopWorkitemResponseWrapper {
5931    success: bool,
5932    error: *const c_char,
5933    workitem: *const WorkitemWrapper,
5934    request_id: i32
5935}
5936#[no_mangle]
5937#[tracing::instrument(skip_all)]
5938pub extern "C" fn pop_workitem (
5939    client: *mut ClientWrapper,
5940    options: *mut PopWorkitemRequestWrapper,
5941    downloadfolder: *const c_char,
5942) -> *mut PopWorkitemResponseWrapper {
5943    let options = match safe_wrapper(options) {
5944        Some(options) => options,
5945        None => {
5946            let error_msg = CString::new("Invalid options").unwrap().into_raw();
5947            let response = PopWorkitemResponseWrapper {
5948                success: false,
5949                error: error_msg,
5950                workitem: std::ptr::null(),
5951                request_id: 0
5952            };
5953            return Box::into_raw(Box::new(response));
5954        }
5955    };
5956    let client_wrapper = match safe_wrapper(client) {
5957        Some(client) => client,
5958        None => {
5959            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
5960            let response = PopWorkitemResponseWrapper {
5961                success: false,
5962                error: error_msg,
5963                workitem: std::ptr::null(),
5964                request_id: options.request_id
5965            };
5966            return Box::into_raw(Box::new(response));
5967        }
5968    };
5969    let client = client_wrapper.client.clone();
5970    let request = PopWorkitemRequest {
5971        wiq: c_char_to_str(options.wiq),
5972        wiqid: c_char_to_str(options.wiqid),
5973        ..Default::default()
5974    };
5975    if client.is_none() {
5976        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
5977        let response = PopWorkitemResponseWrapper {
5978            success: false,
5979            error: error_msg,
5980            workitem: std::ptr::null(),
5981            request_id: options.request_id
5982        };
5983        return Box::into_raw(Box::new(response));
5984    }
5985    let downloadfolder = c_char_to_str(downloadfolder);
5986    let mut _downloadfolder = Some(downloadfolder.as_str());
5987    if downloadfolder.is_empty() {
5988        _downloadfolder = None;
5989    }
5990    let client = client.unwrap();
5991    let result = tokio::task::block_in_place(|| {
5992        let handle = client.get_runtime_handle();
5993            handle.block_on(client
5994            .pop_workitem(request, _downloadfolder)
5995            )
5996    });
5997    debug!("pop_workitem completed, parse result");
5998
5999    match result {
6000        Ok(data) => {
6001            let workitem = match data.workitem {
6002                Some(workitem) => {
6003                    let workitem = wrap_workitem(workitem);
6004                    trace!("wrap workitem");
6005                    Box::into_raw(Box::new(workitem))
6006                },
6007                None => {
6008                    std::ptr::null()
6009                }
6010            };
6011            Box::into_raw(Box::new(PopWorkitemResponseWrapper {
6012                success: true,
6013                error: std::ptr::null(),
6014                workitem,
6015                request_id: options.request_id
6016            }))
6017        }
6018        Err(e) => {
6019            let error_msg = CString::new(format!("Pop workitem failed: {:?}", e))
6020                .unwrap()
6021                .into_raw();
6022            Box::into_raw(Box::new(PopWorkitemResponseWrapper {
6023                success: false,
6024                error: error_msg,
6025                workitem: std::ptr::null(),
6026                request_id: options.request_id
6027            }))
6028        }
6029    }
6030}
6031#[no_mangle]
6032#[tracing::instrument(skip_all)]
6033pub extern "C" fn pop_workitem_async (
6034    client: *mut ClientWrapper,
6035    options: *mut PopWorkitemRequestWrapper,
6036    downloadfolder: *const c_char,
6037    callback: extern "C" fn(*mut PopWorkitemResponseWrapper),
6038) {
6039    let options = match safe_wrapper(options) {
6040        Some(options) => options,
6041        None => {
6042            let error_msg = CString::new("Invalid options").unwrap().into_raw();
6043            let response = PopWorkitemResponseWrapper {
6044                success: false,
6045                error: error_msg,
6046                workitem: std::ptr::null(),
6047                request_id: 0
6048            };
6049            return callback(Box::into_raw(Box::new(response)));
6050        }
6051    };
6052    let client_wrapper = match safe_wrapper(client) {
6053        Some(client) => client,
6054        None => {
6055            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
6056            let response = PopWorkitemResponseWrapper {
6057                success: false,
6058                error: error_msg,
6059                workitem: std::ptr::null(),
6060                request_id: options.request_id
6061            };
6062            return callback(Box::into_raw(Box::new(response)));
6063        }
6064    };
6065    let client = client_wrapper.client.clone();
6066    let request = PopWorkitemRequest {
6067        wiq: c_char_to_str(options.wiq),
6068        wiqid: c_char_to_str(options.wiqid),
6069        ..Default::default()
6070    };
6071    if client.is_none() {
6072        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
6073        let response = PopWorkitemResponseWrapper {
6074            success: false,
6075            error: error_msg,
6076            workitem: std::ptr::null(),
6077            request_id: options.request_id
6078        };
6079        return callback(Box::into_raw(Box::new(response)));
6080    }
6081    let downloadfolder = c_char_to_str(downloadfolder);
6082    let client = client.unwrap();
6083    let handle = client.get_runtime_handle();
6084    let request_id = options.request_id;
6085    handle.spawn(async move {
6086        let mut _downloadfolder = Some(downloadfolder.as_str());
6087        if downloadfolder.is_empty() {
6088            _downloadfolder = None;
6089        }
6090    
6091        let result = client
6092            .pop_workitem(request, _downloadfolder)
6093            .await;
6094        let response = match result {
6095            Ok(data) => {
6096                let workitem = match data.workitem {
6097                    Some(workitem) => {
6098                        let workitem = wrap_workitem(workitem);
6099                        trace!("wrap workitem");
6100                        Box::into_raw(Box::new(workitem))
6101                    },
6102                    None => {
6103                        std::ptr::null()
6104                    }
6105                };
6106                let response = PopWorkitemResponseWrapper {
6107                    success: true,
6108                    error: std::ptr::null(),
6109                    workitem,
6110                    request_id: request_id
6111                };
6112                Box::into_raw(Box::new(response))
6113            }
6114            Err(e) => {
6115                let error_msg = CString::new(format!("Pop workitem failed: {:?}", e))
6116                    .unwrap()
6117                    .into_raw();
6118                let response = PopWorkitemResponseWrapper {
6119                    success: false,
6120                    error: error_msg,
6121                    workitem: std::ptr::null(),
6122                    request_id: request_id
6123                };
6124                Box::into_raw(Box::new(response))
6125            }
6126        };
6127        trace!("callback with result");
6128        callback(response);
6129    });
6130}
6131#[no_mangle]
6132#[tracing::instrument(skip_all)]
6133pub extern "C" fn free_pop_workitem_response(response: *mut PopWorkitemResponseWrapper) {
6134    if response.is_null() {
6135        return;
6136    }
6137    unsafe {
6138        if !(*response).error.is_null() {
6139            let _ = CString::from_raw((*response).error as *mut c_char);
6140        }
6141        if !(*response).workitem.is_null() {
6142            free_workitem((*response).workitem as *mut WorkitemWrapper);
6143        }
6144        let _ = Box::from_raw(response);
6145    }
6146}
6147#[no_mangle]
6148#[tracing::instrument(skip_all)]
6149pub extern "C" fn free_workitem_file(file: *mut WorkitemFileWrapper) {
6150    if file.is_null() {
6151        return;
6152    }
6153    unsafe {
6154        if !(*file).filename.is_null() {
6155            let _ = CString::from_raw((*file).filename as *mut c_char);
6156        }
6157        if !(*file).id.is_null() {
6158            let _ = CString::from_raw((*file).id as *mut c_char);
6159        }
6160        let _ = Box::from_raw(file);
6161    }
6162}
6163#[no_mangle]
6164#[tracing::instrument(skip_all)]
6165pub extern "C" fn free_workitem(workitem: *mut WorkitemWrapper) {
6166    if workitem.is_null() {
6167        return;
6168    }
6169    unsafe {
6170        if !(*workitem).id.is_null() {
6171            let _ = CString::from_raw((*workitem).id as *mut c_char);
6172        }
6173        if !(*workitem).name.is_null() {
6174            let _ = CString::from_raw((*workitem).name as *mut c_char);
6175        }
6176        if !(*workitem).payload.is_null() {
6177            let _ = CString::from_raw((*workitem).payload as *mut c_char);
6178        }
6179        if !(*workitem).state.is_null() {
6180            let _ = CString::from_raw((*workitem).state as *mut c_char);
6181        }
6182        if !(*workitem).wiq.is_null() {
6183            let _ = CString::from_raw((*workitem).wiq as *mut c_char);
6184        }
6185        if !(*workitem).wiqid.is_null() {
6186            let _ = CString::from_raw((*workitem).wiqid as *mut c_char);
6187        }
6188        if !(*workitem).username.is_null() {
6189            let _ = CString::from_raw((*workitem).username as *mut c_char);
6190        }
6191        if !(*workitem).success_wiqid.is_null() {
6192            let _ = CString::from_raw((*workitem).success_wiqid as *mut c_char);
6193        }
6194        if !(*workitem).failed_wiqid.is_null() {
6195            let _ = CString::from_raw((*workitem).failed_wiqid as *mut c_char);
6196        }
6197        if !(*workitem).success_wiq.is_null() {
6198            let _ = CString::from_raw((*workitem).success_wiq as *mut c_char);
6199        }
6200        if !(*workitem).failed_wiq.is_null() {
6201            let _ = CString::from_raw((*workitem).failed_wiq as *mut c_char);
6202        }
6203        if !(*workitem).errormessage.is_null() {
6204            let _ = CString::from_raw((*workitem).errormessage as *mut c_char);
6205        }
6206        if !(*workitem).errorsource.is_null() {
6207            let _ = CString::from_raw((*workitem).errorsource as *mut c_char);
6208        }
6209        if !(*workitem).errortype.is_null() {
6210            let _ = CString::from_raw((*workitem).errortype as *mut c_char);
6211        }
6212
6213        // Free the array of `WorkitemFileWrapper` pointers if it exists
6214        if !(*workitem).files.is_null() && (*workitem).files_len > 0 {
6215            for i in 0..(*workitem).files_len as isize {
6216                let file_ptr = *(*workitem).files.offset(i);
6217                if !file_ptr.is_null() {
6218                    free_workitem_file(file_ptr as *mut WorkitemFileWrapper);
6219                }
6220            }
6221            // Free the array of pointers itself
6222            let _ = Box::from_raw((*workitem).files as *mut *const WorkitemFileWrapper);
6223        }
6224        let _ = Box::from_raw(workitem); // Take ownership to deallocate
6225    }
6226}
6227
6228
6229#[no_mangle]
6230#[tracing::instrument(skip_all)]
6231pub extern "C" fn pop_workitem2_async (
6232    _client: *mut ClientWrapper,
6233    _options: *mut PopWorkitemRequestWrapper,
6234    _downloadfolder: *const c_char,
6235    request_id: i32,
6236    callback: extern "C" fn(*mut PopWorkitemResponseWrapper),
6237) {
6238    callback(Box::into_raw(Box::new(PopWorkitemResponseWrapper {
6239        success: true,
6240        error: std::ptr::null(),
6241        workitem: std::ptr::null(),
6242        request_id: request_id
6243    })));
6244}
6245
6246#[repr(C)]
6247#[derive(Debug, Clone)]
6248pub struct UpdateWorkitemRequestWrapper {
6249    workitem: *const WorkitemWrapper,
6250    ignoremaxretries: bool,    
6251    files: *const *const WorkitemFileWrapper,
6252    files_len: i32,
6253    request_id: i32
6254}
6255#[repr(C)]
6256#[derive(Debug, Clone)]
6257pub struct UpdateWorkitemResponseWrapper {
6258    success: bool,
6259    error: *const c_char,
6260    workitem: *const WorkitemWrapper,
6261    request_id: i32
6262}
6263#[no_mangle]
6264#[tracing::instrument(skip_all)]
6265pub extern "C" fn update_workitem (
6266    client: *mut ClientWrapper,
6267    options: *mut UpdateWorkitemRequestWrapper,
6268) -> *mut UpdateWorkitemResponseWrapper {
6269    let options = match safe_wrapper(options) {
6270        Some(options) => options,
6271        None => {
6272            let error_msg = CString::new("Invalid options").unwrap().into_raw();
6273            let response = UpdateWorkitemResponseWrapper {
6274                success: false,
6275                error: error_msg,
6276                workitem: std::ptr::null(),
6277                request_id: 0
6278            };
6279            return Box::into_raw(Box::new(response));
6280        }
6281    };
6282    let client_wrapper = match safe_wrapper(client) {
6283        Some(client) => client,
6284        None => {
6285            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
6286            let response = UpdateWorkitemResponseWrapper {
6287                success: false,
6288                error: error_msg,
6289                workitem: std::ptr::null(),
6290                request_id: options.request_id
6291            };
6292            return Box::into_raw(Box::new(response));
6293        }
6294    };
6295    trace!("grab references");
6296    let client = client_wrapper.client.clone();
6297    let files_len = options.files_len;
6298    debug!("files_len: {:?}", files_len);
6299    let mut files: Vec<WorkitemFile> = vec![];
6300    if files_len > 0 {
6301        debug!("get files of options");
6302        let _files = unsafe { &*options.files };
6303        debug!("slice files");
6304        let _files = unsafe { std::slice::from_raw_parts(_files, files_len.try_into().unwrap()) };
6305        debug!("loop files");
6306        files = _files.iter().map(|f| {
6307            debug!("process a file");
6308            let file = unsafe { &**f };
6309            debug!("create WorkitemFile instance 2");
6310            let filename = c_char_to_str(file.filename);
6311            debug!("filename: {:?}", filename);
6312            let id = c_char_to_str(file.id);
6313            debug!("id: {:?}", id);
6314            let compressed = file.compressed;
6315            debug!("compressed: {:?}", compressed); 
6316            WorkitemFile {
6317                filename: c_char_to_str(file.filename),
6318                id: c_char_to_str(file.id),
6319                compressed: file.compressed,
6320                ..Default::default()
6321                // file: file.file.clone(),
6322            }
6323        }).collect();
6324    }
6325    debug!("unwrap workitem");
6326    let workitem = unsafe { &*options.workitem };
6327    debug!("convert workitem wrapper to workitem");
6328    let workitem = workitem.as_workitem();
6329    let request = UpdateWorkitemRequest {
6330        workitem: Some(workitem),
6331        ignoremaxretries: options.ignoremaxretries,
6332        files,
6333    };
6334    
6335    if client.is_none() {
6336        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
6337        let response = UpdateWorkitemResponseWrapper {
6338            success: false,
6339            error: error_msg,
6340            workitem: std::ptr::null(),
6341            request_id: options.request_id
6342        };
6343        return Box::into_raw(Box::new(response));
6344    }
6345    let client = client.unwrap();
6346    let result = tokio::task::block_in_place(|| {
6347        let handle = client.get_runtime_handle();
6348            handle.block_on(client
6349            .update_workitem(request)
6350            )
6351    });
6352
6353    match result {
6354        Ok(resp) => {
6355            Box::into_raw(Box::new(match resp.workitem {
6356                Some(workitem) => {
6357                    let workitem = wrap_workitem(workitem);
6358                    UpdateWorkitemResponseWrapper {
6359                        success: true,
6360                        error: std::ptr::null(),
6361                        workitem: Box::into_raw(Box::new(workitem)),
6362                        request_id: options.request_id
6363                    }
6364                }
6365                None => {
6366                    let error_msg = CString::new("Update workitem failed: workitem not found").unwrap().into_raw();
6367                    UpdateWorkitemResponseWrapper {
6368                        success: false,
6369                        error: error_msg,
6370                        workitem: std::ptr::null(),
6371                        request_id: options.request_id
6372                    }
6373                }
6374            }))            
6375        }
6376        Err(e) => {
6377            let error_msg = CString::new(format!("Update workitem failed: {:?}", e))
6378                .unwrap()
6379                .into_raw();
6380            Box::into_raw(Box::new(UpdateWorkitemResponseWrapper {
6381                success: false,
6382                error: error_msg,
6383                workitem: std::ptr::null(),
6384                request_id: options.request_id
6385            }))
6386        }
6387    }
6388}
6389#[no_mangle]
6390#[tracing::instrument(skip_all)]
6391pub extern "C" fn update_workitem_async (
6392    client: *mut ClientWrapper,
6393    options: *mut UpdateWorkitemRequestWrapper,
6394    callback: extern "C" fn(*mut UpdateWorkitemResponseWrapper),
6395) {
6396    let options = match safe_wrapper(options) {
6397        Some(options) => options,
6398        None => {
6399            let error_msg = CString::new("Invalid options").unwrap().into_raw();
6400            let response = UpdateWorkitemResponseWrapper {
6401                success: false,
6402                error: error_msg,
6403                workitem: std::ptr::null(),
6404                request_id: 0
6405            };
6406            return callback(Box::into_raw(Box::new(response)));
6407        }
6408    };
6409    let client_wrapper = match safe_wrapper(client) {
6410        Some(client) => client,
6411        None => {
6412            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
6413            let response = UpdateWorkitemResponseWrapper {
6414                success: false,
6415                error: error_msg,
6416                workitem: std::ptr::null(),
6417                request_id: options.request_id
6418            };
6419            return callback(Box::into_raw(Box::new(response)));
6420        }
6421    };
6422    trace!("grab references");
6423    let client = client_wrapper.client.clone();
6424    let files_len = options.files_len;
6425    debug!("files_len: {:?}", files_len);
6426    let mut files: Vec<WorkitemFile> = vec![];
6427    if files_len > 0 {
6428        debug!("get files of options");
6429        let _files = unsafe { &*options.files };
6430        debug!("slice files");
6431        let _files = unsafe { std::slice::from_raw_parts(_files, files_len.try_into().unwrap()) };
6432        debug!("loop files");
6433        files = _files.iter().map(|f| {
6434            debug!("process a file");
6435            let file = unsafe { &**f };
6436            debug!("create WorkitemFile instance 2");
6437            let filename = c_char_to_str(file.filename);
6438            debug!("filename: {:?}", filename);
6439            let id = c_char_to_str(file.id);
6440            debug!("id: {:?}", id);
6441            let compressed = file.compressed;
6442            debug!("compressed: {:?}", compressed); 
6443            WorkitemFile {
6444                filename: c_char_to_str(file.filename),
6445                id: c_char_to_str(file.id),
6446                compressed: file.compressed,
6447                ..Default::default()
6448                // file: file.file.clone(),
6449            }
6450        }).collect();
6451    }
6452    debug!("unwrap workitem");
6453    let workitem = unsafe { &*options
6454    .workitem };
6455
6456    debug!("convert workitem wrapper to workitem");
6457    let workitem = workitem.as_workitem();
6458    let request = UpdateWorkitemRequest {
6459        workitem: Some(workitem),
6460        ignoremaxretries: options.ignoremaxretries,
6461        files,
6462    };
6463
6464    if client.is_none() {
6465        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
6466        let response = UpdateWorkitemResponseWrapper {
6467            success: false,
6468            error: error_msg,
6469            workitem: std::ptr::null(),
6470            request_id: options.request_id
6471        };
6472        return callback(Box::into_raw(Box::new(response)));
6473    }
6474    let client = client.unwrap();
6475    let handle = client.get_runtime_handle();
6476    let request_id = options.request_id;
6477    handle.spawn(async move {
6478        let result = client
6479            .update_workitem(request)
6480            .await;
6481        let response = match result {
6482            Ok(resp) => {
6483                let response = match resp.workitem {
6484                    Some(workitem) => {
6485                        let workitem = wrap_workitem(workitem);
6486                        UpdateWorkitemResponseWrapper {
6487                            success: true,
6488                            error: std::ptr::null(),
6489                            workitem: Box::into_raw(Box::new(workitem)),
6490                            request_id,
6491                        }
6492                    }
6493                    None => {
6494                        let error_msg = CString::new("Update workitem failed: workitem not found").unwrap().into_raw();
6495                        UpdateWorkitemResponseWrapper {
6496                            success: false,
6497                            error: error_msg,
6498                            workitem: std::ptr::null(),
6499                            request_id,
6500                        }
6501                    }
6502                };
6503                Box::into_raw(Box::new(response))
6504            }
6505            Err(e) => {
6506                let error_msg = CString::new(format!("Update workitem failed: {:?}", e))
6507                    .unwrap()
6508                    .into_raw();
6509                Box::into_raw(Box::new(UpdateWorkitemResponseWrapper {
6510                    success: false,
6511                    error: error_msg,
6512                    workitem: std::ptr::null(),
6513                    request_id,
6514                }))
6515            }
6516        };
6517        callback(response);
6518    });
6519}
6520#[no_mangle]
6521#[tracing::instrument(skip_all)]
6522pub extern "C" fn free_update_workitem_response(response: *mut UpdateWorkitemResponseWrapper) {
6523    if response.is_null() {
6524        return;
6525    }
6526    unsafe {
6527        if !(*response).error.is_null() {
6528            let _ = CString::from_raw((*response).error as *mut c_char);
6529        }
6530        if !(*response).workitem.is_null() {
6531            free_workitem((*response).workitem as *mut WorkitemWrapper);
6532        }
6533        let _ = Box::from_raw(response);
6534    }
6535}
6536
6537#[repr(C)]
6538#[derive(Debug, Clone)]
6539pub struct DeleteWorkitemRequestWrapper {
6540    id: *const c_char,
6541    request_id: i32
6542}
6543#[repr(C)]
6544#[derive(Debug, Clone)]
6545pub struct DeleteWorkitemResponseWrapper {
6546    success: bool,
6547    error: *const c_char,
6548    request_id: i32
6549}
6550#[no_mangle]
6551#[tracing::instrument(skip_all)]
6552pub extern "C" fn delete_workitem( 
6553    client: *mut ClientWrapper,
6554    options: *mut DeleteWorkitemRequestWrapper,
6555) -> *mut DeleteWorkitemResponseWrapper {
6556    let options = match safe_wrapper(options) {
6557        Some(options) => options,
6558        None => {
6559            let error_msg = CString::new("Invalid options").unwrap().into_raw();
6560            let response = DeleteWorkitemResponseWrapper {
6561                success: false,
6562                error: error_msg,
6563                request_id: 0
6564            };
6565            return Box::into_raw(Box::new(response));
6566        }
6567    };
6568    let client_wrapper = match safe_wrapper(client) {
6569        Some(client) => client,
6570        None => {
6571            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
6572            let response = DeleteWorkitemResponseWrapper {
6573                success: false,
6574                error: error_msg,
6575                request_id: options.request_id
6576            };
6577            return Box::into_raw(Box::new(response));
6578        }
6579    };
6580    let client = client_wrapper.client.clone();
6581    let request = DeleteWorkitemRequest {
6582        id: c_char_to_str(options.id),
6583    };
6584    if client.is_none() {
6585        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
6586        let response = DeleteWorkitemResponseWrapper {
6587            success: false,
6588            error: error_msg,
6589            request_id: options.request_id
6590        };
6591        return Box::into_raw(Box::new(response));
6592    }
6593    let client = client.unwrap();
6594    let result = tokio::task::block_in_place(|| {
6595        let handle = client.get_runtime_handle();
6596            handle.block_on(client
6597            .delete_workitem(request)
6598            )
6599    });
6600
6601    let response = match result {
6602        Ok(_) => {
6603            let response = DeleteWorkitemResponseWrapper {
6604                success: true,
6605                error: std::ptr::null(),
6606                request_id: options.request_id
6607            };
6608            Box::into_raw(Box::new(response))
6609        }
6610        Err(e) => {
6611            let error_msg = CString::new(format!("Delete workitem failed: {:?}", e))
6612                .unwrap()
6613                .into_raw();
6614            let response = DeleteWorkitemResponseWrapper {
6615                success: false,
6616                error: error_msg,
6617                request_id: options.request_id
6618            };
6619            Box::into_raw(Box::new(response))
6620        }
6621    };
6622    debug!("return response {:?}", response);
6623    response
6624}
6625#[no_mangle]
6626#[tracing::instrument(skip_all)]
6627pub extern "C" fn delete_workitem_async( 
6628    client: *mut ClientWrapper,
6629    options: *mut DeleteWorkitemRequestWrapper,
6630    callback: extern "C" fn(*mut DeleteWorkitemResponseWrapper),
6631) {
6632    let options = match safe_wrapper(options) {
6633        Some(options) => options,
6634        None => {
6635            let error_msg = CString::new("Invalid options").unwrap().into_raw();
6636            let response = DeleteWorkitemResponseWrapper {
6637                success: false,
6638                error: error_msg,
6639                request_id: 0
6640            };
6641            return callback(Box::into_raw(Box::new(response)));
6642        }
6643    };
6644    let client_wrapper = match safe_wrapper(client) {
6645        Some(client) => client,
6646        None => {
6647            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
6648            let response = DeleteWorkitemResponseWrapper {
6649                success: false,
6650                error: error_msg,
6651                request_id: options.request_id
6652            };
6653            return callback(Box::into_raw(Box::new(response)));
6654        }
6655    };
6656    let client = client_wrapper.client.clone();
6657    let request = DeleteWorkitemRequest {
6658        id: c_char_to_str(options.id),
6659    };
6660    if client.is_none() {
6661        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
6662        let response = DeleteWorkitemResponseWrapper {
6663            success: false,
6664            error: error_msg,
6665            request_id: options.request_id
6666        };
6667        return callback(Box::into_raw(Box::new(response)));
6668    }
6669    let client = client.unwrap();
6670    let handle = client.get_runtime_handle();
6671    let request_id = options.request_id;
6672    handle.spawn(async move {
6673        let result = client
6674            .delete_workitem(request)
6675            .await;
6676        let response = match result {
6677            Ok(_) => {
6678                debug!("success");
6679                let response = DeleteWorkitemResponseWrapper {
6680                    success: true,
6681                    error: std::ptr::null(),
6682                    request_id,
6683                };
6684                Box::into_raw(Box::new(response))
6685            }
6686            Err(e) => {
6687                let error_msg = CString::new(format!("Delete workitem failed: {:?}", e))
6688                    .unwrap()
6689                    .into_raw();
6690                debug!("failed: {:?}", error_msg);
6691                let response = DeleteWorkitemResponseWrapper {
6692                    success: false,
6693                    error: error_msg,
6694                    request_id,
6695                };
6696                Box::into_raw(Box::new(response))
6697            }
6698        };
6699        debug!("callback {:?}", response);
6700        callback(response);
6701    });
6702}
6703#[no_mangle]
6704#[tracing::instrument(skip_all)]
6705pub extern "C" fn free_delete_workitem_response(response: *mut DeleteWorkitemResponseWrapper) {
6706    if response.is_null() {
6707        return;
6708    }
6709    unsafe {
6710        if !(*response).error.is_null() {
6711            let _ = CString::from_raw((*response).error as *mut c_char);
6712        }
6713        let _ = Box::from_raw(response);
6714    }
6715}
6716
6717
6718
6719
6720
6721#[repr(C)]
6722#[derive(Debug, Clone)]
6723pub struct ClientEventWrapper {
6724    event: *const c_char,
6725    reason: *const c_char,
6726}
6727impl Default for ClientEventWrapper {
6728    fn default() -> Self { 
6729        ClientEventWrapper {
6730            event: std::ptr::null(),
6731            reason: std::ptr::null(),
6732        }
6733     }
6734}
6735#[repr(C)]
6736pub struct ClientEventResponseWrapper {
6737    success: bool,
6738    eventid: *const c_char,
6739    error: *const c_char,
6740}
6741
6742#[no_mangle]
6743#[tracing::instrument(skip_all)]
6744pub extern "C" fn on_client_event(
6745    client: *mut ClientWrapper
6746) -> *mut ClientEventResponseWrapper {
6747    let client_wrapper = match safe_wrapper(client) {
6748        Some(client) => client,
6749        None => {
6750            let error_msg = CString::new("Invalid options, client is None").unwrap().into_raw();
6751            let response = ClientEventResponseWrapper {
6752                success: false,
6753                eventid: std::ptr::null(),
6754                error: error_msg,
6755            };
6756            return Box::into_raw(Box::new(response));
6757        }
6758    };
6759    let mut client = client_wrapper.client.clone();
6760    if client.is_none() {
6761        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
6762        let response = ClientEventResponseWrapper {
6763            success: false,
6764            eventid: std::ptr::null(),
6765            error: error_msg,
6766        };
6767        return Box::into_raw(Box::new(response));
6768    }
6769    let client = client.as_mut().unwrap();
6770    let eventid = Client::get_uniqueid();
6771    let _eventid = eventid.clone();
6772    tokio::task::block_in_place(|| {
6773        let handle = client.get_runtime_handle();
6774        handle.block_on(client.on_event(Box::new({
6775            move |event: ClientEvent| {
6776                let clientid = _eventid.clone();
6777                debug!("client event: {:?}", event);
6778    
6779                let mut e = CLIENT_EVENTS.lock().unwrap();
6780                let queue = e.get_mut(&clientid);
6781                match queue {
6782                    Some(q) => {
6783                        q.push_back(event);
6784                    }
6785                    None => {
6786                        let mut q = std::collections::VecDeque::new();
6787                        q.push_back(event);
6788                        e.insert(clientid, q);
6789                    }
6790                }
6791            }
6792        })));
6793    });
6794    
6795    let mut events = CLIENT_EVENTS.lock().unwrap();
6796    let _eventid = eventid.clone();
6797    let queue = events.get_mut(&_eventid);
6798    if queue.is_none() {
6799        let q = std::collections::VecDeque::new();
6800        let k = String::from(&eventid);
6801        events.insert(k, q);
6802    };
6803    let response = ClientEventResponseWrapper {
6804        success: true,
6805        eventid: CString::new(eventid).unwrap().into_raw(),
6806        error: std::ptr::null(),
6807    };
6808    return Box::into_raw(Box::new(response));
6809}
6810type ClientEventCallback = extern "C" fn(*mut ClientEventWrapper);
6811#[no_mangle]
6812#[tracing::instrument(skip_all)]
6813pub extern "C" fn on_client_event_async(
6814    client: *mut ClientWrapper,
6815    event_callback: ClientEventCallback,
6816)  -> *mut ClientEventResponseWrapper {
6817    debug!("on_client_event_async::begin");
6818    let client_wrapper = match safe_wrapper(client) {
6819        Some(client) => client,
6820        None => {
6821            let error_msg = CString::new("Invalid options, client is None").unwrap().into_raw();
6822            let response = ClientEventResponseWrapper {
6823                success: false,
6824                eventid: std::ptr::null(),
6825                error: error_msg,
6826            };
6827            return Box::into_raw(Box::new(response));
6828        }
6829    };
6830    let mut client = client_wrapper.client.clone();
6831    if client.is_none() {
6832        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
6833        let response = ClientEventResponseWrapper {
6834            success: false,
6835            eventid: std::ptr::null(),
6836            error: error_msg,
6837        };
6838        return Box::into_raw(Box::new(response));
6839    }
6840    let client = client.as_mut().unwrap();
6841    let eventid = Client::get_uniqueid();
6842    debug!("on_client_event_async::eventid: {:?}", eventid);
6843    let _eventid = eventid.clone();
6844    tokio::task::block_in_place(|| {
6845        let handle = client.get_runtime_handle();
6846            handle.block_on(client
6847            .on_event(
6848                Box::new(move |event: ClientEvent| {
6849                    let clientid = _eventid.clone();
6850                    debug!("client event: {:?}", event);
6851                    let mut e = CLIENT_EVENTS.lock().unwrap();
6852                    let queue = e.get_mut(&clientid);
6853                    match queue {
6854                        Some(_q) => {
6855                        }
6856                        None => {
6857                            // Stop the event listener if the queue is not found
6858                            return;
6859                        }
6860                    };
6861                    let event = match event {
6862                        ClientEvent::Connecting => ClientEventWrapper { event: CString::new("Connecting").unwrap().into_raw(),reason: std::ptr::null() },
6863                        ClientEvent::Connected => ClientEventWrapper { event: CString::new("Connected").unwrap().into_raw(),reason: std::ptr::null() },
6864                        ClientEvent::Disconnected(reason) => ClientEventWrapper { event: CString::new("Disconnected").unwrap().into_raw(),reason: CString::new(reason).unwrap().into_raw() },
6865                        ClientEvent::SignedIn => ClientEventWrapper { event: CString::new("SignedIn").unwrap().into_raw(),reason: std::ptr::null() },
6866                        // ClientEvent::SignedOut => ClientEventWrapper { event: CString::new("SignedOut").unwrap().into_raw(),reason: std::ptr::null() },
6867                    };
6868                    let event = Box::into_raw(Box::new(event));
6869
6870                    event_callback(event);
6871                    debug!("client event: {:?}", event);
6872                }),
6873            )
6874        )
6875    });
6876
6877    let mut events = CLIENT_EVENTS.lock().unwrap();
6878    let _eventid = eventid.clone();
6879    let queue = events.get_mut(&_eventid);
6880    if queue.is_none() {
6881        debug!("create event queue, for eventid: {:?}", eventid);
6882        let q = std::collections::VecDeque::new();
6883        let k = String::from(&eventid);
6884        events.insert(k, q);
6885    };
6886    debug!("on_client_event_async::end");
6887    let response = ClientEventResponseWrapper {
6888        success: true,
6889        eventid: CString::new(eventid).unwrap().into_raw(),
6890        error: std::ptr::null(),
6891    };
6892    return Box::into_raw(Box::new(response));
6893
6894}
6895
6896#[no_mangle]
6897#[tracing::instrument(skip_all)]
6898pub extern "C" fn next_client_event (
6899    clientid: *const c_char,    
6900) -> *mut ClientEventWrapper {
6901    trace!("unwrap clientid");
6902    let clientid = c_char_to_str(clientid);
6903    trace!("clientid {:}", clientid);
6904    let clientid = clientid.to_string();
6905    trace!("unwrap events");
6906    let mut e = CLIENT_EVENTS.lock().unwrap();
6907    trace!("get queue");
6908    let queue = e.get_mut(&clientid);
6909    match queue {
6910        Some(q) => {
6911            match q.pop_front() {
6912                Some(event) => {
6913                    debug!("got client event");
6914                    let event = match event {
6915                        ClientEvent::Connecting => ClientEventWrapper { event: CString::new("Connecting").unwrap().into_raw(),reason: std::ptr::null() },
6916                        ClientEvent::Connected => ClientEventWrapper { event: CString::new("Connected").unwrap().into_raw(),reason: std::ptr::null() },
6917                        ClientEvent::Disconnected(reason) => ClientEventWrapper { event: CString::new("Disconnected").unwrap().into_raw(),reason: CString::new(reason).unwrap().into_raw() },
6918                        ClientEvent::SignedIn => ClientEventWrapper { event: CString::new("SignedIn").unwrap().into_raw(),reason: std::ptr::null() },
6919                        // ClientEvent::SignedOut => ClientEventWrapper { event: CString::new("SignedOut").unwrap().into_raw(),reason: std::ptr::null() },
6920                    };
6921                    Box::into_raw(Box::new(event))
6922                }
6923                None => {
6924                    trace!("No event");
6925                    Box::into_raw(Box::new(ClientEventWrapper::default())) 
6926                },
6927            }
6928        },
6929        None => {
6930            debug!("Queue for {:} not found", clientid);
6931            Box::into_raw(Box::new(ClientEventWrapper::default())) 
6932        },
6933    }
6934}
6935
6936#[repr(C)]
6937pub struct OffClientEventResponseWrapper {
6938    success: bool,
6939    error: *const c_char,
6940}
6941#[no_mangle]
6942#[tracing::instrument(skip_all)]
6943pub extern "C" fn off_client_event(
6944    eventid: *const c_char,
6945) -> *mut OffClientEventResponseWrapper {
6946    let eventid = c_char_to_str(eventid);
6947    if eventid.is_empty() {
6948        let error_msg = CString::new("eventid is required").unwrap().into_raw();
6949        let response = OffClientEventResponseWrapper {
6950            success: false,
6951            error: error_msg,
6952        };
6953        return Box::into_raw(Box::new(response));
6954    }
6955    trace!("eventid: {:?}", eventid);
6956    
6957    let mut e = CLIENT_EVENTS.lock().unwrap();
6958    let queue = e.get_mut(&eventid);
6959    if let Some(q) = queue {
6960        q.clear();
6961        e.remove(&eventid);
6962    };
6963    Box::into_raw(Box::new(OffClientEventResponseWrapper {
6964        success: true,
6965        error: std::ptr::null(),
6966    }))    
6967}
6968
6969#[no_mangle]
6970#[tracing::instrument(skip_all)]
6971pub extern "C" fn free_off_event_response(response: *mut OffClientEventResponseWrapper) {
6972    if response.is_null() {
6973        return;
6974    }
6975    unsafe {
6976        if !(*response).error.is_null() {
6977            let _ = CString::from_raw((*response).error as *mut c_char);
6978        }
6979        let _ = Box::from_raw(response);
6980    }
6981}
6982#[no_mangle]
6983#[tracing::instrument(skip_all)]
6984pub extern "C" fn free_event_response(response: *mut ClientEventResponseWrapper) {
6985    if response.is_null() {
6986        return;
6987    }
6988    unsafe {
6989        if !(*response).error.is_null() {
6990            let _ = CString::from_raw((*response).error as *mut c_char);
6991        }
6992        if !(*response).eventid.is_null() {
6993            let _ = CString::from_raw((*response).eventid as *mut c_char);
6994        }
6995        let _ = Box::from_raw(response);
6996    }    
6997}
6998#[no_mangle]
6999#[tracing::instrument(skip_all)]
7000pub extern "C" fn free_client_event(response: *mut ClientEventWrapper) {
7001    if response.is_null() {
7002        return;
7003    }
7004    unsafe {
7005        if !(*response).event.is_null() {
7006            let _ = CString::from_raw((*response).event as *mut c_char);
7007        }
7008        if !(*response).reason.is_null() {
7009            let _ = CString::from_raw((*response).reason as *mut c_char);
7010        }
7011        let _ = Box::from_raw(response);
7012    }        
7013}
7014#[repr(C)]
7015pub struct RpcResponseWrapper {
7016    success: bool,
7017    result: *const c_char,
7018    error: *const c_char,
7019    request_id: i32
7020}
7021#[no_mangle]
7022#[tracing::instrument(skip_all)]
7023pub extern "C" fn rpc(
7024    client: *mut ClientWrapper,
7025    options: *mut QueueMessageRequestWrapper,
7026) -> *mut RpcResponseWrapper {
7027    let options = match safe_wrapper(options) {
7028        Some(options) => options,
7029        None => {
7030            let error_msg = CString::new("Invalid options").unwrap().into_raw();
7031            let response = RpcResponseWrapper {
7032                success: false,
7033                result: std::ptr::null(),
7034                error: error_msg,
7035                request_id: 0
7036            };
7037            return Box::into_raw(Box::new(response));
7038        }
7039    };
7040    let client_wrapper = match safe_wrapper(client) {
7041        Some(client) => client,
7042        None => {
7043            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
7044            let response = RpcResponseWrapper {
7045                success: false,
7046                result: std::ptr::null(),
7047                error: error_msg,
7048                request_id: options.request_id
7049            };
7050            return Box::into_raw(Box::new(response));
7051        }
7052    };
7053    let client = client_wrapper.client.clone();
7054
7055    if client.is_none() {
7056        let error_msg = CString::new("Client is not connected").unwrap().into_raw();
7057        let response = RpcResponseWrapper {
7058            success: false,
7059            result: std::ptr::null(),
7060            error: error_msg,
7061            request_id: options.request_id
7062        };
7063        return Box::into_raw(Box::new(response));
7064    }
7065    let client = client.unwrap();
7066    
7067    let result = tokio::task::block_in_place(|| {
7068        let handle = client.get_runtime_handle();
7069        let request = QueueMessageRequest {
7070            queuename: c_char_to_str(options.queuename),
7071            correlation_id: c_char_to_str(options.correlation_id),
7072            replyto: c_char_to_str(options.replyto),
7073            routingkey: c_char_to_str(options.routingkey),
7074            exchangename: c_char_to_str(options.exchangename),
7075            data: c_char_to_str(options.data),
7076            striptoken: options.striptoken,
7077            expiration: options.expiration,
7078        };
7079    
7080        handle.block_on(client.rpc(request))
7081    });
7082
7083    match result {
7084        Ok(data) => {
7085            let result = CString::new(data).unwrap().into_raw();
7086            let response = RpcResponseWrapper {
7087                success: true,
7088                result,
7089                error: std::ptr::null(),
7090                request_id: options.request_id
7091            };
7092            Box::into_raw(Box::new(response))
7093        }
7094        Err(e) => {
7095            let error_msg = CString::new(format!("RPC failed: {:?}", e))
7096                .unwrap()
7097                .into_raw();
7098            // let error_msg = CString::new(format!("RPC failed: {:?}", e))
7099            //     .into_raw();
7100            let response = RpcResponseWrapper {
7101                success: false,
7102                result: std::ptr::null(),
7103                error: error_msg,
7104                request_id: options.request_id
7105            };
7106            Box::into_raw(Box::new(response))
7107        }
7108    }
7109}
7110pub type RpcResponseCallback = extern "C" fn(*mut RpcResponseWrapper);
7111#[no_mangle]
7112#[tracing::instrument(skip_all)]
7113pub extern "C" fn rpc_async(
7114    client: *mut ClientWrapper,
7115    options: *mut QueueMessageRequestWrapper,
7116    response_callback: RpcResponseCallback,
7117) {
7118    // Validate the options pointer
7119    let options = match safe_wrapper(options) {
7120        Some(o) => o,
7121        None => {
7122            let error_msg = CString::new("Invalid options").unwrap().into_raw();
7123            let response = RpcResponseWrapper {
7124                success: false,
7125                result: std::ptr::null(),
7126                error: error_msg,
7127                request_id: 0
7128            };
7129            response_callback(Box::into_raw(Box::new(response)));
7130            return;
7131        }
7132    };
7133
7134    // Validate the client pointer
7135    let client_wrapper = match safe_wrapper(client) {
7136        Some(c) => c,
7137        None => {
7138            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
7139            let response = RpcResponseWrapper {
7140                success: false,
7141                result: std::ptr::null(),
7142                error: error_msg,
7143                request_id: options.request_id
7144            };
7145            response_callback(Box::into_raw(Box::new(response)));
7146            return;
7147        }
7148    };
7149
7150    // Ensure that the client is actually connected.
7151    let client = match client_wrapper.client.clone() {
7152        Some(c) => c,
7153        None => {
7154            let error_msg = CString::new("Client is not connected").unwrap().into_raw();
7155            let response = RpcResponseWrapper {
7156                success: false,
7157                result: std::ptr::null(),
7158                error: error_msg,
7159                request_id: options.request_id
7160            };
7161            response_callback(Box::into_raw(Box::new(response)));
7162            return;
7163        }
7164    };
7165
7166    // Build the QueueMessageRequest from the provided options.
7167    let request = QueueMessageRequest {
7168        queuename: c_char_to_str(options.queuename),
7169        correlation_id: c_char_to_str(options.correlation_id),
7170        replyto: c_char_to_str(options.replyto),
7171        routingkey: c_char_to_str(options.routingkey),
7172        exchangename: c_char_to_str(options.exchangename),
7173        data: c_char_to_str(options.data),
7174        striptoken: options.striptoken,
7175        expiration: options.expiration
7176    };
7177
7178    // Get the runtime handle from the client.
7179    let runtime_handle = client.get_runtime_handle();
7180
7181    let request_id = options.request_id;
7182
7183    // Spawn an asynchronous task using the runtime.
7184    runtime_handle.spawn(async move {
7185        // Await the RPC call.
7186        let result = client.rpc(request).await;
7187
7188        // Build the response wrapper.
7189        let response = match result {
7190            Ok(data) => {
7191                let result_c = CString::new(data).unwrap().into_raw();
7192                RpcResponseWrapper {
7193                    success: true,
7194                    result: result_c,
7195                    error: std::ptr::null(),
7196                    request_id: request_id
7197                }
7198            }
7199            Err(e) => {
7200                let error_msg = CString::new(format!("RPC failed: {:?}", e))
7201                    .unwrap()
7202                    .into_raw();
7203                RpcResponseWrapper {
7204                    success: false,
7205                    result: std::ptr::null(),
7206                    error: error_msg,
7207                    request_id: request_id
7208                }
7209            }
7210        };
7211
7212        // Call the provided callback with the result.
7213        response_callback(Box::into_raw(Box::new(response)));
7214    });
7215}
7216
7217// #[tracing::instrument(skip_all)]
7218// #[no_mangle]
7219// pub extern "C" fn rpc(
7220//     client: *mut ClientWrapper,
7221//     options: *mut QueueMessageRequestWrapper,
7222// ) -> *mut RpcResponseWrapper {
7223//     // Validate input...
7224//     let options = match safe_wrapper(options) {
7225//         Some(options) => options,
7226//         None => {
7227//             let error_msg = CString::new("Invalid options").unwrap().into_raw();
7228//             let response = RpcResponseWrapper {
7229//                 success: false,
7230//                 result: std::ptr::null(),
7231//                 error: error_msg,
7232//             };
7233//             return Box::into_raw(Box::new(response));
7234//         }
7235//     };
7236//     let client_wrapper = match safe_wrapper(client) {
7237//         Some(client) => client,
7238//         None => {
7239//             let error_msg = CString::new("Client is not connected").unwrap().into_raw();
7240//             let response = RpcResponseWrapper {
7241//                 success: false,
7242//                 result: std::ptr::null(),
7243//                 error: error_msg,
7244//             };
7245//             return Box::into_raw(Box::new(response));
7246//         }
7247//     };
7248//     let client = client_wrapper.client.clone();
7249//     if client.is_none() {
7250//         let error_msg = CString::new("Client is not connected").unwrap().into_raw();
7251//         let response = RpcResponseWrapper {
7252//             success: false,
7253//             result: std::ptr::null(),
7254//             error: error_msg,
7255//         };
7256//         return Box::into_raw(Box::new(response));
7257//     }
7258//     let client = client.unwrap();
7259
7260//     // Create owned request values so they're Send
7261//     let request = QueueMessageRequest {
7262//         queuename: c_char_to_str(options.queuename),
7263//         correlation_id: c_char_to_str(options.correlation_id),
7264//         replyto: c_char_to_str(options.replyto),
7265//         routingkey: c_char_to_str(options.routingkey),
7266//         exchangename: c_char_to_str(options.exchangename),
7267//         data: c_char_to_str(options.data),
7268//         striptoken: options.striptoken,
7269//         expiration: options.expiration,
7270//     };
7271
7272//     // Create a new thread to run the async code
7273//     let handle = std::thread::spawn(move || {
7274//         // Create a new runtime in this thread.
7275//         let rt = tokio::runtime::Runtime::new().expect("Failed to create Tokio runtime");
7276//         // Run the async call inside the runtime
7277//         rt.block_on(client.rpc(request))
7278//     });
7279
7280//     // Wait for the thread to complete (this blocks the current thread)
7281//     let result = match handle.join() {
7282//         Ok(result) => result,
7283//         Err(e) => {
7284//             let error_msg = CString::new(format!("Thread panicked: {:?}", e))
7285//                 .unwrap()
7286//                 .into_raw();
7287//             let response = RpcResponseWrapper {
7288//                 success: false,
7289//                 result: std::ptr::null(),
7290//                 error: error_msg,
7291//             };
7292//             return Box::into_raw(Box::new(response));
7293//         }
7294//     };
7295
7296//     match result {
7297//         Ok(data) => {
7298//             let result = CString::new(data).unwrap().into_raw();
7299//             let response = RpcResponseWrapper {
7300//                 success: true,
7301//                 result,
7302//                 error: std::ptr::null(),
7303//             };
7304//             Box::into_raw(Box::new(response))
7305//         }
7306//         Err(e) => {
7307//             let error_msg = CString::new(format!("RPC failed: {:?}", e))
7308//                 .unwrap()
7309//                 .into_raw();
7310//             let response = RpcResponseWrapper {
7311//                 success: false,
7312//                 result: std::ptr::null(),
7313//                 error: error_msg,
7314//             };
7315//             Box::into_raw(Box::new(response))
7316//         }
7317//     }
7318// }
7319
7320#[no_mangle]
7321#[tracing::instrument(skip_all)]
7322pub extern "C" fn free_rpc_response(response: *mut RpcResponseWrapper) {
7323    if response.is_null() {
7324        return;
7325    }
7326    unsafe {
7327        if !(*response).error.is_null() {
7328            let _ = CString::from_raw((*response).error as *mut c_char);
7329        }
7330        if !(*response).result.is_null() {
7331            let _ = CString::from_raw((*response).result as *mut c_char);
7332        }
7333        let _ = Box::from_raw(response);
7334    }
7335}