1#![allow(unsafe_code)]
6
7use crate::server::MockServer;
8use std::ffi::{CStr, CString};
9use std::os::raw::c_char;
10use std::ptr;
11use std::sync::Arc;
12use tokio::runtime::Runtime;
13use tokio::sync::Mutex;
14
15pub struct MockServerHandle {
17 server: Arc<Mutex<MockServer>>,
18 runtime: Runtime,
19}
20
21#[no_mangle]
26pub unsafe extern "C" fn mockforge_server_new(port: u16) -> *mut MockServerHandle {
27 let runtime = match Runtime::new() {
28 Ok(rt) => rt,
29 Err(_) => return ptr::null_mut(),
30 };
31
32 let server = runtime.block_on(async { MockServer::new().port(port).start().await });
34
35 let server = match server {
36 Ok(s) => s,
37 Err(_) => return ptr::null_mut(),
38 };
39
40 let handle = MockServerHandle {
41 server: Arc::new(Mutex::new(server)),
42 runtime,
43 };
44
45 Box::into_raw(Box::new(handle))
46}
47
48#[no_mangle]
53pub unsafe extern "C" fn mockforge_server_destroy(handle: *mut MockServerHandle) {
54 if handle.is_null() {
55 return;
56 }
57
58 let handle = Box::from_raw(handle);
59 let server = handle.server.clone();
60
61 handle.runtime.block_on(async move {
62 let mut server = server.lock().await;
63 let _ = std::mem::take(&mut *server).stop().await;
64 });
65}
66
67#[no_mangle]
74pub unsafe extern "C" fn mockforge_server_stub(
75 handle: *mut MockServerHandle,
76 method: *const c_char,
77 path: *const c_char,
78 status: u16,
79 body: *const c_char,
80) -> i32 {
81 if handle.is_null() || method.is_null() || path.is_null() || body.is_null() {
82 return -1;
83 }
84
85 let handle = &*handle;
86
87 let method = match CStr::from_ptr(method).to_str() {
88 Ok(s) => s,
89 Err(_) => return -1,
90 };
91
92 let path = match CStr::from_ptr(path).to_str() {
93 Ok(s) => s,
94 Err(_) => return -1,
95 };
96
97 let body = match CStr::from_ptr(body).to_str() {
98 Ok(s) => s,
99 Err(_) => return -1,
100 };
101
102 let body_value: serde_json::Value = match serde_json::from_str(body) {
103 Ok(v) => v,
104 Err(_) => return -1,
105 };
106
107 let server = handle.server.clone();
108 let result = handle.runtime.block_on(async move {
109 let mut server = server.lock().await;
110 server.stub_response(method, path, body_value).await
111 });
112
113 match result {
114 Ok(_) => 0,
115 Err(_) => -1,
116 }
117}
118
119#[no_mangle]
125pub unsafe extern "C" fn mockforge_server_url(handle: *const MockServerHandle) -> *mut c_char {
126 if handle.is_null() {
127 return ptr::null_mut();
128 }
129
130 let handle = &*handle;
131 let server = handle.server.clone();
132
133 let url = handle.runtime.block_on(async move {
134 let server = server.lock().await;
135 server.url()
136 });
137
138 match CString::new(url) {
139 Ok(s) => s.into_raw(),
140 Err(_) => ptr::null_mut(),
141 }
142}
143
144#[no_mangle]
149pub unsafe extern "C" fn mockforge_free_string(s: *mut c_char) {
150 if !s.is_null() {
151 let _ = CString::from_raw(s);
152 }
153}
154
155#[no_mangle]
160pub unsafe extern "C" fn mockforge_last_error() -> *mut c_char {
161 ptr::null_mut()
163}