Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.oxd.sh/llms.txt

Use this file to discover all available pages before exploring further.

Architecture

React Native bridges to the C library through platform-specific native modules:
  • Android — JNI (same bridge as Java / Kotlin)
  • iOS — Direct C interop from Swift (same as Swift)

Android native module

1. Place native libraries

android/app/src/main/jniLibs/
  arm64-v8a/liboxaccel.so
  arm64-v8a/liboxaccel_jni.so
  armeabi-v7a/liboxaccel.so
  armeabi-v7a/liboxaccel_jni.so

2. Create the module

// android/app/src/main/java/sh/oxd/accel/OxAccelModule.java
package sh.oxd.accel;

import com.facebook.react.bridge.*;
import java.nio.ByteBuffer;
import android.util.Base64;

public class OxAccelModule extends ReactContextBaseJavaModule {
    static { System.loadLibrary("oxaccel_jni"); }

    private static native long   nCreate(String apiKey, String relayHost, int port,
                                         boolean fec, boolean compression, boolean multipath);
    private static native int    nConnect(long ctx);
    private static native int    nSend(long ctx, ByteBuffer data, int len);
    private static native int    nRecv(long ctx, ByteBuffer buf, int bufLen);
    private static native long[] nStats(long ctx);
    private static native void   nDestroy(long ctx);
    private static native String nVersion();

    private long ctx = 0;

    OxAccelModule(ReactApplicationContext context) { super(context); }

    @Override public String getName() { return "OxAccel"; }

    @ReactMethod
    public void create(ReadableMap config, Promise promise) {
        ctx = nCreate(
            config.getString("apiKey"),
            config.getString("relayHost"),
            config.getInt("relayPort"),
            config.getBoolean("enableFec"),
            config.getBoolean("enableCompression"),
            config.getBoolean("enableMultipath")
        );
        promise.resolve(ctx != 0);
    }

    @ReactMethod
    public void connect(Promise promise) {
        int err = nConnect(ctx);
        if (err == 0) promise.resolve(null);
        else promise.reject("ACCEL_ERR", "Connect failed: " + err);
    }

    @ReactMethod
    public void send(String base64Data, Promise promise) {
        byte[] data = Base64.decode(base64Data, Base64.NO_WRAP);
        ByteBuffer buf = ByteBuffer.allocateDirect(data.length);
        buf.put(data).flip();
        int err = nSend(ctx, buf, data.length);
        if (err == 0) promise.resolve(null);
        else promise.reject("ACCEL_ERR", "Send failed: " + err);
    }

    @ReactMethod
    public void recv(Promise promise) {
        ByteBuffer buf = ByteBuffer.allocateDirect(65536);
        int received = nRecv(ctx, buf, 65536);
        if (received >= 0) {
            byte[] data = new byte[received];
            buf.get(data, 0, received);
            promise.resolve(Base64.encodeToString(data, Base64.NO_WRAP));
        } else {
            promise.reject("ACCEL_ERR", "Recv failed");
        }
    }

    @ReactMethod
    public void destroy(Promise promise) {
        if (ctx != 0) { nDestroy(ctx); ctx = 0; }
        promise.resolve(null);
    }
}

iOS native module

1. Add bridging header

// ios/OxAccel-Bridging-Header.h
#include "oxaccel.h"

2. Create the module

// ios/OxAccelModule.swift
import Foundation

@objc(OxAccelModule)
class OxAccelModule: NSObject {
    private var ctx: OpaquePointer?

    @objc func create(_ config: NSDictionary, resolve: RCTPromiseResolveBlock,
                      reject: RCTPromiseRejectBlock) {
        var cfg = OxAccelConfig(
            api_key: strdup(config["apiKey"] as? String ?? ""),
            relay_host: strdup(config["relayHost"] as? String ?? "relay.oxd.sh"),
            relay_port: UInt16(config["relayPort"] as? Int ?? 51820),
            enable_fec: config["enableFec"] as? Bool ?? true,
            enable_compression: config["enableCompression"] as? Bool ?? false,
            enable_multipath: config["enableMultipath"] as? Bool ?? true
        )
        ctx = ox_accel_create(&cfg)
        free(UnsafeMutablePointer(mutating: cfg.api_key))
        free(UnsafeMutablePointer(mutating: cfg.relay_host))
        resolve(ctx != nil)
    }

    @objc func connect(_ resolve: RCTPromiseResolveBlock,
                       reject: RCTPromiseRejectBlock) {
        guard let ctx = ctx else { reject("ERR", "Not created", nil); return }
        let err = ox_accel_connect(ctx)
        if err == Ok { resolve(nil) }
        else { reject("ERR", "Connect failed: \(err.rawValue)", nil) }
    }

    @objc func send(_ base64: String, resolve: RCTPromiseResolveBlock,
                    reject: RCTPromiseRejectBlock) {
        guard let ctx = ctx, let data = Data(base64Encoded: base64) else {
            reject("ERR", "Invalid", nil); return
        }
        let err = data.withUnsafeBytes { buf in
            ox_accel_send(ctx, buf.baseAddress?.assumingMemoryBound(to: UInt8.self), buf.count)
        }
        if err == Ok { resolve(nil) }
        else { reject("ERR", "Send failed: \(err.rawValue)", nil) }
    }

    @objc func destroy(_ resolve: RCTPromiseResolveBlock,
                       reject: RCTPromiseRejectBlock) {
        if let ctx = ctx { ox_accel_destroy(ctx); self.ctx = nil }
        resolve(nil)
    }
}

TypeScript usage

import { NativeModules } from 'react-native';
const { OxAccel } = NativeModules;

await OxAccel.create({
    apiKey: 'your-api-key',
    relayHost: 'relay.oxd.sh',
    relayPort: 51820,
    enableFec: true,
    enableCompression: false,
    enableMultipath: true,
});

await OxAccel.connect();

// Send (base64-encoded data over the bridge)
const data = btoa('hello world');
await OxAccel.send(data);

// Cleanup
await OxAccel.destroy();
React Native’s JS bridge requires serialized data. Binary payloads are base64-encoded across the bridge, then decoded on the native side before passing to ox_accel_send. For high-frequency sends, consider using TurboModules with JSI for direct memory access.