refactor clash bridge
This commit is contained in:
12 files changed
+157
-9
No files matched your search
@@ -8,4 +8,4 @@ include_directories(${CLASH_OUTPUT}/${ANDROID_ABI} ${CLASH_SOURCE})
|
||||
link_directories(${CLASH_OUTPUT}/${CMAKE_ANDROID_ARCH_ABI})
|
||||
link_libraries(log clash)
|
||||
|
||||
add_library(bridge SHARED main.cpp main.h init.cpp query.cpp patch.cpp tun.cpp defer.cpp event_queue.cpp)
|
||||
add_library(bridge SHARED main.cpp main.h init.cpp query.cpp patch.cpp tun.cpp defer.cpp log.cpp event_queue.cpp)
|
||||
@@ -0,0 +1,51 @@
|
||||
#include "libclash.h"
|
||||
#include "main.h"
|
||||
|
||||
static jobject logCallback;
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_github_kr328_clash_core_bridge_Bridge_setLogCallback(JNIEnv *env, jclass clazz,
|
||||
jobject callback) {
|
||||
UNUSED(clazz);
|
||||
|
||||
Master::runWithContext<void>(env, [&](Master::Context *context) {
|
||||
if ( logCallback != nullptr )
|
||||
context->removeGlobalReference(logCallback);
|
||||
|
||||
if ( callback == nullptr ) {
|
||||
logCallback = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
logCallback = context->newGlobalReference(callback);
|
||||
|
||||
EventQueue::getInstance()->registerHandler(LOG_RECEIVED, 0, [](const event_t *event) {
|
||||
Master::runWithAttached<int>([&](JNIEnv *env) {
|
||||
Master::runWithContext<void>(env, [&](Master::Context *context) {
|
||||
context->logCallbackMessage(logCallback, event->payload);
|
||||
});
|
||||
|
||||
return 0;
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_github_kr328_clash_core_bridge_Bridge_enableLogReport(JNIEnv *env, jclass clazz) {
|
||||
UNUSED(env);
|
||||
UNUSED(clazz);
|
||||
|
||||
enableLogReport();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_github_kr328_clash_core_bridge_Bridge_disableLogReport(JNIEnv *env, jclass clazz) {
|
||||
UNUSED(env);
|
||||
UNUSED(clazz);
|
||||
|
||||
disableLogReport();
|
||||
}
|
||||
@@ -16,7 +16,9 @@ Master::Master(JavaVM *vm, JNIEnv *env): vm(vm) {
|
||||
cCompletableFuture = g<jclass>(env, env->FindClass("java/util/concurrent/CompletableFuture"));
|
||||
cProxyGroup = g<jclass>(env, env->FindClass("com/github/kr328/clash/core/model/ProxyGroup"));
|
||||
cProxy = g<jclass>(env, env->FindClass("com/github/kr328/clash/core/model/Proxy"));
|
||||
cLogEvent = g<jclass>(env, env->FindClass("com/github/kr328/clash/core/event/LogEvent"));
|
||||
iTunCallback = g<jclass>(env, env->FindClass("com/github/kr328/clash/core/bridge/TunCallback"));
|
||||
iLogCallback = g<jclass>(env, env->FindClass("com/github/kr328/clash/core/bridge/LogCallback"));
|
||||
cClashExceptionConstructor = env->GetMethodID(cClashException, "<init>",
|
||||
"(Ljava/lang/String;)V");
|
||||
cTrafficConstructor = env->GetMethodID(cTraffic, "<init>", "(JJ)V");
|
||||
@@ -24,6 +26,7 @@ Master::Master(JavaVM *vm, JNIEnv *env): vm(vm) {
|
||||
cCompletableFutureConstructor = env->GetMethodID(cCompletableFuture, "<init>", "()V");
|
||||
cProxyGroupConstructor = env->GetMethodID(cProxyGroup, "<init>", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[Lcom/github/kr328/clash/core/model/Proxy;)V");
|
||||
cProxyConstructor = env->GetMethodID(cProxy, "<init>", "(Ljava/lang/String;Ljava/lang/String;J)V");
|
||||
cLogEventConstructor = env->GetMethodID(cLogEvent, "<init>", "(Ljava/lang/String;)V");
|
||||
mCompletableFutureComplete = env->GetMethodID(cCompletableFuture, "complete",
|
||||
"(Ljava/lang/Object;)Z");
|
||||
mCompletableFutureCompleteExceptionally = env->GetMethodID(cCompletableFuture,
|
||||
@@ -31,6 +34,7 @@ Master::Master(JavaVM *vm, JNIEnv *env): vm(vm) {
|
||||
"(Ljava/lang/Throwable;)Z");
|
||||
mTunCallbackOnNewSocket = env->GetMethodID(iTunCallback, "onNewSocket", "(I)V");
|
||||
mTunCallbackOnStop = env->GetMethodID(iTunCallback, "onStop", "()V");
|
||||
mLogCallbackOnMessage = env->GetMethodID(iLogCallback, "onMessage", "(Lcom/github/kr328/clash/core/event/LogEvent;)V");
|
||||
|
||||
sDirect = g<jstring>(env, env->NewStringUTF("Direct"));
|
||||
sReject = g<jstring>(env, env->NewStringUTF("Reject"));
|
||||
@@ -224,6 +228,12 @@ jobject Master::Context::createProxyGroup(char const *name, proxy_type_t type,
|
||||
return env->NewObject(master->cProxyGroup, master->cProxyGroupConstructor, env->NewStringUTF(name), ts, env->NewStringUTF(current), proxies);
|
||||
}
|
||||
|
||||
void Master::Context::logCallbackMessage(jobject callback, const char *data) {
|
||||
jobject event = env->NewObject(master->cLogEvent, master->cLogEventConstructor, env->NewStringUTF(data));
|
||||
|
||||
env->CallVoidMethod(callback, master->mLogCallbackOnMessage, event);
|
||||
}
|
||||
|
||||
static void enqueue_event(const event_t *e) {
|
||||
EventQueue::getInstance()->enqueueEvent(e);
|
||||
}
|
||||
|
||||
@@ -25,17 +25,21 @@ private:
|
||||
jclass cCompletableFuture;
|
||||
jclass cProxyGroup;
|
||||
jclass cProxy;
|
||||
jclass cLogEvent;
|
||||
jclass iTunCallback;
|
||||
jclass iLogCallback;
|
||||
jmethodID cClashExceptionConstructor;
|
||||
jmethodID cTrafficConstructor;
|
||||
jmethodID cGeneralConstructor;
|
||||
jmethodID cCompletableFutureConstructor;
|
||||
jmethodID cProxyGroupConstructor;
|
||||
jmethodID cProxyConstructor;
|
||||
jmethodID cLogEventConstructor;
|
||||
jmethodID mCompletableFutureComplete;
|
||||
jmethodID mCompletableFutureCompleteExceptionally;
|
||||
jmethodID mTunCallbackOnNewSocket;
|
||||
jmethodID mTunCallbackOnStop;
|
||||
jmethodID mLogCallbackOnMessage;
|
||||
|
||||
private:
|
||||
jstring sDirect;
|
||||
@@ -86,6 +90,7 @@ public:
|
||||
bool completeExceptionallyCompletableFuture(jobject completable, jthrowable throwable);
|
||||
void tunCallbackNewSocket(jobject callback, int fd);
|
||||
void tunCallbackStop(jobject callback);
|
||||
void logCallbackMessage(jobject callback, const char *data);
|
||||
|
||||
public:
|
||||
jobject createProxy(char const *name, proxy_type_t type, long delay);
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#include "main.h"
|
||||
|
||||
#include <android/log.h>
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_com_github_kr328_clash_core_bridge_Bridge_queryGeneral(JNIEnv *env, jclass clazz) {
|
||||
@@ -92,7 +90,7 @@ Java_com_github_kr328_clash_core_bridge_Bridge_queryProxyGroups(JNIEnv *env, jcl
|
||||
group_name,
|
||||
group->base.proxy_type,
|
||||
now,
|
||||
context->createProxyArray(group->proxies_size, jproxies);
|
||||
context->createProxyArray(group->proxies_size, jproxies));
|
||||
|
||||
delete[] jproxies;
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
NEW_SOCKET, TUN_STOP, COMPLETE
|
||||
NEW_SOCKET, TUN_STOP, COMPLETE, LOG_RECEIVED
|
||||
} event_type_t;
|
||||
|
||||
typedef struct event_t {
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package main
|
||||
|
||||
//#include "event.h"
|
||||
import "C"
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Dreamacro/clash/log"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var logLocker sync.Mutex
|
||||
var closeChan chan struct{}
|
||||
|
||||
//export enableLogReport
|
||||
func enableLogReport() {
|
||||
logLocker.Lock()
|
||||
defer logLocker.Unlock()
|
||||
|
||||
|
||||
if closeChan != nil {
|
||||
close(closeChan)
|
||||
}
|
||||
|
||||
closeChan = make(chan struct{})
|
||||
|
||||
go func(closed chan struct{}) {
|
||||
subscriber := log.Subscribe()
|
||||
defer log.UnSubscribe(subscriber)
|
||||
defer log.Infoln("Log broadcast disabled")
|
||||
|
||||
for {
|
||||
select {
|
||||
case item := <-subscriber:
|
||||
msg := item.(*log.Event)
|
||||
|
||||
if msg.LogLevel < log.Level() {
|
||||
continue
|
||||
}
|
||||
|
||||
<- sendEvent(C.LOG_RECEIVED, 0, fmt.Sprintf("%s:%s", msg.LogLevel.String(), msg.Payload)).result
|
||||
case <-closeChan:
|
||||
return
|
||||
}
|
||||
}
|
||||
}(closeChan)
|
||||
}
|
||||
|
||||
//export disableLogReport
|
||||
func disableLogReport() {
|
||||
logLocker.Lock()
|
||||
defer logLocker.Unlock()
|
||||
|
||||
if closeChan != nil {
|
||||
close(closeChan)
|
||||
|
||||
closeChan = nil
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,8 @@ import java.io.InputStream
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
object Clash {
|
||||
private val logReceivers = mutableMapOf<String, (LogEvent) -> Unit>()
|
||||
|
||||
init {
|
||||
val context = Global.application
|
||||
|
||||
@@ -23,6 +25,12 @@ object Clash {
|
||||
Bridge.initialize(bytes, context.cacheDir.absolutePath, BuildConfig.VERSION_NAME)
|
||||
Bridge.reset()
|
||||
|
||||
Bridge.setLogCallback {
|
||||
synchronized(logReceivers) {
|
||||
logReceivers.forEach { (_, e) -> e(it) }
|
||||
}
|
||||
}
|
||||
|
||||
Log.i("Clash core initialized")
|
||||
}
|
||||
|
||||
@@ -102,10 +110,18 @@ object Clash {
|
||||
}
|
||||
|
||||
fun registerLogReceiver(key: String, receiver: (LogEvent) -> Unit) {
|
||||
|
||||
synchronized(logReceivers) {
|
||||
if ( logReceivers.isEmpty() )
|
||||
Bridge.enableLogReport()
|
||||
logReceivers[key] = receiver
|
||||
}
|
||||
}
|
||||
|
||||
fun unregisterLogReceiver(key: String) {
|
||||
|
||||
synchronized(logReceivers) {
|
||||
logReceivers.remove(key)
|
||||
if ( logReceivers.isEmpty() )
|
||||
Bridge.disableLogReport();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,4 +38,8 @@ public final class Bridge {
|
||||
|
||||
public static native CompletableFuture<Object> loadProfile(String path, String base);
|
||||
public static native CompletableFuture<Object> performHealthCheck(String group);
|
||||
|
||||
public static native void setLogCallback(LogCallback callback);
|
||||
public static native void enableLogReport();
|
||||
public static native void disableLogReport();
|
||||
}
|
||||
@@ -1,7 +1,11 @@
|
||||
package com.github.kr328.clash.core.bridge;
|
||||
|
||||
import androidx.annotation.Keep;
|
||||
|
||||
import com.github.kr328.clash.core.event.LogEvent;
|
||||
|
||||
interface LogCallback {
|
||||
@Keep
|
||||
@SuppressWarnings("unused")
|
||||
public interface LogCallback {
|
||||
void onMessage(LogEvent event);
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package com.github.kr328.clash.core.bridge;
|
||||
import androidx.annotation.Keep;
|
||||
|
||||
@Keep
|
||||
@SuppressWarnings("unused")
|
||||
public interface TunCallback {
|
||||
void onNewSocket(int socket);
|
||||
void onStop();
|
||||
|
||||
@@ -13,8 +13,9 @@ data class LogEvent(
|
||||
val message: String,
|
||||
val time: Long = System.currentTimeMillis()
|
||||
) : Parcelable {
|
||||
private constructor(data: List<String>): this(Level.fromString(data[0]), data[1])
|
||||
@Keep
|
||||
constructor(level: String, message: String): this(Level.fromString(level), message)
|
||||
constructor(data: String) : this(data.split(":", limit = 2))
|
||||
|
||||
companion object {
|
||||
const val DEBUG_VALUE = "debug"
|
||||
|
||||
Reference in new issue
Block a user