Skip to content

Commit

Permalink
Merge pull request #14 from LostLuma/feature/native-http-client
Browse files Browse the repository at this point in the history
Add minimal native HTTP client
  • Loading branch information
Pixaurora authored Oct 26, 2024
2 parents ca0b2b0 + 6656be9 commit 68b953f
Show file tree
Hide file tree
Showing 27 changed files with 681 additions and 214 deletions.
8 changes: 8 additions & 0 deletions projects/catculator/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Catculator

Native implementations of some of Kit Tunes features.

## Development

Test new binaries by setting the `catculator.natives_path` system property when running the game:
Example: `-Dcatculator.natives_path=/home/lilly/projects/kit-tunes/projects/catculator/target/debug`
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package net.pixaurora.catculator.api.error;

public class ClientResponseException extends Exception {
public ClientResponseException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package net.pixaurora.catculator.api.http;

import net.pixaurora.catculator.impl.http.ClientImpl;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;

public interface Client extends AutoCloseable {
static @NotNull Client create(String userAgent) throws IOException {
return new ClientImpl(userAgent);
}

@NotNull RequestBuilder get(String url);
@NotNull RequestBuilder post(String url);

@Override
void close(); // Remove throws Exception from AutoCloseable
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package net.pixaurora.catculator.api.http;

import net.pixaurora.catculator.api.error.ClientResponseException;
import org.jetbrains.annotations.NotNull;

public interface RequestBuilder {
@NotNull Response send() throws ClientResponseException;

@NotNull RequestBuilder body(byte[] data);
@NotNull RequestBuilder query(String key, String value);
@NotNull RequestBuilder header(String key, String value);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package net.pixaurora.catculator.api.http;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public interface Response {
int status();
byte[] body();
@Nullable String header(@NotNull String name);

default boolean ok() {
return this.status() >= 200 && this.status() < 300;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public static Server create() {
return new ServerImpl();
}

public String runServer() throws IOException;
public String run() throws IOException;

public void close();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package net.pixaurora.catculator.impl.http;

import net.pixaurora.catculator.api.http.Client;
import net.pixaurora.catculator.api.http.RequestBuilder;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;

public class ClientImpl implements Client {
private final long ptr;
private boolean active = true;

public ClientImpl(String userAgent) throws IOException {
this.ptr = create(userAgent);
}

@Override
public @NotNull RequestBuilder get(String url) {
if (this.active) {
return this.request("GET", url);
} else {
throw new RuntimeException("HTTP client inactive.");
}
}

@Override
public @NotNull RequestBuilder post(String url) {
if (this.active) {
return this.request("POST", url);
} else {
throw new RuntimeException("HTTP client inactive.");
}
}

@Override
public void close() {
if (!this.active) {
return;
}

this.drop();
this.active = false;
}

private native @NotNull RequestBuilder request(String method, String url);

private static native long create(@NotNull String userAgent) throws IOException;
private native void drop();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package net.pixaurora.catculator.impl.http;

import net.pixaurora.catculator.api.http.RequestBuilder;
import net.pixaurora.catculator.api.http.Response;
import org.jetbrains.annotations.NotNull;

public class RequestBuilderImpl implements RequestBuilder {
private long ptr;

private RequestBuilderImpl(long ptr) {
this.ptr = ptr;
}

@Override
public @NotNull Response send() {
return this.send0();
}

@Override
public @NotNull RequestBuilder body(byte[] data) {
this.body0(data);
return this;
}

@Override
public @NotNull RequestBuilder query(String key, String value) {
this.query0(key, value);
return this;
}

@Override
public @NotNull RequestBuilder header(String key, String value) {
this.header0(key, value);
return this;
}

private native @NotNull Response send0();

private native void body0(byte[] data);
private native void query0(String key, String value);
private native void header0(String key, String value);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package net.pixaurora.catculator.impl.http;

import net.pixaurora.catculator.api.http.Response;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Map;

public class ResponseImpl implements Response {
private final int status;
private final byte[] body;
private final Map<String, String> headers;

private ResponseImpl(int status, byte[] body, Map<String, String> headers) {
this.status = status;
this.body = body;
this.headers = headers;
}

@Override
public int status() {
return this.status;
}

@Override
public byte[] body() {
return this.body;
}

@Override
public @Nullable String header(@NotNull String name) {
return this.headers.get(name);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,20 @@
import net.pixaurora.catculator.api.http.Server;

public class ServerImpl implements Server {
private final long pointer;
private final long ptr;

public ServerImpl() {
this.pointer = create();
this.ptr = create();
}

private static native long create();

@Override
public String runServer() {
return this.runServer0();
public String run() {
return this.run0();
}

private native String runServer0();
private native String run0();

@Override
public void close() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package net.pixaurora.catculator.impl.util;

import org.jetbrains.annotations.NotNull;

import java.util.HashMap;
import java.util.Map;

public class JniUtil {
private static @NotNull Map<String, String> newMap() {
return new HashMap<>();
}
}
9 changes: 0 additions & 9 deletions projects/catculator/src/main/rust/bridge.rs

This file was deleted.

1 change: 0 additions & 1 deletion projects/catculator/src/main/rust/bridge/http.rs

This file was deleted.

83 changes: 83 additions & 0 deletions projects/catculator/src/main/rust/bridge/http/client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
use jni::{
objects::{JClass, JObject, JString, JValue},
sys::jlong,
JNIEnv,
};
use reqwest::{blocking::Client, Method};

use crate::{
bridge::{drop_box, pack_box, pull_box},
utils::JStringToString,
Error, Result,
};

const REQUEST_BUILDER_CLASS: &str = "net/pixaurora/catculator/impl/http/RequestBuilderImpl";

fn create(env: &mut JNIEnv, user_agent: JString) -> Result<jlong> {
let client = Client::builder()
.https_only(true)
.user_agent(user_agent.to_string(env)?)
.build()?;

Ok(pack_box(client))
}

#[no_mangle]
pub extern "system" fn Java_net_pixaurora_catculator_impl_http_ClientImpl_create<'r>(
mut env: JNIEnv<'r>,
_class: JClass<'r>,
user_agent: JString<'r>,
) -> jlong {
match create(&mut env, user_agent) {
Ok(ptr) => return ptr,
Err(error) => error.throw(&mut env),
}

jlong::default()
}

#[no_mangle]
pub extern "system" fn Java_net_pixaurora_catculator_impl_http_ClientImpl_drop<'r>(
mut env: JNIEnv<'r>,
this: JObject<'r>,
) -> () {
if let Err(error) = drop_box::<Client>(&mut env, &this) {
panic!("Couldn't drop http client due to an error! {}", error);
}
}

fn request<'r>(
env: &mut JNIEnv<'r>,
this: &JObject<'r>,
method: JString<'r>,
url: JString<'r>,
) -> Result<JObject<'r>> {
let client = pull_box::<Client>(env, this)?;

let method = match Method::from_bytes(method.to_string(env)?.as_bytes()) {
Ok(method) => method,
Err(_) => return Err(Error::String(String::from("Invalid HTTP method."))),
};

let ptr = pack_box(client.request(method, url.to_string(env)?));

let class = env.find_class(REQUEST_BUILDER_CLASS)?;
let instance = env.new_object(class, "(J)V", &[JValue::Long(ptr)])?;

Ok(instance)
}

#[no_mangle]
pub extern "system" fn Java_net_pixaurora_catculator_impl_http_ClientImpl_request<'r>(
mut env: JNIEnv<'r>,
this: JObject<'r>,
method: JString<'r>,
url: JString<'r>,
) -> JObject<'r> {
match request(&mut env, &this, method, url) {
Ok(object) => return object,
Err(error) => error.throw(&mut env),
};

JObject::null()
}
Loading

0 comments on commit 68b953f

Please sign in to comment.