openiap_clib/
lib.rs

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