mirror of
https://github.com/TeamPiped/reqwest4j.git
synced 2024-08-14 23:54:39 +00:00
Compare commits
67 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4df5c18721 | ||
|
|
45e38e0e91 | ||
|
|
160b6565f5 | ||
|
|
6961ffaebb | ||
|
|
8944b04def | ||
|
|
b4c5d8fde6 | ||
|
|
d4d275c466 | ||
|
|
b63ad1eeca | ||
|
|
912e312361 | ||
|
|
f0492d094e | ||
|
|
44a3794c6c | ||
|
|
c1954425a8 | ||
|
|
1b29ee314c | ||
|
|
6f1f4f7357 | ||
|
|
16c1e705db | ||
|
|
b594d71860 | ||
|
|
8af02b0b70 | ||
|
|
f2b86d2dde | ||
|
|
1423005cd1 | ||
|
|
d5b8bd46ae | ||
|
|
12b7aa3a46 | ||
|
|
452519987a | ||
|
|
de6f9e7c90 | ||
|
|
f6d5000750 | ||
|
|
ea12d11343 | ||
|
|
5a0e34ed3e | ||
|
|
0b58ffbb76 | ||
|
|
bdedb3e79b | ||
|
|
6ad484fcec | ||
|
|
54ea93a1a4 | ||
|
|
5408d34a22 | ||
|
|
bfd4ac68e6 | ||
|
|
36106ff373 | ||
|
|
7e08097657 | ||
|
|
2aa53ae682 | ||
|
|
207078caee | ||
|
|
52bb8f76e4 | ||
|
|
e1088e76bc | ||
|
|
f6cdafe9f5 | ||
|
|
330a2dd8f9 | ||
|
|
b3f224e9e9 | ||
|
|
244119c1c7 | ||
|
|
dd7fb60064 | ||
|
|
122270a92a | ||
|
|
9d5b9ae4b8 | ||
|
|
88630df150 | ||
|
|
c40f40ce18 | ||
|
|
2c81e10652 | ||
|
|
31bfff42e3 | ||
|
|
b48dab9a97 | ||
|
|
4eafc585a2 | ||
|
|
2d2a00e50b | ||
|
|
3d7d8456d3 | ||
|
|
12b61f0967 | ||
|
|
ea03b98c3e | ||
|
|
2af849dc8f | ||
|
|
b7b9c918a8 | ||
|
|
70b4734f3d | ||
|
|
7d686cff56 | ||
|
|
41073ce8d5 | ||
|
|
fdca2569ec | ||
|
|
e41411d9ec | ||
|
|
29cf27d24f | ||
|
|
da5a77e2f0 | ||
|
|
eb46230403 | ||
|
|
75cfd8dadd | ||
|
|
4d463b5a3e |
13 changed files with 797 additions and 400 deletions
30
.github/workflows/ci.yml
vendored
Normal file
30
.github/workflows/ci.yml
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
java: [ 21 ]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
|
- uses: Swatinem/rust-cache@v2
|
||||||
|
with:
|
||||||
|
workspaces: |
|
||||||
|
reqwest-jni
|
||||||
|
- run: cargo install cross
|
||||||
|
- name: set up JDK ${{ matrix.java }}
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
java-version: ${{ matrix.java }}
|
||||||
|
distribution: zulu
|
||||||
|
cache: "gradle"
|
||||||
|
- name: Run Build
|
||||||
|
run: ./gradlew shadowJar
|
||||||
9
.github/workflows/publish-maven.yml
vendored
9
.github/workflows/publish-maven.yml
vendored
|
|
@ -12,17 +12,18 @@ jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
- uses: Swatinem/rust-cache@v2
|
- uses: Swatinem/rust-cache@v2
|
||||||
with:
|
with:
|
||||||
workspaces: |
|
workspaces: |
|
||||||
reqwest-jni
|
reqwest-jni
|
||||||
- run: cargo install cross
|
- run: cargo install cross
|
||||||
- name: set up JDK
|
- name: set up JDK
|
||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
java-version: 17
|
java-version: 21
|
||||||
distribution: temurin
|
distribution: zulu
|
||||||
check-latest: true
|
check-latest: true
|
||||||
cache: "gradle"
|
cache: "gradle"
|
||||||
- name: Save Private Key
|
- name: Save Private Key
|
||||||
|
|
|
||||||
16
build.gradle
16
build.gradle
|
|
@ -3,7 +3,7 @@ plugins {
|
||||||
id "maven-publish"
|
id "maven-publish"
|
||||||
id "signing"
|
id "signing"
|
||||||
id "fr.stardustenterprises.rust.importer" version "3.2.5"
|
id "fr.stardustenterprises.rust.importer" version "3.2.5"
|
||||||
id 'com.github.johnrengelman.shadow' version '7.1.2'
|
id 'com.github.johnrengelman.shadow' version '8.1.1'
|
||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
|
|
@ -17,14 +17,14 @@ dependencies {
|
||||||
// javac -h
|
// javac -h
|
||||||
tasks.register('generateJniHeaders', JavaCompile) {
|
tasks.register('generateJniHeaders', JavaCompile) {
|
||||||
classpath = sourceSets.main.compileClasspath
|
classpath = sourceSets.main.compileClasspath
|
||||||
destinationDir file("${buildDir}/generated/jni")
|
destinationDir file("${layout.buildDirectory}/generated/jni")
|
||||||
source = sourceSets.main.java
|
source = sourceSets.main.java
|
||||||
options.compilerArgs += [
|
options.compilerArgs += [
|
||||||
'-h', file("${buildDir}/generated/jni"),
|
'-h', file("${layout.buildDirectory}/generated/jni"),
|
||||||
'-d', file("${buildDir}/generated/jni-classes"),
|
'-d', file("${layout.buildDirectory}/generated/jni-classes"),
|
||||||
]
|
]
|
||||||
doLast {
|
doLast {
|
||||||
delete file("${buildDir}/generated/jni-classes")
|
delete file("${layout.buildDirectory}/generated/jni-classes")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -36,6 +36,8 @@ rustImport {
|
||||||
java {
|
java {
|
||||||
withSourcesJar()
|
withSourcesJar()
|
||||||
withJavadocJar()
|
withJavadocJar()
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_21
|
||||||
|
targetCompatibility = JavaVersion.VERSION_21
|
||||||
}
|
}
|
||||||
|
|
||||||
signing {
|
signing {
|
||||||
|
|
@ -43,9 +45,7 @@ signing {
|
||||||
}
|
}
|
||||||
|
|
||||||
group = 'rocks.kavin'
|
group = 'rocks.kavin'
|
||||||
version = '1.0.4'
|
version = '1.0.14'
|
||||||
sourceCompatibility = JavaVersion.VERSION_17
|
|
||||||
targetCompatibility = JavaVersion.VERSION_17
|
|
||||||
|
|
||||||
publishing {
|
publishing {
|
||||||
repositories {
|
repositories {
|
||||||
|
|
|
||||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
3
gradle/wrapper/gradle-wrapper.properties
vendored
3
gradle/wrapper/gradle-wrapper.properties
vendored
|
|
@ -1,6 +1,7 @@
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://downloads.gradle.org/distributions/gradle-7.6-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|
|
||||||
34
gradlew
vendored
34
gradlew
vendored
|
|
@ -15,6 +15,8 @@
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
#
|
#
|
||||||
|
|
@ -55,7 +57,7 @@
|
||||||
# Darwin, MinGW, and NonStop.
|
# Darwin, MinGW, and NonStop.
|
||||||
#
|
#
|
||||||
# (3) This script is generated from the Groovy template
|
# (3) This script is generated from the Groovy template
|
||||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
# within the Gradle project.
|
# within the Gradle project.
|
||||||
#
|
#
|
||||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
|
|
@ -83,10 +85,9 @@ done
|
||||||
# This is normally unused
|
# This is normally unused
|
||||||
# shellcheck disable=SC2034
|
# shellcheck disable=SC2034
|
||||||
APP_BASE_NAME=${0##*/}
|
APP_BASE_NAME=${0##*/}
|
||||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||||
|
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
|
||||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
' "$PWD" ) || exit
|
||||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
MAX_FD=maximum
|
MAX_FD=maximum
|
||||||
|
|
@ -133,10 +134,13 @@ location of your Java installation."
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
JAVACMD=java
|
JAVACMD=java
|
||||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
if ! command -v java >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
location of your Java installation."
|
location of your Java installation."
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Increase the maximum file descriptors if we can.
|
# Increase the maximum file descriptors if we can.
|
||||||
|
|
@ -144,7 +148,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||||
case $MAX_FD in #(
|
case $MAX_FD in #(
|
||||||
max*)
|
max*)
|
||||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||||
# shellcheck disable=SC3045
|
# shellcheck disable=SC2039,SC3045
|
||||||
MAX_FD=$( ulimit -H -n ) ||
|
MAX_FD=$( ulimit -H -n ) ||
|
||||||
warn "Could not query maximum file descriptor limit"
|
warn "Could not query maximum file descriptor limit"
|
||||||
esac
|
esac
|
||||||
|
|
@ -152,7 +156,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||||
'' | soft) :;; #(
|
'' | soft) :;; #(
|
||||||
*)
|
*)
|
||||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||||
# shellcheck disable=SC3045
|
# shellcheck disable=SC2039,SC3045
|
||||||
ulimit -n "$MAX_FD" ||
|
ulimit -n "$MAX_FD" ||
|
||||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||||
esac
|
esac
|
||||||
|
|
@ -197,11 +201,15 @@ if "$cygwin" || "$msys" ; then
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Collect all arguments for the java command;
|
|
||||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
# shell script including quotes and variable substitutions, so put them in
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
# double quotes to make sure that they get re-expanded; and
|
|
||||||
# * put everything else in single quotes, so that it's not re-expanded.
|
# Collect all arguments for the java command:
|
||||||
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||||
|
# and any embedded shellness will be escaped.
|
||||||
|
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||||
|
# treated as '${Hostname}' itself on the command line.
|
||||||
|
|
||||||
set -- \
|
set -- \
|
||||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
|
|
|
||||||
22
gradlew.bat
vendored
22
gradlew.bat
vendored
|
|
@ -13,6 +13,8 @@
|
||||||
@rem See the License for the specific language governing permissions and
|
@rem See the License for the specific language governing permissions and
|
||||||
@rem limitations under the License.
|
@rem limitations under the License.
|
||||||
@rem
|
@rem
|
||||||
|
@rem SPDX-License-Identifier: Apache-2.0
|
||||||
|
@rem
|
||||||
|
|
||||||
@if "%DEBUG%"=="" @echo off
|
@if "%DEBUG%"=="" @echo off
|
||||||
@rem ##########################################################################
|
@rem ##########################################################################
|
||||||
|
|
@ -43,11 +45,11 @@ set JAVA_EXE=java.exe
|
||||||
%JAVA_EXE% -version >NUL 2>&1
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
if %ERRORLEVEL% equ 0 goto execute
|
if %ERRORLEVEL% equ 0 goto execute
|
||||||
|
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
echo location of your Java installation.
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
|
|
@ -57,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
if exist "%JAVA_EXE%" goto execute
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
echo location of your Java installation.
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,5 @@
|
||||||
"automerge": true,
|
"automerge": true,
|
||||||
"platformAutomerge": true
|
"platformAutomerge": true
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"enabledManagers": ["cargo", "github-actions"]
|
}
|
||||||
}
|
|
||||||
|
|
|
||||||
802
reqwest-jni/Cargo.lock
generated
802
reqwest-jni/Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -7,9 +7,11 @@ edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
jni = "0.21.1"
|
jni = "0.21.1"
|
||||||
reqwest = {version = "0.11.18", features = ["rustls-tls", "stream", "brotli", "gzip"], default-features = false}
|
reqwest = {version = "0.12.4", features = ["rustls-tls", "stream", "brotli", "gzip", "socks"], default-features = false}
|
||||||
tokio = {version = "1.28.2", features = ["full"]}
|
tokio = {version = "1.37.0", features = ["rt-multi-thread", "time"], default-features = false}
|
||||||
once_cell = "1.18.0"
|
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
crate-type = ["cdylib"]
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
lto = true
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,55 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::sync::{Arc, OnceLock};
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
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 once_cell::sync::Lazy;
|
use jni::JNIEnv;
|
||||||
use reqwest::{Client, Method, Url};
|
use reqwest::{Client, Method, Url};
|
||||||
use tokio::runtime::Runtime;
|
use tokio::runtime::Runtime;
|
||||||
|
|
||||||
static RUNTIME: Lazy<Runtime> = Lazy::new(|| Runtime::new().unwrap());
|
static RUNTIME: OnceLock<Runtime> = OnceLock::new();
|
||||||
static CLIENT: Lazy<Client> = Lazy::new(||
|
static CLIENT: OnceLock<Client> = OnceLock::new();
|
||||||
Client::builder()
|
|
||||||
.user_agent("Mozilla/5.0 (Windows NT 10.0; rv:102.0) Gecko/20100101 Firefox/102.0")
|
#[no_mangle]
|
||||||
|
pub extern "system" fn Java_rocks_kavin_reqwest4j_ReqwestUtils_init(
|
||||||
|
mut env: JNIEnv,
|
||||||
|
_: JClass,
|
||||||
|
proxy: JString,
|
||||||
|
user: JString,
|
||||||
|
pass: JString,
|
||||||
|
) {
|
||||||
|
let builder = Client::builder()
|
||||||
|
.user_agent("Mozilla/5.0 (Windows NT 10.0; rv:102.0) Gecko/20100101 Firefox/102.0");
|
||||||
|
|
||||||
|
let builder = match env.get_string(&proxy) {
|
||||||
|
Ok(proxy) => {
|
||||||
|
let proxy = proxy.to_str().unwrap();
|
||||||
|
let proxy = reqwest::Proxy::all(proxy).unwrap();
|
||||||
|
let proxy = match env.get_string(&user) {
|
||||||
|
Ok(user) => {
|
||||||
|
let user = user.to_str().unwrap();
|
||||||
|
let pass = env.get_string(&pass).unwrap();
|
||||||
|
let pass = pass.to_str().unwrap();
|
||||||
|
proxy.basic_auth(user, pass)
|
||||||
|
}
|
||||||
|
Err(_) => proxy,
|
||||||
|
};
|
||||||
|
builder.proxy(proxy)
|
||||||
|
}
|
||||||
|
Err(_) => builder,
|
||||||
|
};
|
||||||
|
|
||||||
|
let client = builder
|
||||||
|
// timeout for establishing connection
|
||||||
|
.connect_timeout(Duration::from_secs(10))
|
||||||
|
// timeout for entire request, till body is read
|
||||||
|
.timeout(Duration::from_secs(30))
|
||||||
.build()
|
.build()
|
||||||
.unwrap()
|
.unwrap();
|
||||||
);
|
CLIENT.set(client).unwrap();
|
||||||
|
RUNTIME.set(Runtime::new().unwrap()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "system" fn Java_rocks_kavin_reqwest4j_ReqwestUtils_fetch(
|
pub extern "system" fn Java_rocks_kavin_reqwest4j_ReqwestUtils_fetch(
|
||||||
|
|
@ -24,7 +60,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();
|
||||||
|
|
||||||
|
|
@ -32,7 +67,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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -43,16 +82,34 @@ 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 request = CLIENT.request(method, url);
|
let client = CLIENT.get();
|
||||||
|
|
||||||
let request = headers.into_iter().fold(request, |request, (key, value)| {
|
if client.is_none() {
|
||||||
request.header(key, value)
|
env.throw_new("java/lang/IllegalStateException", "Client not initialized")
|
||||||
});
|
.unwrap();
|
||||||
|
return JObject::null().into_raw();
|
||||||
|
}
|
||||||
|
|
||||||
|
let client = client.unwrap();
|
||||||
|
|
||||||
|
let request = client.request(method, url);
|
||||||
|
|
||||||
|
let request = headers
|
||||||
|
.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
|
||||||
|
|
@ -60,48 +117,113 @@ pub extern "system" fn Java_rocks_kavin_reqwest4j_ReqwestUtils_fetch(
|
||||||
request.body(body)
|
request.body(body)
|
||||||
};
|
};
|
||||||
|
|
||||||
// send request
|
// `JNIEnv` cannot be sent between threads safely
|
||||||
let response = RUNTIME.block_on(async {
|
let jvm = env.get_java_vm().unwrap();
|
||||||
request.send().await
|
let jvm = Arc::new(jvm);
|
||||||
});
|
|
||||||
|
|
||||||
if let Err(error) = response {
|
// create CompletableFuture
|
||||||
let error = error.to_string();
|
let _future = env
|
||||||
env.throw_new("java/lang/RuntimeException", error).unwrap();
|
.new_object("java/util/concurrent/CompletableFuture", "()V", &[])
|
||||||
return JObject::null().into_raw();
|
.unwrap();
|
||||||
|
let future = env.new_global_ref(&_future).unwrap();
|
||||||
|
let future = Arc::new(future);
|
||||||
|
|
||||||
|
let runtime = RUNTIME.get().unwrap();
|
||||||
|
|
||||||
|
// send request in a async task
|
||||||
|
{
|
||||||
|
let jvm = Arc::clone(&jvm);
|
||||||
|
let future = Arc::clone(&future);
|
||||||
|
|
||||||
|
runtime.spawn(async move {
|
||||||
|
// send request
|
||||||
|
let response = request.send().await;
|
||||||
|
|
||||||
|
match response {
|
||||||
|
Ok(response) => {
|
||||||
|
// get response
|
||||||
|
let status = response.status().as_u16() as i32;
|
||||||
|
|
||||||
|
let final_url = response.url().to_string();
|
||||||
|
|
||||||
|
let response_headers = response.headers().clone();
|
||||||
|
|
||||||
|
let body = response.bytes().await.unwrap_or_default().to_vec();
|
||||||
|
|
||||||
|
// send response in a blocking task
|
||||||
|
runtime.spawn_blocking(move || {
|
||||||
|
let mut env = jvm.attach_current_thread().unwrap();
|
||||||
|
|
||||||
|
let final_url = env.new_string(final_url).unwrap();
|
||||||
|
|
||||||
|
let body = env.byte_array_from_slice(&body).unwrap();
|
||||||
|
|
||||||
|
let headers = env.new_object("java/util/HashMap", "()V", &[]).unwrap();
|
||||||
|
let headers: JMap = JMap::from_env(&mut env, &headers).unwrap();
|
||||||
|
|
||||||
|
response_headers.iter().for_each(|(key, value)| {
|
||||||
|
let key = env.new_string(key.as_str()).unwrap();
|
||||||
|
let value = env.new_string(value.to_str().unwrap()).unwrap();
|
||||||
|
headers
|
||||||
|
.put(&mut env, &JObject::from(key), &JObject::from(value))
|
||||||
|
.unwrap();
|
||||||
|
});
|
||||||
|
|
||||||
|
// return response to CompletableFuture
|
||||||
|
let response = env
|
||||||
|
.new_object(
|
||||||
|
"rocks/kavin/reqwest4j/Response",
|
||||||
|
"(ILjava/util/Map;[BLjava/lang/String;)V",
|
||||||
|
&[
|
||||||
|
status.into(),
|
||||||
|
(&headers).into(),
|
||||||
|
(&body).into(),
|
||||||
|
(&final_url).into(),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let future = future.as_obj();
|
||||||
|
env.call_method(
|
||||||
|
future,
|
||||||
|
"complete",
|
||||||
|
"(Ljava/lang/Object;)Z",
|
||||||
|
&[(&response).into()],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Err(error) => {
|
||||||
|
// send error in a blocking task
|
||||||
|
runtime.spawn_blocking(move || {
|
||||||
|
let mut env = jvm.attach_current_thread().unwrap();
|
||||||
|
|
||||||
|
let error = error.to_string();
|
||||||
|
let error = env.new_string(error).unwrap();
|
||||||
|
// create Exception
|
||||||
|
let exception = env
|
||||||
|
.new_object(
|
||||||
|
"java/lang/Exception",
|
||||||
|
"(Ljava/lang/String;)V",
|
||||||
|
&[(&error).into()],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let future = future.as_obj();
|
||||||
|
|
||||||
|
// pass error to CompletableFuture
|
||||||
|
env.call_method(
|
||||||
|
future,
|
||||||
|
"completeExceptionally",
|
||||||
|
"(Ljava/lang/Throwable;)Z",
|
||||||
|
&[(&exception).into()],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let response = response.unwrap();
|
_future.into_raw()
|
||||||
|
|
||||||
// get response
|
|
||||||
let status = response.status().as_u16() as i32;
|
|
||||||
|
|
||||||
let headers = env.new_object("java/util/HashMap", "()V", &[]).unwrap();
|
|
||||||
let headers: JMap = JMap::from_env(&mut env, &headers).unwrap();
|
|
||||||
|
|
||||||
response.headers().iter().for_each(|(key, value)| {
|
|
||||||
let key = env.new_string(key.as_str()).unwrap();
|
|
||||||
let value = env.new_string(value.to_str().unwrap()).unwrap();
|
|
||||||
headers.put(&mut env, &JObject::from(key), &JObject::from(value)).unwrap();
|
|
||||||
});
|
|
||||||
|
|
||||||
let final_url = response.url().to_string();
|
|
||||||
let final_url = env.new_string(final_url).unwrap();
|
|
||||||
|
|
||||||
let body = RUNTIME.block_on(async {
|
|
||||||
response.bytes().await.unwrap_or_default().to_vec()
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
let body = env.byte_array_from_slice(&body).unwrap();
|
|
||||||
|
|
||||||
// return response
|
|
||||||
let response = env.new_object("rocks/kavin/reqwest4j/Response", "(ILjava/util/Map;[BLjava/lang/String;)V", &[
|
|
||||||
status.into(),
|
|
||||||
(&headers).into(),
|
|
||||||
(&body).into(),
|
|
||||||
(&final_url).into(),
|
|
||||||
]).unwrap();
|
|
||||||
|
|
||||||
response.into_raw()
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
public class ReqwestUtils {
|
public class ReqwestUtils {
|
||||||
|
|
||||||
|
|
@ -14,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);
|
||||||
|
|
@ -25,8 +41,11 @@ 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 (
|
||||||
stream.transferTo(new FileOutputStream(nativeFile));
|
var stream = cl.getResourceAsStream("META-INF/natives/" + native_folder + "/" + arch + "/libreqwest" + extension);
|
||||||
|
var fileOutputStream = new FileOutputStream(nativeFile)
|
||||||
|
) {
|
||||||
|
stream.transferTo(fileOutputStream);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
@ -34,7 +53,9 @@ public class ReqwestUtils {
|
||||||
System.load(nativeFile.getAbsolutePath());
|
System.load(nativeFile.getAbsolutePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static native Response fetch(String url, String method, byte[] body,
|
public static native void init(String proxy, String user, String pass);
|
||||||
Map<String, String> headers);
|
|
||||||
|
public static native CompletableFuture<Response> fetch(String url, String method, byte[] body,
|
||||||
|
Map<String, String> headers);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue