diff --git a/core/src/main/java/com/github/kr328/clash/core/event/ErrorEvent.kt b/core/src/main/java/com/github/kr328/clash/core/event/ErrorEvent.kt new file mode 100644 index 0000000..37be929 --- /dev/null +++ b/core/src/main/java/com/github/kr328/clash/core/event/ErrorEvent.kt @@ -0,0 +1,31 @@ +package com.github.kr328.clash.core.event + +import android.os.Parcel +import android.os.Parcelable +import com.github.kr328.clash.core.serialization.Parcels +import kotlinx.serialization.Serializable + +@Serializable +data class ErrorEvent(val type: Type, val message: String): Event, Parcelable { + enum class Type { + + } + + override fun writeToParcel(parcel: Parcel, flags: Int) { + Parcels.dump(serializer(), this, parcel) + } + + override fun describeContents(): Int { + return 0 + } + + companion object CREATOR : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): ErrorEvent { + return Parcels.load(serializer(), parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } +} \ No newline at end of file diff --git a/core/src/main/java/com/github/kr328/clash/core/event/LogEvent.kt b/core/src/main/java/com/github/kr328/clash/core/event/LogEvent.kt index b71c0bd..5bf2232 100644 --- a/core/src/main/java/com/github/kr328/clash/core/event/LogEvent.kt +++ b/core/src/main/java/com/github/kr328/clash/core/event/LogEvent.kt @@ -1,5 +1,8 @@ package com.github.kr328.clash.core.event +import android.os.Parcel +import android.os.Parcelable +import com.github.kr328.clash.core.serialization.Parcels import kotlinx.serialization.Decoder import kotlinx.serialization.Encoder import kotlinx.serialization.KSerializer @@ -10,12 +13,23 @@ import java.lang.IllegalArgumentException @Serializable data class LogEvent(val level: Level, val message: String): - Event { + Event, Parcelable { companion object { const val DEBUG_VALUE = 1 const val INFO_VALUE = 2 const val WARN_VALUE = 3 const val ERROR_VALUE = 4 + + @JvmField + val CREATOR = object: Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): LogEvent { + return Parcels.load(serializer(), parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } } @Serializable(LevelSerializer::class) @@ -45,4 +59,12 @@ data class LogEvent(val level: Level, val message: String): encoder.encodeInt(obj.value) } } + + 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/event/ProxyChangedEvent.kt b/core/src/main/java/com/github/kr328/clash/core/event/ProxyChangedEvent.kt index 46175c2..0f409b7 100644 --- a/core/src/main/java/com/github/kr328/clash/core/event/ProxyChangedEvent.kt +++ b/core/src/main/java/com/github/kr328/clash/core/event/ProxyChangedEvent.kt @@ -1,5 +1,28 @@ package com.github.kr328.clash.core.event +import android.os.Parcel +import android.os.Parcelable import com.github.kr328.clash.core.event.Event +import com.github.kr328.clash.core.serialization.Parcels +import kotlinx.serialization.Serializable -class ProxyChangedEvent : Event \ No newline at end of file +@Serializable +data class ProxyChangedEvent(val name: String, val selected: String) : Event,Parcelable { + override fun writeToParcel(parcel: Parcel, flags: Int) { + Parcels.dump(serializer(), this, parcel) + } + + override fun describeContents(): Int { + return 0 + } + + companion object CREATOR : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): ProxyChangedEvent { + return Parcels.load(serializer(), parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } +} \ No newline at end of file diff --git a/core/src/main/java/com/github/kr328/clash/core/event/TrafficEvent.kt b/core/src/main/java/com/github/kr328/clash/core/event/TrafficEvent.kt index 1342546..a1f733d 100644 --- a/core/src/main/java/com/github/kr328/clash/core/event/TrafficEvent.kt +++ b/core/src/main/java/com/github/kr328/clash/core/event/TrafficEvent.kt @@ -1,6 +1,27 @@ package com.github.kr328.clash.core.event +import android.os.Parcel +import android.os.Parcelable +import com.github.kr328.clash.core.serialization.Parcels import kotlinx.serialization.Serializable @Serializable -data class TrafficEvent(val down: Long, val up: Long, val total: Long): Event \ No newline at end of file +data class TrafficEvent(val down: Long, val up: Long, val total: Long): Event, Parcelable { + override fun writeToParcel(parcel: Parcel, flags: Int) { + Parcels.dump(serializer(), this, parcel) + } + + override fun describeContents(): Int { + return 0 + } + + companion object CREATOR : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): TrafficEvent { + return Parcels.load(serializer(), parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } +} \ No newline at end of file diff --git a/service/src/main/aidl/com/github/kr328/clash/core/ClashProcessStatus.aidl b/service/src/main/aidl/com/github/kr328/clash/core/ClashProcessStatus.aidl deleted file mode 100644 index 4d17b7c..0000000 --- a/service/src/main/aidl/com/github/kr328/clash/core/ClashProcessStatus.aidl +++ /dev/null @@ -1,3 +0,0 @@ -package com.github.kr328.clash.core; - -parcelable ClashProcessStatus; \ No newline at end of file diff --git a/service/src/main/aidl/com/github/kr328/clash/core/event/Event.aidl b/service/src/main/aidl/com/github/kr328/clash/core/event/Event.aidl new file mode 100644 index 0000000..8c1a067 --- /dev/null +++ b/service/src/main/aidl/com/github/kr328/clash/core/event/Event.aidl @@ -0,0 +1,7 @@ +package com.github.kr328.clash.core.event; + +parcelable ProcessEvent; +parcelable LogEvent; +parcelable ProxyChangedEvent; +parcelable TrafficEvent; +parcelable ErrorEvent; \ No newline at end of file diff --git a/service/src/main/aidl/com/github/kr328/clash/service/IClashEventObserver.aidl b/service/src/main/aidl/com/github/kr328/clash/service/IClashEventObserver.aidl new file mode 100644 index 0000000..ad9bebc --- /dev/null +++ b/service/src/main/aidl/com/github/kr328/clash/service/IClashEventObserver.aidl @@ -0,0 +1,11 @@ +package com.github.kr328.clash.service; + +import com.github.kr328.clash.core.event.Event; + +interface IClashEventObserver { + void onProcessEvent(in ProcessEvent event); + void onProxyChangedEvent(in ProxyChangedEvent event); + void onLogEvent(in LogEvent event); + void onErrorEvent(in ErrorEvent event); + void onTrafficEvent(in TrafficEvent event); +} diff --git a/service/src/main/aidl/com/github/kr328/clash/service/IClashEventService.aidl b/service/src/main/aidl/com/github/kr328/clash/service/IClashEventService.aidl new file mode 100644 index 0000000..373bf3b --- /dev/null +++ b/service/src/main/aidl/com/github/kr328/clash/service/IClashEventService.aidl @@ -0,0 +1,11 @@ +package com.github.kr328.clash.service; + +import com.github.kr328.clash.service.IClashEventObserver; + +interface IClashEventService { + void registerEventObserver(String id, in IClashEventObserver observer); + void unregisterEventObserver(String id); + + void acquireEvent(String id, int event); + void releaseEvent(String id, int event); +} 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 deleted file mode 100644 index e15118d..0000000 --- a/service/src/main/aidl/com/github/kr328/clash/service/IClashObserver.aidl +++ /dev/null @@ -1,9 +0,0 @@ -package com.github.kr328.clash.service; - -import com.github.kr328.clash.core.model.ClashProcessStatus; - -interface IClashObserver { - void onProxyChanged(); - 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 be64382..ddc541d 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,14 +1,13 @@ package com.github.kr328.clash.service; -import com.github.kr328.clash.service.IClashObserver; -import com.github.kr328.clash.core.model.ClashProcessStatus; +import com.github.kr328.clash.service.IClashEventObserver; +import com.github.kr328.clash.service.IClashEventService; +import com.github.kr328.clash.core.event.Event; interface IClashService { - void start(); - void stop(); - ClashProcessStatus getClashProcessStatus(); - void registerObserver(String id, boolean notifyCurrent, in IClashObserver observer); - void unregisterObserver(String id); + IClashEventService getEventService(); void startTunDevice(in ParcelFileDescriptor fd, int mtu); void stopTunDevice(); + void start(); + void stop(); } diff --git a/service/src/main/java/com/github/kr328/clash/service/ClashEventService.kt b/service/src/main/java/com/github/kr328/clash/service/ClashEventService.kt new file mode 100644 index 0000000..c0c48bc --- /dev/null +++ b/service/src/main/java/com/github/kr328/clash/service/ClashEventService.kt @@ -0,0 +1,123 @@ +package com.github.kr328.clash.service + +import android.os.Handler +import android.os.Looper +import com.github.kr328.clash.core.event.* +import java.util.* +import kotlin.concurrent.thread + +class ClashEventService(private val master: Master) : IClashEventService.Stub() { + interface Master { + fun requireEvent(event: Int) + fun releaseEvent(event: Int) + } + + companion object { + private val EVENT_SET = setOf(Event.EVENT_LOG, Event.EVENT_TRAFFIC, Event.EVENT_PROXY_CHANGED) + } + + private data class EventObserverRecord(val observer: IClashEventObserver, val acquiredEvent: MutableSet) + + private val observers = mutableMapOf() + private lateinit var handler: Handler + + init { + thread { + Looper.prepare() + + handler = Handler() + + Looper.loop() + } + } + + fun preformProcessEvent(event: ProcessEvent) { + handler.post { + observers.values.forEach { + it.observer.onProcessEvent(event) + } + } + } + + fun preformLogEvent(event: LogEvent) { + handler.post { + observers.values.forEach { + it.observer.onLogEvent(event) + } + } + } + + fun preformProxyChangedEvent(event: ProxyChangedEvent) { + handler.post { + observers.values.forEach { + it.observer.onProxyChangedEvent(event) + } + } + } + + fun preformTrafficEvent(event: TrafficEvent) { + handler.post { + observers.values.forEach { + it.observer.onTrafficEvent(event) + } + } + } + + fun preformErrorEvent(event: ErrorEvent) { + handler.post { + observers.values.forEach { + it.observer.onErrorEvent(event) + } + } + } + + override fun acquireEvent(id: String?, event: Int) { + handler.post { + require(id != null) + + observers[id]?.acquiredEvent?.add(event) + + recastEventRequirement() + } + } + + override fun releaseEvent(id: String?, event: Int) { + handler.post { + require(id != null) + + observers[id]?.acquiredEvent?.remove(event) + + recastEventRequirement() + } + } + + override fun unregisterEventObserver(id: String?) { + handler.post { + require(id != null) + + observers.remove(id) + + recastEventRequirement() + } + } + + override fun registerEventObserver(id: String?, observer: IClashEventObserver?) { + handler.post { + require(id != null && observer != null) + + observers[id] = EventObserverRecord(observer, mutableSetOf()) + } + } + + fun recastEventRequirement() { + handler.post { + val req = observers.values.flatMap { + it.acquiredEvent + }.toSet() + val rel = EVENT_SET - req + + req.forEach(master::requireEvent) + rel.forEach(master::releaseEvent) + } + } +} \ No newline at end of file