1+ use std:: net:: Ipv4Addr ;
2+ use std:: str:: FromStr ;
3+ use std:: time:: { Duration , Instant } ;
4+ use colored_text:: Colorize ;
5+ use futures:: StreamExt ;
6+ use crate :: database:: { parse_server, server, ServerHistory , ServerInfo } ;
7+ use crate :: logger;
8+ use crate :: config:: MainConfig ;
9+ use crate :: logger:: DefaultColor ;
10+ use crate :: manager:: TaskManager ;
11+ use crate :: scanning:: scanner:: { scan, ScanConfig } ;
12+ use crate :: scanning:: utils:: { format_time, prettier_ping_result, save_server} ;
13+
14+ pub async fn rescan ( ) {
15+ let _ = TaskManager :: spawn ( "Rescan" , move |cancel_token| async move {
16+ logger:: info ( "Getting all servers from the database..." . into ( ) ) . send ( ) . await ;
17+
18+ let servers = match server:: get_total_servers ( ) . await {
19+ Ok ( s) => s,
20+ Err ( e) => {
21+ logger:: critical ( format ! ( "Failed to load servers: {}" , e. hex( DefaultColor :: Highlight . hex( ) ) ) ) . prefix ( "Rescan" ) . send ( ) . await ;
22+ return ;
23+ }
24+ } ;
25+
26+ if servers. is_empty ( ) {
27+ logger:: warning ( "No servers found in database to rescan." . into ( ) ) . prefix ( "Rescan" ) . send ( ) . await ;
28+ return ;
29+ }
30+
31+
32+ let start_time = Instant :: now ( ) ;
33+
34+ let mut targets = Vec :: new ( ) ;
35+ for s in servers {
36+ if let Ok ( ipv4) = Ipv4Addr :: from_str ( & s. server_ip ) {
37+ targets. push ( ( ipv4, s. server_port ) ) ;
38+ }
39+ }
40+
41+ let mut found_batch: Vec < ( ServerInfo , ServerHistory ) > = Vec :: new ( ) ;
42+
43+ let total_targets = targets. len ( ) ;
44+ let mut total_found_count = 0 ;
45+ let mut processed_count = 0 ;
46+
47+ logger:: info ( format ! (
48+ "Scanning {} targets..." ,
49+ total_targets. hex( DefaultColor :: Highlight . hex( ) )
50+ ) ) . prefix ( "Rescan" ) . send ( ) . await ;
51+
52+ let main_cfg = MainConfig :: get ( ) . expect ( "Config not loaded!" ) ;
53+
54+ let config = ScanConfig {
55+ ping_timeout : Duration :: from_millis ( main_cfg. general . ping_timeout ) ,
56+ query_timeout : Duration :: from_millis ( main_cfg. general . query_timeout ) ,
57+ join_timeout : Duration :: from_millis ( main_cfg. general . join_timeout ) ,
58+ with_uuid : main_cfg. general . do_uuid_fetch ,
59+ max_tasks : main_cfg. get_scanner_tasks ( ) ,
60+ ..ScanConfig :: default ( )
61+ } ;
62+
63+ // Core part: scanning
64+ let scan_stream = scan ( targets, config) ;
65+ tokio:: pin!( scan_stream) ;
66+
67+ // Scan stream
68+ while let Some ( maybe_result) = scan_stream. next ( ) . await {
69+ if cancel_token. is_cancelled ( ) {
70+ logger:: warning ( "Scan interrupted. Saving results..." . to_string ( ) )
71+ . prefix ( "Rescan" ) . send ( ) . await ;
72+ break ;
73+ }
74+
75+ processed_count += 1 ;
76+
77+ // Success
78+ if let Some ( result) = maybe_result {
79+ let parsed = parse_server ( result. ip , result. port , result. ping . clone ( ) , result. query , result. join ) ;
80+ found_batch. push ( parsed) ;
81+ total_found_count += 1 ;
82+
83+ let mut output = String :: new ( ) ;
84+ output. push_str (
85+ & format ! (
86+ "Found server: {}:{}\n " ,
87+ result. ip. to_string( ) . hex( DefaultColor :: Highlight . hex( ) ) ,
88+ result. port. hex( DefaultColor :: Highlight . hex( ) )
89+ )
90+ ) ;
91+ output. push_str ( & prettier_ping_result ( result. ping ) . await ) ;
92+ logger:: success ( output) . prefix ( "Rescan" ) . send ( ) . await ;
93+
94+ if found_batch. len ( ) >= 30 {
95+ let batch_to_insert = std:: mem:: take ( & mut found_batch) ;
96+ save_server ( & batch_to_insert) . await ;
97+ }
98+ }
99+
100+ // Progress calc
101+ let elapsed = start_time. elapsed ( ) . as_secs_f64 ( ) ;
102+ let ips_per_second = processed_count as f64 / elapsed;
103+
104+ if ips_per_second > 0.0 {
105+ let remaining_ips = total_targets. saturating_sub ( processed_count) ;
106+ let remaining_secs = remaining_ips as f64 / ips_per_second;
107+ let percent = format ! ( "{:.2}" , ( processed_count as f64 / total_targets as f64 ) * 100.0 ) ;
108+
109+ if processed_count % 10000 == 0 || processed_count == total_targets {
110+ logger:: info ( format ! (
111+ "Progress: {}/{} IPs ({}%) - ETA: {}" ,
112+ processed_count. hex( DefaultColor :: Highlight . hex( ) ) ,
113+ total_targets. hex( DefaultColor :: Highlight . hex( ) ) ,
114+ percent. hex( DefaultColor :: Highlight . hex( ) ) ,
115+ format_time( remaining_secs as u64 )
116+ ) ) . prefix ( "Rescan" ) . send ( ) . await ;
117+ }
118+ }
119+ }
120+
121+ if !found_batch. is_empty ( ) {
122+ save_server ( & found_batch) . await ;
123+ }
124+
125+ // Finished
126+ let elapsed_time = start_time. elapsed ( ) ;
127+
128+ let pps = if elapsed_time. as_secs ( ) > 0 {
129+ total_targets as f64 / elapsed_time. as_secs_f64 ( )
130+ } else {
131+ 0.0
132+ } ;
133+
134+ let percent = if total_found_count > 0 {
135+ format ! ( "{:.2}" , ( total_found_count as f64 / processed_count as f64 ) * 100.0 )
136+ } else {
137+ "0.00" . to_string ( )
138+ } ;
139+
140+ logger:: info (
141+ format ! (
142+ "Rescan finished in {}. Updated {} servers from {} targets, {}%. ({}{})" ,
143+ format_time( elapsed_time. as_secs( ) ) . hex( DefaultColor :: Highlight . hex( ) ) ,
144+ total_found_count. hex( DefaultColor :: Highlight . hex( ) ) ,
145+ total_targets. hex( DefaultColor :: Highlight . hex( ) ) ,
146+ percent. hex( DefaultColor :: Highlight . hex( ) ) ,
147+ pps. round( ) . hex( DefaultColor :: Highlight . hex( ) ) ,
148+ "pps" . hex( DefaultColor :: DarkHighlight . hex( ) )
149+ )
150+ ) . send ( ) . await ;
151+ } ) . await ;
152+ }
0 commit comments