1use std::sync::Arc;
23
24use jni::JNIEnv;
25use jni::objects::{JClass, JString};
26use jni::sys::{jlong, jboolean, jbyteArray, jstring, jobject};
27use jni::objects::JValue;
28use crate::module_rpc::{RiModuleRPC, RiModuleClient, RiModuleEndpoint, RiMethodCall, RiMethodResponse};
29use crate::java::exception::{check_not_null, throw_ri_error};
30
31fn read_string(env: &mut JNIEnv, value: &JString, arg: &str) -> Option<String> {
34 match env.get_string(value) {
35 Ok(s) => Some(s.into()),
36 Err(e) => {
37 throw_ri_error(env, &format!("Failed to read {arg}: {e}"));
38 None
39 }
40 }
41}
42
43fn read_byte_array(env: &mut JNIEnv, array: jbyteArray, arg: &str) -> Option<Vec<u8>> {
46 if array.is_null() {
47 return Some(Vec::new());
48 }
49 match env.convert_byte_array(unsafe { jni::objects::JByteArray::from_raw(array) }) {
50 Ok(v) => Some(v),
51 Err(e) => {
52 throw_ri_error(env, &format!("Failed to read {arg}: {e}"));
53 None
54 }
55 }
56}
57
58fn write_byte_array(env: &mut JNIEnv, data: &[u8]) -> jbyteArray {
61 match env.byte_array_from_slice(data) {
62 Ok(array) => array.into_raw(),
63 Err(_) => std::ptr::null_mut(),
64 }
65}
66
67unsafe fn clone_rpc_arc(ptr: jlong) -> Option<Arc<RiModuleRPC>> {
75 if ptr == 0 {
76 return None;
77 }
78 let arc = Arc::from_raw(ptr as *const RiModuleRPC);
79 let cloned = arc.clone();
80 let _ = Arc::into_raw(arc);
81 Some(cloned)
82}
83
84#[no_mangle]
89pub extern "system" fn Java_com_dunimd_ri_modulerpc_RiModuleRPC_new0(
90 _env: JNIEnv,
91 _class: JClass,
92) -> jlong {
93 Arc::into_raw(Arc::new(RiModuleRPC::new())) as jlong
94}
95
96#[no_mangle]
97pub extern "system" fn Java_com_dunimd_ri_modulerpc_RiModuleRPC_free0(
98 _env: JNIEnv,
99 _class: JClass,
100 ptr: jlong,
101) {
102 if ptr != 0 {
103 unsafe {
104 let _ = Arc::from_raw(ptr as *const RiModuleRPC);
105 }
106 }
107}
108
109#[no_mangle]
114pub extern "system" fn Java_com_dunimd_ri_modulerpc_RiModuleClient_new0(
115 mut env: JNIEnv,
116 _class: JClass,
117 rpc_ptr: jlong,
118) -> jlong {
119 match unsafe { clone_rpc_arc(rpc_ptr) } {
120 Some(arc) => Box::into_raw(Box::new(RiModuleClient::new(arc))) as jlong,
121 None => {
122 throw_ri_error(&mut env, "RiModuleRPC pointer is null");
123 0
124 }
125 }
126}
127
128#[no_mangle]
129pub extern "system" fn Java_com_dunimd_ri_modulerpc_RiModuleClient_call0(
130 mut env: JNIEnv,
131 _class: JClass,
132 ptr: jlong,
133 module_name: JString,
134 method_name: JString,
135 params: jbyteArray,
136) -> jlong {
137 if !check_not_null(&mut env, ptr, "RiModuleClient") {
138 return 0;
139 }
140 let (Some(module), Some(method), Some(params_vec)) = (
141 read_string(&mut env, &module_name, "module name"),
142 read_string(&mut env, &method_name, "method name"),
143 read_byte_array(&mut env, params, "params"),
144 ) else {
145 return 0;
146 };
147
148 let client = unsafe { &*(ptr as *const RiModuleClient) };
149 crate::java::runtime::block_on_jni(&mut env, "RiModuleClient::call", async move {
150 client.call(&module, &method, params_vec).await
151 })
152 .map(|response| Box::into_raw(Box::new(response)) as jlong)
153 .unwrap_or(0)
154}
155
156#[no_mangle]
157pub extern "system" fn Java_com_dunimd_ri_modulerpc_RiModuleClient_callWithTimeout0(
158 mut env: JNIEnv,
159 _class: JClass,
160 ptr: jlong,
161 module_name: JString,
162 method_name: JString,
163 params: jbyteArray,
164 timeout_ms: jlong,
165) -> jlong {
166 if !check_not_null(&mut env, ptr, "RiModuleClient") {
167 return 0;
168 }
169 let (Some(module), Some(method), Some(params_vec)) = (
170 read_string(&mut env, &module_name, "module name"),
171 read_string(&mut env, &method_name, "method name"),
172 read_byte_array(&mut env, params, "params"),
173 ) else {
174 return 0;
175 };
176 let timeout = crate::java::runtime::ttl_from_jlong(timeout_ms).unwrap_or(5000);
177
178 let client = unsafe { &*(ptr as *const RiModuleClient) };
179 crate::java::runtime::block_on_jni(&mut env, "RiModuleClient::call_with_timeout", async move {
180 client
181 .call_with_timeout(&module, &method, params_vec, timeout)
182 .await
183 })
184 .map(|response| Box::into_raw(Box::new(response)) as jlong)
185 .unwrap_or(0)
186}
187
188#[no_mangle]
189pub extern "system" fn Java_com_dunimd_ri_modulerpc_RiModuleClient_free0(
190 _env: JNIEnv,
191 _class: JClass,
192 ptr: jlong,
193) {
194 if ptr != 0 {
195 unsafe {
196 let _ = Box::from_raw(ptr as *mut RiModuleClient);
197 }
198 }
199}
200
201#[no_mangle]
206pub extern "system" fn Java_com_dunimd_ri_modulerpc_RiModuleEndpoint_new0(
207 mut env: JNIEnv,
208 _class: JClass,
209 module_name: JString,
210) -> jlong {
211 let Some(module) = read_string(&mut env, &module_name, "module name") else {
212 return 0;
213 };
214
215 let endpoint = Box::new(RiModuleEndpoint::new(&module));
216 Box::into_raw(endpoint) as jlong
217}
218
219#[no_mangle]
220pub extern "system" fn Java_com_dunimd_ri_modulerpc_RiModuleEndpoint_getModuleName0<'local>(
221 mut env: JNIEnv<'local>,
222 _class: JClass<'local>,
223 ptr: jlong,
224) -> jstring {
225 if !check_not_null(&mut env, ptr, "RiModuleEndpoint") {
226 return std::ptr::null_mut();
227 }
228
229 let endpoint = unsafe { &*(ptr as *const RiModuleEndpoint) };
230 match env.new_string(endpoint.module_name()) {
231 Ok(s) => s.into_raw(),
232 Err(_) => std::ptr::null_mut(),
233 }
234}
235
236#[no_mangle]
237pub extern "system" fn Java_com_dunimd_ri_modulerpc_RiModuleEndpoint_listMethods0<'local>(
238 mut env: JNIEnv<'local>,
239 _class: JClass<'local>,
240 ptr: jlong,
241) -> jobject {
242 if !check_not_null(&mut env, ptr, "RiModuleEndpoint") {
243 return std::ptr::null_mut();
244 }
245
246 let endpoint = unsafe { &*(ptr as *const RiModuleEndpoint) };
247 let methods = futures::executor::block_on(endpoint.list_methods());
248
249 let Ok(list) = env.new_object("java/util/ArrayList", "()V", &[]) else {
251 return std::ptr::null_mut();
252 };
253 for method in methods.iter() {
254 let Ok(s) = env.new_string(method) else {
255 continue;
256 };
257 let _ = env.call_method(
258 &list,
259 "add",
260 "(Ljava/lang/Object;)Z",
261 &[JValue::Object(&s)],
262 );
263 }
264 list.into_raw()
265}
266
267#[no_mangle]
268pub extern "system" fn Java_com_dunimd_ri_modulerpc_RiModuleEndpoint_free0(
269 _env: JNIEnv,
270 _class: JClass,
271 ptr: jlong,
272) {
273 if ptr != 0 {
274 unsafe {
275 let _ = Box::from_raw(ptr as *mut RiModuleEndpoint);
276 }
277 }
278}
279
280#[no_mangle]
285pub extern "system" fn Java_com_dunimd_ri_modulerpc_RiMethodCall_new0(
286 mut env: JNIEnv,
287 _class: JClass,
288 method_name: JString,
289 params: jbyteArray,
290) -> jlong {
291 let (Some(method), Some(params_vec)) = (
292 read_string(&mut env, &method_name, "method name"),
293 read_byte_array(&mut env, params, "params"),
294 ) else {
295 return 0;
296 };
297
298 let call = Box::new(RiMethodCall::new(method, params_vec));
299 Box::into_raw(call) as jlong
300}
301
302#[no_mangle]
303pub extern "system" fn Java_com_dunimd_ri_modulerpc_RiMethodCall_getMethodName0<'local>(
304 mut env: JNIEnv<'local>,
305 _class: JClass<'local>,
306 ptr: jlong,
307) -> jstring {
308 if !check_not_null(&mut env, ptr, "RiMethodCall") {
309 return std::ptr::null_mut();
310 }
311
312 let call = unsafe { &*(ptr as *const RiMethodCall) };
313 match env.new_string(&call.method_name) {
314 Ok(s) => s.into_raw(),
315 Err(_) => std::ptr::null_mut(),
316 }
317}
318
319#[no_mangle]
320pub extern "system" fn Java_com_dunimd_ri_modulerpc_RiMethodCall_getParams0(
321 mut env: JNIEnv,
322 _class: JClass,
323 ptr: jlong,
324) -> jbyteArray {
325 if !check_not_null(&mut env, ptr, "RiMethodCall") {
326 return std::ptr::null_mut();
327 }
328
329 let call = unsafe { &*(ptr as *const RiMethodCall) };
330 write_byte_array(&mut env, &call.params)
331}
332
333#[no_mangle]
334pub extern "system" fn Java_com_dunimd_ri_modulerpc_RiMethodCall_getTimeoutMs0(
335 mut env: JNIEnv,
336 _class: JClass,
337 ptr: jlong,
338) -> jlong {
339 if !check_not_null(&mut env, ptr, "RiMethodCall") {
340 return 0;
341 }
342
343 let call = unsafe { &*(ptr as *const RiMethodCall) };
344 call.timeout_ms as jlong
345}
346
347#[no_mangle]
348pub extern "system" fn Java_com_dunimd_ri_modulerpc_RiMethodCall_setTimeoutMs0(
349 mut env: JNIEnv,
350 _class: JClass,
351 ptr: jlong,
352 timeout_ms: jlong,
353) {
354 if !check_not_null(&mut env, ptr, "RiMethodCall") {
355 return;
356 }
357
358 let call = unsafe { &mut *(ptr as *mut RiMethodCall) };
359 call.timeout_ms = timeout_ms.max(0) as u64;
360}
361
362#[no_mangle]
363pub extern "system" fn Java_com_dunimd_ri_modulerpc_RiMethodCall_free0(
364 _env: JNIEnv,
365 _class: JClass,
366 ptr: jlong,
367) {
368 if ptr != 0 {
369 unsafe {
370 let _ = Box::from_raw(ptr as *mut RiMethodCall);
371 }
372 }
373}
374
375#[no_mangle]
380pub extern "system" fn Java_com_dunimd_ri_modulerpc_RiMethodResponse_isSuccess0(
381 mut env: JNIEnv,
382 _class: JClass,
383 ptr: jlong,
384) -> jboolean {
385 if !check_not_null(&mut env, ptr, "RiMethodResponse") {
386 return 0;
387 }
388
389 let response = unsafe { &*(ptr as *const RiMethodResponse) };
390 response.success as jboolean
391}
392
393#[no_mangle]
394pub extern "system" fn Java_com_dunimd_ri_modulerpc_RiMethodResponse_getData0(
395 mut env: JNIEnv,
396 _class: JClass,
397 ptr: jlong,
398) -> jbyteArray {
399 if !check_not_null(&mut env, ptr, "RiMethodResponse") {
400 return std::ptr::null_mut();
401 }
402
403 let response = unsafe { &*(ptr as *const RiMethodResponse) };
404 write_byte_array(&mut env, &response.data)
405}
406
407#[no_mangle]
408pub extern "system" fn Java_com_dunimd_ri_modulerpc_RiMethodResponse_getError0<'local>(
409 mut env: JNIEnv<'local>,
410 _class: JClass<'local>,
411 ptr: jlong,
412) -> jstring {
413 if !check_not_null(&mut env, ptr, "RiMethodResponse") {
414 return std::ptr::null_mut();
415 }
416
417 let response = unsafe { &*(ptr as *const RiMethodResponse) };
418 match env.new_string(&response.error) {
419 Ok(s) => s.into_raw(),
420 Err(_) => std::ptr::null_mut(),
421 }
422}
423
424#[no_mangle]
425pub extern "system" fn Java_com_dunimd_ri_modulerpc_RiMethodResponse_isTimeout0(
426 mut env: JNIEnv,
427 _class: JClass,
428 ptr: jlong,
429) -> jboolean {
430 if !check_not_null(&mut env, ptr, "RiMethodResponse") {
431 return 0;
432 }
433
434 let response = unsafe { &*(ptr as *const RiMethodResponse) };
435 response.is_timeout as jboolean
436}
437
438#[no_mangle]
439pub extern "system" fn Java_com_dunimd_ri_modulerpc_RiMethodResponse_free0(
440 _env: JNIEnv,
441 _class: JClass,
442 ptr: jlong,
443) {
444 if ptr != 0 {
445 unsafe {
446 let _ = Box::from_raw(ptr as *mut RiMethodResponse);
447 }
448 }
449}