@@ -5,9 +5,11 @@ use anyhow::Result;
55use flexi_logger:: writers:: LogWriter ;
66use flexi_logger:: { DeferredNow , Record } ;
77use once_cell:: sync:: Lazy ;
8+ use std:: collections:: VecDeque ;
89use std:: process:: Stdio ;
9- use std:: sync:: Arc ;
10+ use std:: sync:: { Arc , OnceLock } ;
1011use tokio:: io:: AsyncBufReadExt ;
12+ use tokio:: sync:: { RwLock , RwLockReadGuard } ;
1113use tokio:: { io:: BufReader , process:: Command } ;
1214use tokio:: { process:: Child , sync:: Mutex } ;
1315use tracing:: { info, warn} ;
@@ -36,6 +38,39 @@ impl ChildGuard {
3638 }
3739}
3840
41+ const LOGS_QUEUE_LEN : usize = 100 ;
42+
43+ pub struct ClashLogger {
44+ logs : Arc < RwLock < VecDeque < String > > > ,
45+ }
46+
47+ impl ClashLogger {
48+ pub fn global ( ) -> & ' static ClashLogger {
49+ static LOGGER : OnceLock < ClashLogger > = OnceLock :: new ( ) ;
50+
51+ LOGGER . get_or_init ( || ClashLogger {
52+ logs : Arc :: new ( RwLock :: new ( VecDeque :: with_capacity ( LOGS_QUEUE_LEN + 10 ) ) ) ,
53+ } )
54+ }
55+
56+ pub async fn get_logs ( & self ) -> RwLockReadGuard < ' _ , VecDeque < String > > {
57+ self . logs . read ( ) . await
58+ }
59+
60+ pub async fn append_log ( & self , text : String ) {
61+ let mut logs = self . logs . write ( ) . await ;
62+ if logs. len ( ) > LOGS_QUEUE_LEN {
63+ logs. pop_front ( ) ;
64+ }
65+ logs. push_back ( text) ;
66+ }
67+
68+ pub async fn clear_logs ( & self ) {
69+ let mut logs = self . logs . write ( ) . await ;
70+ logs. clear ( ) ;
71+ }
72+ }
73+
3974pub struct CoreManager {
4075 running_child : Arc < Mutex < Option < ChildGuard > > > ,
4176 running_config : Arc < Mutex < Option < ClashConfig > > > ,
@@ -81,6 +116,7 @@ impl CoreManager {
81116
82117 pub async fn stop_core ( & mut self ) -> Result < ( ) > {
83118 info ! ( "Stopping core" ) ;
119+ ClashLogger :: global ( ) . clear_logs ( ) . await ;
84120
85121 let child_guard = self . running_child . lock ( ) . await . take ( ) ;
86122 drop ( child_guard) ;
@@ -176,6 +212,7 @@ pub async fn run_with_logging(
176212 tokio:: spawn ( async move {
177213 let w = shared_writer_clone. lock ( ) . await ;
178214 while let Ok ( Some ( line) ) = stdout_reader. next_line ( ) . await {
215+ ClashLogger :: global ( ) . append_log ( line. clone ( ) ) . await ;
179216 let mut now = DeferredNow :: default ( ) ;
180217 let arg = format_args ! ( "{}" , line) ;
181218 let record = Record :: builder ( )
@@ -192,6 +229,7 @@ pub async fn run_with_logging(
192229 tokio:: spawn ( async move {
193230 let w = shared_writer_clone. lock ( ) . await ;
194231 while let Ok ( Some ( line) ) = stderr_reader. next_line ( ) . await {
232+ ClashLogger :: global ( ) . append_log ( line. clone ( ) ) . await ;
195233 let mut now = DeferredNow :: default ( ) ;
196234 let arg = format_args ! ( "{}" , line) ;
197235 let record = Record :: builder ( )
0 commit comments