@@ -87,6 +87,7 @@ use tokio::{
8787use tokio_util:: sync:: CancellationToken ;
8888use uuid:: Uuid ;
8989
90+ mod app_api;
9091mod callback_tracker;
9192mod categories;
9293mod category_runtime;
@@ -532,158 +533,6 @@ impl EmulebbCore {
532533 Self :: new ( version, index, unique_runtime_dir ( "emulebb-core-transfers" ) )
533534 }
534535
535- pub fn app_info ( & self ) -> AppInfo {
536- AppInfo {
537- name : "eMuleBB" . to_string ( ) ,
538- version : self . version . clone ( ) ,
539- api_version : "v1" . to_string ( ) ,
540- lifecycle : AppLifecycle {
541- state : self . lifecycle_state_name ( ) . to_string ( ) ,
542- } ,
543- capabilities : vec ! [
544- "transfers" . to_string( ) ,
545- "searches" . to_string( ) ,
546- "servers" . to_string( ) ,
547- "sharedFiles" . to_string( ) ,
548- "sharedDirectories" . to_string( ) ,
549- "uploads" . to_string( ) ,
550- "logs" . to_string( ) ,
551- "categoriesRead" . to_string( ) ,
552- "categoryAssignment" . to_string( ) ,
553- "categoryCrud" . to_string( ) ,
554- "renameFile" . to_string( ) ,
555- "transferDetails" . to_string( ) ,
556- "fileRatingComment" . to_string( ) ,
557- "friends" . to_string( ) ,
558- "peerControls" . to_string( ) ,
559- ] ,
560- }
561- }
562-
563- pub async fn capture_diagnostic_dump ( & self , full_memory : bool ) -> Result < DiagnosticDumpResult > {
564- let dump_dir = self
565- . transfer_root
566- . parent ( )
567- . unwrap_or ( self . transfer_root . as_path ( ) )
568- . join ( "diagnostics" ) ;
569- fs:: create_dir_all ( & dump_dir) . with_context ( || {
570- format ! (
571- "failed to create diagnostics directory {}" ,
572- dump_dir. display( )
573- )
574- } ) ?;
575-
576- let stamp = Utc :: now ( ) . format ( "%Y%m%dT%H%M%SZ" ) ;
577- let path = dump_dir. join ( format ! (
578- "emulebb-rust-diagnostic-dump-{stamp}-{}.json" ,
579- Uuid :: new_v4( )
580- ) ) ;
581- let payload = serde_json:: to_vec_pretty ( & json ! ( {
582- "app" : self . app_info( ) ,
583- "status" : self . status( ) . await ,
584- "fullMemory" : full_memory,
585- "kind" : "json" ,
586- "capturedAt" : Utc :: now( ) ,
587- } ) ) ?;
588- fs:: write ( & path, & payload)
589- . with_context ( || format ! ( "failed to write diagnostic dump {}" , path. display( ) ) ) ?;
590- Ok ( DiagnosticDumpResult {
591- ok : true ,
592- path : path. display ( ) . to_string ( ) ,
593- full_memory,
594- } )
595- }
596-
597- pub async fn preferences ( & self ) -> Preferences {
598- self . state . lock ( ) . await . preferences . clone ( )
599- }
600-
601- pub async fn update_preferences ( & self , request : PreferencesUpdate ) -> Result < Preferences > {
602- ensure ! (
603- !preferences_update_is_empty( & request) ,
604- "preferences PATCH requires at least one preference"
605- ) ;
606- let preferences = {
607- let mut state = self . state . lock ( ) . await ;
608- let mut preferences = state. preferences . clone ( ) ;
609- apply_preferences_update ( & mut preferences, request) ?;
610- profile_state:: persist_preferences ( & self . metadata_store , & preferences) ?;
611- state. preferences = preferences. clone ( ) ;
612- preferences
613- } ;
614- self . ed2k_transfers
615- . apply_upload_queue_policy ( & ed2k_upload_queue_policy_from_preferences (
616- self . ed2k_network
617- . as_ref ( )
618- . map ( |network| & network. config . upload_queue ) ,
619- & preferences,
620- ) )
621- . await ;
622- self . ed2k_transfers
623- . apply_download_limit ( ed2k_download_limit_bytes_per_sec_from_preferences (
624- & preferences,
625- ) )
626- . await ;
627- // Apply the global connection budget + per-file source caps live, like
628- // the download limit (eMule GetMaxConnections / GetMaxConperFive /
629- // GetConfiguredMaxSourcesPerFile preference changes take effect at once).
630- self . ed2k_transfers . apply_download_coordinator_config (
631- ed2k_download_coordinator_config_from_preferences ( & preferences) ,
632- ) ;
633- // Apply the credit-system toggle live (eMule thePrefs.GetCreditSystem()):
634- // when off, upload scoring uses the neutral 1.0 credit ratio for everyone.
635- self . ed2k_transfers
636- . set_credit_system_enabled ( preferences. credit_system ) ;
637- Ok ( preferences)
638- }
639-
640- pub async fn status ( & self ) -> Status {
641- let transfer_counts = self . ed2k_transfers . try_transfer_counts ( ) ;
642- let state = self . state . lock ( ) . await ;
643- let kad_running = state. kad_running ;
644- let transfer_counts = transfer_counts. unwrap_or_else ( |error| {
645- tracing:: warn!( "failed to read persisted ED2K transfer counts: {error}" ) ;
646- None
647- } ) ;
648- let transfer_counts = transfer_counts. unwrap_or_else ( || {
649- tracing:: debug!( "metadata transfer counts are busy; using in-memory status counts" ) ;
650- let total = state. transfers . len ( ) ;
651- let mut active = 0 ;
652- let mut completed = 0 ;
653- for transfer in state. transfers . values ( ) {
654- match transfer. state . as_str ( ) {
655- "downloading" | "queued" => active += 1 ,
656- "completed" => completed += 1 ,
657- _ => { }
658- }
659- }
660- MetadataTransferCounts {
661- active,
662- completed,
663- total,
664- }
665- } ) ;
666- drop ( state) ;
667-
668- Status {
669- lifecycle : AppLifecycle {
670- state : "running" . to_string ( ) ,
671- } ,
672- uptime_secs : self . started_at . elapsed ( ) . as_secs ( ) ,
673- kad : self . kad_status ( kad_running) . await ,
674- ed2k : self . ed2k_status ( ) . await ,
675- indexing : IndexingStatus {
676- enabled : true ,
677- backend : "sqlite-fts5" . to_string ( ) ,
678- } ,
679- transfers : TransferStats {
680- active : transfer_counts. active ,
681- completed : transfer_counts. completed ,
682- total : transfer_counts. total ,
683- } ,
684- }
685- }
686-
687536 pub async fn import_kad_nodes_url ( & self , url : & str ) -> Result < bool > {
688537 let url = validate_url_import ( url) ?;
689538 match fetch_url_bytes ( & url) . await {
0 commit comments