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