2025-04-19 12:07:22 -06:00
|
|
|
use craftping::sync::ping;
|
|
|
|
|
use serde_json::json;
|
|
|
|
|
use sha256::digest;
|
|
|
|
|
use std::{
|
|
|
|
|
net::{IpAddr, SocketAddr, TcpStream},
|
|
|
|
|
time::Duration,
|
|
|
|
|
};
|
|
|
|
|
|
2025-04-27 11:41:00 -06:00
|
|
|
use crate::database::DatabaseResult;
|
|
|
|
|
|
2025-04-19 12:07:22 -06:00
|
|
|
pub fn scan(
|
|
|
|
|
ip: IpAddr,
|
|
|
|
|
port: &i32,
|
|
|
|
|
timeout: Duration,
|
2025-04-27 11:41:00 -06:00
|
|
|
) -> Result<DatabaseResult, Box<dyn std::error::Error>> {
|
2025-04-19 12:07:22 -06:00
|
|
|
let port = *port as u16;
|
|
|
|
|
let socket = SocketAddr::new(ip, port);
|
|
|
|
|
let ip = ip.to_string();
|
|
|
|
|
|
|
|
|
|
let mut stream = TcpStream::connect_timeout(&socket, timeout)?;
|
2025-04-27 11:41:00 -06:00
|
|
|
stream.set_read_timeout(Some(timeout))?;
|
|
|
|
|
stream.set_write_timeout(Some(timeout))?;
|
2025-04-19 12:07:22 -06:00
|
|
|
let pong = ping(&mut stream, &ip, port)?;
|
|
|
|
|
|
|
|
|
|
let icon_hash = match pong.favicon {
|
|
|
|
|
Some(icon) => digest(icon),
|
2025-04-27 11:41:00 -06:00
|
|
|
None => "None".to_string(),
|
2025-04-19 12:07:22 -06:00
|
|
|
};
|
|
|
|
|
|
2025-04-27 11:41:00 -06:00
|
|
|
Ok(DatabaseResult {
|
|
|
|
|
ip: ip.to_string(),
|
|
|
|
|
port: port as u16,
|
|
|
|
|
version: pong.version,
|
|
|
|
|
protocol: pong.protocol as u32,
|
|
|
|
|
max_players: pong.max_players as u32,
|
|
|
|
|
online_players: pong.online_players as u32,
|
|
|
|
|
players_list: if let Some(sample) = pong.sample {
|
|
|
|
|
Some(
|
|
|
|
|
sample
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|a| (a.id.clone(), a.name.clone()))
|
|
|
|
|
.collect(),
|
|
|
|
|
)
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
},
|
|
|
|
|
description: pong.description.unwrap_or(json!("")).to_string(),
|
|
|
|
|
icon_hash: icon_hash,
|
|
|
|
|
mod_info: if let Some(mod_info) = pong.mod_info {
|
|
|
|
|
Some((
|
|
|
|
|
mod_info.mod_type,
|
|
|
|
|
mod_info
|
|
|
|
|
.mod_list
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|a| (a.mod_id.clone(), a.version.clone()))
|
|
|
|
|
.collect(),
|
|
|
|
|
))
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
},
|
|
|
|
|
forge_data: if let Some(forge_data) = pong.forge_data {
|
|
|
|
|
Some((
|
|
|
|
|
forge_data
|
|
|
|
|
.channels
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|a| (a.version.clone(), a.res.clone(), a.required))
|
|
|
|
|
.collect(),
|
|
|
|
|
forge_data
|
|
|
|
|
.mods
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|a| (a.mod_marker.clone(), a.mod_id.clone()))
|
|
|
|
|
.collect(),
|
|
|
|
|
forge_data.fml_network_version,
|
|
|
|
|
))
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
},
|
|
|
|
|
enforces_secure_chat: pong.enforces_secure_chat,
|
|
|
|
|
previews_chat: pong.previews_chat,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// Ok(serde_json::to_string(&json!({
|
|
|
|
|
// "version": pong.version,
|
|
|
|
|
// "protocol": pong.protocol,
|
|
|
|
|
// "max_players": pong.max_players,
|
|
|
|
|
// "online_players": pong.online_players,
|
|
|
|
|
// "players_list": pong.sample,
|
2025-04-19 12:07:22 -06:00
|
|
|
|
2025-04-27 11:41:00 -06:00
|
|
|
// "description": pong.description,
|
|
|
|
|
// "icon": icon_hash,
|
2025-04-19 12:07:22 -06:00
|
|
|
|
2025-04-27 11:41:00 -06:00
|
|
|
// "mod_info": pong.mod_info,
|
|
|
|
|
// "forge_data": pong.forge_data,
|
2025-04-19 12:07:22 -06:00
|
|
|
|
2025-04-27 11:41:00 -06:00
|
|
|
// "enforces_secure_chat": pong.enforces_secure_chat,
|
|
|
|
|
// "previews_chat": pong.previews_chat
|
|
|
|
|
// }))?)
|
2025-04-19 12:07:22 -06:00
|
|
|
}
|