mirror of
https://github.com/RustySamovar/RustySamovar.git
synced 2024-11-22 02:45:34 +00:00
Refactoring, moving out proto to separate repo, fixed login bug
This commit is contained in:
parent
39f2618916
commit
4d32da1e2e
6
.gitignore
vendored
6
.gitignore
vendored
@ -9,15 +9,9 @@ Cargo.lock
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
|
||||
# *.proto files
|
||||
/protobuf/
|
||||
|
||||
# keys
|
||||
/keys/
|
||||
|
||||
# Vim temp files
|
||||
.*.swp
|
||||
.*.swo
|
||||
|
||||
# Autogenerated files
|
||||
/gen/
|
||||
|
21
Cargo.toml
21
Cargo.toml
@ -8,11 +8,26 @@ edition = "2018"
|
||||
[dependencies]
|
||||
kcp = { path = "../kcp" }
|
||||
mhycrypt = { path = "../mhycrypt" }
|
||||
proto = { path = "../proto" }
|
||||
packet-processor-macro = { path = "packet-processor-macro" }
|
||||
packet-processor = { path = "packet-processor" }
|
||||
|
||||
prost = "0.8"
|
||||
bytes = "1.1.0"
|
||||
base64 = "0.13.0"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
actix-web = { version = "3", features = ["openssl"] }
|
||||
futures = "0.3"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
pretty_env_logger = "0.4"
|
||||
num-traits = "0.2"
|
||||
num-derive = "0.3"
|
||||
base64 = "0.13.0"
|
||||
|
||||
[build-dependencies]
|
||||
prost-build = { version = "0.8.0" }
|
||||
pretty-hex = "0.2"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
openssl = { version = "0.10", features = ["vendored"] }
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
openssl = "0.10"
|
||||
|
65
build.rs
65
build.rs
@ -1,65 +0,0 @@
|
||||
use std::io::Result;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let proto_dir = "protobuf";
|
||||
|
||||
let protos = vec![
|
||||
// Dispatch protocol
|
||||
"QueryRegionListHttpRsp",
|
||||
"QueryCurrRegionHttpRsp",
|
||||
"RegionSimpleInfo",
|
||||
"RegionInfo",
|
||||
|
||||
// Game protocol
|
||||
"packet_header",
|
||||
|
||||
"GetPlayerTokenReq",
|
||||
"GetPlayerTokenRsp",
|
||||
"PlayerLoginReq",
|
||||
"OpenStateUpdateNotify",
|
||||
"StoreWeightLimitNotify",
|
||||
"PlayerStoreNotify",
|
||||
"AvatarDataNotify",
|
||||
"PlayerEnterSceneNotify",
|
||||
"PlayerLoginRsp",
|
||||
"GetPlayerSocialDetailReq",
|
||||
"GetPlayerSocialDetailRsp",
|
||||
"EnterSceneReadyReq",
|
||||
"EnterSceneReadyRsp",
|
||||
"SceneInitFinishReq",
|
||||
"EnterScenePeerNotify",
|
||||
"WorldDataNotify",
|
||||
"WorldPlayerInfoNotify",
|
||||
"ScenePlayerInfoNotify",
|
||||
"PlayerEnterSceneInfoNotify",
|
||||
"PlayerGameTimeNotify",
|
||||
"SceneTimeNotify",
|
||||
"SceneDataNotify",
|
||||
"HostPlayerNotify",
|
||||
"SceneTeamUpdateNotify",
|
||||
"SceneInitFinishRsp",
|
||||
"EnterSceneDoneReq",
|
||||
"SceneEntityAppearNotify",
|
||||
"EnterSceneDoneRsp",
|
||||
"PostEnterSceneReq",
|
||||
"PostEnterSceneRsp",
|
||||
|
||||
"WorldPlayerRTTNotify",
|
||||
"PingReq",
|
||||
"PingRsp",
|
||||
"PlayerDataNotify",
|
||||
|
||||
"EnterWorldAreaReq",
|
||||
"EnterWorldAreaRsp",
|
||||
|
||||
];
|
||||
|
||||
let protos: Vec<String> = protos.iter().map(|&x| format!("{}/{}.proto", proto_dir, x)).collect();
|
||||
|
||||
let ret = prost_build::compile_protos(&protos, &[format!("{}/", proto_dir)]);
|
||||
|
||||
match ret {
|
||||
Ok(_) => return Ok(()),
|
||||
Err(e) => panic!("{}", e),
|
||||
}
|
||||
}
|
27
gen_ids.sh
27
gen_ids.sh
@ -1,27 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
#echo "#[macro_use]";
|
||||
#echo "extern crate num_derive;";
|
||||
|
||||
#echo "";
|
||||
|
||||
echo "// Autogenerated file, do not edit!"
|
||||
|
||||
echo "";
|
||||
|
||||
echo "#[repr(u16)]";
|
||||
echo "#[derive(FromPrimitive, ToPrimitive)]";
|
||||
echo "#[derive(Debug, PartialEq, Eq, Clone, Hash)]";
|
||||
|
||||
echo "pub enum PacketId {";
|
||||
|
||||
for f in protobuf/*; do
|
||||
CMD_ID=`cat $f | grep CMD_ID | cut -d'=' -f2 | tr -d ' ;\015'`;
|
||||
|
||||
if [ "x${CMD_ID}" != "x" ]; then
|
||||
NAME=`echo $f | cut -d'/' -f2 | cut -d'.' -f1`;
|
||||
echo " ${NAME} = ${CMD_ID},"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "}";
|
7
misc/gen_key.sh
Executable file
7
misc/gen_key.sh
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo -ne "\x45\x63\x32\x62" > fake.ec2b
|
||||
echo -ne "\x10\x00\x00\x00" >> fake.ec2b
|
||||
dd if=/dev/urandom bs=16 count=1 >> fake.ec2b
|
||||
echo -ne "\x00\x08\x00\x00" >> fake.ec2b
|
||||
dd if=/dev/urandom bs=2048 count=1 >> fake.ec2b
|
5
misc/grab_key.sh
Executable file
5
misc/grab_key.sh
Executable file
@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
xxd -r text.log > gptr.bin
|
||||
./xor.py gptr.bin 0x20
|
||||
dd if=gptr.bin of=key.bin bs=4096 count=1 skip=1
|
3
misc/ssl_stuff/gen_cert.sh
Executable file
3
misc/ssl_stuff/gen_cert.sh
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 3650 -config ssl.conf -nodes -sha256 -extensions 'req_ext'
|
41
misc/ssl_stuff/ssl.conf
Normal file
41
misc/ssl_stuff/ssl.conf
Normal file
@ -0,0 +1,41 @@
|
||||
[ req ]
|
||||
default_bits = 2048
|
||||
distinguished_name = req_distinguished_name
|
||||
req_extensions = req_ext
|
||||
extensions = req_ext
|
||||
prompt = no
|
||||
|
||||
[ req_distinguished_name ]
|
||||
countryName = CN
|
||||
stateOrProvinceName = Beijing
|
||||
localityName = Xicheng
|
||||
organizationName = oYoHim
|
||||
|
||||
[ req_ext ]
|
||||
subjectAltName = @alt_names
|
||||
|
||||
[ alt_names ]
|
||||
DNS.1 = api-os-takumi.mihoyo.com
|
||||
DNS.2 = api-takumi.mihoyo.com
|
||||
DNS.3 = autopatchhk.yuanshen.com
|
||||
DNS.4 = autopatchcn.yuanshen.com
|
||||
DNS.5 = dispatchosglobal.yuanshen.com
|
||||
DNS.6 = hk4e-api-os-static.mihoyo.com
|
||||
DNS.7 = hk4e-api-static.mihoyo.com
|
||||
DNS.8 = hk4e-api-os.mihoyo.com
|
||||
DNS.9 = hk4e-api.mihoyo.com
|
||||
DNS.10 = hk4e-sdk-os.mihoyo.com
|
||||
DNS.11 = hk4e-sdk.mihoyo.com
|
||||
DNS.12 = log-upload-os.mihoyo.com
|
||||
DNS.13 = log-upload.mihoyo.com
|
||||
DNS.14 = osusadispatch.yuanshen.com
|
||||
DNS.15 = oseurodispatch.yuanshen.com
|
||||
DNS.16 = osasiadispatch.yuanshen.com
|
||||
DNS.17 = sdk-os-static.mihoyo.com
|
||||
DNS.18 = sdk-static.mihoyo.com
|
||||
DNS.19 = webstatic-sea.mihoyo.com
|
||||
DNS.20 = webstatic.mihoyo.com
|
||||
DNS.21 = uploadstatic-sea.mihoyo.com
|
||||
DNS.22 = uploadstatic.mihoyo.com
|
||||
DNS.23 = devlog-upload.mihoyo.com
|
||||
DNS.24 = localhost
|
9
misc/xor.py
Executable file
9
misc/xor.py
Executable file
@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
|
||||
filename = sys.argv[1]
|
||||
key = int(sys.argv[2], 16)
|
||||
|
||||
data = open(filename, "rb").read()
|
||||
open(filename, "wb").write(bytes([i ^ key for i in data]))
|
14
packet-processor-macro/.gitignore
vendored
Normal file
14
packet-processor-macro/.gitignore
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
/target/
|
||||
|
||||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||
Cargo.lock
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
|
||||
# Vim temp files
|
||||
.*.swp
|
||||
.*.swo
|
16
packet-processor-macro/Cargo.toml
Normal file
16
packet-processor-macro/Cargo.toml
Normal file
@ -0,0 +1,16 @@
|
||||
[package]
|
||||
name = "packet-processor-macro"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
regex = "1"
|
||||
syn = { version = "1.0", features = ["full","derive"] }
|
||||
quote = "1.0"
|
||||
proc-macro2 = "1.0"
|
||||
convert_case = "0.4.0"
|
107
packet-processor-macro/src/lib.rs
Normal file
107
packet-processor-macro/src/lib.rs
Normal file
@ -0,0 +1,107 @@
|
||||
extern crate regex;
|
||||
extern crate convert_case;
|
||||
|
||||
use proc_macro::{self, TokenStream};
|
||||
use quote::quote;
|
||||
use syn::{parse_macro_input, AttributeArgs};
|
||||
use regex::Regex;
|
||||
use convert_case::{Case, Casing};
|
||||
|
||||
fn get_nested_meta_name(nested_meta: &syn::NestedMeta) -> String {
|
||||
match nested_meta {
|
||||
syn::NestedMeta::Meta(meta) => match meta {
|
||||
syn::Meta::Path(ident) => ident.get_ident().cloned().unwrap().to_string(),
|
||||
_ => panic!("Unsupported macro argument"),
|
||||
},
|
||||
syn::NestedMeta::Lit(_) => panic!("Only identifiers are supported as an arguments to the macro"),
|
||||
}
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn packet_processor(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let args = parse_macro_input!(args as AttributeArgs);
|
||||
//let input = parse_macro_input!(input as DeriveInput);
|
||||
|
||||
let mut found_struct = false;
|
||||
let mut struct_name = None;
|
||||
|
||||
let modified_struct: proc_macro::TokenStream = input.into_iter().map(|r| {
|
||||
match &r {
|
||||
&proc_macro::TokenTree::Ident(ref ident) if ident.to_string() == "struct" => { // react on keyword "struct" so we don't randomly modify non-structs
|
||||
found_struct = true;
|
||||
r
|
||||
},
|
||||
&proc_macro::TokenTree::Ident(ref ident) if found_struct == true && struct_name == None => { // Next ident right after "struct" is the struct name
|
||||
struct_name = Some(ident.to_string());
|
||||
r
|
||||
},
|
||||
&proc_macro::TokenTree::Group(ref group) if group.delimiter() == proc_macro::Delimiter::Brace && found_struct == true => { // Opening brackets for the struct
|
||||
let mut stream = proc_macro::TokenStream::new();
|
||||
|
||||
stream.extend(
|
||||
vec![proc_macro::TokenStream::from(quote!(packet_callbacks: HashMap<proto::PacketId, fn(&mut Self, u32, &proto::PacketHead, Vec<u8>) -> ()>,))]
|
||||
);
|
||||
stream.extend(group.stream());
|
||||
|
||||
proc_macro::TokenTree::Group(
|
||||
proc_macro::Group::new(
|
||||
proc_macro::Delimiter::Brace,
|
||||
stream
|
||||
)
|
||||
)
|
||||
}
|
||||
_ => r
|
||||
}
|
||||
}).collect();
|
||||
|
||||
let args = args.clone().into_iter().map(|a| get_nested_meta_name(&a));
|
||||
let re = Regex::new(r"Req$").unwrap();
|
||||
|
||||
let request = args.clone().into_iter().filter(|a| a.ends_with("Req"));
|
||||
let notify = args.clone().into_iter().filter(|a| a.ends_with("Notify"));
|
||||
let response = request.clone().into_iter().map(|a| re.replace_all(&a, "Rsp").to_string());
|
||||
let req_handler = request.clone().into_iter().map(|a| format!("process_{}", &a[..a.len()-3].to_case(Case::Snake)));
|
||||
let notify_handler = notify.clone().into_iter().map(|a| format!("process_{}", &a[..a.len()-6].to_case(Case::Snake)));
|
||||
|
||||
let request: Vec<proc_macro2::TokenStream> = request.map(|a| a.parse().unwrap()).collect();
|
||||
let notify: Vec<proc_macro2::TokenStream> = notify.map(|a| a.parse().unwrap()).collect();
|
||||
let response: Vec<proc_macro2::TokenStream> = response.map(|a| a.parse().unwrap()).collect();
|
||||
let req_handler: Vec<proc_macro2::TokenStream> = req_handler.map(|a| a.parse().unwrap()).collect();
|
||||
let notify_handler: Vec<proc_macro2::TokenStream> = notify_handler.map(|a| a.parse().unwrap()).collect();
|
||||
|
||||
let struct_name: proc_macro2::TokenStream = match &struct_name {
|
||||
None => panic!("Failed to find struct name"),
|
||||
Some(name) => name.clone().parse().unwrap(),
|
||||
};
|
||||
|
||||
let implementation = vec![proc_macro::TokenStream::from(quote!(
|
||||
impl PacketProcessor for #struct_name {
|
||||
fn register(&mut self) {
|
||||
let mut callbacks = &mut self.packet_callbacks;
|
||||
#(register_callback!(callbacks, #request, #response, #req_handler);)*
|
||||
#(register_callback!(callbacks, #notify, #notify_handler);)*
|
||||
}
|
||||
|
||||
fn supported(&self) -> Vec<proto::PacketId> {
|
||||
return self.packet_callbacks.keys().cloned().collect();
|
||||
}
|
||||
|
||||
fn process(&mut self, user_id: u32, packet_id: proto::PacketId, metadata: Vec<u8>, data: Vec<u8>) {
|
||||
let callback = self.packet_callbacks.get(&packet_id);
|
||||
let metadata = proto::PacketHead::decode(&mut std::io::Cursor::new(metadata)).unwrap();
|
||||
|
||||
match callback {
|
||||
Some(callback) => callback(self, user_id, &metadata, data),
|
||||
None => println!("Unhandled packet {:?}", packet_id),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
))];
|
||||
|
||||
let mut ret = proc_macro::TokenStream::new();
|
||||
ret.extend(modified_struct);
|
||||
ret.extend(implementation);
|
||||
//println!("{}", ret);
|
||||
ret
|
||||
}
|
14
packet-processor/.gitignore
vendored
Normal file
14
packet-processor/.gitignore
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
/target/
|
||||
|
||||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||
Cargo.lock
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
|
||||
# Vim temp files
|
||||
.*.swp
|
||||
.*.swo
|
9
packet-processor/Cargo.toml
Normal file
9
packet-processor/Cargo.toml
Normal file
@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "packet-processor"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
proto = { path = "../../proto" }
|
32
packet-processor/src/lib.rs
Normal file
32
packet-processor/src/lib.rs
Normal file
@ -0,0 +1,32 @@
|
||||
pub trait PacketProcessor {
|
||||
fn register(&mut self);
|
||||
fn supported(&self) -> Vec<proto::PacketId>;
|
||||
fn process(&mut self, user_id: u32, packet_id: proto::PacketId, metadata: Vec<u8>, data: Vec<u8>);
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! register_callback {
|
||||
($hashmap:ident, $req:ident, $rsp:ident, $handler:ident) => {
|
||||
$hashmap.insert(proto::PacketId::$req, |slef: &mut Self, user_id: u32, metadata: &proto::PacketHead, data: Vec<u8>| {
|
||||
let req = proto::$req::decode(&mut std::io::Cursor::new(data)).unwrap();
|
||||
let mut rsp = proto::$rsp::default();
|
||||
|
||||
println!("Received REQ {:?}", req);
|
||||
|
||||
slef.$handler(user_id, &metadata, &req, &mut rsp);
|
||||
|
||||
let message = IpcMessage::new_from_proto(user_id, proto::PacketId::$rsp, metadata, &rsp);
|
||||
slef.packets_to_send_tx.send(message).unwrap();
|
||||
});
|
||||
};
|
||||
|
||||
($hashmap:ident, $notify:ident, $handler:ident) => {
|
||||
$hashmap.insert(proto::PacketId::$notify, |slef: &mut Self, user_id: u32, metadata: &proto::PacketHead, data: Vec<u8>| {
|
||||
let notify = proto::$req::decode(&mut std::io::Cursor::new(data)).unwrap();
|
||||
println!("Received NOTIFY {:?}", notify);
|
||||
|
||||
slef.$handler(user_id, &metadata, ¬ify);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
14
src/main.rs
14
src/main.rs
@ -1,3 +1,5 @@
|
||||
extern crate pretty_env_logger;
|
||||
|
||||
#[macro_use]
|
||||
extern crate num_derive;
|
||||
|
||||
@ -6,19 +8,15 @@ use std::thread;
|
||||
mod server;
|
||||
mod utils;
|
||||
|
||||
pub mod proto {
|
||||
include!(concat!(env!("OUT_DIR"), "/proto.rs"));
|
||||
include!(concat!("..", "/gen", "/packet_id.rs"));
|
||||
include!(concat!("..", "/gen", "/player_prop.rs"));
|
||||
include!(concat!("..", "/gen", "/open_state.rs"));
|
||||
}
|
||||
|
||||
use server::NetworkServer;
|
||||
use server::DispatchServer;
|
||||
|
||||
fn main() {
|
||||
pretty_env_logger::init();
|
||||
|
||||
thread::spawn(|| {
|
||||
let mut ds = DispatchServer::new("127.0.0.1", 9696);
|
||||
//let mut ds = DispatchServer::new("127.0.0.1", 9696);
|
||||
let mut ds = DispatchServer::new();
|
||||
ds.run();
|
||||
});
|
||||
|
||||
|
@ -1,20 +1,67 @@
|
||||
use std::sync::mpsc;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use prost::Message;
|
||||
|
||||
use crate::server::IpcMessage;
|
||||
|
||||
use packet_processor_macro::*;
|
||||
#[macro_use]
|
||||
use packet_processor::*;
|
||||
|
||||
#[packet_processor(GetPlayerTokenReq)]
|
||||
pub struct AuthManager {
|
||||
conv_to_user: HashMap<u32, u32>,
|
||||
user_to_conv: HashMap<u32, u32>,
|
||||
packets_to_send_tx: mpsc::Sender<IpcMessage>,
|
||||
}
|
||||
|
||||
impl AuthManager {
|
||||
const SPOOFED_PLAYER_UID: u32 = 1337;
|
||||
|
||||
pub fn new(packets_to_send_tx: mpsc::Sender<IpcMessage>) -> AuthManager {
|
||||
let am = AuthManager {
|
||||
let mut am = AuthManager {
|
||||
conv_to_user: HashMap::new(),
|
||||
user_to_conv: HashMap::new(),
|
||||
packet_callbacks: HashMap::new(),
|
||||
packets_to_send_tx: packets_to_send_tx,
|
||||
};
|
||||
|
||||
am.register();
|
||||
|
||||
return am;
|
||||
}
|
||||
|
||||
pub fn process_packet(&mut self, conv: u32, packet_id: u16, metadata: Vec<u8>, data: Vec<u8>) {
|
||||
pub fn process_get_player_token(&mut self, conv: u32, metadata: &proto::PacketHead, req: &proto::GetPlayerTokenReq, rsp: &mut proto::GetPlayerTokenRsp) {
|
||||
let seed: u64 = 0x123456789ABCDEF0; // TODO: use real value!
|
||||
let uid = self.get_uid_by_account_id(req.account_uid.parse().unwrap());
|
||||
|
||||
rsp.account_type = req.account_type;
|
||||
rsp.account_uid = req.account_uid.clone();
|
||||
rsp.token = format!("token-game-{}", req.account_uid);
|
||||
rsp.secret_key_seed = seed;
|
||||
rsp.uid = uid;
|
||||
|
||||
self.conv_to_user.insert(conv, uid);
|
||||
self.user_to_conv.insert(uid, conv);
|
||||
}
|
||||
|
||||
fn get_uid_by_account_id(&self, account_uid: u32) -> u32 {
|
||||
// TODO!
|
||||
return AuthManager::SPOOFED_PLAYER_UID;
|
||||
}
|
||||
|
||||
pub fn resolve_conv(&self, conv: u32) -> Option<u32> {
|
||||
match self.conv_to_user.get(&conv) {
|
||||
Some(uid) => return Some(*uid),
|
||||
None => return None,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn resolve_uid(&self, uid: u32) -> Option<u32> {
|
||||
match self.user_to_conv.get(&uid) {
|
||||
Some(conv) => return Some(*conv),
|
||||
None => return None,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -76,6 +76,12 @@ impl ClientConnection {
|
||||
match self.ikcp.recv(&mut buf) {
|
||||
Err(_) => break,
|
||||
Ok(size) => {
|
||||
#[cfg(feature = "raw_packet_dump")]
|
||||
{
|
||||
use pretty_hex::*;
|
||||
let cfg = HexConfig {title: true, width: 16, group: 0, ascii: true, ..HexConfig::default() };
|
||||
println!("{:?}", buf[..size].to_vec().hex_conf(cfg));
|
||||
}
|
||||
mhycrypt::mhy_xor(&mut buf[..size], &self.key);
|
||||
let data = buf[..size].to_owned();
|
||||
packets.push(data);
|
||||
|
@ -3,104 +3,126 @@ use std::net::TcpListener;
|
||||
use std::net::TcpStream;
|
||||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
use std::sync::Arc;
|
||||
|
||||
extern crate futures;
|
||||
extern crate base64;
|
||||
extern crate actix_web;
|
||||
extern crate openssl;
|
||||
|
||||
use serde::{Deserialize,Serialize};
|
||||
use futures::executor;
|
||||
|
||||
use actix_web::{rt::System, web, get, App, HttpRequest, HttpResponse, HttpServer, Responder, middleware::Logger};
|
||||
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod, SslVerifyMode, SslOptions, SslMode};
|
||||
|
||||
use prost::Message;
|
||||
extern crate base64;
|
||||
|
||||
use crate::proto;
|
||||
use mhycrypt;
|
||||
|
||||
type RequestCallback = fn(slef: &DispatchServer, args: Vec<(&str, &str)>) -> (String, String);
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DispatchServer {
|
||||
listener: TcpListener,
|
||||
callbacks: HashMap<String, RequestCallback>,
|
||||
ip: String,
|
||||
port: u16,
|
||||
}
|
||||
|
||||
#[derive(Deserialize,Debug)]
|
||||
struct ClientInfo {
|
||||
version: String,
|
||||
lang: i32,
|
||||
platform: i32,
|
||||
binary: i32,
|
||||
time: i32,
|
||||
channel_id: i32,
|
||||
sub_channel_id: i32,
|
||||
account_type: Option<i32>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize,Debug)]
|
||||
struct TokenToVerify
|
||||
{
|
||||
uid: String,
|
||||
token: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize,Debug)]
|
||||
struct ActionToCheck
|
||||
{
|
||||
action_type: String,
|
||||
api_name: String,
|
||||
username: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize,Debug)]
|
||||
struct LoginData {
|
||||
account: String,
|
||||
is_crypto: bool,
|
||||
password: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize,Debug)]
|
||||
struct GranterData {
|
||||
app_id: String,
|
||||
channel_id: String,
|
||||
device: String,
|
||||
sign: String,
|
||||
data: String,
|
||||
}
|
||||
|
||||
impl DispatchServer {
|
||||
pub fn new(ip: &str, port: u16) -> DispatchServer {
|
||||
let mut callbacks = HashMap::new();
|
||||
|
||||
let mut ds = DispatchServer {
|
||||
listener: TcpListener::bind(format!("{}:{}", ip, port)).unwrap(),
|
||||
callbacks: callbacks,
|
||||
ip: ip.to_string(),
|
||||
port: port,
|
||||
};
|
||||
|
||||
ds.callbacks.insert("/query_region_list".to_string(), DispatchServer::query_region_list);
|
||||
ds.callbacks.insert("/query_cur_region".to_string(), DispatchServer::query_cur_region);
|
||||
ds.callbacks.insert("/account/risky/api/check".to_string(), DispatchServer::risky_api_check);
|
||||
ds.callbacks.insert("/hk4e_global/mdk/shield/api/login".to_string(), DispatchServer::risky_api_check);
|
||||
ds.callbacks.insert("/hk4e_global/combo/granter/login/v2/login".to_string(), DispatchServer::granter_login);
|
||||
ds.callbacks.insert("/hk4e_global/mdk/shield/api/verify".to_string(), DispatchServer::shield_verify);
|
||||
pub fn new() -> DispatchServer {
|
||||
let ds = DispatchServer { };
|
||||
|
||||
return ds;
|
||||
}
|
||||
|
||||
pub fn run(&self) {
|
||||
for stream in self.listener.incoming() {
|
||||
let stream = stream.unwrap();
|
||||
|
||||
self.handle_connection(stream);
|
||||
}
|
||||
pub fn run(self) {
|
||||
let mut sys = System::new("http-server");
|
||||
let slef = Arc::new(self);
|
||||
executor::block_on(slef.run_internal());
|
||||
System::current().stop();
|
||||
println!("Finished!");
|
||||
}
|
||||
|
||||
fn handle_connection(&self, mut stream: TcpStream) {
|
||||
let mut buffer = [0; 1024];
|
||||
async fn run_internal(self: &Arc<Self>) {
|
||||
//let (http_port, https_port) = (2880, 2443);
|
||||
let (http_port, https_port) = (80, 443);
|
||||
|
||||
stream.read(&mut buffer).unwrap();
|
||||
let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls_server()).unwrap();
|
||||
builder.set_verify(SslVerifyMode::NONE);
|
||||
builder.set_min_proto_version(None).unwrap();
|
||||
builder.set_cipher_list("DEFAULT").unwrap();
|
||||
builder.set_mode(SslMode::NO_AUTO_CHAIN | SslMode::SEND_FALLBACK_SCSV);
|
||||
builder.set_private_key_file("keys/ssl.key", SslFiletype::PEM).unwrap();
|
||||
builder.set_certificate_chain_file("keys/ssl.cer").unwrap();
|
||||
|
||||
let buffer = String::from_utf8_lossy(&buffer);
|
||||
let http_server = HttpServer::new(move || {
|
||||
App::new()
|
||||
.wrap(Logger::default())
|
||||
.route("/", web::get().to(|| HttpResponse::Ok()))
|
||||
.route("/query_region_list", web::get().to(DispatchServer::query_region_list))
|
||||
.route("/query_cur_region", web::get().to(DispatchServer::query_cur_region))
|
||||
//.route("", web::post().to(DispatchServer::))
|
||||
.route("/hk4e_global/mdk/shield/api/verify", web::post().to(DispatchServer::shield_verify))
|
||||
.route("/account/risky/api/check", web::post().to(DispatchServer::risky_api_check))
|
||||
.route("/hk4e_global/mdk/shield/api/login", web::post().to(DispatchServer::shield_login))
|
||||
.route("/hk4e_global/combo/granter/login/v2/login", web::post().to(DispatchServer::granter_login))
|
||||
})
|
||||
.bind(format!("127.0.0.1:{}", http_port)).expect("Failed to bind HTTP port")
|
||||
.bind_openssl(format!("127.0.0.1:{}", https_port), builder).expect("Failed to bind HTTPS port")
|
||||
.run();
|
||||
|
||||
let data = buffer.split_whitespace().collect::<Vec<_>>();
|
||||
let method = data[0];
|
||||
let url = data[1];
|
||||
|
||||
println!("Access to '{}' using {}", url, method);
|
||||
|
||||
let (status_code, contents) = match method {
|
||||
"GET" | "POST" => {
|
||||
let parts = url.split('?').collect::<Vec<_>>();
|
||||
let uri = parts[0];
|
||||
let params = if parts.len() > 1 { parts[1].split('&').collect::<Vec<_>>() } else { Vec::new() };
|
||||
let params = params.into_iter().map(|x| x.split('=').collect::<Vec<_>>()).filter(|x| x.len() > 1).map(|x| (x[0], x[1])).collect();
|
||||
|
||||
match self.callbacks.get(uri) {
|
||||
Some(callback) => callback(&self, params),
|
||||
None => ("404 Not Found".into(), "Nothing here".into()),
|
||||
}
|
||||
},
|
||||
_ => ("400 Bad Request".into(), "You are stupid".into()),
|
||||
};
|
||||
|
||||
//let contents = fs::read_to_string(filename).unwrap();
|
||||
|
||||
let status_line = format!("HTTP/1.1 {}", status_code);
|
||||
|
||||
let response = format!(
|
||||
"{}\r\nContent-Length: {}\r\n\r\n{}",
|
||||
status_line,
|
||||
contents.len(),
|
||||
contents
|
||||
);
|
||||
|
||||
stream.write(response.as_bytes()).unwrap();
|
||||
stream.flush().unwrap();
|
||||
http_server.stop(true).await;
|
||||
}
|
||||
|
||||
fn query_region_list(&self, args: Vec<(&str, &str)>) -> (String, String) {
|
||||
println!("Args: {:?}", args);
|
||||
async fn query_region_list(c: web::Query<ClientInfo>) -> String {
|
||||
println!("Client: {:?}", c);
|
||||
|
||||
let keys = self.load_keys("master");
|
||||
let keys = DispatchServer::load_keys("master");
|
||||
|
||||
let mut region_info = proto::RegionSimpleInfo::default();
|
||||
region_info.name = "private_server".into();
|
||||
region_info.title = "Private Server".into();
|
||||
region_info.r#type = "DEV_PUBLIC".into();
|
||||
region_info.dispatch_url = format!("http://localhost:{}/query_cur_region", self.port);
|
||||
region_info.dispatch_url = format!("http://localhost:{}/query_cur_region", 80);
|
||||
|
||||
let mut region_list = proto::QueryRegionListHttpRsp::default();
|
||||
region_list.region_list = vec![region_info];
|
||||
@ -120,13 +142,13 @@ impl DispatchServer {
|
||||
|
||||
region_list.encode(&mut region_list_buf).unwrap();
|
||||
|
||||
return ("200 OK".into(), base64::encode(region_list_buf));
|
||||
return base64::encode(region_list_buf);
|
||||
}
|
||||
|
||||
fn query_cur_region(&self, args: Vec<(&str, &str)>) -> (String, String) {
|
||||
println!("Args: {:?}", args);
|
||||
async fn query_cur_region(c: web::Query<ClientInfo>) -> String {
|
||||
println!("Client: {:?}", c);
|
||||
|
||||
let keys = self.load_keys("master");
|
||||
let keys = DispatchServer::load_keys("master");
|
||||
|
||||
let mut region_info = proto::RegionInfo::default();
|
||||
region_info.gateserver_ip = "127.0.0.1".to_string();
|
||||
@ -138,7 +160,7 @@ impl DispatchServer {
|
||||
region_config.client_secret_key = keys.0.clone();
|
||||
|
||||
let json_config = format!("{{\"coverSwitch\": [\"8\"], \"perf_report_config_url\": \"http://localhost:{}/config/verify\", \"perf_report_record_url\": \"http://localhost:{}/dataUpload\" }}",
|
||||
self.port, self.port);
|
||||
80, 80);
|
||||
|
||||
let mut custom_config = json_config.as_bytes().to_owned();
|
||||
|
||||
@ -150,38 +172,57 @@ impl DispatchServer {
|
||||
|
||||
region_config.encode(&mut region_conf_buf).unwrap();
|
||||
|
||||
return ("200 OK".into(), base64::encode(region_conf_buf));
|
||||
return base64::encode(region_conf_buf);
|
||||
}
|
||||
|
||||
fn risky_api_check(&self, args: Vec<(&str, &str)>) -> (String, String) {
|
||||
async fn risky_api_check(a: web::Json<ActionToCheck>) -> String {
|
||||
println!("Action: {:?}", a);
|
||||
|
||||
let email = "ceo@hoyolab.com";
|
||||
let name = "Ceo";
|
||||
let token = "Fake-token-hahaha";
|
||||
let uid = 0x1234;
|
||||
|
||||
let payload = self.build_account_data(email, name, token, uid);
|
||||
let payload = DispatchServer::build_account_data(email, name, token, uid);
|
||||
|
||||
return ("200 OK".into(), self.make_answer(0, &payload));
|
||||
return DispatchServer::make_answer(0, &payload);
|
||||
}
|
||||
|
||||
fn granter_login(&self, args: Vec<(&str, &str)>) -> (String, String) {
|
||||
let payload = self.verify_token_v2();
|
||||
async fn shield_login(l: web::Json<LoginData>) -> String {
|
||||
println!("Login: {:?}", l);
|
||||
|
||||
return ("200 OK".into(), self.make_answer(0, &payload));
|
||||
}
|
||||
|
||||
fn shield_verify(&self, args: Vec<(&str, &str)>) -> (String, String) {
|
||||
let email = "ceo@hoyolab.com";
|
||||
let name = "Ceo";
|
||||
let token = "Fake-token-hahaha";
|
||||
let uid = 0x1234;
|
||||
|
||||
let payload = self.build_account_data(email, name, token, uid);
|
||||
let payload = DispatchServer::build_account_data(email, name, token, uid);
|
||||
|
||||
return ("200 OK".into(), self.make_answer(0, &payload));
|
||||
return DispatchServer::make_answer(0, &payload);
|
||||
}
|
||||
|
||||
fn load_keys(&self, name: &str) -> (Vec<u8>, Vec<u8>) {
|
||||
async fn granter_login(g: web::Json<GranterData>) -> String {
|
||||
println!("Granter: {:?}", g);
|
||||
|
||||
let payload = DispatchServer::verify_token_v2();
|
||||
|
||||
return DispatchServer::make_answer(0, &payload);
|
||||
}
|
||||
|
||||
async fn shield_verify(t: web::Json<TokenToVerify>) -> String {
|
||||
println!("Token: {:?}", t);
|
||||
|
||||
let email = "ceo@hoyolab.com";
|
||||
let name = "Ceo";
|
||||
let token = "Fake-token-hahaha";
|
||||
let uid = t.uid.parse().unwrap();
|
||||
|
||||
let payload = DispatchServer::build_account_data(email, name, token, uid);
|
||||
|
||||
return DispatchServer::make_answer(0, &payload);
|
||||
}
|
||||
|
||||
fn load_keys(name: &str) -> (Vec<u8>, Vec<u8>) {
|
||||
// Key
|
||||
let filename = format!("./{}/{}.key", "keys", name);
|
||||
let mut f = fs::File::open(&filename).expect(&format!("File '{}' not found", filename));
|
||||
@ -197,12 +238,16 @@ impl DispatchServer {
|
||||
return (ec2b, key);
|
||||
}
|
||||
|
||||
fn verify_token_v2(&self) -> String {
|
||||
fn verify_token_v2() -> String {
|
||||
let account_type = 1;
|
||||
let combo_id = 0x4321;
|
||||
let combo_token = "Fake-token-hehehe";
|
||||
let open_id = 0x1234;
|
||||
|
||||
#[cfg(not(feature = "raw_packet_dump"))]
|
||||
let combo_token = "Fake-token-hehehe";
|
||||
#[cfg(feature = "raw_packet_dump")]
|
||||
let combo_token = std::str::from_utf8(&[32u8; 4096*3]).unwrap();
|
||||
|
||||
return format!("{{
|
||||
\"account_type\": \"{}\",
|
||||
\"combo_id\": \"{}\",
|
||||
@ -213,7 +258,7 @@ impl DispatchServer {
|
||||
}}", account_type, combo_id, combo_token, open_id);
|
||||
}
|
||||
|
||||
fn build_account_data(&self, email: &str, name: &str, token: &str, uid: i32) -> String {
|
||||
fn build_account_data(email: &str, name: &str, token: &str, uid: i32) -> String {
|
||||
let payload = format!("{{
|
||||
\"account\": {{
|
||||
\"apple_name\": \"\",
|
||||
@ -242,7 +287,7 @@ impl DispatchServer {
|
||||
return payload.into();
|
||||
}
|
||||
|
||||
fn make_answer(&self, code: i32, data: &str) -> String {
|
||||
fn make_answer(code: i32, data: &str) -> String {
|
||||
let message = match code {
|
||||
0 => "OK",
|
||||
-1 => "not matched",
|
||||
|
@ -4,6 +4,7 @@ use std::collections::HashMap;
|
||||
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
||||
|
||||
use crate::server::GameWorld;
|
||||
use packet_processor::PacketProcessor;
|
||||
use crate::server::IpcMessage;
|
||||
|
||||
pub struct GameServer {
|
||||
@ -27,15 +28,15 @@ impl GameServer {
|
||||
let world_processor = thread::spawn(move || {
|
||||
println!("Starting world processor");
|
||||
// TODO: Load worlds!
|
||||
loop {
|
||||
}
|
||||
//loop {
|
||||
//}
|
||||
});
|
||||
|
||||
loop {
|
||||
let IpcMessage(conv, packet_id, metadata, data) = self.packets_to_process_rx.recv().unwrap();
|
||||
let IpcMessage(user_id, packet_id, metadata, data) = self.packets_to_process_rx.recv().unwrap();
|
||||
|
||||
// TODO: each conv will have a distinct world!
|
||||
let world = match self.worlds.entry(conv) {
|
||||
// TODO: each user_id will have a distinct world!
|
||||
let world = match self.worlds.entry(user_id) {
|
||||
Occupied(world) => world.into_mut(),
|
||||
Vacant(entry) => {
|
||||
let mut world = GameWorld::new(self.packets_to_send_tx.clone());
|
||||
@ -43,7 +44,7 @@ impl GameServer {
|
||||
},
|
||||
};
|
||||
|
||||
world.process_packet(conv, packet_id, metadata, data);
|
||||
world.process(user_id, packet_id, metadata, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,12 +1,9 @@
|
||||
use crate::proto;
|
||||
|
||||
use prost;
|
||||
use prost::Message;
|
||||
|
||||
pub struct IpcMessage(pub u32, pub proto::PacketId, pub Vec<u8>, pub Vec<u8>);
|
||||
|
||||
impl IpcMessage {
|
||||
pub fn new_from_proto<M: prost::Message>(conv: u32, packet_id: proto::PacketId, metadata: &proto::PacketHead, data: &M) -> IpcMessage {
|
||||
pub fn new_from_proto<M: prost::Message>(user_id: u32, packet_id: proto::PacketId, metadata: &proto::PacketHead, data: &M) -> IpcMessage {
|
||||
println!("Replying with {:?}", packet_id);
|
||||
println!("Data: {:?}", data);
|
||||
|
||||
@ -19,7 +16,7 @@ impl IpcMessage {
|
||||
metadata.encode(&mut metabuf).unwrap();
|
||||
|
||||
return IpcMessage(
|
||||
conv,
|
||||
user_id,
|
||||
packet_id,
|
||||
metabuf,
|
||||
buf
|
||||
|
@ -16,21 +16,25 @@ use crate::utils::HandshakePacket;
|
||||
use crate::utils::DataPacket;
|
||||
use crate::server::ClientConnection;
|
||||
use crate::server::GameServer;
|
||||
use crate::server::AuthManager;
|
||||
|
||||
use crate::server::IpcMessage;
|
||||
|
||||
use crate::proto;
|
||||
use crate::proto::PacketHead;
|
||||
use crate::proto::GetPlayerTokenRsp;
|
||||
use crate::proto::get_player_token_rsp;
|
||||
use proto::PacketHead;
|
||||
use proto::GetPlayerTokenRsp;
|
||||
use proto::get_player_token_rsp;
|
||||
|
||||
use prost::Message;
|
||||
|
||||
use packet_processor::PacketProcessor;
|
||||
|
||||
extern crate kcp;
|
||||
|
||||
pub struct NetworkServer {
|
||||
socket: UdpSocket,
|
||||
clients: Arc<Mutex<HashMap<u32,ClientConnection>>>,
|
||||
packets_to_process_tx: Option<mpsc::Sender<IpcMessage>>,
|
||||
packets_to_send_tx: Option<mpsc::Sender<IpcMessage>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -59,6 +63,7 @@ impl NetworkServer {
|
||||
},
|
||||
clients: Arc::new(Mutex::new(HashMap::new())),
|
||||
packets_to_process_tx: None,
|
||||
packets_to_send_tx: None,
|
||||
};
|
||||
|
||||
print!("Connection established\n");
|
||||
@ -76,12 +81,20 @@ impl NetworkServer {
|
||||
let (packets_to_send_tx, packets_to_send_rx) = mpsc::channel();
|
||||
|
||||
self.packets_to_process_tx = Some(packets_to_process_tx);
|
||||
self.packets_to_send_tx = Some(packets_to_send_tx.clone()); // TODO: hack!
|
||||
|
||||
let clients = self.clients.clone();
|
||||
let mut auth_manager = Arc::new(Mutex::new(AuthManager::new(packets_to_send_tx.clone())));
|
||||
let am = auth_manager.clone();
|
||||
|
||||
let packet_relaying_thread = thread::spawn(move || {
|
||||
loop {
|
||||
let IpcMessage(conv, packet_id, metadata, data) = packets_to_send_rx.recv().unwrap();
|
||||
let IpcMessage(user_id, packet_id, metadata, data) = packets_to_send_rx.recv().unwrap();
|
||||
|
||||
let conv = match packet_id {
|
||||
proto::PacketId::GetPlayerTokenRsp => user_id, // Mapping is not performed on those
|
||||
_ => am.lock().unwrap().resolve_uid(user_id).unwrap_or_else(|| panic!("Unknown user ID {}!", user_id)),
|
||||
};
|
||||
|
||||
let data_packet = DataPacket::new(packet_id.clone() as u16, metadata, data.clone());
|
||||
|
||||
@ -110,7 +123,7 @@ impl NetworkServer {
|
||||
|
||||
loop {
|
||||
match self.socket.recv_from(&mut buffer) {
|
||||
Ok( (bytes_number, source_address) ) => self.process_udp_packet(source_address, &buffer[..bytes_number]),
|
||||
Ok( (bytes_number, source_address) ) => self.process_udp_packet(source_address, &buffer[..bytes_number], &mut auth_manager),
|
||||
Err(e) => panic!("Failed to receive data: {}", e),
|
||||
}
|
||||
}
|
||||
@ -120,16 +133,16 @@ impl NetworkServer {
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
fn process_udp_packet(&mut self, source_address: SocketAddr, packet_bytes: &[u8]) {
|
||||
print!("Received packet! Len = {}\n", packet_bytes.len());
|
||||
fn process_udp_packet(&mut self, source_address: SocketAddr, packet_bytes: &[u8], auth_manager: &mut Arc<Mutex<AuthManager>>) {
|
||||
//print!("Received packet! Len = {}\n", packet_bytes.len());
|
||||
|
||||
let hs_packet = HandshakePacket::new(packet_bytes);
|
||||
|
||||
match hs_packet {
|
||||
Ok(hs_packet) => {
|
||||
print!("Received handshake packet: {:#?}\n", hs_packet);
|
||||
//print!("Received handshake packet: {:#?}\n", hs_packet);
|
||||
if hs_packet.is_connect() {
|
||||
print!("Sending reply to CONNECT\n");
|
||||
//print!("Sending reply to CONNECT\n");
|
||||
// TODO: assign conv and token!
|
||||
let conv = 0x96969696u32;
|
||||
let token = 0x42424242u32;
|
||||
@ -158,13 +171,13 @@ impl NetworkServer {
|
||||
};
|
||||
|
||||
for packet in packets.iter() {
|
||||
self.process_game_packet(conv, packet);
|
||||
self.process_game_packet(conv, packet, auth_manager);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn process_game_packet(&mut self, conv: u32, packet: &[u8]) {
|
||||
fn process_game_packet(&mut self, conv: u32, packet: &[u8], auth_manager: &mut Arc<Mutex<AuthManager>>) {
|
||||
let data = match DataPacket::new_from_bytes(packet) {
|
||||
Ok(data) => data,
|
||||
Err(e) => panic!("Malformed data packet: {:#?}!", e),
|
||||
@ -183,13 +196,46 @@ impl NetworkServer {
|
||||
}
|
||||
};
|
||||
|
||||
println!("Got packet {:?}", packet_id);
|
||||
let user_id = match packet_id {
|
||||
proto::PacketId::GetPlayerTokenReq => {
|
||||
auth_manager.lock().unwrap().process(conv, packet_id, data.metadata, data.data);
|
||||
return;
|
||||
},
|
||||
_ => match auth_manager.lock().unwrap().resolve_conv(conv) {
|
||||
None => {
|
||||
println!("Unknown user with conv {}! Skipping", conv);
|
||||
return;
|
||||
},
|
||||
Some(user_id) => user_id,
|
||||
},
|
||||
};
|
||||
|
||||
if packet_id == proto::PacketId::UnionCmdNotify {
|
||||
let union = proto::UnionCmdNotify::decode(&mut Cursor::new(&data.data)).unwrap();
|
||||
for u_cmd in union.cmd_list.into_iter() {
|
||||
self.send_packet_to_process(user_id, u_cmd.message_id as u16, &data.metadata, &u_cmd.body);
|
||||
}
|
||||
} else {
|
||||
self.send_packet_to_process(user_id, data.packet_id, &data.metadata, &data.data);
|
||||
}
|
||||
}
|
||||
|
||||
fn send_packet_to_process(&mut self, user_id: u32, packet_id: u16, metadata: &[u8], data: &[u8])
|
||||
{
|
||||
let sender = match &self.packets_to_process_tx {
|
||||
Some(sender) => sender,
|
||||
None => panic!("Processing queue wasn't set up!"),
|
||||
};
|
||||
|
||||
sender.send( IpcMessage(conv, packet_id, data.metadata, data.data) ).unwrap();
|
||||
let packet_id: proto::PacketId = match FromPrimitive::from_u16(packet_id) {
|
||||
Some(packet_id) => packet_id,
|
||||
None => {
|
||||
println!("Skipping unknown packet ID {}", packet_id);
|
||||
return;
|
||||
},
|
||||
};
|
||||
|
||||
println!("Got packet {:?}", packet_id);
|
||||
sender.send( IpcMessage(user_id, packet_id, metadata.to_vec(), data.to_vec()) ).unwrap();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user