2.1.0 Protos

This commit is contained in:
xavo95 2025-01-22 02:51:30 +01:00
commit 82ec48a57c
Signed by: xavo95
GPG key ID: CBF8ADED6DEBB783
11 changed files with 24134 additions and 0 deletions

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
.idea
**/target
**/generated

495
Cargo.lock generated Normal file
View file

@ -0,0 +1,495 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
[[package]]
name = "anyhow"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
[[package]]
name = "bitflags"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "bytes"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "crc32fast"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
dependencies = [
"cfg-if",
]
[[package]]
name = "either"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "errno"
version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
dependencies = [
"libc",
"windows-sys",
]
[[package]]
name = "fastrand"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
[[package]]
name = "fixedbitset"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
[[package]]
name = "getrandom"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "hashbrown"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "indexmap"
version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652"
dependencies = [
"equivalent",
"hashbrown",
]
[[package]]
name = "itertools"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
[[package]]
name = "libc"
version = "0.2.169"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
[[package]]
name = "linux-raw-sys"
version = "0.4.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
[[package]]
name = "log"
version = "0.4.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "multimap"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03"
[[package]]
name = "once_cell"
version = "1.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
[[package]]
name = "petgraph"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db"
dependencies = [
"fixedbitset",
"indexmap",
]
[[package]]
name = "prettyplease"
version = "0.2.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6924ced06e1f7dfe3fa48d57b9f74f55d8915f5036121bef647ef4b204895fac"
dependencies = [
"proc-macro2",
"syn",
]
[[package]]
name = "proc-macro2"
version = "1.0.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
dependencies = [
"unicode-ident",
]
[[package]]
name = "prost"
version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c0fef6c4230e4ccf618a35c59d7ede15dea37de8427500f50aff708806e42ec"
dependencies = [
"bytes",
"prost-derive",
]
[[package]]
name = "prost-build"
version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0f3e5beed80eb580c68e2c600937ac2c4eedabdfd5ef1e5b7ea4f3fba84497b"
dependencies = [
"heck",
"itertools",
"log",
"multimap",
"once_cell",
"petgraph",
"prettyplease",
"prost",
"prost-types",
"regex",
"syn",
"tempfile",
]
[[package]]
name = "prost-derive"
version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "157c5a9d7ea5c2ed2d9fb8f495b64759f7816c7eaea54ba3978f0d63000162e3"
dependencies = [
"anyhow",
"itertools",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "prost-types"
version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc2f1e56baa61e93533aebc21af4d2134b70f66275e0fcdf3cbe43d77ff7e8fc"
dependencies = [
"prost",
]
[[package]]
name = "quote"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "rustix"
version = "0.38.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
dependencies = [
"bitflags",
"errno",
"libc",
"linux-raw-sys",
"windows-sys",
]
[[package]]
name = "ryu"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
[[package]]
name = "serde"
version = "1.0.217"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.217"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.137"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b"
dependencies = [
"itoa",
"memchr",
"ryu",
"serde",
]
[[package]]
name = "syn"
version = "2.0.96"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "tempfile"
version = "3.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704"
dependencies = [
"cfg-if",
"fastrand",
"getrandom",
"once_cell",
"rustix",
"windows-sys",
]
[[package]]
name = "thiserror"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "unicode-ident"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wicked-waifus-protocol"
version = "0.1.0"
dependencies = [
"byteorder",
"crc32fast",
"prettyplease",
"prost",
"prost-build",
"quote",
"serde",
"serde_json",
"syn",
"thiserror",
"wicked-waifus-protocol-derive",
]
[[package]]
name = "wicked-waifus-protocol-derive"
version = "0.1.0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"

10
Cargo.toml Normal file
View file

@ -0,0 +1,10 @@
[workspace]
members = ["wicked-waifus-protocol", "wicked-waifus-protocol-derive"]
resolver = "2"
[workspace.package]
edition = "2021"
version = "0.1.0"
[workspace.dependencies]
wicked-waifus-protocol-derive = { path = "wicked-waifus-protocol-derive" }

View file

@ -0,0 +1,12 @@
[package]
name = "wicked-waifus-protocol-derive"
edition.workspace = true
version.workspace = true
[dependencies]
syn = "2.0.53"
quote = "1.0.35"
proc-macro2 = "1.0.79"
[lib]
proc-macro = true

View file

@ -0,0 +1,27 @@
use proc_macro::TokenStream;
use quote::{quote, ToTokens};
use syn::{parse_macro_input, DeriveInput, Meta, MetaList};
#[proc_macro_derive(MessageID, attributes(message_id))]
pub fn message_id_derive(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let struct_name = input.ident;
let id = match input
.attrs
.iter()
.find(|attr| attr.path().is_ident("message_id"))
{
Some(attr) => match attr.meta {
Meta::List(MetaList { ref tokens, .. }) => tokens.into_token_stream(),
_ => panic!("Invalid message_id attribute value"),
},
_ => 0u16.into_token_stream(),
};
TokenStream::from(quote! {
impl crate::MessageID for #struct_name {
const MESSAGE_ID: u16 = #id;
}
})
}

