split traffic
This commit is contained in:
26 files changed
+321
-172
No files matched your search
@@ -106,14 +106,15 @@ abstract class BaseActivity : AppCompatActivity(), IClashEventObserver {
|
||||
override fun onProcessEvent(event: ProcessEvent?) =
|
||||
this@BaseActivity.onProcessEvent(event)
|
||||
|
||||
override fun onProxyChangedEvent(event: ProxyChangedEvent?) =
|
||||
this@BaseActivity.onProxyChangedEvent(event)
|
||||
|
||||
override fun onErrorEvent(event: ErrorEvent?) =
|
||||
this@BaseActivity.onErrorEvent(event)
|
||||
|
||||
override fun onTrafficEvent(event: TrafficEvent?) =
|
||||
this@BaseActivity.onTrafficEvent(event)
|
||||
override fun onSpeedEvent(event: SpeedEvent?) =
|
||||
this@BaseActivity.onSpeedEvent(event)
|
||||
|
||||
override fun onBandwidthEvent(event: BandwidthEvent?) {
|
||||
this@BaseActivity.onBandwidthEvent(event)
|
||||
}
|
||||
|
||||
override fun onProfileChanged(event: ProfileChangedEvent?) =
|
||||
this@BaseActivity.onProfileChanged(event)
|
||||
@@ -123,8 +124,8 @@ abstract class BaseActivity : AppCompatActivity(), IClashEventObserver {
|
||||
override fun onErrorEvent(event: ErrorEvent?) {}
|
||||
override fun onProfileChanged(event: ProfileChangedEvent?) {}
|
||||
override fun onProcessEvent(event: ProcessEvent?) {}
|
||||
override fun onProxyChangedEvent(event: ProxyChangedEvent?) {}
|
||||
override fun onTrafficEvent(event: TrafficEvent?) {}
|
||||
override fun onSpeedEvent(event: SpeedEvent?) {}
|
||||
override fun onBandwidthEvent(event: BandwidthEvent?) {}
|
||||
override fun asBinder(): IBinder {
|
||||
return observerBinder
|
||||
}
|
||||
|
||||
@@ -2,14 +2,10 @@ package com.github.kr328.clash
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
import android.net.VpnService
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import com.github.kr328.clash.core.event.Event
|
||||
import com.github.kr328.clash.core.event.ProcessEvent
|
||||
import com.github.kr328.clash.core.event.ProfileChangedEvent
|
||||
import com.github.kr328.clash.core.event.TrafficEvent
|
||||
import com.github.kr328.clash.core.event.*
|
||||
import com.github.kr328.clash.core.utils.ByteFormatter
|
||||
import com.github.kr328.clash.service.TunService
|
||||
import kotlinx.android.synthetic.main.activity_main.*
|
||||
@@ -92,7 +88,7 @@ class MainActivity : BaseActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTrafficEvent(event: TrafficEvent?) {
|
||||
override fun onBandwidthEvent(event: BandwidthEvent?) {
|
||||
runOnUiThread {
|
||||
if (lastEvent == ProcessEvent.STARTED) {
|
||||
activity_main_clash_status_summary.text =
|
||||
@@ -115,7 +111,7 @@ class MainActivity : BaseActivity() {
|
||||
it.eventService.registerEventObserver(
|
||||
MainActivity::class.java.simpleName,
|
||||
this,
|
||||
intArrayOf(Event.EVENT_TRAFFIC)
|
||||
intArrayOf(Event.EVENT_BANDWIDTH)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -21,13 +21,27 @@ class ProxyActivity : BaseActivity() {
|
||||
it.visibility = View.GONE
|
||||
}
|
||||
|
||||
activity_proxies_swipe.setOnRefreshListener {
|
||||
refreshList()
|
||||
}
|
||||
|
||||
refreshList()
|
||||
}
|
||||
|
||||
private fun refreshList() {
|
||||
if (!activity_proxies_swipe.isRefreshing)
|
||||
activity_proxies_swipe.isRefreshing = true
|
||||
|
||||
runClash { clash ->
|
||||
val proxies = clash.queryAllProxies().proxies
|
||||
val packet = clash.queryAllProxies()
|
||||
val proxies = packet.proxies
|
||||
val adapterProxies = proxies
|
||||
.mapValues {
|
||||
ListProxyGroup.ListProxy(it.value.name,
|
||||
ListProxyGroup.ListProxy(
|
||||
it.value.name,
|
||||
it.value.type.toString(),
|
||||
it.value.delay)
|
||||
it.value.delay
|
||||
)
|
||||
}
|
||||
|
||||
val listData = proxies
|
||||
@@ -41,16 +55,24 @@ class ProxyActivity : BaseActivity() {
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
.filter {
|
||||
when (packet.mode) {
|
||||
"Global" -> it.value.name == "GLOBAL"
|
||||
"Rule" -> it.value.name != "GLOBAL"
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
.sortedWith(compareBy(
|
||||
{
|
||||
it.value.type != ProxyPacket.Type.SELECT
|
||||
}, {
|
||||
it.value.name
|
||||
}))
|
||||
})
|
||||
)
|
||||
.map {
|
||||
ListProxyGroup(
|
||||
it.value.name,
|
||||
it.value.type.toString(),
|
||||
it.value.type,
|
||||
it.value.all.mapNotNull { hash ->
|
||||
adapterProxies[hash]
|
||||
},
|
||||
@@ -65,6 +87,7 @@ class ProxyActivity : BaseActivity() {
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
activity_proxies_list.visibility = View.VISIBLE
|
||||
activity_proxies_swipe.isRefreshing = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,9 +11,10 @@ import com.github.kr328.clash.R
|
||||
import com.github.kr328.clash.model.ListProxyGroup
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
|
||||
class ProxyAdapter(private val context: Context): RecyclerView.Adapter<ProxyAdapter.Holder>() {
|
||||
class ProxyAdapter(private val context: Context) : RecyclerView.Adapter<ProxyAdapter.Holder>() {
|
||||
var proxies: List<ListProxyGroup.ListProxy> = emptyList()
|
||||
var now: ListProxyGroup.ListProxy? = null
|
||||
var clickable: Boolean = false
|
||||
|
||||
class Holder(view: View) : RecyclerView.ViewHolder(view) {
|
||||
val name: TextView = view.findViewById(R.id.adapter_proxy_name)
|
||||
@@ -33,21 +34,32 @@ class ProxyAdapter(private val context: Context): RecyclerView.Adapter<ProxyAdap
|
||||
override fun onBindViewHolder(holder: Holder, position: Int) {
|
||||
val current = proxies[position]
|
||||
|
||||
if ( current === now ) {
|
||||
if (current === now) {
|
||||
holder.card.setCardBackgroundColor(context.getColor(R.color.colorAccent))
|
||||
holder.name.setTextColor(Color.WHITE)
|
||||
holder.type.setTextColor(Color.WHITE - 0x22222222)
|
||||
holder.delay.setTextColor(Color.WHITE - 0x11111111)
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
holder.card.setCardBackgroundColor(Color.WHITE)
|
||||
holder.name.setTextColor(Color.BLACK)
|
||||
holder.type.setTextColor(Color.LTGRAY)
|
||||
holder.delay.setTextColor(Color.DKGRAY)
|
||||
}
|
||||
|
||||
holder.card.isFocusable = clickable
|
||||
holder.card.isClickable = clickable
|
||||
|
||||
holder.name.text = current.name
|
||||
holder.type.text = current.type
|
||||
holder.delay.text = if ( current.delay > 0 ) current.delay.toString() else ""
|
||||
holder.delay.text = if (current.delay > 0) current.delay.toString() else ""
|
||||
|
||||
if (clickable) {
|
||||
holder.card.setOnClickListener {
|
||||
notifyItemChanged(proxies.indexOf(now))
|
||||
notifyItemChanged(position)
|
||||
|
||||
now = current
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,22 +8,25 @@ import android.widget.TextView
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.github.kr328.clash.R
|
||||
import com.github.kr328.clash.core.utils.Log
|
||||
import com.github.kr328.clash.core.model.ProxyPacket
|
||||
import com.github.kr328.clash.model.ListProxyGroup
|
||||
|
||||
class ProxyGroupAdapter(private val context: Context) : RecyclerView.Adapter<ProxyGroupAdapter.Holder>() {
|
||||
class ProxyGroupAdapter(private val context: Context) :
|
||||
RecyclerView.Adapter<ProxyGroupAdapter.Holder>() {
|
||||
var data: List<ListProxyGroup> = emptyList()
|
||||
|
||||
class Holder(view: View) : RecyclerView.ViewHolder(view) {
|
||||
val name: TextView = view.findViewById(R.id.adapter_proxy_group_name)
|
||||
val list: RecyclerView = view.findViewById(R.id.adapter_proxy_group_list)
|
||||
val expend: View = view.findViewById(R.id.adapter_proxy_group_expand)
|
||||
val test: View = view.findViewById(R.id.adapter_proxy_group_url_test)
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
|
||||
return Holder(LayoutInflater.from(context)
|
||||
.inflate(R.layout.adapter_proxy_group, parent, false)).apply {
|
||||
list.layoutManager = object: GridLayoutManager(context, 2) {
|
||||
return Holder(
|
||||
LayoutInflater.from(context)
|
||||
.inflate(R.layout.adapter_proxy_group, parent, false)
|
||||
).apply {
|
||||
list.layoutManager = object : GridLayoutManager(context, 2) {
|
||||
override fun canScrollHorizontally(): Boolean = false
|
||||
override fun canScrollVertically(): Boolean = false
|
||||
}
|
||||
@@ -38,19 +41,16 @@ class ProxyGroupAdapter(private val context: Context) : RecyclerView.Adapter<Pro
|
||||
override fun onBindViewHolder(holder: Holder, position: Int) {
|
||||
val current = data[position]
|
||||
|
||||
holder.test.visibility =
|
||||
if (current.type == ProxyPacket.Type.SELECT) View.VISIBLE else View.GONE
|
||||
holder.name.text = current.name
|
||||
holder.list.visibility = if (current.hide) View.GONE else View.VISIBLE
|
||||
|
||||
Log.i("${current.hide}")
|
||||
|
||||
(holder.list.adapter as ProxyAdapter).apply {
|
||||
proxies = current.proxies
|
||||
now = current.now
|
||||
clickable = current.type == ProxyPacket.Type.SELECT
|
||||
|
||||
holder.expend.setOnClickListener {
|
||||
current.hide = !current.hide
|
||||
this@ProxyGroupAdapter.notifyItemChanged(position)
|
||||
}
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,12 @@
|
||||
package com.github.kr328.clash.model
|
||||
|
||||
data class ListProxyGroup(val name: String, val type: String, val proxies: List<ListProxy>, var now: ListProxy?, var hide: Boolean = false) {
|
||||
import com.github.kr328.clash.core.model.ProxyPacket
|
||||
|
||||
data class ListProxyGroup(
|
||||
val name: String,
|
||||
val type: ProxyPacket.Type,
|
||||
val proxies: List<ListProxy>,
|
||||
var now: ListProxy?
|
||||
) {
|
||||
data class ListProxy(val name: String, val type: String, val delay: Long)
|
||||
}
|
||||
@@ -15,8 +15,13 @@
|
||||
android:layout_height="60dp" />
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/activity_proxies_list"
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
android:id="@+id/activity_proxies_swipe"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
android:layout_height="wrap_content">
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/activity_proxies_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
</LinearLayout>
|
||||
@@ -8,6 +8,7 @@
|
||||
android:id="@+id/adapter_proxy_card"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
app:cardUseCompatPadding="true"
|
||||
app:cardElevation="2dp"
|
||||
app:cardCornerRadius="5dp">
|
||||
@@ -19,10 +20,11 @@
|
||||
<TextView
|
||||
android:id="@+id/adapter_proxy_name"
|
||||
android:textColor="@android:color/black"
|
||||
android:text="@string/app_name"
|
||||
android:maxLines="1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toStartOf="@id/adapter_proxy_delay"
|
||||
android:layout_alignParentStart="true"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/adapter_proxy_type"
|
||||
@@ -30,7 +32,6 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="12sp"
|
||||
android:text="@string/app_name"
|
||||
android:maxLines="1"/>
|
||||
|
||||
<TextView
|
||||
@@ -39,11 +40,9 @@
|
||||
android:textSize="12sp"
|
||||
android:id="@+id/adapter_proxy_delay"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toEndOf="@id/adapter_proxy_name"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:minWidth="30dp"/>
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</RelativeLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/adapter_proxy_group_root"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:animateLayoutChanges="true"
|
||||
android:paddingStart="12dp"
|
||||
android:paddingEnd="12dp"
|
||||
android:paddingTop="12dp">
|
||||
android:paddingStart="15dp"
|
||||
android:paddingEnd="15dp"
|
||||
android:paddingTop="15dp">
|
||||
|
||||
<TextView
|
||||
android:padding="2dp"
|
||||
@@ -18,19 +18,14 @@
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<View
|
||||
android:id="@+id/adapter_proxy_group_url_test"
|
||||
android:focusable="true"
|
||||
android:clickable="true"
|
||||
android:layout_width="22dp"
|
||||
android:layout_height="22dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:background="@drawable/ic_url_test"
|
||||
android:layout_toStartOf="@id/adapter_proxy_group_expand"/>
|
||||
|
||||
<View
|
||||
android:id="@+id/adapter_proxy_group_expand"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:layout_width="22dp"
|
||||
android:layout_height="22dp"
|
||||
android:background="@drawable/ic_expand_more"/>
|
||||
android:background="@drawable/ic_url_test" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/adapter_proxy_group_list"
|
||||
|
||||
@@ -16,7 +16,6 @@ func handlePullTrafficEvent(client *net.UnixConn) {
|
||||
traffic := tunnel.DefaultManager
|
||||
buf := &bytes.Buffer{}
|
||||
|
||||
defer close(trafficExit)
|
||||
defer ticker.Stop()
|
||||
|
||||
go func() {
|
||||
@@ -26,7 +25,7 @@ func handlePullTrafficEvent(client *net.UnixConn) {
|
||||
_, err := client.Read(buf[:])
|
||||
|
||||
if err != nil {
|
||||
trafficExit <- 0
|
||||
close(trafficExit)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -38,23 +37,67 @@ func handlePullTrafficEvent(client *net.UnixConn) {
|
||||
buf.Reset()
|
||||
|
||||
var Packet struct {
|
||||
Up int64 `json:"up"`
|
||||
Down int64 `json:"down"`
|
||||
Total int64 `json:"total"`
|
||||
Up int64 `json:"up"`
|
||||
Down int64 `json:"down"`
|
||||
}
|
||||
|
||||
up, down := traffic.Now()
|
||||
snapshot := traffic.Snapshot()
|
||||
|
||||
Packet.Up = up
|
||||
Packet.Down = down
|
||||
Packet.Total = snapshot.DownloadTotal + snapshot.UploadTotal
|
||||
|
||||
json.NewEncoder(buf).Encode(&Packet)
|
||||
|
||||
writeCommandPacket(client, buf.Bytes())
|
||||
if writeCommandPacket(client, buf.Bytes()) != nil {
|
||||
return
|
||||
}
|
||||
case <-trafficExit:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func handlePullBandwidthEvent(client *net.UnixConn) {
|
||||
bandWidthExit := make(chan int)
|
||||
ticker := time.NewTicker(time.Second)
|
||||
|
||||
mgr := tunnel.DefaultManager
|
||||
buf := &bytes.Buffer{}
|
||||
|
||||
defer ticker.Stop()
|
||||
|
||||
go func() {
|
||||
|
||||
for {
|
||||
var buf [4]byte
|
||||
|
||||
_, err := client.Read(buf[:])
|
||||
|
||||
if err != nil {
|
||||
close(bandWidthExit)
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
buf.Reset()
|
||||
|
||||
var Packet struct {
|
||||
Total int64 `json:"total"`
|
||||
}
|
||||
|
||||
sp := mgr.Snapshot()
|
||||
|
||||
Packet.Total = sp.DownloadTotal + sp.UploadTotal
|
||||
|
||||
json.NewEncoder(buf).Encode(&Packet)
|
||||
|
||||
if writeCommandPacket(client, buf.Bytes()) != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,9 +12,11 @@ func handleQueryProxies(client *net.UnixConn) {
|
||||
proxies := tunnel.Instance().Proxies()
|
||||
|
||||
var root struct {
|
||||
Mode string `json:"mode"`
|
||||
Proxies map[string]interface{} `json:"proxies"`
|
||||
}
|
||||
|
||||
root.Mode = tunnel.Instance().Mode().String()
|
||||
root.Proxies = make(map[string]interface{})
|
||||
|
||||
for k, p := range proxies {
|
||||
|
||||
@@ -16,19 +16,22 @@ const (
|
||||
commandQueryProxies uint32 = 5
|
||||
commandPullTraffic uint32 = 6
|
||||
commandPullLog uint32 = 7
|
||||
commandPullBandwidth uint32 = 8
|
||||
commandSetProxy uint32 = 9
|
||||
)
|
||||
|
||||
var handlers map[uint32]func(*net.UnixConn) = make(map[uint32]func(*net.UnixConn))
|
||||
|
||||
func init() {
|
||||
handlers[commandPing] = handlePing // ping.go
|
||||
handlers[commandTunStart] = handleTunStart // tun.go
|
||||
handlers[commandTunStop] = handleTunStop // tun.go
|
||||
handlers[commandProfileDefault] = handleProfileDefault // profile.go
|
||||
handlers[commandProfileReload] = handleProfileReload // profile.go
|
||||
handlers[commandQueryProxies] = handleQueryProxies // proxies.go
|
||||
handlers[commandPullTraffic] = handlePullTrafficEvent // event.go
|
||||
handlers[commandPullLog] = nil // event.go
|
||||
handlers[commandPing] = handlePing // ping.go
|
||||
handlers[commandTunStart] = handleTunStart // tun.go
|
||||
handlers[commandTunStop] = handleTunStop // tun.go
|
||||
handlers[commandProfileDefault] = handleProfileDefault // profile.go
|
||||
handlers[commandProfileReload] = handleProfileReload // profile.go
|
||||
handlers[commandQueryProxies] = handleQueryProxies // proxies.go
|
||||
handlers[commandPullTraffic] = handlePullTrafficEvent // event.go
|
||||
handlers[commandPullLog] = nil // event.go
|
||||
handlers[commandPullBandwidth] = handlePullBandwidthEvent // event.go
|
||||
}
|
||||
|
||||
// Start local control server
|
||||
|
||||
@@ -4,10 +4,10 @@ import android.content.Context
|
||||
import android.net.LocalSocket
|
||||
import android.util.Log
|
||||
import com.github.kr328.clash.core.Constants.TAG
|
||||
import com.github.kr328.clash.core.event.BandwidthEvent
|
||||
import com.github.kr328.clash.core.event.LogEvent
|
||||
import com.github.kr328.clash.core.event.ProcessEvent
|
||||
import com.github.kr328.clash.core.event.ProxyChangedEvent
|
||||
import com.github.kr328.clash.core.event.TrafficEvent
|
||||
import com.github.kr328.clash.core.event.SpeedEvent
|
||||
import com.github.kr328.clash.core.model.RawProxyPacket
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.JsonConfiguration
|
||||
@@ -28,9 +28,10 @@ class Clash(
|
||||
const val COMMAND_TUN_STOP = 2
|
||||
const val COMMAND_PROFILE_RELOAD = 4
|
||||
const val COMMAND_QUERY_PROXIES = 5
|
||||
const val COMMAND_PULL_TRAFFIC = 6
|
||||
const val COMMAND_PULL_SPEED = 6
|
||||
const val COMMAND_PULL_LOG = 7
|
||||
const val COMMAND_PULL_PROXY_CHANGED = 8
|
||||
const val COMMAND_PULL_BANDWIDTH = 8
|
||||
const val COMMAND_SET_PROXY = 9
|
||||
|
||||
const val PING_REPLY = 233
|
||||
}
|
||||
@@ -60,21 +61,19 @@ class Clash(
|
||||
return runControl(COMMAND_QUERY_PROXIES) { _, input, _ ->
|
||||
val data = input.readString()
|
||||
|
||||
Log.d(TAG, data)
|
||||
|
||||
Json(JsonConfiguration.Stable.copy(strictMode = false))
|
||||
.parse(RawProxyPacket.serializer(), data)
|
||||
}
|
||||
}
|
||||
|
||||
fun pullTrafficEvent(initial: (LocalSocket) -> Unit, callback: (TrafficEvent) -> Unit) {
|
||||
runControlNoException(COMMAND_PULL_TRAFFIC) { socket, input, _ ->
|
||||
fun pullSpeedEvent(initial: (LocalSocket) -> Unit, callback: (SpeedEvent) -> Unit) {
|
||||
runControlNoException(COMMAND_PULL_SPEED) { socket, input, _ ->
|
||||
initial(socket)
|
||||
|
||||
while (!Thread.currentThread().isInterrupted) {
|
||||
callback(
|
||||
Json(JsonConfiguration.Stable).parse(
|
||||
TrafficEvent.serializer(),
|
||||
SpeedEvent.serializer(),
|
||||
input.readString()
|
||||
)
|
||||
)
|
||||
@@ -97,17 +96,14 @@ class Clash(
|
||||
}
|
||||
}
|
||||
|
||||
fun pullProxyChangedEvent(
|
||||
initial: (LocalSocket) -> Unit,
|
||||
callback: (ProxyChangedEvent) -> Unit
|
||||
) {
|
||||
runControlNoException(COMMAND_PULL_PROXY_CHANGED) { socket, input, _ ->
|
||||
fun pullBandwidthEvent(initial: (LocalSocket) -> Unit, callback: (BandwidthEvent) -> Unit) {
|
||||
runControlNoException(COMMAND_PULL_BANDWIDTH) { socket, input, _ ->
|
||||
initial(socket)
|
||||
|
||||
while (!Thread.currentThread().isInterrupted) {
|
||||
callback(
|
||||
Json(JsonConfiguration.Stable).parse(
|
||||
ProxyChangedEvent.serializer(),
|
||||
BandwidthEvent.serializer(),
|
||||
input.readString()
|
||||
)
|
||||
)
|
||||
|
||||
+5
-4
@@ -6,7 +6,7 @@ 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, Parcelable {
|
||||
data class BandwidthEvent(val total: Long): Parcelable {
|
||||
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||
Parcels.dump(serializer(), this, parcel)
|
||||
}
|
||||
@@ -15,13 +15,14 @@ data class TrafficEvent(val down: Long, val up: Long, val total: Long) : Event,
|
||||
return 0
|
||||
}
|
||||
|
||||
companion object CREATOR : Parcelable.Creator<TrafficEvent> {
|
||||
override fun createFromParcel(parcel: Parcel): TrafficEvent {
|
||||
companion object CREATOR : Parcelable.Creator<BandwidthEvent> {
|
||||
override fun createFromParcel(parcel: Parcel): BandwidthEvent {
|
||||
return Parcels.load(serializer(), parcel)
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<TrafficEvent?> {
|
||||
override fun newArray(size: Int): Array<BandwidthEvent?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,9 +2,8 @@ package com.github.kr328.clash.core.event
|
||||
|
||||
interface Event {
|
||||
companion object {
|
||||
const val EVENT_CLOSE = 0
|
||||
const val EVENT_LOG = 1
|
||||
const val EVENT_PROXY_CHANGED = 2
|
||||
const val EVENT_TRAFFIC = 3
|
||||
const val EVENT_SPEED = 3
|
||||
const val EVENT_BANDWIDTH = 4
|
||||
}
|
||||
}
|
||||
@@ -0,0 +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 SpeedEvent(val down: Long, val up: 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<SpeedEvent> {
|
||||
override fun createFromParcel(parcel: Parcel): SpeedEvent {
|
||||
return Parcels.load(serializer(), parcel)
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<SpeedEvent?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import com.github.kr328.clash.core.serialization.Parcels
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class ProxyPacket(val proxies: Map<Int, Proxy>): Parcelable {
|
||||
data class ProxyPacket(val mode: String, val proxies: Map<Int, Proxy>): Parcelable {
|
||||
@Serializable
|
||||
data class Proxy(val name: String, val type: Type, val now: Int, val all: Set<Int>, val delay: Long)
|
||||
|
||||
@@ -84,7 +84,7 @@ data class ProxyPacket(val proxies: Map<Int, Proxy>): Parcelable {
|
||||
entry.value.first to Proxy(entry.key, type, now, all, delay)
|
||||
}
|
||||
|
||||
return ProxyPacket(proxies.toMap())
|
||||
return ProxyPacket(rawProxy.mode, proxies.toMap())
|
||||
}
|
||||
|
||||
@JvmField
|
||||
|
||||
@@ -3,7 +3,7 @@ package com.github.kr328.clash.core.model
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class RawProxyPacket(val proxies: Map<String, RawProxy>) {
|
||||
data class RawProxyPacket(val mode: String, val proxies: Map<String, RawProxy>) {
|
||||
@Serializable
|
||||
data class RawProxy(val type: String,
|
||||
val all: List<String> = emptyList(),
|
||||
|
||||
@@ -10,7 +10,7 @@ object ByteFormatter {
|
||||
bytes > 1024 ->
|
||||
String.format("%.2f KB", (bytes.toDouble() / 1024))
|
||||
else ->
|
||||
"$bytes Byte"
|
||||
"$bytes Bytes"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ package com.github.kr328.clash.core.event;
|
||||
|
||||
parcelable ProcessEvent;
|
||||
parcelable LogEvent;
|
||||
parcelable ProxyChangedEvent;
|
||||
parcelable TrafficEvent;
|
||||
parcelable SpeedEvent;
|
||||
parcelable BandwidthEvent;
|
||||
parcelable ErrorEvent;
|
||||
parcelable ProfileChangedEvent;
|
||||
parcelable ProfileChangedEvent;
|
||||
@@ -4,9 +4,9 @@ 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);
|
||||
void onSpeedEvent(in SpeedEvent event);
|
||||
void onBandwidthEvent(in BandwidthEvent event);
|
||||
void onProfileChanged(in ProfileChangedEvent event);
|
||||
}
|
||||
@@ -2,22 +2,22 @@ package com.github.kr328.clash.service
|
||||
|
||||
import android.net.LocalSocket
|
||||
import com.github.kr328.clash.core.Clash
|
||||
import com.github.kr328.clash.core.event.BandwidthEvent
|
||||
import com.github.kr328.clash.core.event.LogEvent
|
||||
import com.github.kr328.clash.core.event.ProxyChangedEvent
|
||||
import com.github.kr328.clash.core.event.TrafficEvent
|
||||
import com.github.kr328.clash.core.event.SpeedEvent
|
||||
import com.github.kr328.clash.core.utils.Log
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
class ClashEventPuller(private val clash: Clash, private val master: Master) {
|
||||
interface Master {
|
||||
fun onLogPulled(event: LogEvent)
|
||||
fun onTrafficPulled(event: TrafficEvent)
|
||||
fun onProxyChangedPulled(event: ProxyChangedEvent)
|
||||
fun onSpeedPulled(event: SpeedEvent)
|
||||
fun onBandwidthPulled(event: BandwidthEvent)
|
||||
}
|
||||
|
||||
private var logSocket: LocalSocket? = null
|
||||
private var trafficSocket: LocalSocket? = null
|
||||
private var proxyChangedSocket: LocalSocket? = null
|
||||
private var speedSocket: LocalSocket? = null
|
||||
private var bandwidthSocket: LocalSocket? = null
|
||||
|
||||
fun startLogPuller() {
|
||||
synchronized(LogEvent::class) {
|
||||
@@ -47,45 +47,81 @@ class ClashEventPuller(private val clash: Clash, private val master: Master) {
|
||||
}
|
||||
}
|
||||
|
||||
fun startSpeedPull() {
|
||||
synchronized(SpeedEvent::class) {
|
||||
if (speedSocket != null)
|
||||
return
|
||||
}
|
||||
|
||||
thread {
|
||||
clash.pullSpeedEvent({
|
||||
synchronized(SpeedEvent::class) {
|
||||
if (speedSocket != null) {
|
||||
it.close()
|
||||
return@pullSpeedEvent
|
||||
} else {
|
||||
speedSocket = it
|
||||
Log.i("Speed puller started")
|
||||
}
|
||||
|
||||
}
|
||||
}) {
|
||||
master.onSpeedPulled(it)
|
||||
}
|
||||
|
||||
synchronized(SpeedEvent::class) {
|
||||
Log.i("Speed puller stopped")
|
||||
|
||||
speedSocket = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun startBandwidthPull() {
|
||||
synchronized(BandwidthEvent::class) {
|
||||
if (bandwidthSocket != null)
|
||||
return
|
||||
}
|
||||
|
||||
thread {
|
||||
clash.pullBandwidthEvent({
|
||||
synchronized(BandwidthEvent::class) {
|
||||
if (bandwidthSocket != null) {
|
||||
it.close()
|
||||
return@pullBandwidthEvent
|
||||
} else {
|
||||
bandwidthSocket = it
|
||||
Log.i("Bandwidth puller started")
|
||||
}
|
||||
|
||||
}
|
||||
}) {
|
||||
master.onBandwidthPulled(it)
|
||||
}
|
||||
|
||||
synchronized(BandwidthEvent::class) {
|
||||
Log.i("Bandwidth puller stopped")
|
||||
|
||||
bandwidthSocket = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun stopLogPull() {
|
||||
synchronized(LogEvent::class) {
|
||||
logSocket.closeSilent()
|
||||
}
|
||||
}
|
||||
|
||||
fun startTrafficPull() {
|
||||
synchronized(TrafficEvent::class) {
|
||||
if (trafficSocket != null)
|
||||
return
|
||||
}
|
||||
|
||||
thread {
|
||||
clash.pullTrafficEvent({
|
||||
synchronized(TrafficEvent::class) {
|
||||
if (trafficSocket != null) {
|
||||
it.close()
|
||||
return@pullTrafficEvent
|
||||
} else {
|
||||
trafficSocket = it
|
||||
Log.i("Traffic puller started")
|
||||
}
|
||||
|
||||
}
|
||||
}) {
|
||||
master.onTrafficPulled(it)
|
||||
}
|
||||
|
||||
synchronized(TrafficEvent::class) {
|
||||
Log.i("Traffic puller stopped")
|
||||
|
||||
trafficSocket = null
|
||||
}
|
||||
fun stopSpeedPull() {
|
||||
synchronized(SpeedEvent::class) {
|
||||
speedSocket.closeSilent()
|
||||
}
|
||||
}
|
||||
|
||||
fun stopTrafficPull() {
|
||||
synchronized(TrafficEvent::class) {
|
||||
trafficSocket.closeSilent()
|
||||
fun stopBandwidthPull() {
|
||||
synchronized(BandwidthEvent::class) {
|
||||
bandwidthSocket.closeSilent()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ class ClashEventService(private val master: Master) : IClashEventService.Stub()
|
||||
|
||||
companion object {
|
||||
private val EVENT_SET =
|
||||
setOf(Event.EVENT_LOG, Event.EVENT_TRAFFIC, Event.EVENT_PROXY_CHANGED)
|
||||
setOf(Event.EVENT_LOG, Event.EVENT_SPEED, Event.EVENT_BANDWIDTH)
|
||||
}
|
||||
|
||||
private data class EventObserverRecord(
|
||||
@@ -23,7 +23,7 @@ class ClashEventService(private val master: Master) : IClashEventService.Stub()
|
||||
private val handler = Executors.newSingleThreadExecutor()
|
||||
|
||||
private var currentProcessEvent = ProcessEvent.STOPPED
|
||||
private var currentTrafficEvent = TrafficEvent(0, 0, 0)
|
||||
private var currentBandwidthEvent = BandwidthEvent(0)
|
||||
|
||||
fun preformProcessEvent(event: ProcessEvent) {
|
||||
handler.submit {
|
||||
@@ -44,22 +44,22 @@ class ClashEventService(private val master: Master) : IClashEventService.Stub()
|
||||
}
|
||||
}
|
||||
|
||||
fun preformProxyChangedEvent(event: ProxyChangedEvent) {
|
||||
fun preformSpeedEvent(event: SpeedEvent) {
|
||||
handler.submit {
|
||||
observers.values.forEach {
|
||||
if (it.acquiredEvent.contains(Event.EVENT_PROXY_CHANGED))
|
||||
it.observer.onProxyChangedEvent(event)
|
||||
if (it.acquiredEvent.contains(Event.EVENT_SPEED))
|
||||
it.observer.onSpeedEvent(event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun preformTrafficEvent(event: TrafficEvent) {
|
||||
fun preformBandwidthEvent(event: BandwidthEvent) {
|
||||
handler.submit {
|
||||
currentTrafficEvent = event
|
||||
currentBandwidthEvent = event
|
||||
|
||||
observers.values.forEach {
|
||||
if (it.acquiredEvent.contains(Event.EVENT_TRAFFIC))
|
||||
it.observer.onTrafficEvent(event)
|
||||
if ( it.acquiredEvent.contains(Event.EVENT_BANDWIDTH) )
|
||||
it.observer.onBandwidthEvent(event)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -111,8 +111,8 @@ class ClashEventService(private val master: Master) : IClashEventService.Stub()
|
||||
if (initial) {
|
||||
observer.onProcessEvent(currentProcessEvent)
|
||||
|
||||
if (events.contains(Event.EVENT_TRAFFIC))
|
||||
observer.onTrafficEvent(currentTrafficEvent)
|
||||
if (events.contains(Event.EVENT_BANDWIDTH))
|
||||
observer.onBandwidthEvent(currentBandwidthEvent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ class ClashProfileService(context: Context, private val master: Master) :
|
||||
fun preformProfileChanged()
|
||||
}
|
||||
|
||||
val database by lazy {
|
||||
private val database by lazy {
|
||||
ClashDatabase.getInstance(context).openClashProfileDao()
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ import android.os.ParcelFileDescriptor
|
||||
import com.github.kr328.clash.core.Clash
|
||||
import com.github.kr328.clash.core.event.*
|
||||
import com.github.kr328.clash.core.model.ProxyPacket
|
||||
import com.github.kr328.clash.core.model.RawProxyPacket
|
||||
import com.github.kr328.clash.core.utils.Log
|
||||
import com.github.kr328.clash.service.data.ClashDatabase
|
||||
import java.io.File
|
||||
@@ -45,7 +44,7 @@ class ClashService : Service(), IClashEventObserver, ClashEventService.Master,
|
||||
this@ClashService.eventService.preformErrorEvent(
|
||||
ErrorEvent(ErrorEvent.Type.QUERY_PROXY_FAILURE, e.toString())
|
||||
)
|
||||
ProxyPacket(emptyMap())
|
||||
ProxyPacket("Unknown", emptyMap())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,7 +99,7 @@ class ClashService : Service(), IClashEventObserver, ClashEventService.Master,
|
||||
eventService.registerEventObserver(
|
||||
ClashService::class.java.name,
|
||||
this@ClashService,
|
||||
intArrayOf(Event.EVENT_TRAFFIC)
|
||||
intArrayOf(Event.EVENT_SPEED)
|
||||
)
|
||||
Intent.ACTION_SCREEN_OFF ->
|
||||
eventService.registerEventObserver(
|
||||
@@ -117,10 +116,12 @@ class ClashService : Service(), IClashEventObserver, ClashEventService.Master,
|
||||
return
|
||||
|
||||
when (event) {
|
||||
Event.EVENT_TRAFFIC ->
|
||||
puller.startTrafficPull()
|
||||
Event.EVENT_SPEED ->
|
||||
puller.startSpeedPull()
|
||||
Event.EVENT_LOG ->
|
||||
puller.startLogPuller()
|
||||
Event.EVENT_BANDWIDTH ->
|
||||
puller.startBandwidthPull()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,10 +130,12 @@ class ClashService : Service(), IClashEventObserver, ClashEventService.Master,
|
||||
return
|
||||
|
||||
when (event) {
|
||||
Event.EVENT_TRAFFIC ->
|
||||
puller.stopTrafficPull()
|
||||
Event.EVENT_SPEED ->
|
||||
puller.stopSpeedPull()
|
||||
Event.EVENT_LOG ->
|
||||
puller.stopLogPull()
|
||||
Event.EVENT_BANDWIDTH ->
|
||||
puller.stopBandwidthPull()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,7 +158,7 @@ class ClashService : Service(), IClashEventObserver, ClashEventService.Master,
|
||||
eventService.registerEventObserver(
|
||||
ClashService::class.java.name,
|
||||
this@ClashService,
|
||||
intArrayOf(Event.EVENT_TRAFFIC)
|
||||
intArrayOf(Event.EVENT_SPEED)
|
||||
)
|
||||
|
||||
registerReceiver(screenReceiver, IntentFilter().apply {
|
||||
@@ -201,7 +204,8 @@ class ClashService : Service(), IClashEventObserver, ClashEventService.Master,
|
||||
eventService.recastEventRequirement()
|
||||
}
|
||||
ProcessEvent.STOPPED -> {
|
||||
eventService.preformTrafficEvent(TrafficEvent(0, 0, 0))
|
||||
eventService.preformSpeedEvent(SpeedEvent(0, 0))
|
||||
eventService.preformBandwidthEvent(BandwidthEvent(0))
|
||||
|
||||
notification.cancel()
|
||||
}
|
||||
@@ -230,7 +234,7 @@ class ClashService : Service(), IClashEventObserver, ClashEventService.Master,
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTrafficEvent(event: TrafficEvent?) {
|
||||
override fun onSpeedEvent(event: SpeedEvent?) {
|
||||
notification.setSpeed(event?.up ?: 0, event?.down ?: 0)
|
||||
}
|
||||
|
||||
@@ -242,15 +246,15 @@ class ClashService : Service(), IClashEventObserver, ClashEventService.Master,
|
||||
eventService.preformLogEvent(event)
|
||||
}
|
||||
|
||||
override fun onTrafficPulled(event: TrafficEvent) {
|
||||
eventService.preformTrafficEvent(event)
|
||||
override fun onSpeedPulled(event: SpeedEvent) {
|
||||
eventService.preformSpeedEvent(event)
|
||||
}
|
||||
|
||||
override fun onProxyChangedPulled(event: ProxyChangedEvent) {
|
||||
eventService.preformProxyChangedEvent(event)
|
||||
override fun onBandwidthPulled(event: BandwidthEvent) {
|
||||
eventService.preformBandwidthEvent(event)
|
||||
}
|
||||
|
||||
override fun onProxyChangedEvent(event: ProxyChangedEvent?) {}
|
||||
override fun onBandwidthEvent(event: BandwidthEvent?) {}
|
||||
override fun onLogEvent(event: LogEvent?) {}
|
||||
override fun onErrorEvent(event: ErrorEvent?) {}
|
||||
override fun asBinder(): IBinder = object : Binder() {
|
||||
|
||||
@@ -142,11 +142,11 @@ class TunService : VpnService(), IClashEventObserver {
|
||||
return this
|
||||
}
|
||||
|
||||
override fun onSpeedEvent(event: SpeedEvent?) {}
|
||||
override fun onBandwidthEvent(event: BandwidthEvent?) {}
|
||||
override fun onLogEvent(event: LogEvent?) {}
|
||||
override fun onErrorEvent(event: ErrorEvent?) {}
|
||||
override fun onProfileChanged(event: ProfileChangedEvent?) {}
|
||||
override fun onProxyChangedEvent(event: ProxyChangedEvent?) {}
|
||||
override fun onTrafficEvent(event: TrafficEvent?) {}
|
||||
override fun asBinder(): IBinder = object : Binder() {
|
||||
override fun queryLocalInterface(descriptor: String): IInterface? {
|
||||
return this@TunService
|
||||
|
||||
Reference in new issue
Block a user