use std::
{
sync::LazyLock,
time::{ Instant, Duration },
net::{ UdpSocket, SocketAddr },
};
use dashmap::DashMap;
use crate::
{
config,
consts::SharedKeys,
network::
{
server,
voice::
{
self,
consts,
VoiceCode,
VoicePacket,
},
},
};
pub struct Connection
{
addr: SocketAddr, id: usize, seq: usize, server_seq: usize, packet_accumulator: usize, }
pub static CONNECTIONS: LazyLock<DashMap<usize, (Option<Connection>, String)>> = LazyLock::new(|| DashMap::new());
impl Connection
{
pub fn peer_addr(&self) -> &SocketAddr
{
&self.addr
}
pub fn seq(&self) -> &usize
{
&self.seq
}
pub fn server_seq(&self) -> &usize
{
&self.server_seq
}
pub fn server_seq_mut(&mut self) -> &mut usize
{
&mut self.server_seq
}
}
fn parse_opus_len(bytes: &[u8]) -> (usize, usize)
{
if bytes.is_empty() { return (0, 0); }
let b0 = bytes[0] as usize;
if b0 < 252
{
(b0, 1)
} else if bytes.len() >= 2
{
let b1 = bytes[1] as usize;
(b1 * 4 + b0, 2)
} else
{
(0, 0)
}
}
fn validate_opus_packet(packet: Option<&[u8]>) -> bool
{
let packet = match packet
{
Some(p) => p,
None => return false
};
if packet.is_empty() { return false; }
let toc = packet[0];
let framing = toc & 0x03;
match framing
{
0 => true,
1 => (packet.len() - 1) % 2 == 0,
2 =>
{
if packet.len() < 2 { return false; }
let (len, count) = parse_opus_len(&packet[1..]);
if count == 0 { return false; }
packet.len() >= 1 + count + len
},
3 => {
if packet.len() < 2 { return false; }
let frame_count = packet[1] & 0x3F;
frame_count > 0
},
_ => false
}
}
pub fn find_key(id: &usize) -> Option<SharedKeys>
{
server::CONNECTIONS.iter()
.find(|entry| entry.value().id() == Some(id))
.map(|c| c.keys().unwrap().clone())
}
pub fn find_channel(id: &usize) -> Option<Option<String>>
{
server::CONNECTIONS.iter()
.find(|entry| entry.value().id() == Some(id))
.map(|c| c.channel().clone())
}
pub fn remove_connection(id: &usize) {
if let Some((_, (conn, _))) = CONNECTIONS.remove(id) &&
let Some(conn) = conn
{
log::info!("Close voice connection: {}", conn.peer_addr());
}
}
pub fn reset_last_activity(id: &usize)
{
if let Some(mut conn) = server::CONNECTIONS.iter_mut()
.find(|entry| entry.value().id() == Some(id))
{
*conn.last_activity_mut() = Instant::now() -
Duration::from_millis(config::read_config("min_message_delay"));
}
}
pub fn listen_client_voice(socket: UdpSocket)
{
loop
{
let (received, addr) = voice::receive(&socket).unwrap();
let id = match received.id
{
Some(id) => id,
None => continue };
let username: String;
if let Some(mut conn) = CONNECTIONS.get_mut(&id)
{
if let Some(conn) = conn.0.as_mut()
{
if conn.addr != addr
{
if conn.addr.ip() == addr.ip()
{
conn.addr = addr;
} else { continue; } }
if received.seq <= conn.seq { continue; } conn.seq = received.seq;
conn.packet_accumulator += 1;
if conn.packet_accumulator >= consts::ACTIVITY_TRESHOLD
{
conn.packet_accumulator = 0; reset_last_activity(&id); }
} else {
conn.0 = Some(Connection
{
addr: addr,
id: id,
seq: 0,
server_seq: 0,
packet_accumulator: 0,
});
log::info!("New voice connection: {}", addr);
}
username = conn.1.clone();
} else { continue; }
if received.code.is_none() && !validate_opus_packet(received.voice.as_deref()) { continue; }
if received.code == Some(VoiceCode::PONG) && let Some(ref target_id) = received.target_id
{
if let Some(ref keys) = find_key(&target_id)
{
let addr = match CONNECTIONS.get(target_id)
.and_then(|entry| entry.0.as_ref().map(|conn| conn.addr))
{
Some(a) => a,
None => continue
};
voice::send(&socket, VoicePacket
{
code: Some(VoiceCode::PONG),
id: Some(id),
timestamp: received.timestamp,
..Default::default()
}, &addr, target_id, keys).unwrap();
}
continue;
}
let sender_channel = find_channel(&id);
let mut addresses: Vec<(SocketAddr, SharedKeys, usize)> = Vec::new();
for connection in CONNECTIONS.iter()
{
if let (Some(conn), _) = connection.value()
{
if conn.addr != addr
{
if sender_channel != find_channel(&conn.id) { continue; }
if let Some(keys) = find_key(&conn.id)
{
addresses.push((conn.addr, keys, conn.id));
}
}
}
}
for (addr, keys, recipient_id) in addresses.iter()
{
voice::send(&socket, VoicePacket
{
voice: received.voice.clone(),
username: Some(username.to_string()),
code: received.code.clone(),
id: Some(id),
timestamp: received.timestamp,
..Default::default()
}, addr, recipient_id, keys).unwrap();
}
}
}