diff --git a/src/main.rs b/src/main.rs index 9cc68c4..fa42051 100644 --- a/src/main.rs +++ b/src/main.rs @@ -28,11 +28,11 @@ async fn shutdown_signal() { } #[derive(Clone)] -struct ActionHandler( - Arc>, - Arc, - reqwest::Client, -); +struct ActionHandler { + parser: Arc>, + settings: Arc, + client: reqwest::Client, +} pub const SERIALIZE_OPTIONS: SerializeOptions = SerializeOptions::new() .skip_default_fields(false) @@ -58,29 +58,25 @@ impl WebSocketHandler for ActionHandler { } }) .collect::(); - event!(Level::DEBUG, "{} {}", direction_char, hex); - let mut parser = self.0.lock().unwrap(); - let parsed = parser.parse(&buf); + debug!("{} {}", direction_char, hex); + let mut parser = self.parser.lock().unwrap(); + let parsed = parser.parse(buf); let parsed = match parsed { Ok(parsed) => parsed, Err(e) => { - event!(Level::ERROR, "Failed to parse message: {:?}", e); + error!("Failed to parse message: {:?}", e); return Some(msg); } }; - event!( - Level::INFO, - "拦截到: {}, {}, {:?}, {}", - direction_char, - parsed.id, - parsed.msg_type, - parsed.method_name + info!( + "监听到: {}, {}, {:?}, {}", + direction_char, parsed.id, parsed.msg_type, parsed.method_name ); if direction_char == '\u{2193}' { return Some(msg); } if let Err(e) = self.send_message(parsed) { - event!(Level::ERROR, "Failed to send message: {:?}", e); + error!("Failed to send message: {:?}", e); } } Some(msg) @@ -89,31 +85,30 @@ impl WebSocketHandler for ActionHandler { impl ActionHandler { fn send_message(&self, mut parsed: LiqiMessage) -> Result<(), Box> { - let settings = self.1.clone(); - let json_body: String; - event!(Level::INFO, "Method: {}", parsed.method_name); - if settings - .send_method - .iter() - .all(|x| !parsed.method_name.contains(x)) - { + let settings = self.settings.clone(); + let json_data: JsonValue; + if !settings.is_method(&parsed.method_name) { return Ok(()); } - if parsed.method_name.contains(".lq.ActionPrototype") { - let name = parsed.data.get("name").ok_or("No name field")?.to_string(); - event!(Level::INFO, "Action: {}", name); - if settings.send_action.iter().all(|x| !name.contains(x)) { - event!(Level::INFO, "Action {} not in send_action", name); + if parsed.method_name == ".lq.ActionPrototype" { + let name = parsed + .data + .get("name") + .ok_or("No name field")? + .as_str() + .ok_or("name is not a string")? + .to_owned(); + if !settings.is_action(&name) { return Ok(()); } let data = parsed.data.get_mut("data").ok_or("No data field")?; - if name.contains("ActionNewRound") { + if name == "ActionNewRound" { data.as_object_mut() .ok_or("data is not an object")? .insert("md5".to_string(), json!(RANDOM_MD5)); } - json_body = serde_json::to_string(data)?; - } else if parsed.method_name.contains(".lq.FastTest.syncGame") { + json_data = data.take(); + } else if parsed.method_name == ".lq.FastTest.syncGame" { let game_restore = parsed .data .get("game_restore") @@ -124,16 +119,17 @@ impl ActionHandler { .ok_or("actions is not an array")?; let mut actions: Vec = vec![]; for item in game_restore.iter() { - let action_name = item.get("name").ok_or("No name field")?.as_str().ok_or( - " - name is not a string - ", - )?; - let action_data = item.get("data").ok_or("No data field")?.as_str().unwrap_or( - " - data is not a string", - ); - if action_data.len() == 0 { + let action_name = item + .get("name") + .ok_or("No name field")? + .as_str() + .ok_or("name is not a string")?; + let action_data = item + .get("data") + .ok_or("No data field")? + .as_str() + .unwrap_or("data is not a string"); + if action_data.is_empty() { let action = Action { name: action_name.to_string(), data: JsonValue::Object(Map::new()), @@ -141,13 +137,13 @@ impl ActionHandler { actions.push(action); } else { let b64 = BASE64_STANDARD.decode(action_data)?; - let parser = self.0.lock().unwrap(); + let parser = self.parser.lock().unwrap(); let action_type = parser .pool - .get_message_by_name(&action_name) + .get_message_by_name(action_name) .ok_or("Invalid action type")?; let mut action_obj = DynamicMessage::decode(action_type, b64.as_ref())?; - if action_name.contains(".lq.ActionNewRound") { + if action_name == ".lq.ActionNewRound" { action_obj.set_field_by_name("md5", Value::String(RANDOM_MD5.to_string())); } let value: JsonValue = my_serialize(action_obj)?; @@ -163,26 +159,22 @@ impl ActionHandler { "sync_game_actions".to_string(), serde_json::to_value(actions)?, ); - json_body = serde_json::to_string(&map)?; + json_data = JsonValue::Object(map); } else { - json_body = serde_json::to_string(&parsed.data)?; + json_data = parsed.data; } // post data to API, no verification - let client = self.2.clone(); - let future = client - .post(&settings.api_url) - .body(json_body.to_owned()) - .send(); + let client = self.client.clone(); + let future = client.post(&settings.api_url).json(&json_data).send(); handle_future(future); - event!(Level::INFO, "已发送: {}", json_body); + info!("已发送: {}", json_data); - let json_obj: JsonValue = serde_json::from_str(&json_body)?; - if let Some(liqi_data) = json_obj.get("liqi") { + if let Some(liqi_data) = json_data.get("liqi") { let res = client.post(&settings.api_url).json(liqi_data).send(); handle_future(res); - event!(Level::INFO, "已发送: {:?}", liqi_data); + info!("已发送: {:?}", liqi_data); } Ok(()) @@ -196,10 +188,10 @@ fn handle_future( match future.await { Ok(res) => { let body = res.text().await.unwrap_or_default(); - event!(Level::INFO, "小助手已接收: {}", body); + info!("小助手已接收: {}", body); } Err(e) => { - event!(Level::ERROR, "请求失败: {:?}", e); + error!("请求失败: {:?}", e); } } }); @@ -221,26 +213,27 @@ async fn main() { // print red declaimer text println!( - "{}", "\x1b[31m 本项目完全免费开源,如果您购买了此程序,请立即退款! 项目地址: https://github.com/Xerxes-2/mahjong_helper_majsoul_hudsucker/ 本程序仅供学习交流使用,严禁用于商业用途! 请遵守当地法律法规,对于使用本程序所产生的任何后果,作者概不负责! - 请勿将本程序用于非法用途,否则后果自负! \x1b[0m" ); let parser = parser::Parser::new(); let settings = settings::Settings::new(); - if let Err(e) = settings { - error!("{}", e); - // press any key to exit - println!("按任意键退出"); - let _ = std::io::stdin().read(&mut [0u8]).unwrap(); - return; - } - let settings = settings.unwrap(); + let settings = match settings { + Ok(settings) => settings, + Err(e) => { + error!("{}", e); + // press any key to exit + println!("按任意键退出"); + let mut stdin = std::io::stdin(); + let _ = stdin.read(&mut [0u8]).unwrap_or_default(); + return; + } + }; let client = reqwest::ClientBuilder::new() .danger_accept_invalid_certs(true) .build() @@ -250,11 +243,11 @@ async fn main() { .with_addr(SocketAddr::from(([127, 0, 0, 1], 23410))) .with_rustls_client() .with_ca(ca) - .with_websocket_handler(ActionHandler( - Arc::new(Mutex::new(parser)), - Arc::new(settings), + .with_websocket_handler(ActionHandler { + parser: Arc::new(Mutex::new(parser)), + settings: Arc::new(settings), client, - )) + }) .with_graceful_shutdown(shutdown_signal()) .build(); diff --git a/src/parser.rs b/src/parser.rs index 5f43bd0..6f55ba4 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -3,7 +3,6 @@ use prost_reflect::{DescriptorPool, DynamicMessage, MessageDescriptor}; use serde::Serialize; use serde_json::Value as JsonValue; use std::{collections::HashMap, error::Error}; -use tracing::*; use crate::SERIALIZE_OPTIONS; @@ -46,7 +45,8 @@ impl Parser { pub fn new() -> Self { let json_str = include_str!("liqi.json"); let proto_json = serde_json::from_str(json_str).expect("Failed to parse liqi.json"); - let pool = DescriptorPool::decode(include_bytes!("liqi.desc").as_ref()).unwrap(); + let pool = DescriptorPool::decode(include_bytes!("liqi.desc").as_ref()) + .expect("Failed to decode liqi.desc"); Self { total: 0, respond_type: HashMap::new(), @@ -57,7 +57,7 @@ impl Parser { pub fn parse(&mut self, buf: &[u8]) -> Result> { let msg_type_byte = buf[0]; - if msg_type_byte < 1 || msg_type_byte > 3 { + if !(1..=3).contains(&msg_type_byte) { return Err("Invalid message type".into()); } let msg_type = match msg_type_byte { @@ -73,11 +73,11 @@ impl Parser { MessageType::Notify => { let blks = buf_to_blocks(&buf[1..]).ok_or("Failed to parse blocks")?; method_name = String::from_utf8(blks[0].data.clone())?; - let method_name_list: Vec<&str> = method_name.split(".").collect(); + let method_name_list: Vec<&str> = method_name.split('.').collect(); let message_name = method_name_list[2]; let message_type = self .pool - .get_message_by_name(&to_fqn(&message_name)) + .get_message_by_name(&to_fqn(message_name)) .ok_or("Invalid message type")?; let dyn_msg = DynamicMessage::decode(message_type, blks[1].data.as_ref())?; data_obj = my_serialize(dyn_msg)?; @@ -93,7 +93,7 @@ impl Parser { let my_decoded = decode(&decoded); let action_type = self .pool - .get_message_by_name(&to_fqn(&action_name)) + .get_message_by_name(&to_fqn(action_name)) .ok_or("Invalid action type")?; let action_msg = DynamicMessage::decode(action_type, my_decoded.as_ref())?; let action_obj = my_serialize(action_msg)?; @@ -113,7 +113,7 @@ impl Parser { // ascii decode into method name, method_name = msg_block[0]["data"].decode() let method_block = &blocks[0]; method_name = String::from_utf8(method_block.data.to_owned())?; - let method_name_list: Vec<&str> = method_name.split(".").collect(); + let method_name_list: Vec<&str> = method_name.split('.').collect(); let lq = method_name_list[1]; let service = method_name_list[2]; let rpc = method_name_list[3]; @@ -143,7 +143,7 @@ impl Parser { MessageType::Response => { msg_id = u16::from_le_bytes([buf[1], buf[2]]) as usize; let blocks = buf_to_blocks(&buf[3..]).ok_or("Failed to parse blocks")?; - assert!(blocks[0].data.len() == 0); + assert!(blocks[0].data.is_empty()); let resp_type: MessageDescriptor; (method_name, resp_type) = self .respond_type @@ -176,8 +176,6 @@ struct Block { } fn buf_to_blocks(buf: &[u8]) -> Option> { - let hex_str = buf.iter().map(|b| format!("{:02x}", b)).collect::(); - event!(Level::DEBUG, "buf: {}", hex_str); let mut blocks = Vec::new(); let mut i = 0; let l = buf.len(); @@ -228,13 +226,13 @@ fn parse_var_int(buf: &[u8], p: usize) -> (usize, usize) { } fn decode(data: &[u8]) -> Vec { - let keys = vec![0x84, 0x5E, 0x4E, 0x42, 0x39, 0xA2, 0x1F, 0x60, 0x1C]; + let keys = [0x84, 0x5E, 0x4E, 0x42, 0x39, 0xA2, 0x1F, 0x60, 0x1C]; let mut data = data.to_vec(); let k = keys.len(); let d = data.len(); for i in 0..d { - let u = (23 ^ d) + 5 * i + keys[i % k] & 255; + let u = ((23 ^ d) + 5 * i + keys[i % k]) & 255; data[i] ^= u as u8; } - return data; + data } diff --git a/src/settings.rs b/src/settings.rs index 4a19eb0..864f0a7 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -1,6 +1,6 @@ use serde::Deserialize; -use serde_json; -use tracing::event; +use std::collections::HashSet; +use tracing::info; #[derive(Deserialize, Debug)] pub struct Settings { @@ -10,6 +10,10 @@ pub struct Settings { pub send_action: Vec, #[serde(rename(deserialize = "API_URL"))] pub api_url: String, + #[serde(skip)] + methods_set: HashSet, + #[serde(skip)] + actions_set: HashSet, } impl Settings { @@ -28,9 +32,19 @@ impl Settings { |_| std::fs::read_to_string("settings.json"), ) .map_err(|e| format!("无法读取settings.json: {}", e))?; - let settings: Settings = + let mut settings: Settings = serde_json::from_str(&settings).map_err(|e| format!("无法解析settings.json: {}", e))?; - event!(tracing::Level::INFO, "已载入配置: {:?}", settings); + info!("已载入配置: {:?}", settings); + settings.methods_set = settings.send_method.iter().cloned().collect(); + settings.actions_set = settings.send_action.iter().cloned().collect(); Ok(settings) } + + pub fn is_method(&self, method: &str) -> bool { + self.methods_set.contains(method) + } + + pub fn is_action(&self, action: &str) -> bool { + self.actions_set.contains(action) + } }