refactor clash bridge

This commit is contained in:
Kr328 committed 2020-06-11 23:48:44 +08:00
1 parent f34d71eb88
commit d7f0cf91c7
12 files changed
+157 -9

No files matched your search

+1 -1
View File
@@ -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)
+51
View File
@@ -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();
}
+10
View File
@@ -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);
}
+5
View File
@@ -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 -3
View File
@@ -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;
+1 -1
View File
@@ -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 {
+58
View File
@@ -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"