refactor: handle_data now returns HandleResult with parsed events
- Add CommandEvent enum (InitServer, ChannelList, ClientList, TextMessage, etc.) - Add HandleResult struct with responses and events - handle_data returns HandleResult instead of Vec<Vec<u8>> - Session uses HandleResult for real event emission - Update socket.rs and tests for new return type
This commit is contained in:
@@ -11,6 +11,69 @@ use crate::protocol::{
|
|||||||
};
|
};
|
||||||
use crate::ProtocolError;
|
use crate::ProtocolError;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, serde::Serialize)]
|
||||||
|
pub struct ChannelEntry {
|
||||||
|
pub cid: u64,
|
||||||
|
pub pid: u64,
|
||||||
|
pub channel_order: u64,
|
||||||
|
pub channel_name: String,
|
||||||
|
pub total_clients: u16,
|
||||||
|
pub channel_needed_subscribe_power: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, serde::Serialize)]
|
||||||
|
pub struct ClientEntry {
|
||||||
|
pub clid: u16,
|
||||||
|
pub cid: u64,
|
||||||
|
pub client_database_id: u64,
|
||||||
|
pub client_nickname: String,
|
||||||
|
pub client_type: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, serde::Serialize)]
|
||||||
|
pub enum CommandEvent {
|
||||||
|
InitServer {
|
||||||
|
client_id: u16,
|
||||||
|
name: String,
|
||||||
|
platform: String,
|
||||||
|
version: String,
|
||||||
|
max_clients: u16,
|
||||||
|
clients_online: u16,
|
||||||
|
channels_online: u16,
|
||||||
|
},
|
||||||
|
ChannelList(Vec<ChannelEntry>),
|
||||||
|
ChannelListFinished,
|
||||||
|
ClientList(Vec<ClientEntry>),
|
||||||
|
ClientEntered {
|
||||||
|
clid: u16,
|
||||||
|
cid: u64,
|
||||||
|
client_nickname: String,
|
||||||
|
},
|
||||||
|
ClientLeft {
|
||||||
|
clid: u16,
|
||||||
|
reason: String,
|
||||||
|
},
|
||||||
|
ClientMoved {
|
||||||
|
clid: u16,
|
||||||
|
cid: u64,
|
||||||
|
},
|
||||||
|
TextMessage {
|
||||||
|
invoker_id: u16,
|
||||||
|
invoker_name: String,
|
||||||
|
message: String,
|
||||||
|
target_mode: u8,
|
||||||
|
},
|
||||||
|
Error {
|
||||||
|
id: u32,
|
||||||
|
message: String,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct HandleResult {
|
||||||
|
pub responses: Vec<Vec<u8>>,
|
||||||
|
pub events: Vec<CommandEvent>,
|
||||||
|
}
|
||||||
|
|
||||||
/// 客户端配置
|
/// 客户端配置
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ClientConfig {
|
pub struct ClientConfig {
|
||||||
@@ -128,8 +191,9 @@ impl Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 处理接收到的数据
|
/// 处理接收到的数据
|
||||||
pub fn handle_data(&mut self, data: &[u8]) -> Result<Vec<Vec<u8>>, ProtocolError> {
|
pub fn handle_data(&mut self, data: &[u8]) -> Result<HandleResult, ProtocolError> {
|
||||||
let mut responses = Vec::new();
|
let mut responses = Vec::new();
|
||||||
|
let mut events = Vec::new();
|
||||||
|
|
||||||
match self.state() {
|
match self.state() {
|
||||||
ConnectionState::Connecting => {
|
ConnectionState::Connecting => {
|
||||||
@@ -191,7 +255,7 @@ impl Client {
|
|||||||
responses.push(self.build_clientinit_packet()?);
|
responses.push(self.build_clientinit_packet()?);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Ok(responses);
|
return Ok(HandleResult { responses, events });
|
||||||
}
|
}
|
||||||
|
|
||||||
if matches!(packet_type, PacketType::Command | PacketType::CommandLow) {
|
if matches!(packet_type, PacketType::Command | PacketType::CommandLow) {
|
||||||
@@ -210,6 +274,34 @@ impl Client {
|
|||||||
self.state_machine
|
self.state_machine
|
||||||
.transition(ConnectionState::ChannelListFinished)
|
.transition(ConnectionState::ChannelListFinished)
|
||||||
.map_err(ProtocolError::PacketParse)?;
|
.map_err(ProtocolError::PacketParse)?;
|
||||||
|
|
||||||
|
events.push(CommandEvent::InitServer {
|
||||||
|
client_id: self.client_id.unwrap_or(0),
|
||||||
|
name: cmd
|
||||||
|
.get("virtualserver_name")
|
||||||
|
.unwrap_or_default()
|
||||||
|
.to_string(),
|
||||||
|
platform: cmd
|
||||||
|
.get("virtualserver_platform")
|
||||||
|
.unwrap_or_default()
|
||||||
|
.to_string(),
|
||||||
|
version: cmd
|
||||||
|
.get("virtualserver_version")
|
||||||
|
.unwrap_or_default()
|
||||||
|
.to_string(),
|
||||||
|
max_clients: cmd
|
||||||
|
.get("virtualserver_maxclients")
|
||||||
|
.and_then(|v| v.parse().ok())
|
||||||
|
.unwrap_or(0),
|
||||||
|
clients_online: cmd
|
||||||
|
.get("virtualserver_clientsonline")
|
||||||
|
.and_then(|v| v.parse().ok())
|
||||||
|
.unwrap_or(0),
|
||||||
|
channels_online: cmd
|
||||||
|
.get("virtualserver_channelsonline")
|
||||||
|
.and_then(|v| v.parse().ok())
|
||||||
|
.unwrap_or(0),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
"initivexpand" => {
|
"initivexpand" => {
|
||||||
// 旧协议密钥交换
|
// 旧协议密钥交换
|
||||||
@@ -220,23 +312,64 @@ impl Client {
|
|||||||
responses.extend(self.handle_initivexpand2(&cmd)?);
|
responses.extend(self.handle_initivexpand2(&cmd)?);
|
||||||
}
|
}
|
||||||
"channellist" => {
|
"channellist" => {
|
||||||
// 频道列表
|
events
|
||||||
|
.push(CommandEvent::ChannelList(Self::parse_channel_entries(&cmd)));
|
||||||
}
|
}
|
||||||
"channellistfinished" => {
|
"channellistfinished" => {
|
||||||
self.state_machine
|
self.state_machine
|
||||||
.transition(ConnectionState::ChannelListFinished)
|
.transition(ConnectionState::ChannelListFinished)
|
||||||
.map_err(ProtocolError::PacketParse)?;
|
.map_err(ProtocolError::PacketParse)?;
|
||||||
|
events.push(CommandEvent::ChannelListFinished);
|
||||||
|
}
|
||||||
|
"clientlist" => {
|
||||||
|
events.push(CommandEvent::ClientList(Self::parse_client_entries(&cmd)));
|
||||||
}
|
}
|
||||||
"notifycliententerview" => {
|
"notifycliententerview" => {
|
||||||
// 客户端进入视图
|
events.push(CommandEvent::ClientEntered {
|
||||||
|
clid: cmd.get("clid").and_then(|v| v.parse().ok()).unwrap_or(0),
|
||||||
|
cid: cmd.get("cid").and_then(|v| v.parse().ok()).unwrap_or(0),
|
||||||
|
client_nickname: cmd
|
||||||
|
.get("client_nickname")
|
||||||
|
.unwrap_or_default()
|
||||||
|
.to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
"notifyclientleftview" => {
|
||||||
|
events.push(CommandEvent::ClientLeft {
|
||||||
|
clid: cmd.get("clid").and_then(|v| v.parse().ok()).unwrap_or(0),
|
||||||
|
reason: cmd.get("reasonmsg").unwrap_or_default().to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
"notifyclientmoved" => {
|
||||||
|
events.push(CommandEvent::ClientMoved {
|
||||||
|
clid: cmd.get("clid").and_then(|v| v.parse().ok()).unwrap_or(0),
|
||||||
|
cid: cmd.get("ctid").and_then(|v| v.parse().ok()).unwrap_or(0),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
"notifytextmessage" => {
|
||||||
|
events.push(CommandEvent::TextMessage {
|
||||||
|
invoker_id: cmd
|
||||||
|
.get("invokerid")
|
||||||
|
.and_then(|v| v.parse().ok())
|
||||||
|
.unwrap_or(0),
|
||||||
|
invoker_name: cmd
|
||||||
|
.get("invokername")
|
||||||
|
.unwrap_or_default()
|
||||||
|
.to_string(),
|
||||||
|
message: cmd.get("msg").unwrap_or_default().to_string(),
|
||||||
|
target_mode: cmd
|
||||||
|
.get("targetmode")
|
||||||
|
.and_then(|v| v.parse().ok())
|
||||||
|
.unwrap_or(0),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
"error" => {
|
"error" => {
|
||||||
if let Some(id) = cmd.get("id") {
|
if let Some(id) = cmd.get("id") {
|
||||||
if id != "0" {
|
if id != "0" {
|
||||||
return Err(ProtocolError::PacketParse(format!(
|
events.push(CommandEvent::Error {
|
||||||
"服务器错误: {}",
|
id: id.parse().unwrap_or(0),
|
||||||
cmd.get("msg").unwrap_or("未知")
|
message: cmd.get("msg").unwrap_or("unknown").to_string(),
|
||||||
)));
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -247,7 +380,58 @@ impl Client {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(responses)
|
Ok(HandleResult { responses, events })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_channel_entries(cmd: &Command) -> Vec<ChannelEntry> {
|
||||||
|
let mut entries = Vec::new();
|
||||||
|
let cid = cmd.get("cid").and_then(|v| v.parse().ok()).unwrap_or(0);
|
||||||
|
let pid = cmd.get("pid").and_then(|v| v.parse().ok()).unwrap_or(0);
|
||||||
|
let channel_order = cmd
|
||||||
|
.get("channel_order")
|
||||||
|
.and_then(|v| v.parse().ok())
|
||||||
|
.unwrap_or(0);
|
||||||
|
let channel_name = cmd.get("channel_name").unwrap_or_default().to_string();
|
||||||
|
let total_clients = cmd
|
||||||
|
.get("total_clients")
|
||||||
|
.and_then(|v| v.parse().ok())
|
||||||
|
.unwrap_or(0);
|
||||||
|
let channel_needed_subscribe_power = cmd
|
||||||
|
.get("channel_needed_subscribe_power")
|
||||||
|
.and_then(|v| v.parse().ok())
|
||||||
|
.unwrap_or(0);
|
||||||
|
|
||||||
|
entries.push(ChannelEntry {
|
||||||
|
cid,
|
||||||
|
pid,
|
||||||
|
channel_order,
|
||||||
|
channel_name,
|
||||||
|
total_clients,
|
||||||
|
channel_needed_subscribe_power,
|
||||||
|
});
|
||||||
|
entries
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_client_entries(cmd: &Command) -> Vec<ClientEntry> {
|
||||||
|
let clid = cmd.get("clid").and_then(|v| v.parse().ok()).unwrap_or(0);
|
||||||
|
let cid = cmd.get("cid").and_then(|v| v.parse().ok()).unwrap_or(0);
|
||||||
|
let client_database_id = cmd
|
||||||
|
.get("client_database_id")
|
||||||
|
.and_then(|v| v.parse().ok())
|
||||||
|
.unwrap_or(0);
|
||||||
|
let client_nickname = cmd.get("client_nickname").unwrap_or_default().to_string();
|
||||||
|
let client_type = cmd
|
||||||
|
.get("client_type")
|
||||||
|
.and_then(|v| v.parse().ok())
|
||||||
|
.unwrap_or(0);
|
||||||
|
|
||||||
|
vec![ClientEntry {
|
||||||
|
clid,
|
||||||
|
cid,
|
||||||
|
client_database_id,
|
||||||
|
client_nickname,
|
||||||
|
client_type,
|
||||||
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 构建 Init2 数据包
|
/// 构建 Init2 数据包
|
||||||
@@ -696,16 +880,16 @@ mod tests {
|
|||||||
server_packet.set_packet_id(0);
|
server_packet.set_packet_id(0);
|
||||||
crypto::encrypt_fake(&mut server_packet).unwrap();
|
crypto::encrypt_fake(&mut server_packet).unwrap();
|
||||||
|
|
||||||
let responses = client.handle_data(&server_packet.to_bytes()).unwrap();
|
let result = client.handle_data(&server_packet.to_bytes()).unwrap();
|
||||||
assert_eq!(responses.len(), 2);
|
assert_eq!(result.responses.len(), 2);
|
||||||
|
|
||||||
let ack = InPacket::parse(Direction::C2S, &responses[0]).unwrap();
|
let ack = InPacket::parse(Direction::C2S, &result.responses[0]).unwrap();
|
||||||
assert_eq!(ack.header.packet_id, 0);
|
assert_eq!(ack.header.packet_id, 0);
|
||||||
assert_eq!(ack.header.flags.packet_type(), PacketType::Ack);
|
assert_eq!(ack.header.flags.packet_type(), PacketType::Ack);
|
||||||
let ack_content = crypto::decrypt_fake(&ack).unwrap();
|
let ack_content = crypto::decrypt_fake(&ack).unwrap();
|
||||||
assert_eq!(ack_content, 0u16.to_be_bytes());
|
assert_eq!(ack_content, 0u16.to_be_bytes());
|
||||||
|
|
||||||
let clientek = InPacket::parse(Direction::C2S, &responses[1]).unwrap();
|
let clientek = InPacket::parse(Direction::C2S, &result.responses[1]).unwrap();
|
||||||
assert_eq!(clientek.header.packet_id, 1);
|
assert_eq!(clientek.header.packet_id, 1);
|
||||||
assert_eq!(clientek.header.flags.packet_type(), PacketType::Command);
|
assert_eq!(clientek.header.flags.packet_type(), PacketType::Command);
|
||||||
assert!(clientek.header.flags.is_newprotocol());
|
assert!(clientek.header.flags.is_newprotocol());
|
||||||
@@ -732,10 +916,10 @@ mod tests {
|
|||||||
ack.set_packet_id(0);
|
ack.set_packet_id(0);
|
||||||
crypto::encrypt_fake(&mut ack).unwrap();
|
crypto::encrypt_fake(&mut ack).unwrap();
|
||||||
|
|
||||||
let responses = client.handle_data(&ack.to_bytes()).unwrap();
|
let result = client.handle_data(&ack.to_bytes()).unwrap();
|
||||||
assert_eq!(responses.len(), 1);
|
assert_eq!(result.responses.len(), 1);
|
||||||
|
|
||||||
let clientinit = InPacket::parse(Direction::C2S, &responses[0]).unwrap();
|
let clientinit = InPacket::parse(Direction::C2S, &result.responses[0]).unwrap();
|
||||||
assert_eq!(clientinit.header.packet_id, 2);
|
assert_eq!(clientinit.header.packet_id, 2);
|
||||||
assert_eq!(clientinit.header.flags.packet_type(), PacketType::Command);
|
assert_eq!(clientinit.header.flags.packet_type(), PacketType::Command);
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ use std::time::Duration;
|
|||||||
use tokio::net::UdpSocket;
|
use tokio::net::UdpSocket;
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
|
|
||||||
use super::client::{Client, ClientConfig};
|
use super::client::{ChannelEntry, Client, ClientConfig, ClientEntry, CommandEvent, HandleResult};
|
||||||
use super::state::ConnectionState;
|
use super::state::ConnectionState;
|
||||||
use crate::protocol::{Command, Direction, InPacket, PacketType};
|
use crate::protocol::Command;
|
||||||
use crate::ProtocolError;
|
use crate::ProtocolError;
|
||||||
|
|
||||||
pub enum SessionCommand {
|
pub enum SessionCommand {
|
||||||
@@ -71,25 +71,6 @@ pub enum SessionEvent {
|
|||||||
Disconnected,
|
Disconnected,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, serde::Serialize)]
|
|
||||||
pub struct ChannelEntry {
|
|
||||||
pub cid: u64,
|
|
||||||
pub pid: u64,
|
|
||||||
pub channel_order: u64,
|
|
||||||
pub channel_name: String,
|
|
||||||
pub total_clients: u16,
|
|
||||||
pub channel_needed_subscribe_power: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, serde::Serialize)]
|
|
||||||
pub struct ClientEntry {
|
|
||||||
pub clid: u16,
|
|
||||||
pub cid: u64,
|
|
||||||
pub client_database_id: u64,
|
|
||||||
pub client_nickname: String,
|
|
||||||
pub client_type: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct SessionHandle {
|
pub struct SessionHandle {
|
||||||
command_tx: mpsc::Sender<SessionCommand>,
|
command_tx: mpsc::Sender<SessionCommand>,
|
||||||
event_rx: mpsc::Receiver<SessionEvent>,
|
event_rx: mpsc::Receiver<SessionEvent>,
|
||||||
@@ -228,20 +209,11 @@ impl Session {
|
|||||||
let mut buf = [0u8; 2048];
|
let mut buf = [0u8; 2048];
|
||||||
loop {
|
loop {
|
||||||
let len = socket.recv(&mut buf).await?;
|
let len = socket.recv(&mut buf).await?;
|
||||||
let responses = client.handle_data(&buf[..len])?;
|
let result = client.handle_data(&buf[..len])?;
|
||||||
for response in &responses {
|
for response in &result.responses {
|
||||||
socket.send(response).await?;
|
socket.send(response).await?;
|
||||||
}
|
}
|
||||||
|
init_events.extend(result.events);
|
||||||
if let Ok(packet) = InPacket::parse(Direction::S2C, &buf[..len]) {
|
|
||||||
if let Some(content) = Self::decrypt_packet_static(&client, &packet) {
|
|
||||||
if let Ok(content_str) = std::str::from_utf8(&content) {
|
|
||||||
for cmd in Command::parse_many(content_str).unwrap_or_default() {
|
|
||||||
Self::collect_init_event(&cmd, &mut init_events);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if client.state() == ConnectionState::ChannelListFinished {
|
if client.state() == ConnectionState::ChannelListFinished {
|
||||||
return Ok::<(), ProtocolError>(());
|
return Ok::<(), ProtocolError>(());
|
||||||
@@ -252,7 +224,7 @@ impl Session {
|
|||||||
.map_err(|_| ProtocolError::Timeout("handshake timed out".to_string()))??;
|
.map_err(|_| ProtocolError::Timeout("handshake timed out".to_string()))??;
|
||||||
|
|
||||||
let (command_tx, command_rx) = mpsc::channel(32);
|
let (command_tx, command_rx) = mpsc::channel(32);
|
||||||
let (event_tx, mut event_rx) = mpsc::channel(32);
|
let (event_tx, event_rx) = mpsc::channel(32);
|
||||||
|
|
||||||
let session = Self {
|
let session = Self {
|
||||||
client,
|
client,
|
||||||
@@ -269,96 +241,6 @@ impl Session {
|
|||||||
Ok((session, handle))
|
Ok((session, handle))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decrypt_packet_static(client: &Client, packet: &InPacket) -> Option<Vec<u8>> {
|
|
||||||
let packet_type = packet.header.flags.packet_type();
|
|
||||||
if packet.header.flags.is_unencrypted() {
|
|
||||||
return Some(packet.data.clone());
|
|
||||||
}
|
|
||||||
if packet_type == PacketType::Ack || packet_type == PacketType::AckLow {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn collect_init_event(cmd: &Command, events: &mut Vec<SessionEvent>) {
|
|
||||||
match cmd.name.as_str() {
|
|
||||||
"initserver" => {
|
|
||||||
let client_id = cmd
|
|
||||||
.get("client_id")
|
|
||||||
.and_then(|v| v.parse().ok())
|
|
||||||
.unwrap_or(0);
|
|
||||||
let name = cmd
|
|
||||||
.get("virtualserver_name")
|
|
||||||
.unwrap_or_default()
|
|
||||||
.to_string();
|
|
||||||
let platform = cmd
|
|
||||||
.get("virtualserver_platform")
|
|
||||||
.unwrap_or_default()
|
|
||||||
.to_string();
|
|
||||||
let version = cmd
|
|
||||||
.get("virtualserver_version")
|
|
||||||
.unwrap_or_default()
|
|
||||||
.to_string();
|
|
||||||
let max_clients = cmd
|
|
||||||
.get("virtualserver_maxclients")
|
|
||||||
.and_then(|v| v.parse().ok())
|
|
||||||
.unwrap_or(0);
|
|
||||||
let clients_online = cmd
|
|
||||||
.get("virtualserver_clientsonline")
|
|
||||||
.and_then(|v| v.parse().ok())
|
|
||||||
.unwrap_or(0);
|
|
||||||
let channels_online = cmd
|
|
||||||
.get("virtualserver_channelsonline")
|
|
||||||
.and_then(|v| v.parse().ok())
|
|
||||||
.unwrap_or(0);
|
|
||||||
|
|
||||||
events.push(SessionEvent::ServerInfo {
|
|
||||||
name,
|
|
||||||
platform,
|
|
||||||
version,
|
|
||||||
max_clients,
|
|
||||||
clients_online,
|
|
||||||
channels_online,
|
|
||||||
});
|
|
||||||
events.push(SessionEvent::Connected { client_id });
|
|
||||||
}
|
|
||||||
"channellist" => {
|
|
||||||
let channels = Self::parse_channel_list(cmd);
|
|
||||||
events.push(SessionEvent::ChannelList(channels));
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_channel_list(cmd: &Command) -> Vec<ChannelEntry> {
|
|
||||||
let mut channels = Vec::new();
|
|
||||||
let cid = cmd.get("cid").and_then(|v| v.parse().ok()).unwrap_or(0);
|
|
||||||
let pid = cmd.get("pid").and_then(|v| v.parse().ok()).unwrap_or(0);
|
|
||||||
let channel_order = cmd
|
|
||||||
.get("channel_order")
|
|
||||||
.and_then(|v| v.parse().ok())
|
|
||||||
.unwrap_or(0);
|
|
||||||
let channel_name = cmd.get("channel_name").unwrap_or_default().to_string();
|
|
||||||
let total_clients = cmd
|
|
||||||
.get("total_clients")
|
|
||||||
.and_then(|v| v.parse().ok())
|
|
||||||
.unwrap_or(0);
|
|
||||||
let channel_needed_subscribe_power = cmd
|
|
||||||
.get("channel_needed_subscribe_power")
|
|
||||||
.and_then(|v| v.parse().ok())
|
|
||||||
.unwrap_or(0);
|
|
||||||
|
|
||||||
channels.push(ChannelEntry {
|
|
||||||
cid,
|
|
||||||
pid,
|
|
||||||
channel_order,
|
|
||||||
channel_name,
|
|
||||||
total_clients,
|
|
||||||
channel_needed_subscribe_power,
|
|
||||||
});
|
|
||||||
channels
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn client_id(&self) -> Option<u16> {
|
pub fn client_id(&self) -> Option<u16> {
|
||||||
self.client.client_id()
|
self.client.client_id()
|
||||||
}
|
}
|
||||||
@@ -374,22 +256,12 @@ impl Session {
|
|||||||
tokio::select! {
|
tokio::select! {
|
||||||
result = self.socket.recv(&mut buf) => {
|
result = self.socket.recv(&mut buf) => {
|
||||||
let len = result?;
|
let len = result?;
|
||||||
let responses = self.client.handle_data(&buf[..len])?;
|
let handle_result = self.client.handle_data(&buf[..len])?;
|
||||||
for response in &responses {
|
for response in &handle_result.responses {
|
||||||
self.socket.send(response).await?;
|
self.socket.send(response).await?;
|
||||||
}
|
}
|
||||||
|
for event in handle_result.events {
|
||||||
if let Ok(packet) = InPacket::parse(Direction::S2C, &buf[..len]) {
|
self.emit_session_event(event).await;
|
||||||
let packet_type = packet.header.flags.packet_type();
|
|
||||||
if packet_type == PacketType::Command || packet_type == PacketType::CommandLow {
|
|
||||||
if let Some(content) = self.decrypt_packet(&packet) {
|
|
||||||
if let Ok(content_str) = std::str::from_utf8(&content) {
|
|
||||||
for cmd in Command::parse_many(content_str).unwrap_or_default() {
|
|
||||||
self.emit_command_event(&cmd).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(command) = self.command_rx.recv() => {
|
Some(command) = self.command_rx.recv() => {
|
||||||
@@ -408,49 +280,17 @@ impl Session {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decrypt_packet(&self, packet: &InPacket) -> Option<Vec<u8>> {
|
async fn emit_session_event(&self, event: CommandEvent) {
|
||||||
let packet_type = packet.header.flags.packet_type();
|
let session_event = match event {
|
||||||
if packet.header.flags.is_unencrypted() {
|
CommandEvent::InitServer {
|
||||||
return Some(packet.data.clone());
|
client_id,
|
||||||
}
|
name,
|
||||||
if packet_type == PacketType::Ack || packet_type == PacketType::AckLow {
|
platform,
|
||||||
return None;
|
version,
|
||||||
}
|
max_clients,
|
||||||
None
|
clients_online,
|
||||||
}
|
channels_online,
|
||||||
|
} => {
|
||||||
async fn emit_command_event(&self, cmd: &Command) {
|
|
||||||
let event = match cmd.name.as_str() {
|
|
||||||
"initserver" => {
|
|
||||||
let client_id = cmd
|
|
||||||
.get("client_id")
|
|
||||||
.and_then(|v| v.parse().ok())
|
|
||||||
.unwrap_or(0);
|
|
||||||
let name = cmd
|
|
||||||
.get("virtualserver_name")
|
|
||||||
.unwrap_or_default()
|
|
||||||
.to_string();
|
|
||||||
let platform = cmd
|
|
||||||
.get("virtualserver_platform")
|
|
||||||
.unwrap_or_default()
|
|
||||||
.to_string();
|
|
||||||
let version = cmd
|
|
||||||
.get("virtualserver_version")
|
|
||||||
.unwrap_or_default()
|
|
||||||
.to_string();
|
|
||||||
let max_clients = cmd
|
|
||||||
.get("virtualserver_maxclients")
|
|
||||||
.and_then(|v| v.parse().ok())
|
|
||||||
.unwrap_or(0);
|
|
||||||
let clients_online = cmd
|
|
||||||
.get("virtualserver_clientsonline")
|
|
||||||
.and_then(|v| v.parse().ok())
|
|
||||||
.unwrap_or(0);
|
|
||||||
let channels_online = cmd
|
|
||||||
.get("virtualserver_channelsonline")
|
|
||||||
.and_then(|v| v.parse().ok())
|
|
||||||
.unwrap_or(0);
|
|
||||||
|
|
||||||
let _ = self
|
let _ = self
|
||||||
.event_tx
|
.event_tx
|
||||||
.send(SessionEvent::ServerInfo {
|
.send(SessionEvent::ServerInfo {
|
||||||
@@ -462,91 +302,39 @@ impl Session {
|
|||||||
channels_online,
|
channels_online,
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
Some(SessionEvent::Connected { client_id })
|
SessionEvent::Connected { client_id }
|
||||||
}
|
}
|
||||||
"channellist" => {
|
CommandEvent::ChannelList(channels) => SessionEvent::ChannelList(channels),
|
||||||
let channels = Self::parse_channel_list(cmd);
|
CommandEvent::ChannelListFinished => return,
|
||||||
Some(SessionEvent::ChannelList(channels))
|
CommandEvent::ClientList(clients) => SessionEvent::ClientList(clients),
|
||||||
}
|
CommandEvent::ClientEntered {
|
||||||
"clientlist" => {
|
|
||||||
let clients = Self::parse_client_list(cmd);
|
|
||||||
Some(SessionEvent::ClientList(clients))
|
|
||||||
}
|
|
||||||
"notifycliententerview" => {
|
|
||||||
let clid = cmd.get("clid").and_then(|v| v.parse().ok()).unwrap_or(0);
|
|
||||||
let cid = cmd.get("cid").and_then(|v| v.parse().ok()).unwrap_or(0);
|
|
||||||
let client_nickname = cmd.get("client_nickname").unwrap_or_default().to_string();
|
|
||||||
Some(SessionEvent::ClientEntered {
|
|
||||||
clid,
|
clid,
|
||||||
cid,
|
cid,
|
||||||
client_nickname,
|
client_nickname,
|
||||||
})
|
} => SessionEvent::ClientEntered {
|
||||||
}
|
clid,
|
||||||
"notifyclientleftview" => {
|
cid,
|
||||||
let clid = cmd.get("clid").and_then(|v| v.parse().ok()).unwrap_or(0);
|
client_nickname,
|
||||||
let reason = cmd.get("reasonmsg").unwrap_or_default().to_string();
|
},
|
||||||
Some(SessionEvent::ClientLeft { clid, reason })
|
CommandEvent::ClientLeft { clid, reason } => SessionEvent::ClientLeft { clid, reason },
|
||||||
}
|
CommandEvent::ClientMoved { clid, cid } => SessionEvent::ClientMoved { clid, cid },
|
||||||
"notifyclientmoved" => {
|
CommandEvent::TextMessage {
|
||||||
let clid = cmd.get("clid").and_then(|v| v.parse().ok()).unwrap_or(0);
|
|
||||||
let cid = cmd.get("ctid").and_then(|v| v.parse().ok()).unwrap_or(0);
|
|
||||||
Some(SessionEvent::ClientMoved { clid, cid })
|
|
||||||
}
|
|
||||||
"notifytextmessage" => {
|
|
||||||
let invoker_id = cmd
|
|
||||||
.get("invokerid")
|
|
||||||
.and_then(|v| v.parse().ok())
|
|
||||||
.unwrap_or(0);
|
|
||||||
let invoker_name = cmd.get("invokername").unwrap_or_default().to_string();
|
|
||||||
let message = cmd.get("msg").unwrap_or_default().to_string();
|
|
||||||
let target_mode = cmd
|
|
||||||
.get("targetmode")
|
|
||||||
.and_then(|v| v.parse().ok())
|
|
||||||
.unwrap_or(0);
|
|
||||||
Some(SessionEvent::TextMessage {
|
|
||||||
invoker_id,
|
invoker_id,
|
||||||
invoker_name,
|
invoker_name,
|
||||||
message,
|
message,
|
||||||
target_mode,
|
target_mode,
|
||||||
})
|
} => SessionEvent::TextMessage {
|
||||||
|
invoker_id,
|
||||||
|
invoker_name,
|
||||||
|
message,
|
||||||
|
target_mode,
|
||||||
|
},
|
||||||
|
CommandEvent::Error { id, message } => {
|
||||||
|
SessionEvent::Error(format!("server error {id}: {message}"))
|
||||||
}
|
}
|
||||||
"error" => {
|
|
||||||
let id = cmd.get("id").unwrap_or("0");
|
|
||||||
if id != "0" {
|
|
||||||
let msg = cmd.get("msg").unwrap_or("unknown error").to_string();
|
|
||||||
Some(SessionEvent::Error(msg))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(event) = event {
|
let _ = self.event_tx.send(session_event).await;
|
||||||
let _ = self.event_tx.send(event).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_client_list(cmd: &Command) -> Vec<ClientEntry> {
|
|
||||||
let clid = cmd.get("clid").and_then(|v| v.parse().ok()).unwrap_or(0);
|
|
||||||
let cid = cmd.get("cid").and_then(|v| v.parse().ok()).unwrap_or(0);
|
|
||||||
let client_database_id = cmd
|
|
||||||
.get("client_database_id")
|
|
||||||
.and_then(|v| v.parse().ok())
|
|
||||||
.unwrap_or(0);
|
|
||||||
let client_nickname = cmd.get("client_nickname").unwrap_or_default().to_string();
|
|
||||||
let client_type = cmd
|
|
||||||
.get("client_type")
|
|
||||||
.and_then(|v| v.parse().ok())
|
|
||||||
.unwrap_or(0);
|
|
||||||
|
|
||||||
vec![ClientEntry {
|
|
||||||
clid,
|
|
||||||
cid,
|
|
||||||
client_database_id,
|
|
||||||
client_nickname,
|
|
||||||
client_type,
|
|
||||||
}]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_command(&mut self, command: SessionCommand) -> Result<(), ProtocolError> {
|
async fn handle_command(&mut self, command: SessionCommand) -> Result<(), ProtocolError> {
|
||||||
|
|||||||
@@ -122,8 +122,8 @@ async fn perform_handshake_until(
|
|||||||
let mut buf = [0u8; 2048];
|
let mut buf = [0u8; 2048];
|
||||||
loop {
|
loop {
|
||||||
let len = socket.recv(&mut buf).await?;
|
let len = socket.recv(&mut buf).await?;
|
||||||
let responses = client.handle_data(&buf[..len])?;
|
let result = client.handle_data(&buf[..len])?;
|
||||||
for response in responses {
|
for response in result.responses {
|
||||||
socket.send(&response).await?;
|
socket.send(&response).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user