Merge pull request #16 from MolotovCherry/main

windows support
This commit is contained in:
Kavin 2023-08-04 01:10:01 +01:00 committed by GitHub
commit 41073ce8d5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 84 additions and 37 deletions

View file

@ -8,4 +8,5 @@ rust {
targets += target("aarch64-unknown-linux-gnu", "libreqwest.so") targets += target("aarch64-unknown-linux-gnu", "libreqwest.so")
targets += target("x86_64-unknown-linux-gnu", "libreqwest.so") targets += target("x86_64-unknown-linux-gnu", "libreqwest.so")
targets += target("x86_64-pc-windows-gnu", "libreqwest.dll")
} }

View file

@ -1,9 +1,9 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::OnceLock; use std::sync::OnceLock;
use jni::JNIEnv;
use jni::objects::{JByteArray, JClass, JMap, JObject, JString}; use jni::objects::{JByteArray, JClass, JMap, JObject, JString};
use jni::sys::jobject; use jni::sys::jobject;
use jni::JNIEnv;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use reqwest::{Client, Method, Url}; use reqwest::{Client, Method, Url};
use tokio::runtime::Runtime; use tokio::runtime::Runtime;
@ -26,13 +26,10 @@ pub extern "system" fn Java_rocks_kavin_reqwest4j_ReqwestUtils_init(
let proxy = reqwest::Proxy::all(proxy).unwrap(); let proxy = reqwest::Proxy::all(proxy).unwrap();
builder.proxy(proxy) builder.proxy(proxy)
} }
Err(_) => { Err(_) => builder,
builder
}
}; };
let client = builder.build() let client = builder.build().unwrap();
.unwrap();
CLIENT.set(client).unwrap(); CLIENT.set(client).unwrap();
} }
@ -45,7 +42,6 @@ pub extern "system" fn Java_rocks_kavin_reqwest4j_ReqwestUtils_fetch(
body: JByteArray, body: JByteArray,
headers: JObject, headers: JObject,
) -> jobject { ) -> jobject {
// set method, url, body, headers // set method, url, body, headers
let method = Method::from_bytes(env.get_string(&method).unwrap().to_bytes()).unwrap(); let method = Method::from_bytes(env.get_string(&method).unwrap().to_bytes()).unwrap();
@ -53,7 +49,11 @@ pub extern "system" fn Java_rocks_kavin_reqwest4j_ReqwestUtils_fetch(
let url = url.to_str(); let url = url.to_str();
if url.is_err() { if url.is_err() {
env.throw_new("java/lang/IllegalArgumentException", "Invalid URL provided, couldn't get string as UTF-8").unwrap(); env.throw_new(
"java/lang/IllegalArgumentException",
"Invalid URL provided, couldn't get string as UTF-8",
)
.unwrap();
return JObject::null().into_raw(); return JObject::null().into_raw();
} }
@ -64,15 +64,24 @@ pub extern "system" fn Java_rocks_kavin_reqwest4j_ReqwestUtils_fetch(
let mut headers = HashMap::new(); let mut headers = HashMap::new();
while let Some((key, value)) = java_headers.next(&mut env).unwrap() { while let Some((key, value)) = java_headers.next(&mut env).unwrap() {
headers.insert( headers.insert(
env.get_string(&JString::from(key)).unwrap().to_str().unwrap().to_string(), env.get_string(&JString::from(key))
env.get_string(&JString::from(value)).unwrap().to_str().unwrap().to_string(), .unwrap()
.to_str()
.unwrap()
.to_string(),
env.get_string(&JString::from(value))
.unwrap()
.to_str()
.unwrap()
.to_string(),
); );
} }
let client = CLIENT.get(); let client = CLIENT.get();
if client.is_none() { if client.is_none() {
env.throw_new("java/lang/IllegalStateException", "Client not initialized").unwrap(); env.throw_new("java/lang/IllegalStateException", "Client not initialized")
.unwrap();
return JObject::null().into_raw(); return JObject::null().into_raw();
} }
@ -80,9 +89,9 @@ pub extern "system" fn Java_rocks_kavin_reqwest4j_ReqwestUtils_fetch(
let request = client.request(method, url); let request = client.request(method, url);
let request = headers.into_iter().fold(request, |request, (key, value)| { let request = headers
request.header(key, value) .into_iter()
}); .fold(request, |request, (key, value)| request.header(key, value));
let request = if body.is_empty() { let request = if body.is_empty() {
request request
@ -94,14 +103,14 @@ pub extern "system" fn Java_rocks_kavin_reqwest4j_ReqwestUtils_fetch(
let jvm = env.get_java_vm().unwrap(); let jvm = env.get_java_vm().unwrap();
// create CompletableFuture // create CompletableFuture
let _future = env.new_object("java/util/concurrent/CompletableFuture", "()V", &[]).unwrap(); let _future = env
.new_object("java/util/concurrent/CompletableFuture", "()V", &[])
.unwrap();
let future = env.new_global_ref(&_future).unwrap(); let future = env.new_global_ref(&_future).unwrap();
RUNTIME.spawn_blocking(move || { RUNTIME.spawn_blocking(move || {
// send request // send request
let response = RUNTIME.block_on(async { let response = RUNTIME.block_on(async { request.send().await });
request.send().await
});
let mut env = jvm.attach_current_thread().unwrap(); let mut env = jvm.attach_current_thread().unwrap();
@ -109,12 +118,22 @@ pub extern "system" fn Java_rocks_kavin_reqwest4j_ReqwestUtils_fetch(
let error = error.to_string(); let error = error.to_string();
let error = env.new_string(error).unwrap(); let error = env.new_string(error).unwrap();
// create Exception // create Exception
let exception = env.new_object("java/lang/Exception", "(Ljava/lang/String;)V", &[ let exception = env
(&error).into(), .new_object(
]).unwrap(); "java/lang/Exception",
"(Ljava/lang/String;)V",
&[(&error).into()],
)
.unwrap();
// pass error to CompletableFuture // pass error to CompletableFuture
env.call_method(future, "completeExceptionally", "(Ljava/lang/Throwable;)Z", &[(&exception).into()]).unwrap(); env.call_method(
return (); future,
"completeExceptionally",
"(Ljava/lang/Throwable;)Z",
&[(&exception).into()],
)
.unwrap();
return;
} }
let response = response.unwrap(); let response = response.unwrap();
@ -128,29 +147,41 @@ pub extern "system" fn Java_rocks_kavin_reqwest4j_ReqwestUtils_fetch(
response.headers().iter().for_each(|(key, value)| { response.headers().iter().for_each(|(key, value)| {
let key = env.new_string(key.as_str()).unwrap(); let key = env.new_string(key.as_str()).unwrap();
let value = env.new_string(value.to_str().unwrap()).unwrap(); let value = env.new_string(value.to_str().unwrap()).unwrap();
headers.put(&mut env, &JObject::from(key), &JObject::from(value)).unwrap(); headers
.put(&mut env, &JObject::from(key), &JObject::from(value))
.unwrap();
}); });
let final_url = response.url().to_string(); let final_url = response.url().to_string();
let final_url = env.new_string(final_url).unwrap(); let final_url = env.new_string(final_url).unwrap();
let body = RUNTIME.block_on(async { let body = RUNTIME.block_on(async { response.bytes().await.unwrap_or_default().to_vec() });
response.bytes().await.unwrap_or_default().to_vec()
});
let body = env.byte_array_from_slice(&body).unwrap(); let body = env.byte_array_from_slice(&body).unwrap();
// return response to CompletableFuture // return response to CompletableFuture
let response = env.new_object("rocks/kavin/reqwest4j/Response", "(ILjava/util/Map;[BLjava/lang/String;)V", &[ let response = env
.new_object(
"rocks/kavin/reqwest4j/Response",
"(ILjava/util/Map;[BLjava/lang/String;)V",
&[
status.into(), status.into(),
(&headers).into(), (&headers).into(),
(&body).into(), (&body).into(),
(&final_url).into(), (&final_url).into(),
]).unwrap(); ],
)
.unwrap();
let future = future.as_obj(); let future = future.as_obj();
env.call_method(future, "complete", "(Ljava/lang/Object;)Z", &[(&response).into()]).unwrap(); env.call_method(
future,
"complete",
"(Ljava/lang/Object;)Z",
&[(&response).into()],
)
.unwrap();
}); });
return _future.into_raw(); _future.into_raw()
} }

View file

@ -15,10 +15,25 @@ public class ReqwestUtils {
default -> throw new RuntimeException("Unsupported architecture"); default -> throw new RuntimeException("Unsupported architecture");
}; };
String os = System.getProperty("os.name").toLowerCase();
String extension;
String native_folder;
if (os.contains("win")) {
extension = ".dll";
native_folder = "windows";
} else if (os.contains("linux")) {
extension = ".so";
native_folder = "linux";
} else {
throw new RuntimeException("OS not supported");
}
File nativeFile; File nativeFile;
try { try {
nativeFile = File.createTempFile("libreqwest", ".so"); nativeFile = File.createTempFile("libreqwest", extension);
nativeFile.deleteOnExit(); nativeFile.deleteOnExit();
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
@ -26,7 +41,7 @@ public class ReqwestUtils {
final var cl = ReqwestUtils.class.getClassLoader(); final var cl = ReqwestUtils.class.getClassLoader();
try (var stream = cl.getResourceAsStream("META-INF/natives/linux/" + arch + "/libreqwest.so")) { try (var stream = cl.getResourceAsStream("META-INF/natives/" + native_folder + "/" + arch + "/libreqwest" + extension)) {
stream.transferTo(new FileOutputStream(nativeFile)); stream.transferTo(new FileOutputStream(nativeFile));
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);