diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1c0de80..d45eac2 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -74,7 +74,11 @@ android:label="@string/application_setting_application" android:exported="false" android:screenOrientation="portrait" /> - + diff --git a/app/src/main/java/com/github/kr328/clash/LogActivity.kt b/app/src/main/java/com/github/kr328/clash/LogActivity.kt new file mode 100644 index 0000000..cc536f6 --- /dev/null +++ b/app/src/main/java/com/github/kr328/clash/LogActivity.kt @@ -0,0 +1,91 @@ +package com.github.kr328.clash + +import android.os.Bundle +import android.os.Handler +import androidx.collection.CircularArray +import androidx.recyclerview.widget.DividerItemDecoration +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.github.kr328.clash.adapter.LogAdapter +import com.github.kr328.clash.core.event.Event +import com.github.kr328.clash.core.event.LogEvent +import com.github.kr328.clash.core.utils.Log +import kotlinx.android.synthetic.main.activity_logs.* + + +class LogActivity : BaseActivity() { + companion object { + const val MAX_EVENT_COUNT = 100 + } + + private var syncLog = false + private val buffer = CircularArray(MAX_EVENT_COUNT) + private val handler = Handler() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_logs) + + setSupportActionBar(activity_logs_toolbar) + + activity_logs_list.also { + val dividerItemDecoration = DividerItemDecoration( + this, + DividerItemDecoration.VERTICAL + ) + it.addItemDecoration(dividerItemDecoration) + + it.adapter = LogAdapter(this, buffer) + it.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false) + } + } + + override fun onStart() { + super.onStart() + + syncLog = true + + activity_logs_list.adapter?.notifyDataSetChanged() + + runClash { + it.eventService.registerEventObserver(LogActivity::class.java.name, + this, + intArrayOf(Event.EVENT_LOG)) + } + } + + override fun onStop() { + super.onStop() + + syncLog = false + } + + override fun onDestroy() { + super.onDestroy() + + runClash { + it.eventService.unregisterEventObserver(LogActivity::class.java.name) + } + } + + override fun onLogEvent(event: LogEvent?) { + handler.post { + buffer.addFirst(event) + + if ( syncLog ) { + activity_logs_list.adapter!!.notifyItemInserted(0) + if ( activity_logs_list.computeVerticalScrollOffset() < 30 ) + activity_logs_list.scrollToPosition(0) + } + + if ( buffer.size() >= MAX_EVENT_COUNT ) { + buffer.removeFromEnd(buffer.size() - MAX_EVENT_COUNT - 1) + + if ( syncLog ) { + activity_logs_list.adapter?.notifyItemRangeRemoved(MAX_EVENT_COUNT - 1, + buffer.size() - MAX_EVENT_COUNT - 1 ) + } + } + } + } +} \ No newline at end of file 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 0f1a8c3..06f73d9 100644 --- a/app/src/main/java/com/github/kr328/clash/MainActivity.kt +++ b/app/src/main/java/com/github/kr328/clash/MainActivity.kt @@ -45,6 +45,10 @@ class MainActivity : BaseActivity() { startActivity(Intent(this, SettingMainActivity::class.java)) } + activity_main_clash_logs.setOnClickListener { + startActivity(Intent(this, LogActivity::class.java)) + } + activity_main_clash_status_icon.setImageResource(R.drawable.ic_clash_stopped) activity_main_clash_status_title.text = getString(R.string.clash_status_stopped) activity_main_clash_status_summary.text = getString(R.string.clash_status_click_to_start) 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 f060cc1..db7e065 100644 --- a/app/src/main/java/com/github/kr328/clash/ProxyActivity.kt +++ b/app/src/main/java/com/github/kr328/clash/ProxyActivity.kt @@ -43,8 +43,6 @@ class ProxyActivity : BaseActivity() { .toMap() for ((_, p) in proxies) { - Log.i("$p -> ${p.index}") - p.value.delay = -1 } diff --git a/app/src/main/java/com/github/kr328/clash/adapter/LogAdapter.kt b/app/src/main/java/com/github/kr328/clash/adapter/LogAdapter.kt new file mode 100644 index 0000000..d0b73d3 --- /dev/null +++ b/app/src/main/java/com/github/kr328/clash/adapter/LogAdapter.kt @@ -0,0 +1,42 @@ +package com.github.kr328.clash.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.collection.CircularArray +import androidx.recyclerview.widget.RecyclerView +import com.github.kr328.clash.R +import com.github.kr328.clash.core.event.LogEvent +import kotlinx.android.synthetic.main.adapter_log.view.* +import java.text.SimpleDateFormat +import java.util.* + +class LogAdapter(private val content: Context, + private val buffer: CircularArray) : RecyclerView.Adapter() { + private val formatter = SimpleDateFormat("hh:MM:ss", Locale.getDefault()) + + class Holder(view: View) : RecyclerView.ViewHolder(view) { + val type: TextView = view.findViewById(R.id.adapter_log_type) + val time: TextView = view.findViewById(R.id.adapter_log_time) + val content: TextView = view.findViewById(R.id.adapter_log_content) + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder { + return Holder(LayoutInflater.from(content) + .inflate(R.layout.adapter_log, parent, false)) + } + + override fun getItemCount(): Int { + return buffer.size() + } + + override fun onBindViewHolder(holder: Holder, position: Int) { + val current = buffer.get(position) + + holder.type.text = current.level.toString() + holder.time.text = formatter.format(Date(current.time)) + holder.content.text = current.message + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_logs.xml b/app/src/main/res/layout/activity_logs.xml new file mode 100644 index 0000000..9aecb2e --- /dev/null +++ b/app/src/main/res/layout/activity_logs.xml @@ -0,0 +1,22 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/adapter_log.xml b/app/src/main/res/layout/adapter_log.xml new file mode 100644 index 0000000..1244128 --- /dev/null +++ b/app/src/main/res/layout/adapter_log.xml @@ -0,0 +1,28 @@ + + + + + + + + \ No newline at end of file diff --git a/core/src/main/golang/server/event.go b/core/src/main/golang/server/event.go index a9387df..f12a253 100644 --- a/core/src/main/golang/server/event.go +++ b/core/src/main/golang/server/event.go @@ -18,17 +18,16 @@ func handlePullTrafficEvent(client *net.UnixConn) { buf := &bytes.Buffer{} defer ticker.Stop() + defer client.Close() go func() { for { var buf [4]byte - _, err := client.Read(buf[:]) + client.Read(buf[:]) - if err != nil { - close(trafficExit) - return - } + close(trafficExit) + return } }() @@ -68,17 +67,16 @@ func handlePullBandwidthEvent(client *net.UnixConn) { buf := &bytes.Buffer{} defer ticker.Stop() + defer client.Close() go func() { for { var buf [4]byte - _, err := client.Read(buf[:]) + client.Read(buf[:]) - if err != nil { - close(bandWidthExit) - return - } + close(bandWidthExit) + return } }() @@ -118,16 +116,18 @@ func handlePullLogEvent(client *net.UnixConn) { subseribe := log.Subscribe() buf := &bytes.Buffer{} + defer log.UnSubscribe(subseribe) + defer client.Close() + go func() { var buf [4]byte for { - _, err := client.Read(buf[:]) + client.Read(buf[:]) - if err != nil { - close(logExit) - return - } + logExit <- 0 + close(logExit) + return } }() 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 ed83043..1c21fab 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 @@ -7,7 +7,7 @@ import kotlinx.serialization.* import kotlinx.serialization.internal.StringDescriptor @Serializable -data class LogEvent(val level: Level, val message: String) : +data class LogEvent(val level: Level, val message: String, val time: Long = System.currentTimeMillis()) : Event, Parcelable { companion object { const val DEBUG_VALUE = 1 diff --git a/service/src/main/java/com/github/kr328/clash/service/ClashEventPuller.kt b/service/src/main/java/com/github/kr328/clash/service/ClashEventPuller.kt index 21d02bf..ad35862 100644 --- a/service/src/main/java/com/github/kr328/clash/service/ClashEventPuller.kt +++ b/service/src/main/java/com/github/kr328/clash/service/ClashEventPuller.kt @@ -127,6 +127,7 @@ class ClashEventPuller(private val clash: Clash, private val master: Master) { private fun LocalSocket?.closeSilent() { runCatching { + this?.outputStream?.write(0) this?.close() } }