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