openiap_clib/
lib.rs

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