View file

@ -0,0 +1,19 @@
[package]
name = "wicked-waifus-protocol"
edition.workspace = true
version.workspace = true
[dependencies]
byteorder = "1.5.0"
crc32fast = "1.4.2"
thiserror = "1.0.63"
prost = "0.13.2"
serde = { version = "1.0.209", features = ["derive"] }
serde_json = "1.0.128"
wicked-waifus-protocol-derive.workspace = true
[build-dependencies]
prost-build = "0.13.2"
quote = "1.0.35"
syn = "2.0.76"
prettyplease = "0.2.22"

View file

@ -0,0 +1,168 @@
use std::{
fs,
io::{self, BufRead},
path::Path,
};
use std::io::Write;
use quote::{format_ident, quote};
const CODEGEN_OUT_DIR: &str = "generated/";
pub fn main() {
let _ = fs::create_dir(CODEGEN_OUT_DIR);
let config_file = "proto/config.csv";
let config_path = Path::new("proto/config.csv");
if config_path.exists() {
println!("cargo:rerun-if-changed={config_file}");
impl_proto_config(config_path, Path::new("generated/proto_config.rs")).unwrap();
}
let proto_file = "proto/wicked-waifus.proto";
if Path::new(&proto_file).exists() {
println!("cargo:rerun-if-changed={proto_file}");
prost_build::Config::new()
.out_dir(CODEGEN_OUT_DIR)
.default_package_filename("wicked-waifus")
.type_attribute(".", "#[derive(wicked_waifus_protocol_derive::MessageID)]")
.type_attribute(".", "#[derive(serde::Serialize, serde::Deserialize)]")
.compile_protos(&[proto_file], &["wicked-waifus"])
.unwrap();
impl_dumper(Path::new("generated/wicked-waifus.rs")).unwrap();
impl_message_id(Path::new("generated/wicked-waifus.rs")).unwrap();
}
}
pub fn impl_proto_config(csv_path: &Path, codegen_path: &Path) -> io::Result<()> {
let file = fs::File::open(csv_path)?;
let reader = io::BufReader::new(file);
let mut match_arms = quote! {};
for line in reader.lines() {
let line = line?;
let mut row = line.split(',');
let message_id = row.next().unwrap().parse::<u16>().unwrap();
let flags = row.next().unwrap().parse::<u8>().unwrap();
match_arms = quote! {
#match_arms
#message_id => MessageFlags(#flags),
}
}
let generated_code = quote! {
pub mod proto_config {
#[derive(Clone, Copy)]
pub struct MessageFlags(u8);
impl MessageFlags {
pub fn value(self) -> u8 {
self.0
}
}
pub fn get_message_flags(id: u16) -> MessageFlags {
match id {
#match_arms
_ => MessageFlags(0),
}
}
}
};
let syntax_tree = syn::parse2(generated_code).unwrap();
let formatted = prettyplease::unparse(&syntax_tree);
fs::write(codegen_path, formatted.as_bytes())?;
Ok(())
}
pub fn impl_message_id(path: &Path) -> io::Result<()> {
let file = fs::File::open(path)?;
let reader = io::BufReader::new(file);
let mut output = Vec::new();
let mut attr = None;
for line in reader.lines() {
let line = line?;
if line.contains("MessageId:") {
attr = Some(make_message_id_attr(&line).unwrap());
} else {
output.push(line);
if let Some(attr) = attr.take() {
output.push(attr);
}
}
}
fs::write(path, output.join("\n").as_bytes())?;
Ok(())
}
fn make_message_id_attr(line: &str) -> Option<String> {
let id = line.trim_start().split(' ').nth(2)?.parse::<u16>().ok()?;
Some(format!("#[message_id({id})]"))
}
pub fn impl_dumper(codegen_path: &Path) -> io::Result<()> {
let file = fs::File::open(codegen_path)?;
let reader = io::BufReader::new(file);
let mut match_arms = quote! {};
let mut id = None;
for line in reader.lines() {
let line = line?;
if line.contains("MessageId:") {
id = Some(
line.trim_start().split(' ').nth(2).unwrap().parse::<u16>().ok().unwrap()
);
} else if line.contains("pub struct") {
if let Some(id) = id.take() {
let name = line.trim_start().split(' ').nth(2).unwrap().to_string();
let name_ident = format_ident!("{}", name);
match_arms = quote! {
#match_arms
#id => Ok((#name, serde_json::to_string_pretty(&#name_ident::decode(data)?)?)),
};
}
}
}
let generated_code = quote! {
pub mod proto_dumper {
use prost::Message;
use crate::*;
use crate::ai::*;
use crate::combat_message::*;
use crate::debug::*;
use crate::summon::*;
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("serde_json::Error: {0}")]
Json(#[from] serde_json::Error),
#[error("serde_json::Error: {0}")]
Decode(#[from] prost::DecodeError),
}
pub fn get_debug_info(id: u16, data: &[u8]) -> Result<(&str, String), Error> {
match id {
#match_arms
_ => Ok(("UnknownType", "".to_string())),
}
}
}
};
let syntax_tree = syn::parse2(generated_code).unwrap();
let formatted = prettyplease::unparse(&syntax_tree);
let mut file = fs::OpenOptions::new().append(true).open(codegen_path)?;
file.write(formatted.as_bytes())?;
Ok(())
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,34 @@
include!("../generated/proto_config.rs");
include!("../generated/wicked-waifus.rs");
pub mod message;
pub use prost::DecodeError as ProtobufDecodeError;
pub use prost::Message as Protobuf;
pub trait MessageID {
const MESSAGE_ID: u16;
fn get_message_id(&self) -> u16 {
Self::MESSAGE_ID
}
}
pub trait ProtocolUnit: Protobuf + MessageID {}
impl<T: Protobuf + MessageID> ProtocolUnit for T {}
#[derive(Debug, PartialEq)]
pub enum MessageRoute {
None,
Gateway,
GameServer,
}
impl From<proto_config::MessageFlags> for MessageRoute {
fn from(flags: proto_config::MessageFlags) -> Self {
match flags.value() & 3 {
0 => Self::Gateway,
2 => Self::GameServer,
_ => Self::None,
}
}
}

View file

@ -0,0 +1,198 @@
use byteorder::{ReadBytesExt, WriteBytesExt, LE};
use std::io::{self, Read, Write};
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("IO Error: {0}")]
Io(#[from] io::Error),
#[error("Invalid message type: {0}")]
InvalidMessageType(u8),
#[error("Checksum mismatch, received: {0}, calculated: {1}")]
InvalidChecksum(u32, u32),
}
#[derive(Debug)]
pub enum Message {
Request {
sequence_number: u32,
rpc_id: u16,
message_id: u16,
payload: Option<Box<[u8]>>,
},
Response {
sequence_number: u32,
rpc_id: u16,
message_id: u16,
payload: Option<Box<[u8]>>,
},
Push {
sequence_number: u32,
message_id: u16,
payload: Option<Box<[u8]>>,
},
}
impl Message {
const TYPE_REQUEST: u8 = 1;
const TYPE_RESPONSE: u8 = 2;
const TYPE_PUSH: u8 = 4;
pub fn encode(&self, out: &mut [u8]) -> io::Result<()> {
let mut w = io::Cursor::new(out);
let (sequence_number, message_id, payload) = match self {
Self::Request {
sequence_number,
message_id,
payload,
..
}
| Self::Response {
sequence_number,
message_id,
payload,
..
}
| Self::Push {
sequence_number,
message_id,
payload,
} => (sequence_number, message_id, payload),
};
w.write_u8(self.get_message_type())?;
w.write_u32::<LE>(*sequence_number)?;
match self {
Self::Request { rpc_id, .. } | Self::Response { rpc_id, .. } => {
w.write_u16::<LE>(*rpc_id)?
}
_ => (),
}
w.write_u16::<LE>(*message_id)?;
if let Some(payload) = payload.as_ref() {
w.write_u32::<LE>(crc32fast::hash(payload))?;
w.write_all(payload)?;
} else {
w.write_u32::<LE>(0)?;
}
Ok(())
}
pub fn decode(src: &[u8]) -> Result<Self, Error> {
let mut r = io::Cursor::new(src);
let message_type = r.read_u8()?;
let sequence_number = r.read_u32::<LE>()?;
let rpc_id = match message_type {
Self::TYPE_REQUEST | Self::TYPE_RESPONSE => r.read_u16::<LE>()?,
_ => 0,
};
let message_id = r.read_u16::<LE>()?;
let recv_crc = r.read_u32::<LE>()?;
let mut payload = vec![0u8; src.len() - r.position() as usize].into_boxed_slice();
let _ = r.read(&mut payload)?;
let calc_crc = crc32fast::hash(&payload);
(recv_crc == calc_crc)
.then_some(())
.ok_or(Error::InvalidChecksum(recv_crc, calc_crc))?;
let msg = match message_type {
Self::TYPE_REQUEST => Self::Request {
sequence_number,
rpc_id,
message_id,
payload: Some(payload),
},
Self::TYPE_RESPONSE => Self::Response {
sequence_number,
rpc_id,
message_id,
payload: Some(payload),
},
Self::TYPE_PUSH => Self::Push {
sequence_number,
message_id,
payload: Some(payload),
},
_ => return Err(Error::InvalidMessageType(message_type)),
};
Ok(msg)
}
pub fn get_encoding_length(&self) -> usize {
match self {
Self::Request { payload, .. } | Self::Response { payload, .. } => {
13 + payload.as_ref().map(|p| p.len()).unwrap_or_default()
}
Self::Push { payload, .. } => {
11 + payload.as_ref().map(|p| p.len()).unwrap_or_default()
}
}
}
pub fn get_message_type(&self) -> u8 {
match self {
Self::Request { .. } => Self::TYPE_REQUEST,
Self::Response { .. } => Self::TYPE_RESPONSE,
Self::Push { .. } => Self::TYPE_PUSH,
}
}
pub fn is_request(&self) -> bool {
matches!(self, Self::Request { .. })
}
pub fn is_push(&self) -> bool {
matches!(self, Self::Push { .. })
}
pub fn get_message_id(&self) -> u16 {
match self {
Self::Request { message_id, .. }
| Self::Response { message_id, .. }
| Self::Push { message_id, .. } => *message_id,
}
}
pub fn get_rpc_id(&self) -> u16 {
match self {
Self::Request { rpc_id, .. } | Self::Response { rpc_id, .. } => *rpc_id,
_ => 0,
}
}
pub fn remove_payload(&mut self) -> Box<[u8]> {
match self {
Self::Request { payload, .. }
| Self::Response { payload, .. }
| Self::Push { payload, .. } => payload.take().unwrap_or_else(|| Box::new([0u8; 0])),
}
}
pub fn set_payload(&mut self, new_payload: Box<[u8]>) {
match self {
Self::Request { payload, .. }
| Self::Response { payload, .. }
| Self::Push { payload, .. } => *payload = Some(new_payload),
}
}
pub fn get_sequence_number(&self) -> u32 {
match self {
Self::Request {
sequence_number, ..
}
| Self::Response {
sequence_number, ..
}
| Self::Push {
sequence_number, ..
} => *sequence_number,
}
}
}