diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1c15fa3..ae35eae 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -44,7 +44,7 @@ android:exported="false" android:screenOrientation="portrait"/> diff --git a/app/src/main/java/com/github/kr328/clash/ProxyActivity.kt b/app/src/main/java/com/github/kr328/clash/ProxyActivity.kt index 0690f76..6bb2dd6 100644 --- a/app/src/main/java/com/github/kr328/clash/ProxyActivity.kt +++ b/app/src/main/java/com/github/kr328/clash/ProxyActivity.kt @@ -1,28 +1,70 @@ package com.github.kr328.clash import android.os.Bundle +import android.view.View import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView import com.github.kr328.clash.adapter.ProxyGroupAdapter -import com.github.kr328.clash.core.model.Proxy +import com.github.kr328.clash.core.model.ProxyPacket +import com.github.kr328.clash.model.ListProxyGroup +import kotlinx.android.synthetic.main.activity_proxies.* class ProxyActivity : BaseActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + setContentView(R.layout.activity_proxies) - val content = RecyclerView(this) + setSupportActionBar(activity_proxies_toolbar) - setContentView(content) - - content.layoutManager = LinearLayoutManager(this) - content.adapter = ProxyGroupAdapter(this) + activity_proxies_list.also { + it.layoutManager = LinearLayoutManager(this) + it.adapter = ProxyGroupAdapter(this) + it.visibility = View.GONE + } runClash { clash -> val proxies = clash.queryAllProxies().proxies + val adapterProxies = proxies + .mapValues { + ListProxyGroup.ListProxy(it.value.name, + it.value.type.toString(), + it.value.delay) + } + + val listData = proxies + .asSequence() + .filter { + when (it.value.type) { + ProxyPacket.Type.URL_TEST -> true + ProxyPacket.Type.FALLBACK -> true + ProxyPacket.Type.LOAD_BALANCE -> true + ProxyPacket.Type.SELECT -> true + else -> false + } + } + .sortedWith(compareBy( + { + it.value.type != ProxyPacket.Type.SELECT + }, { + it.value.name + })) + .map { + ListProxyGroup( + it.value.name, + it.value.type.toString(), + it.value.all.mapNotNull { hash -> + adapterProxies[hash] + }, + adapterProxies[it.value.now] + ) + } + .toList() runOnUiThread { - (content.adapter!! as ProxyGroupAdapter).data = proxies.toList() - .sortedWith(compareBy({ it.second.type == Proxy.TYPE_SELECT }, { it.first })) + (activity_proxies_list.adapter!! as ProxyGroupAdapter).apply { + data = listData + notifyDataSetChanged() + } + activity_proxies_list.visibility = View.VISIBLE } } } diff --git a/app/src/main/java/com/github/kr328/clash/adapter/ProxyAdapter.kt b/app/src/main/java/com/github/kr328/clash/adapter/ProxyAdapter.kt new file mode 100644 index 0000000..ac9c133 --- /dev/null +++ b/app/src/main/java/com/github/kr328/clash/adapter/ProxyAdapter.kt @@ -0,0 +1,53 @@ +package com.github.kr328.clash.adapter + +import android.content.Context +import android.graphics.Color +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +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() { + var proxies: List = emptyList() + var now: ListProxyGroup.ListProxy? = null + + class Holder(view: View) : RecyclerView.ViewHolder(view) { + val name: TextView = view.findViewById(R.id.adapter_proxy_name) + val type: TextView = view.findViewById(R.id.adapter_proxy_type) + val delay: TextView = view.findViewById(R.id.adapter_proxy_delay) + val card: MaterialCardView = view.findViewById(R.id.adapter_proxy_card) + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder { + return Holder(LayoutInflater.from(context).inflate(R.layout.adapter_proxy, parent, false)) + } + + override fun getItemCount(): Int { + return proxies.size + } + + override fun onBindViewHolder(holder: Holder, position: Int) { + val current = proxies[position] + + 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{ + holder.card.setCardBackgroundColor(Color.WHITE) + holder.name.setTextColor(Color.BLACK) + holder.type.setTextColor(Color.LTGRAY) + holder.delay.setTextColor(Color.DKGRAY) + } + + holder.name.text = current.name + holder.type.text = current.type + holder.delay.text = if ( current.delay > 0 ) current.delay.toString() else "" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/github/kr328/clash/adapter/ProxyGroupAdapter.kt b/app/src/main/java/com/github/kr328/clash/adapter/ProxyGroupAdapter.kt index b45dd26..21b2d23 100644 --- a/app/src/main/java/com/github/kr328/clash/adapter/ProxyGroupAdapter.kt +++ b/app/src/main/java/com/github/kr328/clash/adapter/ProxyGroupAdapter.kt @@ -5,21 +5,28 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup 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.model.Proxy +import com.github.kr328.clash.model.ListProxyGroup class ProxyGroupAdapter(private val context: Context) : RecyclerView.Adapter() { - var data: List> = emptyList() + var data: List = emptyList() class Holder(view: View) : RecyclerView.ViewHolder(view) { - val name = view.findViewById(R.id.adapter_proxy_group_name) - val list = view.findViewById(R.id.adapter_proxy_group_list) + val name: TextView = view.findViewById(R.id.adapter_proxy_group_name) + val list: RecyclerView = view.findViewById(R.id.adapter_proxy_group_list) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder { return Holder(LayoutInflater.from(context) - .inflate(R.layout.adapter_proxy_group, parent, false)) + .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 + } + list.adapter = ProxyAdapter(context) + } } override fun getItemCount(): Int { @@ -29,6 +36,11 @@ class ProxyGroupAdapter(private val context: Context) : RecyclerView.Adapter, var now: ListProxy?) { + data class ListProxy(val name: String, val type: String, val delay: Long) +} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_expand.xml b/app/src/main/res/drawable/ic_expand.xml new file mode 100644 index 0000000..8d57dbc --- /dev/null +++ b/app/src/main/res/drawable/ic_expand.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/activity_proxies.xml b/app/src/main/res/layout/activity_proxies.xml new file mode 100644 index 0000000..f0eb146 --- /dev/null +++ b/app/src/main/res/layout/activity_proxies.xml @@ -0,0 +1,22 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/adapter_proxy.xml b/app/src/main/res/layout/adapter_proxy.xml index 0b91e8a..de1bf4e 100644 --- a/app/src/main/res/layout/adapter_proxy.xml +++ b/app/src/main/res/layout/adapter_proxy.xml @@ -1,29 +1,50 @@ + android:layout_height="wrap_content" + xmlns:app="http://schemas.android.com/apk/res-auto"> - + android:layout_height="wrap_content" + app:cardUseCompatPadding="true" + app:cardElevation="2dp" + app:cardCornerRadius="5dp"> + android:padding="15dp" + android:layout_width="wrap_content" + android:layout_height="wrap_content"> + android:textSize="12sp" + android:text="@string/app_name" + android:maxLines="1"/> + + - + \ No newline at end of file diff --git a/app/src/main/res/layout/adapter_proxy_group.xml b/app/src/main/res/layout/adapter_proxy_group.xml index 3e07262..6dd444d 100644 --- a/app/src/main/res/layout/adapter_proxy_group.xml +++ b/app/src/main/res/layout/adapter_proxy_group.xml @@ -1,18 +1,27 @@ + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:animateLayoutChanges="true" + android:paddingStart="12dp" + android:paddingEnd="12dp" + android:paddingTop="12dp"> + + Empty Name Empty Path Invalid Config: %s + + %s - %s 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 1382225..42af651 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 @@ -8,8 +8,7 @@ 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.model.Proxy -import com.github.kr328.clash.core.model.ProxyPacket +import com.github.kr328.clash.core.model.RawProxyPacket import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonConfiguration import org.json.JSONObject @@ -57,14 +56,14 @@ class Clash( } } - fun queryProxies(): ProxyPacket { + fun queryProxies(): RawProxyPacket { return runControl(COMMAND_QUERY_PROXIES) { _, input, _ -> val data = input.readString() Log.d(TAG, data) Json(JsonConfiguration.Stable.copy(strictMode = false)) - .parse(ProxyPacket.serializer(), data) + .parse(RawProxyPacket.serializer(), data) } } diff --git a/core/src/main/java/com/github/kr328/clash/core/model/Proxy.kt b/core/src/main/java/com/github/kr328/clash/core/model/Proxy.kt deleted file mode 100644 index 1d6301b..0000000 --- a/core/src/main/java/com/github/kr328/clash/core/model/Proxy.kt +++ /dev/null @@ -1,30 +0,0 @@ -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 -data class Proxy(val type: String, - val all: List = emptyList(), - val now: String = "", - val history: List = emptyList()) { - @Serializable - data class History(val delay: Long) - - companion object { - const val TYPE_SELECT = "Selector" - const val TYPE_URL_TEST = "URLTest" - const val TYPE_DIRECT = "Direct" - const val TYPE_FALLBACK = "Fallback" - const val TYPE_REJECT = "Reject" - const val TYPE_SHADOWSOCKS = "Shadowsocks" - const val TYPE_SNELL = "Snell" - const val TYPE_SOCKS5 = "Socks5" - const val TYPE_HTTP = "Http" - const val TYPE_VMESS = "Vmess" - const val TYPE_LOAD_BALANCE = "LoadBalance" - const val TYPE_UNKNOWN = "Unknown" - } -} \ No newline at end of file diff --git a/core/src/main/java/com/github/kr328/clash/core/model/ProxyPacket.kt b/core/src/main/java/com/github/kr328/clash/core/model/ProxyPacket.kt index 3aa1167..703754d 100644 --- a/core/src/main/java/com/github/kr328/clash/core/model/ProxyPacket.kt +++ b/core/src/main/java/com/github/kr328/clash/core/model/ProxyPacket.kt @@ -6,7 +6,99 @@ import com.github.kr328.clash.core.serialization.Parcels import kotlinx.serialization.Serializable @Serializable -data class ProxyPacket(val proxies: Map) : Parcelable { +data class ProxyPacket(val proxies: Map): Parcelable { + @Serializable + data class Proxy(val name: String, val type: Type, val now: Int, val all: Set, val delay: Long) + + enum class Type { + SELECT, + URL_TEST, + FALLBACK, + DIRECT, + REJECT, + SHADOWSOCKS, + SNELL, + SOCKS5, + HTTP, + VMESS, + LOAD_BALANCE, + UNKNOWN; + + override fun toString(): String { + return when ( this ) { + SELECT -> "Select" + URL_TEST -> "UrlTest" + FALLBACK -> "Fallback" + DIRECT -> "Direct" + REJECT -> "Reject" + SHADOWSOCKS -> "Shadowsocks" + SNELL -> "Snell" + SOCKS5 -> "Socks5" + HTTP -> "HTTP" + VMESS -> "Vmess" + LOAD_BALANCE -> "LoadBalance" + UNKNOWN -> "Unknown" + } + } + } + + companion object { + private const val TYPE_SELECT = "Selector" + private const val TYPE_URL_TEST = "URLTest" + private const val TYPE_FALLBACK = "Fallback" + private const val TYPE_DIRECT = "Direct" + private const val TYPE_REJECT = "Reject" + private const val TYPE_SHADOWSOCKS = "Shadowsocks" + private const val TYPE_SNELL = "Snell" + private const val TYPE_SOCKS5 = "Socks5" + private const val TYPE_HTTP = "Http" + private const val TYPE_VMESS = "Vmess" + private const val TYPE_LOAD_BALANCE = "LoadBalance" + private const val TYPE_UNKNOWN = "Unknown" + + fun fromRawProxy(rawProxy: RawProxyPacket): ProxyPacket { + val hashed = rawProxy.proxies + .map { it.key to (it.key.hashCode() to it.value) }.toMap() + + val proxies = hashed.map { entry -> + val type = when ( entry.value.second.type ) { + TYPE_SELECT -> Type.SELECT + TYPE_URL_TEST -> Type.URL_TEST + TYPE_FALLBACK -> Type.FALLBACK + TYPE_DIRECT -> Type.DIRECT + TYPE_REJECT -> Type.REJECT + TYPE_SHADOWSOCKS -> Type.SHADOWSOCKS + TYPE_SNELL -> Type.SNELL + TYPE_SOCKS5 -> Type.SOCKS5 + TYPE_HTTP -> Type.HTTP + TYPE_VMESS -> Type.VMESS + TYPE_LOAD_BALANCE -> Type.LOAD_BALANCE + TYPE_UNKNOWN -> Type.UNKNOWN + else -> Type.UNKNOWN + } + + val now = hashed[entry.value.second.now]?.first ?: 0 + val all = entry.value.second.all.mapNotNull { hashed[it]?.first }.toSet() + val delay = entry.value.second.history.firstOrNull()?.delay ?: 0 + + entry.value.first to Proxy(entry.key, type, now, all, delay) + } + + return ProxyPacket(proxies.toMap()) + } + + @JvmField + val CREATOR = object: Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): ProxyPacket { + 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) } @@ -14,15 +106,4 @@ data class ProxyPacket(val proxies: Map) : Parcelable { override fun describeContents(): Int { return 0 } - - companion object CREATOR : Parcelable.Creator { - override fun createFromParcel(parcel: Parcel): ProxyPacket { - 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/model/RawProxyPacket.kt b/core/src/main/java/com/github/kr328/clash/core/model/RawProxyPacket.kt new file mode 100644 index 0000000..ab0daa6 --- /dev/null +++ b/core/src/main/java/com/github/kr328/clash/core/model/RawProxyPacket.kt @@ -0,0 +1,15 @@ +package com.github.kr328.clash.core.model + +import kotlinx.serialization.Serializable + +@Serializable +data class RawProxyPacket(val proxies: Map) { + @Serializable + data class RawProxy(val type: String, + val all: List = emptyList(), + val now: String = "", + val history: List = emptyList()) { + @Serializable + data class History(val delay: Long) + } +} \ No newline at end of file diff --git a/core/src/main/java/com/github/kr328/clash/core/serialization/Parcels.kt b/core/src/main/java/com/github/kr328/clash/core/serialization/Parcels.kt index 7f71655..30368d0 100644 --- a/core/src/main/java/com/github/kr328/clash/core/serialization/Parcels.kt +++ b/core/src/main/java/com/github/kr328/clash/core/serialization/Parcels.kt @@ -18,14 +18,85 @@ object Parcels : AbstractSerialFormat(EmptyModule) { } private class ParcelsEncoder(private val parcel: Parcel) : - ElementValueEncoder() { - override fun encodeValue(value: Any) { - parcel.writeValue(value) + Encoder, CompositeEncoder { + override val context: SerialModule + get() = EmptyModule + + override fun beginCollection( + desc: SerialDescriptor, + collectionSize: Int, + vararg typeParams: KSerializer<*> + ): CompositeEncoder { + encodeInt(collectionSize) + return super.beginCollection(desc, collectionSize, *typeParams) } - override fun encodeNull() { - parcel.writeValue(null) - } + override fun encodeBooleanElement(desc: SerialDescriptor, index: Int, value: Boolean) = + encodeBoolean(value) + override fun encodeByteElement(desc: SerialDescriptor, index: Int, value: Byte) = + encodeByte(value) + override fun encodeCharElement(desc: SerialDescriptor, index: Int, value: Char) = + encodeChar(value) + override fun encodeDoubleElement(desc: SerialDescriptor, index: Int, value: Double) = + encodeDouble(value) + override fun encodeFloatElement(desc: SerialDescriptor, index: Int, value: Float) = + encodeFloat(value) + override fun encodeIntElement(desc: SerialDescriptor, index: Int, value: Int) = + encodeInt(value) + override fun encodeLongElement(desc: SerialDescriptor, index: Int, value: Long) = + encodeLong(value) + override fun encodeShortElement(desc: SerialDescriptor, index: Int, value: Short) = + encodeShort(value) + override fun encodeStringElement(desc: SerialDescriptor, index: Int, value: String) = + encodeString(value) + override fun encodeUnitElement(desc: SerialDescriptor, index: Int) = + encodeUnit() + + override fun encodeNonSerializableElement(desc: SerialDescriptor, index: Int, value: Any) = + throw IllegalArgumentException("Unsupported") + override fun encodeNullableSerializableElement( + desc: SerialDescriptor, + index: Int, + serializer: SerializationStrategy, + value: T? + ) = encodeNullableSerializableValue(serializer, value) + override fun encodeSerializableElement( + desc: SerialDescriptor, + index: Int, + serializer: SerializationStrategy, + value: T + ) = encodeSerializableValue(serializer, value) + + override fun beginStructure( + desc: SerialDescriptor, + vararg typeParams: KSerializer<*> + ): CompositeEncoder = this + + override fun encodeBoolean(value: Boolean) = + parcel.writeByte(if ( value ) 1 else 0) + override fun encodeByte(value: Byte) = + parcel.writeByte(value) + override fun encodeChar(value: Char) = + parcel.writeInt(value.toInt()) + override fun encodeDouble(value: Double) = + parcel.writeDouble(value) + override fun encodeEnum(enumDescription: SerialDescriptor, ordinal: Int) = + parcel.writeInt(ordinal) + override fun encodeFloat(value: Float) = + parcel.writeFloat(value) + override fun encodeInt(value: Int) = + parcel.writeInt(value) + override fun encodeLong(value: Long) = + parcel.writeLong(value) + override fun encodeNotNullMark() = + encodeBoolean(true) + override fun encodeNull() = + encodeBoolean(false) + override fun encodeShort(value: Short) = + parcel.writeInt(value.toInt()) + override fun encodeString(value: String) = + parcel.writeString(value) + override fun encodeUnit() {} } class ParcelsDecoder(private val parcel: Parcel) : Decoder, CompositeDecoder { @@ -36,6 +107,8 @@ object Parcels : AbstractSerialFormat(EmptyModule) { override fun decodeElementIndex(desc: SerialDescriptor) = CompositeDecoder.READ_ALL + override fun decodeCollectionSize(desc: SerialDescriptor) = + decodeInt() override fun decodeBooleanElement(desc: SerialDescriptor, index: Int) = decodeBoolean() @@ -88,57 +161,31 @@ object Parcels : AbstractSerialFormat(EmptyModule) { vararg typeParams: KSerializer<*> ): CompositeDecoder = this - override fun decodeBoolean(): Boolean { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. - } - - override fun decodeByte(): Byte { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. - } - - override fun decodeChar(): Char { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. - } - - override fun decodeDouble(): Double { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. - } - - override fun decodeEnum(enumDescription: SerialDescriptor): Int { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. - } - - override fun decodeFloat(): Float { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. - } - - override fun decodeInt(): Int { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. - } - - override fun decodeLong(): Long { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. - } - - override fun decodeNotNullMark(): Boolean { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. - } - - override fun decodeNull(): Nothing? { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. - } - - override fun decodeShort(): Short { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. - } - - override fun decodeString(): String { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. - } - - override fun decodeUnit() { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. - } + override fun decodeBoolean() = + parcel.readByte() != 0.toByte() + override fun decodeByte() = + parcel.readByte() + override fun decodeChar() = + parcel.readInt().toChar() + override fun decodeDouble() = + parcel.readDouble() + override fun decodeEnum(enumDescription: SerialDescriptor) = + parcel.readInt() + override fun decodeFloat() = + parcel.readFloat() + override fun decodeInt() = + parcel.readInt() + override fun decodeLong() = + parcel.readLong() + override fun decodeNotNullMark() = + decodeBoolean() + override fun decodeNull() = + null + override fun decodeShort() = + parcel.readInt().toShort() + override fun decodeString() = + parcel.readString() ?: throw NullPointerException("String null") + override fun decodeUnit() {} } } 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 c63849f..b72072f 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 @@ -12,9 +12,9 @@ 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.EOFException import java.io.File import java.io.IOException import java.util.concurrent.Executors @@ -40,14 +40,11 @@ class ClashService : Service(), IClashEventObserver, ClashEventService.Master, override fun queryAllProxies(): ProxyPacket { return try { - ProxyPacket(clash.queryProxies().proxies.mapValues { - it.value.copy(history = it.value.history.take(1)) - }) + ProxyPacket.fromRawProxy(clash.queryProxies()) } catch (e: Exception) { this@ClashService.eventService.preformErrorEvent( ErrorEvent(ErrorEvent.Type.QUERY_PROXY_FAILURE, e.toString()) ) - ProxyPacket(emptyMap()) } }