From a6abb51046edfbe32839b8883a15e2b1a2726662 Mon Sep 17 00:00:00 2001 From: Kr328 <39107975+Kr328@users.noreply.github.com> Date: Sun, 24 Nov 2019 16:29:13 +0800 Subject: [PATCH] create event poll --- .../com/github/kr328/clash/MainActivity.kt | 22 ++++++---- .../java/com/github/kr328/clash/core/Clash.kt | 21 ++++++++- .../github/kr328/clash/core/ClashProcess.kt | 9 ++-- .../kr328/clash/core/ClashProcessStatus.kt | 34 --------------- .../github/kr328/clash/core/model/Event.kt | 8 ++++ .../github/kr328/clash/core/model/LogEvent.kt | 43 +++++++++++++++++++ .../kr328/clash/core/model/ProcessEvent.kt | 29 +++++++++++++ .../clash/core/{transact => model}/Proxy.kt | 2 +- .../clash/core/model/ProxyChangedEvent.kt | 3 ++ .../kr328/clash/service/IClashObserver.aidl | 4 +- .../kr328/clash/service/IClashService.aidl | 2 +- .../kr328/clash/service/ClashService.kt | 13 +++--- .../github/kr328/clash/service/TunService.kt | 16 +++---- 13 files changed, 139 insertions(+), 67 deletions(-) delete mode 100644 core/src/main/java/com/github/kr328/clash/core/ClashProcessStatus.kt create mode 100644 core/src/main/java/com/github/kr328/clash/core/model/Event.kt create mode 100644 core/src/main/java/com/github/kr328/clash/core/model/LogEvent.kt create mode 100644 core/src/main/java/com/github/kr328/clash/core/model/ProcessEvent.kt rename core/src/main/java/com/github/kr328/clash/core/{transact => model}/Proxy.kt (94%) create mode 100644 core/src/main/java/com/github/kr328/clash/core/model/ProxyChangedEvent.kt diff --git a/app/src/main/java/com/github/kr328/clash/MainActivity.kt b/app/src/main/java/com/github/kr328/clash/MainActivity.kt index d2c3165..59c61d4 100644 --- a/app/src/main/java/com/github/kr328/clash/MainActivity.kt +++ b/app/src/main/java/com/github/kr328/clash/MainActivity.kt @@ -10,12 +10,11 @@ import android.net.VpnService import android.os.Bundle import android.os.Handler import android.os.IBinder -import android.util.Log import android.view.View import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.MutableLiveData import androidx.lifecycle.observe -import com.github.kr328.clash.core.ClashProcessStatus +import com.github.kr328.clash.core.model.ProcessEvent import com.github.kr328.clash.service.ClashService import com.github.kr328.clash.service.IClashObserver import com.github.kr328.clash.service.IClashService @@ -43,15 +42,20 @@ class MainActivity : AppCompatActivity() { clash?.apply { registerObserver("main_activity",true , object: IClashObserver.Stub() { - override fun onStatusChanged(status: ClashProcessStatus?) { - clashStatus.postValue(status ?: ClashProcessStatus(ClashProcessStatus.STATUS_STOPPED_INT)) + override fun onStatusChanged(event: ProcessEvent?) { + clashStatus.postValue(event ?: ProcessEvent( + ProcessEvent.STATUS_STOPPED_INT + ) + ) } }) } } } - private val clashStatus = MutableLiveData(ClashProcessStatus(ClashProcessStatus.STATUS_STOPPED_INT)) + private val clashStatus = MutableLiveData( + ProcessEvent(ProcessEvent.STATUS_STOPPED_INT) + ) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -75,7 +79,7 @@ class MainActivity : AppCompatActivity() { handler.removeMessages(0) handler.postDelayed({ when ( it ) { - ClashProcessStatus.STATUS_STARTED -> { + ProcessEvent.STATUS_STARTED -> { activity_main_clash_status.setCardBackgroundColor(getColor(R.color.colorAccent)) activity_main_clash_status_icon.setImageResource(R.drawable.ic_clash_started) activity_main_clash_status_title.text = getString(R.string.clash_status_started) @@ -96,11 +100,11 @@ class MainActivity : AppCompatActivity() { } activity_main_clash_status.setOnClickListener { - when ( clashStatus.value ?: ClashProcessStatus.STATUS_STOPPED ) { - ClashProcessStatus.STATUS_STARTED -> { + when ( clashStatus.value ?: ProcessEvent.STATUS_STOPPED ) { + ProcessEvent.STATUS_STARTED -> { clash?.stop() } - ClashProcessStatus.STATUS_STOPPED -> { + ProcessEvent.STATUS_STOPPED -> { VpnService.prepare(this)?.apply { startActivityForResult(this, VPN_REQUEST_CODE) } ?: startService(Intent(this, TunService::class.java)) diff --git a/core/src/main/java/com/github/kr328/clash/core/Clash.kt b/core/src/main/java/com/github/kr328/clash/core/Clash.kt index e745126..3bc8664 100644 --- a/core/src/main/java/com/github/kr328/clash/core/Clash.kt +++ b/core/src/main/java/com/github/kr328/clash/core/Clash.kt @@ -3,7 +3,7 @@ package com.github.kr328.clash.core import android.content.Context import android.util.Log import com.github.kr328.clash.core.Constants.TAG -import com.github.kr328.clash.core.transact.Proxy +import com.github.kr328.clash.core.model.* import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonConfiguration import org.json.JSONObject @@ -15,7 +15,7 @@ class Clash( context: Context, clashDir: File, controllerPath: File, - listener: (ClashProcessStatus) -> Unit + listener: (ProcessEvent) -> Unit ) : BaseClash(controllerPath) { companion object { const val COMMAND_PING = 0 @@ -23,6 +23,7 @@ class Clash( const val COMMAND_TUN_STOP = 2 const val COMMAND_PROFILE_RELOAD = 4 const val COMMAND_QUERY_PROXIES = 5 + const val COMMAND_POLL_EVENT = 6 const val PING_REPLY = 233 } @@ -59,6 +60,22 @@ class Clash( } } + fun pollEvent(listener: (Event) -> Unit) { + runControl(COMMAND_POLL_EVENT) { _, input, _ -> + while ( !Thread.currentThread().isInterrupted ) { + when (val type = input.readInt()) { + Event.EVENT_LOG -> { + listener(Json(JsonConfiguration.Stable).parse(LogEvent.serializer(), input.readString())) + } + Event.EVENT_PROXY_CHANGED -> { + listener(ProxyChangedEvent()) + } + else -> Log.w(TAG, "Invalid event type $type") + } + } + } + } + fun startTunDevice(fd: FileDescriptor, mtu: Int) { runControl(COMMAND_TUN_START) { socket, _, output -> socket.setFileDescriptorsForSend(arrayOf(fd)) diff --git a/core/src/main/java/com/github/kr328/clash/core/ClashProcess.kt b/core/src/main/java/com/github/kr328/clash/core/ClashProcess.kt index 13647f8..ca8ee9c 100644 --- a/core/src/main/java/com/github/kr328/clash/core/ClashProcess.kt +++ b/core/src/main/java/com/github/kr328/clash/core/ClashProcess.kt @@ -3,6 +3,7 @@ package com.github.kr328.clash.core import android.content.Context import android.util.Log import com.github.kr328.clash.core.Constants.TAG +import com.github.kr328.clash.core.model.ProcessEvent import java.io.File import java.io.FileOutputStream import java.io.IOException @@ -12,7 +13,7 @@ import kotlin.concurrent.thread class ClashProcess(private val context: Context, private val clashDir: File, private val controllerPath: File, - private val listener: (ClashProcessStatus) -> Unit) { + private val listener: (ProcessEvent) -> Unit) { companion object { private const val CONTROLLER_STATUS_PREFIX = "[CONTROLLER]" @@ -72,7 +73,7 @@ class ClashProcess(private val context: Context, process = p pid = currentPid - listener(ClashProcessStatus.STATUS_STARTED) + listener(ProcessEvent.STATUS_STARTED) Log.i(TAG, "Clash started pid = $pid") @@ -88,11 +89,11 @@ class ClashProcess(private val context: Context, pid = -1 } - listener(ClashProcessStatus.STATUS_STOPPED) + listener(ProcessEvent.STATUS_STOPPED) } } catch (e: Exception) { - listener(ClashProcessStatus.STATUS_STOPPED) + listener(ProcessEvent.STATUS_STOPPED) throw e } } diff --git a/core/src/main/java/com/github/kr328/clash/core/ClashProcessStatus.kt b/core/src/main/java/com/github/kr328/clash/core/ClashProcessStatus.kt deleted file mode 100644 index 28b00ae..0000000 --- a/core/src/main/java/com/github/kr328/clash/core/ClashProcessStatus.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.github.kr328.clash.core - -import android.os.Parcel -import android.os.Parcelable - -data class ClashProcessStatus(val status: Int) : Parcelable { - companion object { - const val STATUS_STOPPED_INT = 0 - const val STATUS_STARTED_INT = 1 - val STATUS_STOPPED = ClashProcessStatus(STATUS_STOPPED_INT) - val STATUS_STARTED = ClashProcessStatus(STATUS_STARTED_INT) - - @JvmField - val CREATOR = object: Parcelable.Creator { - override fun createFromParcel(parcel: Parcel): ClashProcessStatus { - return ClashProcessStatus(parcel) - } - - override fun newArray(size: Int): Array { - return arrayOfNulls(size) - } - } - } - - constructor(parcel: Parcel) : this(parcel.readInt()) - - override fun writeToParcel(parcel: Parcel, flags: Int) { - parcel.writeInt(status) - } - - override fun describeContents(): Int { - return 0 - } -} \ No newline at end of file diff --git a/core/src/main/java/com/github/kr328/clash/core/model/Event.kt b/core/src/main/java/com/github/kr328/clash/core/model/Event.kt new file mode 100644 index 0000000..2f8f3d1 --- /dev/null +++ b/core/src/main/java/com/github/kr328/clash/core/model/Event.kt @@ -0,0 +1,8 @@ +package com.github.kr328.clash.core.model + +interface Event { + companion object { + const val EVENT_LOG = 1 + const val EVENT_PROXY_CHANGED = 2 + } +} \ No newline at end of file diff --git a/core/src/main/java/com/github/kr328/clash/core/model/LogEvent.kt b/core/src/main/java/com/github/kr328/clash/core/model/LogEvent.kt new file mode 100644 index 0000000..47cf40c --- /dev/null +++ b/core/src/main/java/com/github/kr328/clash/core/model/LogEvent.kt @@ -0,0 +1,43 @@ +package com.github.kr328.clash.core.model + +import kotlinx.serialization.Decoder +import kotlinx.serialization.Encoder +import kotlinx.serialization.KSerializer +import kotlinx.serialization.SerialDescriptor +import kotlinx.serialization.Serializable +import kotlinx.serialization.internal.StringDescriptor +import java.lang.IllegalArgumentException + +@Serializable +data class LogEvent(val level: Level, val message: String): Event { + companion object { + const val DEBUG_VALUE = 1 + const val INFO_VALUE = 2 + const val WARN_VALUE = 3 + const val ERROR_VALUE = 4 + } + + @Serializable(LevelSerializer::class) + enum class Level(val value: Int) { + DEBUG(DEBUG_VALUE), INFO(INFO_VALUE), WARN(WARN_VALUE), ERROR(ERROR_VALUE) + } + + class LevelSerializer : KSerializer { + override val descriptor: SerialDescriptor + get() = StringDescriptor + + override fun deserialize(decoder: Decoder): Level { + return when (val value = decoder.decodeInt()) { + DEBUG_VALUE -> Level.DEBUG + INFO_VALUE -> Level.INFO + WARN_VALUE -> Level.WARN + ERROR_VALUE -> Level.ERROR + else -> throw IllegalArgumentException("Invalid level type $value") + } + } + + override fun serialize(encoder: Encoder, obj: Level) { + encoder.encodeInt(obj.value) + } + } +} \ No newline at end of file diff --git a/core/src/main/java/com/github/kr328/clash/core/model/ProcessEvent.kt b/core/src/main/java/com/github/kr328/clash/core/model/ProcessEvent.kt new file mode 100644 index 0000000..9a26e88 --- /dev/null +++ b/core/src/main/java/com/github/kr328/clash/core/model/ProcessEvent.kt @@ -0,0 +1,29 @@ +package com.github.kr328.clash.core.model + +import android.os.Parcel +import android.os.Parcelable +import com.github.kr328.clash.core.serialization.Parcels +import kotlinx.serialization.Serializable + +@Serializable +enum class ProcessEvent : Parcelable, Event { + STARTED, STOPPED; + + companion object CREATOR : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): ProcessEvent { + return Parcels.load(serializer(), parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } + + override fun writeToParcel(parcel: Parcel, flags: Int) { + Parcels.dump(serializer(), this, parcel) + } + + override fun describeContents(): Int { + return 0 + } +} \ No newline at end of file diff --git a/core/src/main/java/com/github/kr328/clash/core/transact/Proxy.kt b/core/src/main/java/com/github/kr328/clash/core/model/Proxy.kt similarity index 94% rename from core/src/main/java/com/github/kr328/clash/core/transact/Proxy.kt rename to core/src/main/java/com/github/kr328/clash/core/model/Proxy.kt index 2b70caf..72880c0 100644 --- a/core/src/main/java/com/github/kr328/clash/core/transact/Proxy.kt +++ b/core/src/main/java/com/github/kr328/clash/core/model/Proxy.kt @@ -1,4 +1,4 @@ -package com.github.kr328.clash.core.transact +package com.github.kr328.clash.core.model import android.os.Parcel import android.os.Parcelable diff --git a/core/src/main/java/com/github/kr328/clash/core/model/ProxyChangedEvent.kt b/core/src/main/java/com/github/kr328/clash/core/model/ProxyChangedEvent.kt new file mode 100644 index 0000000..bfca74c --- /dev/null +++ b/core/src/main/java/com/github/kr328/clash/core/model/ProxyChangedEvent.kt @@ -0,0 +1,3 @@ +package com.github.kr328.clash.core.model + +class ProxyChangedEvent : Event \ No newline at end of file diff --git a/service/src/main/aidl/com/github/kr328/clash/service/IClashObserver.aidl b/service/src/main/aidl/com/github/kr328/clash/service/IClashObserver.aidl index 4be6895..e15118d 100644 --- a/service/src/main/aidl/com/github/kr328/clash/service/IClashObserver.aidl +++ b/service/src/main/aidl/com/github/kr328/clash/service/IClashObserver.aidl @@ -1,9 +1,9 @@ package com.github.kr328.clash.service; -import com.github.kr328.clash.core.ClashProcessStatus; +import com.github.kr328.clash.core.model.ClashProcessStatus; interface IClashObserver { void onProxyChanged(); - void onNewLog(); + void onNewLogItem(); void onProcessStatusChanged(in ClashProcessStatus status); } diff --git a/service/src/main/aidl/com/github/kr328/clash/service/IClashService.aidl b/service/src/main/aidl/com/github/kr328/clash/service/IClashService.aidl index 271a1b6..be64382 100644 --- a/service/src/main/aidl/com/github/kr328/clash/service/IClashService.aidl +++ b/service/src/main/aidl/com/github/kr328/clash/service/IClashService.aidl @@ -1,7 +1,7 @@ package com.github.kr328.clash.service; import com.github.kr328.clash.service.IClashObserver; -import com.github.kr328.clash.core.ClashProcessStatus; +import com.github.kr328.clash.core.model.ClashProcessStatus; interface IClashService { void start(); diff --git a/service/src/main/java/com/github/kr328/clash/service/ClashService.kt b/service/src/main/java/com/github/kr328/clash/service/ClashService.kt index 3d5da35..23c4e42 100644 --- a/service/src/main/java/com/github/kr328/clash/service/ClashService.kt +++ b/service/src/main/java/com/github/kr328/clash/service/ClashService.kt @@ -13,7 +13,7 @@ import androidx.core.app.NotificationManagerCompat import androidx.lifecycle.LiveData import androidx.lifecycle.Observer import com.github.kr328.clash.core.Clash -import com.github.kr328.clash.core.ClashProcessStatus +import com.github.kr328.clash.core.model.ProcessEvent import com.github.kr328.clash.core.Constants import com.github.kr328.clash.service.data.ClashDatabase import com.github.kr328.clash.service.data.ClashProfileEntity @@ -40,7 +40,8 @@ class ClashService : Service() { private var tunEnabled = false - private var status = ClashProcessStatus(ClashProcessStatus.STATUS_STOPPED_INT) + private var status = + ProcessEvent(ProcessEvent.STATUS_STOPPED_INT) set(value) { field = value @@ -128,7 +129,7 @@ class ClashService : Service() { clash.process.stop() } - override fun getClashProcessStatus(): ClashProcessStatus { + override fun getClashProcessStatus(): ProcessEvent { return status } @@ -161,9 +162,9 @@ class ClashService : Service() { handler.post { when (it.status) { - ClashProcessStatus.STATUS_STARTED_INT -> + ProcessEvent.STATUS_STARTED_INT -> currentProfile.observeForever(defaultProfileObserver) - ClashProcessStatus.STATUS_STOPPED_INT -> + ProcessEvent.STATUS_STOPPED_INT -> currentProfile.removeObserver(defaultProfileObserver) } } @@ -192,7 +193,7 @@ class ClashService : Service() { } private fun updateNotification() { - if ( status == ClashProcessStatus.STATUS_STARTED ) { + if ( status == ProcessEvent.STATUS_STARTED ) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationManagerCompat.from(this) .createNotificationChannel(NotificationChannel(CLASH_STATUS_NOTIFICATION_CHANNEL, diff --git a/service/src/main/java/com/github/kr328/clash/service/TunService.kt b/service/src/main/java/com/github/kr328/clash/service/TunService.kt index 82e7744..1858637 100644 --- a/service/src/main/java/com/github/kr328/clash/service/TunService.kt +++ b/service/src/main/java/com/github/kr328/clash/service/TunService.kt @@ -7,7 +7,7 @@ import android.os.Build import android.os.IBinder import android.os.ParcelFileDescriptor import android.util.Log -import com.github.kr328.clash.core.ClashProcessStatus +import com.github.kr328.clash.core.model.ProcessEvent import com.github.kr328.clash.service.net.DefaultNetworkObserver class TunService : VpnService() { @@ -44,22 +44,22 @@ class TunService : VpnService() { clash.registerObserver("tun", false, object: IClashObserver.Stub() { - override fun onStatusChanged(status: ClashProcessStatus?) { - if ( status == null ) + override fun onStatusChanged(event: ProcessEvent?) { + if ( event == null ) return - Log.d(TAG, "New clash status $status") + Log.d(TAG, "New clash status $event") - when ( status ) { - ClashProcessStatus.STATUS_STOPPED -> + when ( event ) { + ProcessEvent.STATUS_STOPPED -> stopSelf() - ClashProcessStatus.STATUS_STARTED -> + ProcessEvent.STATUS_STARTED -> clash.startTunDevice(fileDescriptor, VPN_MTU) } } }) - if ( clash.clashProcessStatus == ClashProcessStatus.STATUS_STARTED ) + if ( clash.clashProcessStatus == ProcessEvent.STATUS_STARTED ) clash.startTunDevice(fileDescriptor, VPN_MTU) else clash.start()