rush_sync_server/server/utils/
port.rs

1use crate::core::config::Config;
2use crate::core::prelude::*;
3
4pub enum PortStatus {
5    Available,
6    OccupiedByUs,
7    OccupiedByOther,
8}
9
10pub fn check_port_status(port: u16) -> PortStatus {
11    use std::net::{IpAddr, Ipv4Addr, SocketAddr, TcpListener};
12
13    let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), port);
14
15    // frei?
16    if let Ok(listener) = TcpListener::bind(addr) {
17        drop(listener);
18        return PortStatus::Available;
19    }
20
21    // belegt – prüfen ob von uns
22    let ctx = crate::server::shared::get_shared_context();
23    if let Ok(servers) = ctx.servers.read() {
24        if servers.values().any(|s| s.port == port) {
25            return PortStatus::OccupiedByUs;
26        }
27    }
28
29    PortStatus::OccupiedByOther
30}
31
32pub fn is_port_available(port: u16) -> bool {
33    std::net::TcpListener::bind(("127.0.0.1", port))
34        .map(|l| {
35            drop(l);
36            true
37        })
38        .unwrap_or(false)
39}
40
41pub fn find_next_available_port(config: &Config) -> Result<u16> {
42    let ctx = crate::server::shared::get_shared_context();
43    let servers = ctx.servers.read().unwrap();
44    let mut used_ports: Vec<u16> = servers.values().map(|s| s.port).collect();
45    used_ports.sort();
46
47    let mut candidate_port = config.server.port_range_start;
48    let max_port = config.server.port_range_end;
49
50    loop {
51        if candidate_port > max_port {
52            return Err(AppError::Validation(format!(
53                "No available ports in range {}-{}",
54                config.server.port_range_start, config.server.port_range_end
55            )));
56        }
57
58        if !used_ports.contains(&candidate_port) && is_port_available(candidate_port) {
59            return Ok(candidate_port);
60        }
61
62        candidate_port += 1;
63    }
64}
65
66pub fn find_next_available_port_legacy() -> Result<u16> {
67    let ctx = crate::server::shared::get_shared_context();
68    let servers = ctx.servers.read().unwrap();
69    let mut used_ports: Vec<u16> = servers.values().map(|s| s.port).collect();
70    used_ports.sort();
71
72    let mut candidate_port = 8080;
73
74    loop {
75        if !used_ports.contains(&candidate_port) && is_port_available(candidate_port) {
76            return Ok(candidate_port);
77        }
78
79        candidate_port += 1;
80        if candidate_port > 8180 {
81            return Err(AppError::Validation(
82                "No available ports found in default range 8080-8180".to_string(),
83            ));
84        }
85    }
86}