create event poll

This commit is contained in:
Kr328 committed 2019-11-24 16:29:13 +08:00
1 parent 438392ddf6
commit a6abb51046
13 files changed
+139 -67

No files matched your search

@@ -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(ClashProcessStatus.STATUS_STOPPED_INT))
private val clashStatus = MutableLiveData<ProcessEvent>(
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))
@@ -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))
@@ -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
}
}
@@ -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<ClashProcessStatus> {
override fun createFromParcel(parcel: Parcel): ClashProcessStatus {
return ClashProcessStatus(parcel)
}
override fun newArray(size: Int): Array<ClashProcessStatus?> {
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
}
}
@@ -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
}
}
@@ -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<Level> {
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)
}
}
}
@@ -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<ProcessEvent> {
override fun createFromParcel(parcel: Parcel): ProcessEvent {
return Parcels.load(serializer(), parcel)
}
override fun newArray(size: Int): Array<ProcessEvent?> {
return arrayOfNulls(size)
}
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
Parcels.dump(serializer(), this, parcel)
}
override fun describeContents(): Int {
return 0
}
}
@@ -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
@@ -0,0 +1,3 @@
package com.github.kr328.clash.core.model
class ProxyChangedEvent : Event
@@ -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);
}
@@ -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();
@@ -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,
@@ -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()