@@ -3,7 +3,7 @@ pub mod ffmpeg;
33pub mod future;
44pub mod util;
55
6- use std:: { net:: SocketAddr , ops:: Bound , sync:: atomic:: AtomicBool } ;
6+ use std:: { net:: SocketAddr , ops:: Bound , sync:: atomic:: AtomicBool , time :: { SystemTime , UNIX_EPOCH } } ;
77
88use axum:: {
99 Router ,
@@ -143,13 +143,33 @@ struct AudioPlanResolved {
143143 loudness : Option < AudioLoudnessPreset > ,
144144}
145145
146+ #[ derive( Deserialize ) ]
147+ struct RenderLogRequest {
148+ message : String ,
149+ level : Option < String > ,
150+ session : Option < String > ,
151+ context : Option < serde_json:: Value > ,
152+ }
153+
154+ #[ derive( Serialize , Clone ) ]
155+ struct RenderLogEntry {
156+ timestamp_ms : u64 ,
157+ message : String ,
158+ level : String ,
159+ session : Option < String > ,
160+ context : Option < serde_json:: Value > ,
161+ }
162+
146163static RENDER_AUDIO_PLAN : std:: sync:: LazyLock < std:: sync:: Mutex < Option < AudioPlanResolved > > > =
147164 std:: sync:: LazyLock :: new ( || std:: sync:: Mutex :: new ( None ) ) ;
165+ static RENDER_LOGS : std:: sync:: LazyLock < std:: sync:: Mutex < Vec < RenderLogEntry > > > =
166+ std:: sync:: LazyLock :: new ( || std:: sync:: Mutex :: new ( Vec :: new ( ) ) ) ;
148167
149168static RENDER_COMPLETED : AtomicUsize = AtomicUsize :: new ( 0 ) ;
150169static RENDER_TOTAL : AtomicUsize = AtomicUsize :: new ( 0 ) ;
151170static RENDER_CANCEL : AtomicBool = AtomicBool :: new ( false ) ;
152171static NEXT_SESSION_ID : AtomicUsize = AtomicUsize :: new ( 1 ) ;
172+ const MAX_RENDER_LOGS : usize = 2000 ;
153173
154174#[ tokio:: main]
155175async fn main ( ) {
@@ -183,6 +203,12 @@ async fn main() {
183203 . get ( get_progress_handler)
184204 . options ( options_handler) ,
185205 )
206+ . route (
207+ "/render_log" ,
208+ post ( render_log_handler)
209+ . get ( get_render_log_handler)
210+ . options ( options_handler) ,
211+ )
186212 . route (
187213 "/render_cancel" ,
188214 post ( render_cancel_handler) . options ( options_handler) ,
@@ -597,6 +623,59 @@ async fn get_progress_handler(State(_state): State<AppState>) -> impl IntoRespon
597623 ( headers, Json ( response) )
598624}
599625
626+ fn now_ms ( ) -> u64 {
627+ SystemTime :: now ( )
628+ . duration_since ( UNIX_EPOCH )
629+ . map ( |d| d. as_millis ( ) as u64 )
630+ . unwrap_or ( 0 )
631+ }
632+
633+ async fn render_log_handler (
634+ State ( _state) : State < AppState > ,
635+ Json ( payload) : Json < RenderLogRequest > ,
636+ ) -> impl IntoResponse {
637+ let mut headers = HeaderMap :: new ( ) ;
638+ apply_cors ( & mut headers) ;
639+
640+ let entry = RenderLogEntry {
641+ timestamp_ms : now_ms ( ) ,
642+ message : payload. message ,
643+ level : payload. level . unwrap_or_else ( || "info" . to_string ( ) ) ,
644+ session : payload. session ,
645+ context : payload. context ,
646+ } ;
647+
648+ {
649+ let mut logs = RENDER_LOGS . lock ( ) . unwrap ( ) ;
650+ logs. push ( entry. clone ( ) ) ;
651+ if logs. len ( ) > MAX_RENDER_LOGS {
652+ let trim = logs. len ( ) - MAX_RENDER_LOGS ;
653+ logs. drain ( 0 ..trim) ;
654+ }
655+ }
656+
657+ let session = entry. session . as_deref ( ) . unwrap_or ( "-" ) ;
658+ let context = entry
659+ . context
660+ . as_ref ( )
661+ . map ( |value| value. to_string ( ) )
662+ . unwrap_or_default ( ) ;
663+ info ! (
664+ "[render_log:{}] {} session={} context={}" ,
665+ entry. level, entry. message, session, context
666+ ) ;
667+
668+ ( headers, StatusCode :: OK )
669+ }
670+
671+ async fn get_render_log_handler ( State ( _state) : State < AppState > ) -> impl IntoResponse {
672+ let mut headers = HeaderMap :: new ( ) ;
673+ apply_cors ( & mut headers) ;
674+
675+ let logs = RENDER_LOGS . lock ( ) . unwrap ( ) . clone ( ) ;
676+ ( headers, Json ( logs) )
677+ }
678+
600679async fn render_cancel_handler ( State ( _state) : State < AppState > ) -> impl IntoResponse {
601680 let mut headers = HeaderMap :: new ( ) ;
602681 apply_cors ( & mut headers) ;
@@ -617,6 +696,7 @@ async fn reset_handler(State(_state): State<AppState>) -> impl IntoResponse {
617696 DECODER . clear ( ) . await ;
618697 RENDER_CANCEL . store ( false , Ordering :: Relaxed ) ;
619698 * RENDER_AUDIO_PLAN . lock ( ) . unwrap ( ) = None ;
699+ RENDER_LOGS . lock ( ) . unwrap ( ) . clear ( ) ;
620700 ( headers, StatusCode :: OK )
621701}
622702
0 commit comments