feat: stuff happend
This commit is contained in:
parent
b8d2cd7b09
commit
fa37331780
11 changed files with 511 additions and 343 deletions
|
|
@ -1,10 +1,12 @@
|
||||||
|
mod protos;
|
||||||
|
|
||||||
extern crate proc_macro;
|
extern crate proc_macro;
|
||||||
|
|
||||||
use proc_macro2::{Ident, Literal, Span, TokenTree};
|
use proc_macro2::{Ident, Literal, Span, TokenTree};
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use syn::{parse_macro_input, DeriveInput, Data, PathSegment, TraitItem, FieldsNamed, Fields, Visibility, Type, TypePath, Path, ImplItem, ImplItemConst, Expr, ExprLit, Lit, TypeParamBound, TraitBound, TraitBoundModifier, LitInt, Token, FnArg, Receiver, PatType, Pat, TypeInfer, TypeReference, TraitItemFn, Signature, Block, Stmt, Local, LocalInit, LitStr, PathArguments};
|
use syn::{parse_macro_input, DeriveInput, Data, PathSegment, TraitItem, FieldsNamed, Fields, Visibility, Type, TypePath, Path, ImplItem, ImplItemConst, Expr, ExprLit, Lit, TypeParamBound, TraitBound, TraitBoundModifier, LitInt, Token, FnArg, Receiver, PatType, Pat, TypeInfer, TypeReference, TraitItemFn, Signature, Block, Stmt, Local, LocalInit, LitStr, PathArguments, ReturnType};
|
||||||
use quote::{quote, ToTokens, TokenStreamExt};
|
use quote::{quote, ToTokens, TokenStreamExt};
|
||||||
use syn::buffer::TokenBuffer;
|
use syn::buffer::TokenBuffer;
|
||||||
use syn::parse::{Parse, ParseBuffer, ParseStream};
|
use syn::parse::{Parse, ParseBuffer, ParseStream};
|
||||||
|
|
@ -12,6 +14,7 @@ use syn::punctuated::Punctuated;
|
||||||
use syn::spanned::Spanned;
|
use syn::spanned::Spanned;
|
||||||
use syn::token::Comma;
|
use syn::token::Comma;
|
||||||
use syn::Visibility::Public;
|
use syn::Visibility::Public;
|
||||||
|
use crate::protos::{ProtoMethodData, RmcProtocolData};
|
||||||
|
|
||||||
fn self_referece_type() -> Type {
|
fn self_referece_type() -> Type {
|
||||||
Type::Reference(
|
Type::Reference(
|
||||||
|
|
@ -90,9 +93,6 @@ fn single_ident_path(ident: Ident) -> Path{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Example of user-defined [derive mode macro][1]
|
|
||||||
///
|
|
||||||
/// [1]: https://doc.rust-lang.org/reference/procedural-macros.html#derive-mode-macros
|
|
||||||
#[proc_macro_derive(RmcSerialize, attributes(extends, rmc_struct))]
|
#[proc_macro_derive(RmcSerialize, attributes(extends, rmc_struct))]
|
||||||
pub fn rmc_serialize(input: TokenStream) -> TokenStream {
|
pub fn rmc_serialize(input: TokenStream) -> TokenStream {
|
||||||
let derive_input = parse_macro_input!(input as DeriveInput);
|
let derive_input = parse_macro_input!(input as DeriveInput);
|
||||||
|
|
@ -245,6 +245,30 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream {
|
||||||
tokens.into()
|
tokens.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Macro to automatically generate code to use a specific trait as an rmc protocol for calling to
|
||||||
|
/// remote objects or accepting incoming remote requests.
|
||||||
|
/// This is needed in order to be able to use this as part of an rmc server interface.
|
||||||
|
///
|
||||||
|
/// The protocol id which is needed to be specified is specified as a parameter to this attribute.
|
||||||
|
///
|
||||||
|
/// You will also need to assign each function inside the trait a method id by using the
|
||||||
|
/// [`macro@method_id`] attribute.
|
||||||
|
///
|
||||||
|
/// You can also specify to have the protocol to be non-returning by adding a second parameter to
|
||||||
|
/// the attribute which is just `NoReturn` e.g. ` #[rmc_proto(1, NoReturn)]`
|
||||||
|
///
|
||||||
|
/// Example
|
||||||
|
/// ```
|
||||||
|
/// // this rmc protocol has protocol id 1
|
||||||
|
/// use macros::rmc_proto;
|
||||||
|
///
|
||||||
|
/// #[rmc_proto(1)]
|
||||||
|
/// trait ExampleProtocol{
|
||||||
|
/// // this defines an rmc method with id 1
|
||||||
|
/// #[rmc_method(1)]
|
||||||
|
/// async fn hello_world_method(&self, name: String) -> Result<String, ErrorCode>;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn rmc_proto(attr: TokenStream, input: TokenStream) -> TokenStream{
|
pub fn rmc_proto(attr: TokenStream, input: TokenStream) -> TokenStream{
|
||||||
|
|
||||||
|
|
@ -259,263 +283,63 @@ pub fn rmc_proto(attr: TokenStream, input: TokenStream) -> TokenStream{
|
||||||
i.to_string() == "NoReturn"
|
i.to_string() == "NoReturn"
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let param_err_return = match no_return_data{
|
|
||||||
true => quote!{
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
false => quote!{
|
|
||||||
return Err(ErrorCode::Core_InvalidArgument);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut input = parse_macro_input!(input as syn::ItemTrait);
|
let mut input = parse_macro_input!(input as syn::ItemTrait);
|
||||||
|
|
||||||
let info_struct_ident = format!("Raw{}Info",input.ident.to_string());
|
// gigantic ass struct initializer (to summarize this gets all of the data)
|
||||||
let info_struct_ident = Ident::new(&info_struct_ident, input.ident.span());
|
let raw_data = RmcProtocolData{
|
||||||
|
has_returns: !no_return_data,
|
||||||
let raw_details_struct = syn::ItemStruct{
|
name: input.ident.clone(),
|
||||||
vis: Public(Default::default()),
|
id: proto_num,
|
||||||
struct_token: Default::default(),
|
methods: input
|
||||||
fields: Fields::Unit,
|
.items
|
||||||
semi_token: Some(Default::default()),
|
.iter()
|
||||||
ident: info_struct_ident.clone(),
|
.filter_map(|v| match v{ TraitItem::Fn(v) => Some(v), _ => None })
|
||||||
attrs: vec![],
|
.map(|func|{
|
||||||
generics: Default::default()
|
let Some(attr) = func.attrs.iter()
|
||||||
};
|
.find(|a| a.path().segments.last().is_some_and(|s| s.ident.to_string() == "method_id")) else {
|
||||||
|
panic!( "every function inside of an rmc protocol must have a method id");
|
||||||
let raw_details_impl_block = syn::ItemImpl{
|
|
||||||
impl_token: Default::default(),
|
|
||||||
generics: Default::default(),
|
|
||||||
attrs: vec![],
|
|
||||||
brace_token: Default::default(),
|
|
||||||
defaultness: None,
|
|
||||||
trait_: None,
|
|
||||||
self_ty: Box::new(Type::Path(TypePath{
|
|
||||||
qself: None,
|
|
||||||
path: Path{
|
|
||||||
segments: {
|
|
||||||
let mut punc = Punctuated::new();
|
|
||||||
punc.push(PathSegment::from(info_struct_ident));
|
|
||||||
punc
|
|
||||||
},
|
|
||||||
leading_colon: None,
|
|
||||||
}
|
|
||||||
})),
|
|
||||||
unsafety: None,
|
|
||||||
items: vec![
|
|
||||||
ImplItem::Const(
|
|
||||||
ImplItemConst{
|
|
||||||
defaultness: None,
|
|
||||||
semi_token: Default::default(),
|
|
||||||
attrs: vec![],
|
|
||||||
generics: Default::default(),
|
|
||||||
ident: Ident::new("PROTOCOL_ID", Span::call_site()),
|
|
||||||
vis: Public(Default::default()),
|
|
||||||
colon_token: Default::default(),
|
|
||||||
const_token: Default::default(),
|
|
||||||
eq_token: Default::default(),
|
|
||||||
expr: Expr::Lit(ExprLit{
|
|
||||||
attrs: vec![],
|
|
||||||
lit: Lit::Int(proto_num),
|
|
||||||
}),
|
|
||||||
ty: Type::Path(TypePath{
|
|
||||||
qself: None,
|
|
||||||
path: Path{
|
|
||||||
segments: {
|
|
||||||
let mut punc = Punctuated::new();
|
|
||||||
punc.push(PathSegment::from(Ident::new("u16", Span::call_site())));
|
|
||||||
punc
|
|
||||||
},
|
|
||||||
leading_colon: None,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
)
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut raw_trait = input.clone();
|
|
||||||
|
|
||||||
raw_trait.ident = Ident::new(&format!("Raw{}",raw_trait.ident.to_string()), raw_trait.ident.span());
|
|
||||||
raw_trait.colon_token = Some(Default::default());
|
|
||||||
raw_trait.supertraits = {
|
|
||||||
let mut punct = Punctuated::new();
|
|
||||||
punct.push(TypeParamBound::Trait(TraitBound{
|
|
||||||
path: single_ident_path(input.ident.clone()),
|
|
||||||
lifetimes: None,
|
|
||||||
modifier: TraitBoundModifier::None,
|
|
||||||
paren_token: None
|
|
||||||
}));
|
|
||||||
punct
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut functions: Vec<(LitInt, Ident)> = Vec::new();
|
|
||||||
|
|
||||||
let funcs = raw_trait.items.iter_mut().filter_map(|v| if let TraitItem::Fn(v) = v {Some(v)} else { None });
|
|
||||||
|
|
||||||
for func in funcs{
|
|
||||||
|
|
||||||
if matches!(func.default, Some(_)){
|
|
||||||
return syn::Error::new(func.default.span(), "rmc methods may not have bodies").to_compile_error().into();
|
|
||||||
}
|
|
||||||
|
|
||||||
let Some(attr) = func.attrs.iter()
|
|
||||||
.find(|a| a.path().segments.last().is_some_and(|s| s.ident.to_string() == "method_id")) else {
|
|
||||||
let span = func.sig.asyncness.span().join(func.semi_token.unwrap().span()).unwrap_or(func.sig.span());
|
|
||||||
return syn::Error::new(span, "every function inside of an rmc protocol must have a method id").to_compile_error().into();
|
|
||||||
};
|
|
||||||
|
|
||||||
let Ok(func_id): Result<LitInt, _> = attr.parse_args() else {
|
|
||||||
return syn::Error::new(Span::call_site(), "todo: put a propper error message here").to_compile_error().into();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
if !func.sig.inputs.first().is_some_and(|v| matches!(v, FnArg::Receiver(Receiver{
|
|
||||||
colon_token: None,
|
|
||||||
mutability: None,
|
|
||||||
reference: Some(_),
|
|
||||||
..
|
|
||||||
}))){
|
|
||||||
return syn::Error::new(func.sig.inputs.span(), "every protocol function must have a ` & self ` as its first parameter.").to_compile_error().into();
|
|
||||||
}
|
|
||||||
|
|
||||||
let old_ident = func.sig.ident.clone();
|
|
||||||
|
|
||||||
func.sig.ident = Ident::new(&format!("raw_{}", func.sig.ident), func.sig.ident.span());
|
|
||||||
|
|
||||||
let mut new_params: Punctuated<_,_> = Punctuated::new();
|
|
||||||
|
|
||||||
new_params.push_value(FnArg::Receiver(Receiver{
|
|
||||||
attrs: vec![],
|
|
||||||
mutability: None,
|
|
||||||
ty: Box::new(self_referece_type()),
|
|
||||||
colon_token: None,
|
|
||||||
self_token: Default::default(),
|
|
||||||
reference: Some((Default::default(), None))
|
|
||||||
}));
|
|
||||||
|
|
||||||
new_params.push_punct(Comma::default());
|
|
||||||
/*
|
|
||||||
new_params.push_value(FnArg::Typed(PatType{
|
|
||||||
attrs: vec![],
|
|
||||||
pat: Box::new(Pat::Verbatim(quote! { method_id })),
|
|
||||||
colon_token: Default::default(),
|
|
||||||
ty: Box::new(Type::Verbatim(quote!{u32}))
|
|
||||||
}));
|
|
||||||
|
|
||||||
new_params.push_punct(Comma::default());*/
|
|
||||||
|
|
||||||
new_params.push_value(FnArg::Typed(PatType{
|
|
||||||
attrs: vec![],
|
|
||||||
pat: Box::new(Pat::Verbatim(quote! {data})),
|
|
||||||
colon_token: Default::default(),
|
|
||||||
ty: Box::new(Type::Verbatim(quote!{::std::vec::Vec<u8>}))
|
|
||||||
}));
|
|
||||||
|
|
||||||
mem::swap(&mut new_params, &mut func.sig.inputs);
|
|
||||||
let old_params = new_params;
|
|
||||||
|
|
||||||
|
|
||||||
let mut inner_raw_tokens = quote!{
|
|
||||||
let mut cursor = ::std::io::Cursor::new(data);
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut call_params = quote!{};
|
|
||||||
|
|
||||||
|
|
||||||
for param in old_params.iter().skip(1).filter_map(|v| if let FnArg::Typed(t) = v {
|
|
||||||
Some(t)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}){
|
|
||||||
let param_name = &*param.pat;
|
|
||||||
let ty = &*param.ty;
|
|
||||||
|
|
||||||
inner_raw_tokens.append_all(quote!{
|
|
||||||
let Ok(#param_name) = <#ty as crate::rmc::structures::RmcSerialize>::deserialize(&mut cursor) else {
|
|
||||||
#param_err_return
|
|
||||||
};
|
};
|
||||||
});
|
|
||||||
|
|
||||||
call_params.append_all(quote!{#param_name ,})
|
let Ok(id): Result<LitInt, _> = attr.parse_args() else {
|
||||||
}
|
panic!("todo: put a propper error message here");
|
||||||
|
};
|
||||||
|
|
||||||
inner_raw_tokens.append_all(quote!{
|
let funcs = func
|
||||||
let retval = self.#old_ident(#call_params).await;
|
.sig
|
||||||
});
|
.inputs
|
||||||
|
.iter()
|
||||||
|
.skip(1)
|
||||||
|
.map(|f| {
|
||||||
|
let FnArg::Typed(t) = f else {
|
||||||
|
panic!("what");
|
||||||
|
};
|
||||||
|
let Pat::Ident(i) = &*t.pat else {
|
||||||
|
panic!("unable to handle non identifier patterns as parameter bindings");
|
||||||
|
};
|
||||||
|
|
||||||
if !no_return_data{
|
(i.ident.clone(), t.ty.as_ref().clone())
|
||||||
//let
|
}).collect();
|
||||||
|
|
||||||
//inner_raw_tokens.append_all()
|
ProtoMethodData{
|
||||||
}
|
id,
|
||||||
|
name: func.sig.ident.clone(),
|
||||||
|
parameters: funcs
|
||||||
let braced = quote! {
|
|
||||||
{
|
|
||||||
#inner_raw_tokens
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let braced = braced.into();
|
|
||||||
|
|
||||||
func.default = Some(
|
|
||||||
parse_macro_input!(braced as Block)
|
|
||||||
);
|
|
||||||
|
|
||||||
functions.push((func_id, func.sig.ident.clone()));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut inner_match = quote!{};
|
|
||||||
|
|
||||||
for toks in functions.iter().map(|(lit, ident)|{
|
|
||||||
quote! {
|
|
||||||
#lit => self.#ident(data).await,
|
|
||||||
}
|
|
||||||
}){
|
|
||||||
inner_match.append_all(toks);
|
|
||||||
}
|
|
||||||
|
|
||||||
if no_return_data{
|
|
||||||
inner_match.append_all(quote!{
|
|
||||||
_ => return
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
//
|
|
||||||
inner_match.append_all(quote!{
|
|
||||||
_ => return
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
raw_trait.items.push(
|
|
||||||
TraitItem::Verbatim(
|
|
||||||
quote!{
|
|
||||||
async fn rmc_call_proto(&self, method_id: u32, data: Vec<u8>){
|
|
||||||
match method_id{
|
|
||||||
#inner_match
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}).collect()
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
let regular_trait_name = &input.ident;
|
|
||||||
let raw_trait_name = &raw_trait.ident;
|
|
||||||
|
|
||||||
quote!{
|
quote!{
|
||||||
#input
|
#input
|
||||||
#raw_details_struct
|
#raw_data
|
||||||
#raw_details_impl_block
|
|
||||||
#raw_trait
|
|
||||||
|
|
||||||
impl<T: #regular_trait_name + crate::rmc::protocols::ImplementRemoteCalls> #raw_trait_name for T{}
|
|
||||||
}.into()
|
}.into()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Used to specify the method id of methods when making rmc protocols.
|
||||||
|
/// See [`macro@rmc_proto`] for further details.
|
||||||
|
///
|
||||||
|
/// Note: This attribute doesn't do anything by itself and just returns the thing it was attached to
|
||||||
|
/// unchanged.
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn method_id(_attr: TokenStream, input: TokenStream) -> TokenStream{
|
pub fn method_id(_attr: TokenStream, input: TokenStream) -> TokenStream{
|
||||||
// this attribute doesnt do anything by itself, see `rmc_proto`
|
// this attribute doesnt do anything by itself, see `rmc_proto`
|
||||||
|
|
@ -523,6 +347,7 @@ pub fn method_id(_attr: TokenStream, input: TokenStream) -> TokenStream{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn rmc_struct(attr: TokenStream, input: TokenStream) -> TokenStream{
|
pub fn rmc_struct(attr: TokenStream, input: TokenStream) -> TokenStream{
|
||||||
let mut type_data = parse_macro_input!(input as DeriveInput);
|
let mut type_data = parse_macro_input!(input as DeriveInput);
|
||||||
|
|
@ -542,8 +367,8 @@ pub fn rmc_struct(attr: TokenStream, input: TokenStream) -> TokenStream{
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::rmc::protocols::RmcCallable for #struct_name{
|
impl crate::rmc::protocols::RmcCallable for #struct_name{
|
||||||
async fn rmc_call(&self, protocol_id: u16, method_id: u32, rest: Vec<u8>){
|
async fn rmc_call(&self, remote_response_connection: &crate::prudp::socket::SendingConnection, protocol_id: u16, method_id: u32, call_id: u32, rest: Vec<u8>){
|
||||||
<Self as #ident>::rmc_call(self, protocol_id, method_id, rest).await;
|
<Self as #ident>::rmc_call(self, remote_response_connection, protocol_id, method_id, call_id, rest).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
173
macros/src/protos.rs
Normal file
173
macros/src/protos.rs
Normal file
|
|
@ -0,0 +1,173 @@
|
||||||
|
use proc_macro2::{Ident, Span, TokenStream, TokenTree};
|
||||||
|
use quote::{quote, ToTokens};
|
||||||
|
use syn::{LitInt, Token, Type};
|
||||||
|
use syn::token::{Brace, Paren, Semi};
|
||||||
|
|
||||||
|
pub struct ProtoMethodData{
|
||||||
|
pub id: LitInt,
|
||||||
|
pub name: Ident,
|
||||||
|
pub parameters: Vec<(Ident, Type)>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// This is a representation of the code generated by `rmc_proto` it serves to split the logic of
|
||||||
|
/// acquiring data from the actual generation to tidy up the process into first getting then
|
||||||
|
/// generating.
|
||||||
|
///
|
||||||
|
/// Use the [`ToTokens`] trait to generate the actual code.
|
||||||
|
pub struct RmcProtocolData{
|
||||||
|
pub has_returns: bool,
|
||||||
|
pub id: LitInt,
|
||||||
|
pub name: Ident,
|
||||||
|
pub methods: Vec<ProtoMethodData>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToTokens for RmcProtocolData{
|
||||||
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
|
let Self{
|
||||||
|
has_returns,
|
||||||
|
name,
|
||||||
|
id,
|
||||||
|
methods
|
||||||
|
} = self;
|
||||||
|
|
||||||
|
// this gives us the name which the identifier of the corresponding Raw trait
|
||||||
|
let raw_name = Ident::new(&format!("Raw{}", name), name.span());
|
||||||
|
|
||||||
|
|
||||||
|
// boilerplate tokens which all raw traits need
|
||||||
|
quote!{
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub trait #raw_name: #name
|
||||||
|
}.to_tokens(tokens);
|
||||||
|
|
||||||
|
// generate the body of the raw protocol trait
|
||||||
|
Brace::default().surround(tokens, |tokens|{
|
||||||
|
//generate each raw method
|
||||||
|
for method in methods{
|
||||||
|
let ProtoMethodData {
|
||||||
|
name,
|
||||||
|
parameters,
|
||||||
|
..
|
||||||
|
} = method;
|
||||||
|
|
||||||
|
let raw_name = Ident::new(&format!("raw_{}", name), name.span());
|
||||||
|
quote!{
|
||||||
|
async fn #raw_name
|
||||||
|
}.to_tokens(tokens);
|
||||||
|
|
||||||
|
Paren::default().surround(tokens, |tokens|{
|
||||||
|
quote!{ &self, data: ::std::vec::Vec<u8> }.to_tokens(tokens);
|
||||||
|
});
|
||||||
|
|
||||||
|
quote!{
|
||||||
|
-> ::core::result::Result<Vec<u8>, ErrorCode>
|
||||||
|
}.to_tokens(tokens);
|
||||||
|
|
||||||
|
Brace::default().surround(tokens, |tokens|{
|
||||||
|
quote! { let mut cursor = ::std::io::Cursor::new(data); }.to_tokens(tokens);
|
||||||
|
|
||||||
|
for (param_name, param_type) in parameters{
|
||||||
|
quote!{
|
||||||
|
let Ok(#param_name) =
|
||||||
|
<#param_type as crate::rmc::structures::RmcSerialize>::deserialize(
|
||||||
|
&mut cursor
|
||||||
|
) else {
|
||||||
|
return Err(ErrorCode::Core_InvalidArgument);
|
||||||
|
};
|
||||||
|
}.to_tokens(tokens)
|
||||||
|
}
|
||||||
|
|
||||||
|
quote!{
|
||||||
|
let retval = self.#name
|
||||||
|
}.to_tokens(tokens);
|
||||||
|
|
||||||
|
Paren::default().surround(tokens, |tokens|{
|
||||||
|
for (paren_name, _) in parameters{
|
||||||
|
quote!{#paren_name,}.to_tokens(tokens);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
quote!{
|
||||||
|
.await;
|
||||||
|
}.to_tokens(tokens);
|
||||||
|
|
||||||
|
if *has_returns{
|
||||||
|
quote!{
|
||||||
|
let retval = retval?;
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
crate::rmc::structures::RmcSerialize::serialize(&retval, &mut vec).ok();
|
||||||
|
Ok(vec)
|
||||||
|
}.to_tokens(tokens);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
quote!{
|
||||||
|
async fn rmc_call_proto(
|
||||||
|
&self,
|
||||||
|
remote_response_connection: &crate::prudp::socket::SendingConnection,
|
||||||
|
method_id: u32,
|
||||||
|
call_id: u32,
|
||||||
|
data: Vec<u8>,
|
||||||
|
)
|
||||||
|
}.to_tokens(tokens);
|
||||||
|
|
||||||
|
Brace::default().surround(tokens, |tokens|{
|
||||||
|
quote! {
|
||||||
|
let ret = match method_id
|
||||||
|
}.to_tokens(tokens);
|
||||||
|
|
||||||
|
Brace::default().surround(tokens, |tokens|{
|
||||||
|
for method in methods{
|
||||||
|
let ProtoMethodData{
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
..
|
||||||
|
} = method;
|
||||||
|
|
||||||
|
let raw_name = Ident::new(&format!("raw_{}", name), name.span());
|
||||||
|
|
||||||
|
quote!{
|
||||||
|
#id => self.#raw_name(data).await,
|
||||||
|
}.to_tokens(tokens);
|
||||||
|
}
|
||||||
|
quote!{
|
||||||
|
_ => Err(crate::rmc::response::ErrorCode::Core_NotImplemented)
|
||||||
|
}.to_tokens(tokens);
|
||||||
|
});
|
||||||
|
|
||||||
|
Semi::default().to_tokens(tokens);
|
||||||
|
|
||||||
|
if *has_returns{
|
||||||
|
quote!{
|
||||||
|
crate::rmc::response::send_result(
|
||||||
|
remote_response_connection,
|
||||||
|
ret,
|
||||||
|
#id,
|
||||||
|
method_id,
|
||||||
|
call_id,
|
||||||
|
).await
|
||||||
|
}.to_tokens(tokens);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
quote!{
|
||||||
|
impl<T: #name> RawAuth for T{}
|
||||||
|
}.to_tokens(tokens);
|
||||||
|
|
||||||
|
let raw_info_name = Ident::new(&format!("Raw{}Info", name), Span::call_site());
|
||||||
|
|
||||||
|
|
||||||
|
quote!{
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub struct #raw_info_name;
|
||||||
|
|
||||||
|
impl #raw_info_name {
|
||||||
|
pub const PROTOCOL_ID: u16 = #id;
|
||||||
|
}
|
||||||
|
}.to_tokens(tokens);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -1,3 +1,7 @@
|
||||||
|
//! Legacy grpc communication server for being able to use this with pretendos infrastructure
|
||||||
|
//! before account rs is finished.
|
||||||
|
//!
|
||||||
|
//! This WILL be deprecated as soon as account rs is in a stable state.
|
||||||
use tonic::{Request, Status};
|
use tonic::{Request, Status};
|
||||||
|
|
||||||
type InterceptorFunc = Box<(dyn Fn(Request<()>) -> Result<Request<()>, Status> + Send)>;
|
type InterceptorFunc = Box<(dyn Fn(Request<()>) -> Result<Request<()>, Status> + Send)>;
|
||||||
|
|
|
||||||
28
src/main.rs
28
src/main.rs
|
|
@ -1,24 +1,24 @@
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
|
//! # Splatoon RNEX server
|
||||||
|
//!
|
||||||
|
//! This server still includes the code for rnex itself as this is the first rnex server and thus
|
||||||
|
//! also the first and only current usage of rnex, expect this and rnex to be split into seperate
|
||||||
|
//! repos soon.
|
||||||
|
|
||||||
use std::{env, fs};
|
use std::{env, fs};
|
||||||
use std::collections::BTreeMap;
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::net::{Ipv4Addr, SocketAddrV4};
|
use std::net::{Ipv4Addr, SocketAddrV4};
|
||||||
use std::sync::Arc;
|
|
||||||
use chrono::{Local, SecondsFormat};
|
use chrono::{Local, SecondsFormat};
|
||||||
use log::info;
|
use log::info;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use rc4::{KeyInit, Rc4, StreamCipher};
|
|
||||||
use rc4::consts::U5;
|
|
||||||
use simplelog::{ColorChoice, CombinedLogger, Config, LevelFilter, TerminalMode, TermLogger, WriteLogger};
|
use simplelog::{ColorChoice, CombinedLogger, Config, LevelFilter, TerminalMode, TermLogger, WriteLogger};
|
||||||
use tokio::sync::RwLock;
|
|
||||||
use tokio::task::JoinHandle;
|
|
||||||
use crate::nex::account::Account;
|
use crate::nex::account::Account;
|
||||||
use crate::prudp::socket::{EncryptionPair, Unsecure};
|
use crate::prudp::socket::Unsecure;
|
||||||
use crate::prudp::packet::{VirtualPort};
|
use crate::prudp::packet::{VirtualPort};
|
||||||
use crate::prudp::router::Router;
|
use crate::prudp::router::Router;
|
||||||
use crate::prudp::sockaddr::PRUDPSockAddr;
|
use crate::prudp::sockaddr::PRUDPSockAddr;
|
||||||
use crate::prudp::station_url::Type::PRUDP;
|
|
||||||
|
|
||||||
mod endianness;
|
mod endianness;
|
||||||
mod prudp;
|
mod prudp;
|
||||||
|
|
@ -234,6 +234,18 @@ async fn start_secure_server() -> SecureServer{
|
||||||
socket,
|
socket,
|
||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
|
/*
|
||||||
|
define_rmc_proto!(
|
||||||
|
proto AuthClientProtocol{
|
||||||
|
Auth
|
||||||
|
}
|
||||||
|
);*/
|
||||||
|
|
||||||
|
|
||||||
|
//#[rmc_struct(AuthClientProtocol)]
|
||||||
|
struct AuthClient{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
async fn start_servers(){
|
async fn start_servers(){
|
||||||
|
|
||||||
|
|
|
||||||
34
src/rmc/protocols/auth.rs
Normal file
34
src/rmc/protocols/auth.rs
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
use crate::rmc::response::ErrorCode;
|
||||||
|
use crate::rmc::structures::any::Any;
|
||||||
|
use crate::rmc::structures::connection_data::ConnectionData;
|
||||||
|
use crate::rmc::structures::qresult::QResult;
|
||||||
|
use macros::{method_id, rmc_proto};
|
||||||
|
|
||||||
|
|
||||||
|
/// This is the representation for `Ticket Granting`(for details see the
|
||||||
|
/// [kinnay wiki entry](https://github.com/kinnay/NintendoClients/wiki/Authentication-Protocol))
|
||||||
|
#[rmc_proto(10)]
|
||||||
|
pub trait Auth {
|
||||||
|
#[method_id(1)]
|
||||||
|
async fn login(&self, name: String) -> Result<(), ErrorCode>;
|
||||||
|
|
||||||
|
#[method_id(2)]
|
||||||
|
async fn login_ex(
|
||||||
|
&self,
|
||||||
|
name: String,
|
||||||
|
extra_data: Any,
|
||||||
|
) -> Result<(QResult, u32, Vec<u8>, ConnectionData, String), ErrorCode>;
|
||||||
|
|
||||||
|
#[method_id(3)]
|
||||||
|
async fn request_ticket(
|
||||||
|
&self,
|
||||||
|
source_pid: u32,
|
||||||
|
destination_pid: u32,
|
||||||
|
) -> Result<(QResult, Vec<u8>), ErrorCode>;
|
||||||
|
|
||||||
|
#[method_id(4)]
|
||||||
|
async fn get_pid(&self, username: String) -> Result<u32, ErrorCode>;
|
||||||
|
|
||||||
|
#[method_id(5)]
|
||||||
|
async fn get_name(&self, pid: u32) -> Result<String, ErrorCode>;
|
||||||
|
}
|
||||||
|
|
@ -1,3 +1,7 @@
|
||||||
|
#![allow(async_fn_in_trait)]
|
||||||
|
|
||||||
|
pub mod auth;
|
||||||
|
|
||||||
use macros::method_id;
|
use macros::method_id;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::ops::Add;
|
use std::ops::Add;
|
||||||
|
|
@ -10,16 +14,18 @@ use paste::paste;
|
||||||
use tokio::sync::{Mutex, Notify};
|
use tokio::sync::{Mutex, Notify};
|
||||||
use tokio::time::{sleep_until, Instant};
|
use tokio::time::{sleep_until, Instant};
|
||||||
use crate::prudp::socket::{ExternalConnection, SendingConnection};
|
use crate::prudp::socket::{ExternalConnection, SendingConnection};
|
||||||
|
use crate::rmc::response::ErrorCode;
|
||||||
use crate::rmc::structures::connection_data::ConnectionData;
|
use crate::rmc::structures::connection_data::ConnectionData;
|
||||||
|
use crate::rmc::structures::Error;
|
||||||
use crate::rmc::structures::matchmake::AutoMatchmakeParam;
|
use crate::rmc::structures::matchmake::AutoMatchmakeParam;
|
||||||
|
|
||||||
pub struct RmcConnection(pub SendingConnection, pub RmcResponseReceiver);
|
pub struct RmcConnection(pub SendingConnection, pub RmcResponseReceiver);
|
||||||
|
|
||||||
pub struct RmcResponseReceiver(Notify, Mutex<HashMap<(u16, u32), Vec<u8>>>);
|
pub struct RmcResponseReceiver(Notify, Mutex<HashMap<(u32), Vec<u8>>>);
|
||||||
|
|
||||||
impl RmcResponseReceiver{
|
impl RmcResponseReceiver{
|
||||||
// returns none if timed out
|
// returns none if timed out
|
||||||
pub async fn get_response_data(&self, proto: u16, method: u32) -> Option<Vec<u8>>{
|
pub async fn get_response_data(&self, call_id: u32) -> Option<Vec<u8>>{
|
||||||
let mut end_wait_time = Instant::now();
|
let mut end_wait_time = Instant::now();
|
||||||
end_wait_time += Duration::from_secs(5);
|
end_wait_time += Duration::from_secs(5);
|
||||||
|
|
||||||
|
|
@ -29,13 +35,15 @@ impl RmcResponseReceiver{
|
||||||
loop {
|
loop {
|
||||||
let mut locked = self.1.lock().await;
|
let mut locked = self.1.lock().await;
|
||||||
|
|
||||||
if let Some(v) = locked.remove(&(proto, method)){
|
if let Some(v) = locked.remove(&call_id){
|
||||||
return Some(v);
|
return Some(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
drop(locked);
|
||||||
|
|
||||||
|
|
||||||
let notif_fut = self.0.notified();
|
let notif_fut = self.0.notified();
|
||||||
|
|
||||||
drop(locked);
|
|
||||||
|
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
_ = &mut sleep_fut => {
|
_ = &mut sleep_fut => {
|
||||||
|
|
@ -49,6 +57,10 @@ impl RmcResponseReceiver{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait HasRmcConnection{
|
||||||
|
fn get_response_receiver(&self) -> &RmcConnection;
|
||||||
|
}
|
||||||
|
|
||||||
pub trait RemoteObject{
|
pub trait RemoteObject{
|
||||||
fn new(conn: RmcConnection) -> Self;
|
fn new(conn: RmcConnection) -> Self;
|
||||||
}
|
}
|
||||||
|
|
@ -57,84 +69,36 @@ impl RemoteObject for (){
|
||||||
fn new(_: RmcConnection) -> Self {}
|
fn new(_: RmcConnection) -> Self {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
pub trait RmcCallable{
|
pub trait RmcCallable{
|
||||||
//type Remote: RemoteObject;
|
//type Remote: RemoteObject;
|
||||||
//fn new_callable(remote: Self::Remote);
|
//fn new_callable(remote: Self::Remote);
|
||||||
async fn rmc_call(&self, protocol_id: u16, method_id: u32, rest: Vec<u8>);
|
async fn rmc_call(&self, responder: &SendingConnection, protocol_id: u16, method_id: u32, call_id: u32, rest: Vec<u8>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
macro_rules! define_rmc_proto {
|
macro_rules! define_rmc_proto {
|
||||||
(proto $name:ident{
|
(proto $name:ident{
|
||||||
$($protocol:path),*
|
$($protocol:path),*
|
||||||
}) => {
|
}) => {
|
||||||
paste!{
|
paste::paste!{
|
||||||
trait [<Local $name>]: std::any::Any $( + [<Raw $protocol>] + $protocol)* {
|
trait [<Local $name>]: std::any::Any $( + [<Raw $protocol>] + $protocol)* {
|
||||||
async fn rmc_call(&self, protocol_id: u16, method_id: u32, rest: Vec<u8>){
|
async fn rmc_call(&self, remote_response_connection: &crate::prudp::socket::SendingConnection, protocol_id: u16, method_id: u32, call_id: u32, rest: Vec<u8>){
|
||||||
match protocol_id{
|
match protocol_id{
|
||||||
$(
|
$(
|
||||||
[<Raw $protocol Info>]::PROTOCOL_ID => <Self as [<Raw $protocol>]>::rmc_call_proto(self, method_id, rest).await,
|
[<Raw $protocol Info>]::PROTOCOL_ID => <Self as [<Raw $protocol>]>::rmc_call_proto(self, remote_response_connection, method_id, call_id, rest).await,
|
||||||
)*
|
)*
|
||||||
v => log::error!("invalid protocol called on rmc object {}", v)
|
v => log::error!("invalid protocol called on rmc object {}", v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct [<Remote $name>](crate::rmc::protocols::RmcConnection);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
trait RawNotif{
|
|
||||||
async fn rmc_call_proto(&self, method_id: u32, rest: Vec<u8>){
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
trait Notif{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
struct RawNotifInfo;
|
|
||||||
impl RawNotifInfo{
|
|
||||||
const PROTOCOL_ID: u16 = 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait ImplementRemoteCalls{}
|
|
||||||
|
|
||||||
#[rmc_proto(1, NoReturn)]
|
|
||||||
pub trait Another{
|
|
||||||
#[method_id(1)]
|
|
||||||
async fn test(&self, thing: AutoMatchmakeParam);
|
|
||||||
}
|
|
||||||
|
|
||||||
define_rmc_proto!{
|
|
||||||
proto TestProto{
|
|
||||||
Notif,
|
|
||||||
Another
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[rmc_struct(TestProto)]
|
|
||||||
struct TestProtoImplementor{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
impl Notif for TestProtoImplementor{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RawNotif for TestProtoImplementor{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Another for TestProtoImplementor{
|
|
||||||
async fn test(&self, thing: AutoMatchmakeParam) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ImplementRemoteCalls for TestProtoImplementor{}
|
|
||||||
|
|
@ -6,41 +6,42 @@ use crate::prudp::packet::{PRUDPPacket};
|
||||||
use crate::prudp::packet::flags::{NEED_ACK, RELIABLE};
|
use crate::prudp::packet::flags::{NEED_ACK, RELIABLE};
|
||||||
use crate::prudp::packet::PacketOption::FragmentId;
|
use crate::prudp::packet::PacketOption::FragmentId;
|
||||||
use crate::prudp::packet::types::DATA;
|
use crate::prudp::packet::types::DATA;
|
||||||
use crate::prudp::socket::ExternalConnection;
|
use crate::prudp::socket::{ExternalConnection, SendingConnection};
|
||||||
use crate::rmc::structures::qresult::ERROR_MASK;
|
use crate::rmc::structures::qresult::ERROR_MASK;
|
||||||
|
use crate::rmc::structures::RmcSerialize;
|
||||||
use crate::web::DirectionalData::{Incoming, Outgoing};
|
use crate::web::DirectionalData::{Incoming, Outgoing};
|
||||||
use crate::web::WEB_DATA;
|
use crate::web::WEB_DATA;
|
||||||
|
|
||||||
pub enum RMCResponseResult {
|
pub enum RMCResponseResult {
|
||||||
Success{
|
Success {
|
||||||
call_id: u32,
|
call_id: u32,
|
||||||
method_id: u32,
|
method_id: u32,
|
||||||
data: Vec<u8>,
|
data: Vec<u8>,
|
||||||
},
|
},
|
||||||
Error{
|
Error {
|
||||||
error_code: ErrorCode,
|
error_code: ErrorCode,
|
||||||
call_id: u32,
|
call_id: u32,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RMCResponse {
|
pub struct RMCResponse {
|
||||||
pub protocol_id: u8,
|
pub protocol_id: u8,
|
||||||
pub response_result: RMCResponseResult
|
pub response_result: RMCResponseResult,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RMCResponse {
|
impl RMCResponse {
|
||||||
pub fn to_data(self) -> Vec<u8>{
|
pub fn to_data(self) -> Vec<u8> {
|
||||||
generate_response(self.protocol_id, self.response_result).expect("failed to generate response")
|
generate_response(self.protocol_id, self.response_result).expect("failed to generate response")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_response(protocol_id: u8, response: RMCResponseResult) -> io::Result<Vec<u8>>{
|
pub fn generate_response(protocol_id: u8, response: RMCResponseResult) -> io::Result<Vec<u8>> {
|
||||||
let size = 1 + 1 + match &response{
|
let size = 1 + 1 + match &response {
|
||||||
RMCResponseResult::Success {
|
RMCResponseResult::Success {
|
||||||
data,
|
data,
|
||||||
..
|
..
|
||||||
} => 4 + 4 + data.len(),
|
} => 4 + 4 + data.len(),
|
||||||
RMCResponseResult::Error{..} => 4 + 4,
|
RMCResponseResult::Error { .. } => 4 + 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut data_out = Vec::with_capacity(size + 4);
|
let mut data_out = Vec::with_capacity(size + 4);
|
||||||
|
|
@ -50,7 +51,7 @@ pub fn generate_response(protocol_id: u8, response: RMCResponseResult) -> io::Re
|
||||||
data_out.write_all(bytes_of(&u32_size))?;
|
data_out.write_all(bytes_of(&u32_size))?;
|
||||||
data_out.push(protocol_id);
|
data_out.push(protocol_id);
|
||||||
|
|
||||||
match response{
|
match response {
|
||||||
RMCResponseResult::Success {
|
RMCResponseResult::Success {
|
||||||
call_id,
|
call_id,
|
||||||
method_id,
|
method_id,
|
||||||
|
|
@ -61,7 +62,7 @@ pub fn generate_response(protocol_id: u8, response: RMCResponseResult) -> io::Re
|
||||||
let ored_method_id = method_id | 0x8000;
|
let ored_method_id = method_id | 0x8000;
|
||||||
data_out.write_all(bytes_of(&ored_method_id))?;
|
data_out.write_all(bytes_of(&ored_method_id))?;
|
||||||
data_out.write_all(&data)?;
|
data_out.write_all(&data)?;
|
||||||
},
|
}
|
||||||
RMCResponseResult::Error {
|
RMCResponseResult::Error {
|
||||||
call_id,
|
call_id,
|
||||||
error_code
|
error_code
|
||||||
|
|
@ -78,10 +79,44 @@ pub fn generate_response(protocol_id: u8, response: RMCResponseResult) -> io::Re
|
||||||
|
|
||||||
Ok(data_out)
|
Ok(data_out)
|
||||||
}
|
}
|
||||||
pub async fn send_response(original_packet: &PRUDPPacket, connection: &mut ExternalConnection, rmcresponse: RMCResponse){
|
|
||||||
|
pub async fn send_result(
|
||||||
|
connection: &SendingConnection,
|
||||||
|
result: Result<Vec<u8>, ErrorCode>,
|
||||||
|
protocol_id: u8,
|
||||||
|
method_id: u32,
|
||||||
|
call_id: u32,
|
||||||
|
) {
|
||||||
|
let response_result = match result {
|
||||||
|
Ok(v) => RMCResponseResult::Success {
|
||||||
|
call_id,
|
||||||
|
method_id,
|
||||||
|
data: {
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
v.serialize(&mut vec).expect("serialization error");
|
||||||
|
vec
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(e) =>
|
||||||
|
RMCResponseResult::Error {
|
||||||
|
call_id,
|
||||||
|
error_code: e.into()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let response = RMCResponse{
|
||||||
|
response_result,
|
||||||
|
protocol_id
|
||||||
|
};
|
||||||
|
|
||||||
|
send_response(connection, response).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn send_response(connection: &SendingConnection, rmcresponse: RMCResponse) {
|
||||||
connection.send(rmcresponse.to_data()).await;
|
connection.send(rmcresponse.to_data()).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//taken from kinnays error list directly
|
//taken from kinnays error list directly
|
||||||
#[allow(nonstandard_style)]
|
#[allow(nonstandard_style)]
|
||||||
#[repr(u32)]
|
#[repr(u32)]
|
||||||
|
|
@ -356,25 +391,25 @@ pub enum ErrorCode {
|
||||||
Custom_Unknown = 0x00740001,
|
Custom_Unknown = 0x00740001,
|
||||||
Ess_Unknown = 0x00750001,
|
Ess_Unknown = 0x00750001,
|
||||||
Ess_GameSessionError = 0x00750002,
|
Ess_GameSessionError = 0x00750002,
|
||||||
Ess_GameSessionMaintenance = 0x00750003
|
Ess_GameSessionMaintenance = 0x00750003,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<u32> for ErrorCode {
|
impl Into<u32> for ErrorCode {
|
||||||
fn into(self) -> u32 {
|
fn into(self) -> u32 {
|
||||||
unsafe{ transmute(self) }
|
unsafe { transmute(self) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test{
|
mod test {
|
||||||
use hmac::digest::consts::U5;
|
use hmac::digest::consts::U5;
|
||||||
use hmac::digest::KeyInit;
|
use hmac::digest::KeyInit;
|
||||||
use rc4::{Rc4, StreamCipher};
|
use rc4::{Rc4, StreamCipher};
|
||||||
use crate::rmc::response::ErrorCode;
|
use crate::rmc::response::ErrorCode;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test(){
|
fn test() {
|
||||||
let mut data_orig = [0,1,2,3,4,5,6,7,8,9,69,4,20];
|
let mut data_orig = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 69, 4, 20];
|
||||||
let mut data = data_orig;
|
let mut data = data_orig;
|
||||||
|
|
||||||
let mut rc4: Rc4<U5> =
|
let mut rc4: Rc4<U5> =
|
||||||
|
|
@ -390,11 +425,10 @@ mod test{
|
||||||
rc4.apply_keystream(&mut data);
|
rc4.apply_keystream(&mut data);
|
||||||
|
|
||||||
assert_eq!(data_orig, data);
|
assert_eq!(data_orig, data);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_enum_equivilance(){
|
fn test_enum_equivilance() {
|
||||||
let val: u32 = ErrorCode::Core_Unknown.into();
|
let val: u32 = ErrorCode::Core_Unknown.into();
|
||||||
assert_eq!(val, 0x00010001)
|
assert_eq!(val, 0x00010001)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use crate::rmc::structures::RmcSerialize;
|
use crate::rmc::structures::RmcSerialize;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
impl<'a> RmcSerialize for &'a [u8]{
|
impl<'a> RmcSerialize for &'a [u8]{
|
||||||
fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> {
|
fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> {
|
||||||
let u32_size = self.len() as u32;
|
let u32_size = self.len() as u32;
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,9 @@ use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions};
|
||||||
use crate::rmc::structures::RmcSerialize;
|
use crate::rmc::structures::RmcSerialize;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// this is also for implementing `Buffer` this is tecnically not the same as its handled internaly
|
||||||
|
// probably but as it has the same mapping it doesn't matter and simplifies things
|
||||||
impl<T: RmcSerialize> RmcSerialize for Vec<T>{
|
impl<T: RmcSerialize> RmcSerialize for Vec<T>{
|
||||||
fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> {
|
fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> {
|
||||||
let u32_len = self.len() as u32;
|
let u32_len = self.len() as u32;
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ pub enum Error{
|
||||||
VersionMismatch(u8),
|
VersionMismatch(u8),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
pub mod string;
|
pub mod string;
|
||||||
pub mod any;
|
pub mod any;
|
||||||
|
|
@ -30,9 +30,18 @@ pub mod qbuffer;
|
||||||
pub mod primitives;
|
pub mod primitives;
|
||||||
pub mod matchmake;
|
pub mod matchmake;
|
||||||
pub mod variant;
|
pub mod variant;
|
||||||
mod ranking;
|
pub mod ranking;
|
||||||
|
|
||||||
pub trait RmcSerialize: Sized{
|
pub trait RmcSerialize: Sized{
|
||||||
fn serialize(&self, writer: &mut dyn Write) -> Result<()>;
|
fn serialize(&self, writer: &mut dyn Write) -> Result<()>;
|
||||||
fn deserialize(reader: &mut dyn Read) -> Result<Self>;
|
fn deserialize(reader: &mut dyn Read) -> Result<Self>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RmcSerialize for (){
|
||||||
|
fn serialize(&self, writer: &mut dyn Write) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
fn deserialize(reader: &mut dyn Read) -> Result<Self> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -91,4 +91,112 @@ impl<T: RmcSerialize, U: RmcSerialize> RmcSerialize for (T, U){
|
||||||
|
|
||||||
Ok((first, second))
|
Ok((first, second))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: RmcSerialize, U: RmcSerialize, V: RmcSerialize> RmcSerialize for (T, U, V){
|
||||||
|
fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> {
|
||||||
|
self.0.serialize(writer)?;
|
||||||
|
self.1.serialize(writer)?;
|
||||||
|
self.2.serialize(writer)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result<Self> {
|
||||||
|
let first = T::deserialize(reader)?;
|
||||||
|
let second = U::deserialize(reader)?;
|
||||||
|
let third = V::deserialize(reader)?;
|
||||||
|
|
||||||
|
Ok((first, second, third))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: RmcSerialize, U: RmcSerialize, V: RmcSerialize, W: RmcSerialize> RmcSerialize for (T, U, V, W){
|
||||||
|
fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> {
|
||||||
|
self.0.serialize(writer)?;
|
||||||
|
self.1.serialize(writer)?;
|
||||||
|
self.2.serialize(writer)?;
|
||||||
|
self.3.serialize(writer)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result<Self> {
|
||||||
|
let first = T::deserialize(reader)?;
|
||||||
|
let second = U::deserialize(reader)?;
|
||||||
|
let third = V::deserialize(reader)?;
|
||||||
|
let fourth = W::deserialize(reader)?;
|
||||||
|
|
||||||
|
Ok((first, second, third, fourth))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: RmcSerialize, U: RmcSerialize, V: RmcSerialize, W: RmcSerialize, X: RmcSerialize> RmcSerialize for (T, U, V, W, X){
|
||||||
|
fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> {
|
||||||
|
self.0.serialize(writer)?;
|
||||||
|
self.1.serialize(writer)?;
|
||||||
|
self.2.serialize(writer)?;
|
||||||
|
self.3.serialize(writer)?;
|
||||||
|
self.4.serialize(writer)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result<Self> {
|
||||||
|
let first = T::deserialize(reader)?;
|
||||||
|
let second = U::deserialize(reader)?;
|
||||||
|
let third = V::deserialize(reader)?;
|
||||||
|
let fourth = W::deserialize(reader)?;
|
||||||
|
let fifth = X::deserialize(reader)?;
|
||||||
|
|
||||||
|
Ok((first, second, third, fourth, fifth))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: RmcSerialize, U: RmcSerialize, V: RmcSerialize, W: RmcSerialize, X: RmcSerialize, Y: RmcSerialize> RmcSerialize for (T, U, V, W, X, Y){
|
||||||
|
fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> {
|
||||||
|
self.0.serialize(writer)?;
|
||||||
|
self.1.serialize(writer)?;
|
||||||
|
self.2.serialize(writer)?;
|
||||||
|
self.3.serialize(writer)?;
|
||||||
|
self.4.serialize(writer)?;
|
||||||
|
self.5.serialize(writer)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result<Self> {
|
||||||
|
let first = T::deserialize(reader)?;
|
||||||
|
let second = U::deserialize(reader)?;
|
||||||
|
let third = V::deserialize(reader)?;
|
||||||
|
let fourth = W::deserialize(reader)?;
|
||||||
|
let fifth = X::deserialize(reader)?;
|
||||||
|
let sixth = Y::deserialize(reader)?;
|
||||||
|
|
||||||
|
Ok((first, second, third, fourth, fifth, sixth))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: RmcSerialize, U: RmcSerialize, V: RmcSerialize, W: RmcSerialize, X: RmcSerialize, Y: RmcSerialize, Z: RmcSerialize> RmcSerialize for (T, U, V, W, X, Y, Z){
|
||||||
|
fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> {
|
||||||
|
self.0.serialize(writer)?;
|
||||||
|
self.1.serialize(writer)?;
|
||||||
|
self.2.serialize(writer)?;
|
||||||
|
self.3.serialize(writer)?;
|
||||||
|
self.4.serialize(writer)?;
|
||||||
|
self.5.serialize(writer)?;
|
||||||
|
self.6.serialize(writer)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result<Self> {
|
||||||
|
let first = T::deserialize(reader)?;
|
||||||
|
let second = U::deserialize(reader)?;
|
||||||
|
let third = V::deserialize(reader)?;
|
||||||
|
let fourth = W::deserialize(reader)?;
|
||||||
|
let fifth = X::deserialize(reader)?;
|
||||||
|
let sixth = Y::deserialize(reader)?;
|
||||||
|
let seventh = Z::deserialize(reader)?;
|
||||||
|
|
||||||
|
Ok((first, second, third, fourth, fifth, sixth, seventh))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue