rush_sync_server/server/utils/
port.rs1use 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, bind_address: &str) -> PortStatus {
11 if is_port_available(port, bind_address) {
13 return PortStatus::Available;
14 }
15
16 let ctx = crate::server::shared::get_shared_context();
18 if let Ok(servers) = ctx.servers.read() {
19 if servers.values().any(|s| s.port == port) {
20 return PortStatus::OccupiedByUs;
21 }
22 }
23
24 PortStatus::OccupiedByOther
25}
26
27pub fn is_port_available(port: u16, bind_address: &str) -> bool {
28 std::net::TcpListener::bind((bind_address, port))
29 .map(|l| {
30 drop(l);
31 true
32 })
33 .unwrap_or(false)
34}
35
36pub fn find_next_available_port(config: &Config) -> Result<u16> {
37 let ctx = crate::server::shared::get_shared_context();
38 let servers = crate::core::helpers::read_lock(&ctx.servers, "servers")?;
39 let mut used_ports: Vec<u16> = servers.values().map(|s| s.port).collect();
40 used_ports.sort();
41
42 let mut candidate_port = config.server.port_range_start;
43 let max_port = config.server.port_range_end;
44
45 loop {
46 if candidate_port > max_port {
47 return Err(AppError::Validation(format!(
48 "No available ports in range {}-{}",
49 config.server.port_range_start, config.server.port_range_end
50 )));
51 }
52
53 if !used_ports.contains(&candidate_port)
54 && is_port_available(candidate_port, &config.server.bind_address)
55 {
56 return Ok(candidate_port);
57 }
58
59 candidate_port += 1;
60 }
61}