things
This commit is contained in:
parent
4d4fc6c7bf
commit
fc94f655b2
43 changed files with 1957 additions and 694 deletions
|
|
@ -9,7 +9,7 @@ dotenv = "0.15.0"
|
|||
once_cell = "1.20.2"
|
||||
rc4 = "0.1.0"
|
||||
thiserror = "2.0.11"
|
||||
v-byte-helpers = { git = "https://github.com/DJMrTV/VByteMacros", version = "0.1.1" }
|
||||
v-byte-helpers = { git = "https://github.com/RusticMaple/VByteMacros", version = "0.1.1" }
|
||||
simplelog = "0.12.2"
|
||||
chrono = "0.4.39"
|
||||
log = "0.4.25"
|
||||
|
|
@ -48,4 +48,4 @@ path = "src/executables/backend_server_secure.rs"
|
|||
|
||||
[[bin]]
|
||||
name = "edge_node_holder_server"
|
||||
path = "src/executables/edge_node_holder_server.rs"
|
||||
path = "src/executables/edge_node_holder_server.rs"
|
||||
|
|
|
|||
|
|
@ -1,19 +1,18 @@
|
|||
use std::sync::Arc;
|
||||
use std::sync::atomic::AtomicU32;
|
||||
use rnex_core::common::setup;
|
||||
use rnex_core::executables::common::{new_simple_backend};
|
||||
use rnex_core::executables::common::new_simple_backend;
|
||||
use rnex_core::nex::matchmake::MatchmakeManager;
|
||||
use rnex_core::nex::remote_console::RemoteConsole;
|
||||
use rnex_core::nex::user::User;
|
||||
use rnex_core::rmc::protocols::RemoteInstantiatable;
|
||||
use rnex_core::rmc::protocols::{RemoteDisconnectable, RmcPureRemoteObject};
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::AtomicU32;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
setup();
|
||||
|
||||
|
||||
let mmm = Arc::new(MatchmakeManager{
|
||||
gid_counter: AtomicU32::new(1),
|
||||
let mmm = Arc::new(MatchmakeManager {
|
||||
//gid_counter: AtomicU32::new(1),
|
||||
sessions: Default::default(),
|
||||
users: Default::default(),
|
||||
rv_cid_counter: AtomicU32::new(1),
|
||||
|
|
@ -23,15 +22,16 @@ async fn main() {
|
|||
|
||||
MatchmakeManager::initialize_garbage_collect_thread(weak_mmm).await;
|
||||
|
||||
new_simple_backend(move |c, r|{
|
||||
new_simple_backend(move |c, r| {
|
||||
let mmm = mmm.clone();
|
||||
Arc::new_cyclic(move |this| User{
|
||||
Arc::new_cyclic(move |this| User {
|
||||
this: this.clone(),
|
||||
ip: c.prudpsock_addr,
|
||||
pid:c.pid,
|
||||
pid: c.pid,
|
||||
remote: RemoteConsole::new(r),
|
||||
matchmake_manager: mmm,
|
||||
station_url: Default::default()
|
||||
station_url: Default::default(),
|
||||
})
|
||||
}).await;
|
||||
}
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,27 +1,23 @@
|
|||
use once_cell::sync::Lazy;
|
||||
use rnex_core::nex::account::Account;
|
||||
use rnex_core::rmc::protocols::{RmcCallable, RmcConnection, new_rmc_gateway_connection};
|
||||
use rnex_core::rmc::structures::RmcSerialize;
|
||||
use rnex_core::rnex_proxy_common::ConnectionInitData;
|
||||
use std::env;
|
||||
use std::io::Cursor;
|
||||
use std::net::{Ipv4Addr, SocketAddrV4};
|
||||
use std::sync::Arc;
|
||||
use once_cell::sync::Lazy;
|
||||
use rnex_core::nex::account::Account;
|
||||
use rnex_core::rmc::protocols::{RmcCallable, RmcConnection, new_rmc_gateway_connection};
|
||||
use rnex_core::rnex_proxy_common::ConnectionInitData;
|
||||
use rnex_core::rmc::structures::RmcSerialize;
|
||||
use tokio::net::TcpListener;
|
||||
|
||||
use std::error::Error;
|
||||
use log::error;
|
||||
use std::error::Error;
|
||||
|
||||
use crate::reggie::UnitPacketRead;
|
||||
|
||||
const IP_REQ_SERVICE_URL: &str = "https://ipinfo.io/ip";
|
||||
|
||||
|
||||
|
||||
fn try_get_ip() -> Result<Ipv4Addr, Box<dyn Error>> {
|
||||
let mut req = ureq::get(IP_REQ_SERVICE_URL)
|
||||
.call()?;
|
||||
|
||||
pub fn try_get_ip() -> Result<Ipv4Addr, Box<dyn Error>> {
|
||||
let mut req = ureq::get(IP_REQ_SERVICE_URL).call()?;
|
||||
|
||||
Ok(req.body_mut().read_to_string()?.parse()?)
|
||||
}
|
||||
|
|
@ -37,16 +33,14 @@ pub static OWN_IP_PUBLIC: Lazy<Ipv4Addr> = Lazy::new(|| {
|
|||
env::var("SERVER_IP_PUBLIC")
|
||||
.ok()
|
||||
.map(|s| s.parse().expect("invalid ip address"))
|
||||
.unwrap_or_else(||{
|
||||
try_get_ip().unwrap()
|
||||
})
|
||||
.unwrap_or_else(|| try_get_ip().unwrap())
|
||||
});
|
||||
|
||||
pub static SERVER_PORT: Lazy<u16> = Lazy::new(|| {
|
||||
env::var("SERVER_PORT")
|
||||
.ok()
|
||||
.and_then(|s| s.parse().ok())
|
||||
.unwrap_or(10000)
|
||||
.unwrap_or(6000)
|
||||
});
|
||||
|
||||
pub static KERBEROS_SERVER_PASSWORD: Lazy<String> = Lazy::new(|| {
|
||||
|
|
@ -60,24 +54,28 @@ pub static AUTH_SERVER_ACCOUNT: Lazy<Account> =
|
|||
pub static SECURE_SERVER_ACCOUNT: Lazy<Account> =
|
||||
Lazy::new(|| Account::new(2, "Quazal Rendez-Vous", &KERBEROS_SERVER_PASSWORD));
|
||||
|
||||
|
||||
pub async fn new_simple_backend<T: RmcCallable + Sync + Send + 'static,F>(mut creation_function: F)
|
||||
pub async fn new_simple_backend<T: RmcCallable + Sync + Send + 'static, F>(mut creation_function: F)
|
||||
where
|
||||
F: FnMut(ConnectionInitData, RmcConnection) -> Arc<T>,
|
||||
{
|
||||
let listen = TcpListener::bind(SocketAddrV4::new(*OWN_IP_PRIVATE, *SERVER_PORT)).await.unwrap();
|
||||
let listen = TcpListener::bind(SocketAddrV4::new(*OWN_IP_PRIVATE, *SERVER_PORT))
|
||||
.await
|
||||
.unwrap();
|
||||
while let Ok((mut stream, _addr)) = listen.accept().await {
|
||||
let buffer = match stream.read_buffer().await{
|
||||
let buffer = match stream.read_buffer().await {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
error!("an error ocurred whilest reading connection data buffer: {:?}", e);
|
||||
error!(
|
||||
"an error ocurred whilest reading connection data buffer: {:?}",
|
||||
e
|
||||
);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let user_connection_data = ConnectionInitData::deserialize(&mut Cursor::new(buffer));
|
||||
|
||||
let user_connection_data = match user_connection_data{
|
||||
let user_connection_data = match user_connection_data {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
error!("an error ocurred whilest reading connection data: {:?}", e);
|
||||
|
|
@ -85,8 +83,6 @@ where
|
|||
}
|
||||
};
|
||||
let fun_ref = &mut creation_function;
|
||||
new_rmc_gateway_connection(stream.into(), move |r|{
|
||||
fun_ref(user_connection_data, r)
|
||||
});
|
||||
new_rmc_gateway_connection(stream.into(), move |r| fun_ref(user_connection_data, r));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,19 @@
|
|||
use std::hash::{DefaultHasher, Hasher};
|
||||
use std::net::SocketAddrV4;
|
||||
use std::sync::Arc;
|
||||
use crate::grpc::account;
|
||||
use rnex_core::kerberos::{derive_key, KerberosDateTime, Ticket};
|
||||
use crate::reggie::{RemoteEdgeNodeHolder, RemoteEdgeNodeManagement};
|
||||
use crate::{define_rmc_proto, kerberos};
|
||||
use macros::rmc_struct;
|
||||
use rnex_core::kerberos::{KerberosDateTime, Ticket, derive_key};
|
||||
use rnex_core::nex::account::Account;
|
||||
use rnex_core::rmc::protocols::OnlyRemote;
|
||||
use rnex_core::rmc::protocols::auth::{Auth, RawAuth, RawAuthInfo, RemoteAuth};
|
||||
use rnex_core::rmc::response::ErrorCode;
|
||||
use rnex_core::rmc::response::ErrorCode::Core_Unknown;
|
||||
use rnex_core::rmc::structures::any::Any;
|
||||
use rnex_core::rmc::structures::connection_data::ConnectionData;
|
||||
use rnex_core::rmc::structures::qresult::QResult;
|
||||
use crate::{define_rmc_proto, kerberos};
|
||||
use macros::rmc_struct;
|
||||
use crate::reggie::{RemoteEdgeNodeHolder, RemoteEdgeNodeManagement};
|
||||
use rnex_core::rmc::protocols::OnlyRemote;
|
||||
use std::hash::{DefaultHasher, Hasher};
|
||||
use std::net::SocketAddrV4;
|
||||
use std::sync::Arc;
|
||||
|
||||
define_rmc_proto!(
|
||||
proto AuthClientProtocol{
|
||||
|
|
@ -60,10 +60,11 @@ async fn get_login_data_by_pid(pid: u32) -> Option<(u32, [u8; 16])> {
|
|||
Some((pid, passwd))
|
||||
}
|
||||
|
||||
fn station_url_from_sock_addr(sock_addr: SocketAddrV4) -> String{
|
||||
fn station_url_from_sock_addr(sock_addr: SocketAddrV4) -> String {
|
||||
format!(
|
||||
"prudps:/PID=2;sid=1;stream=10;type=2;address={};port={};CID=1",
|
||||
sock_addr.ip(), sock_addr.port()
|
||||
sock_addr.ip(),
|
||||
sock_addr.port()
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -99,7 +100,7 @@ impl Auth for AuthHandler {
|
|||
let mut hasher = DefaultHasher::new();
|
||||
|
||||
hasher.write(name.as_bytes());
|
||||
|
||||
|
||||
let Ok(addr) = self.control_server.get_url(hasher.finish()).await else {
|
||||
return Err(ErrorCode::Core_Exception);
|
||||
};
|
||||
|
|
@ -117,7 +118,7 @@ impl Auth for AuthHandler {
|
|||
source_login_data.0,
|
||||
ticket.into(),
|
||||
connection_data,
|
||||
self.build_name.to_string() //format!("{}; Rust NEX Version {} by DJMrTV", self.build_name, env!("CARGO_PKG_VERSION")),
|
||||
self.build_name.to_string(), //format!("{}; Rust NEX Version {} by DJMrTV", self.build_name, env!("CARGO_PKG_VERSION")),
|
||||
))
|
||||
}
|
||||
|
||||
|
|
@ -157,32 +158,30 @@ impl Auth for AuthHandler {
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use rnex_core::rmc::response::RMCResponse;
|
||||
use rnex_core::rmc::structures::RmcSerialize;
|
||||
use rnex_core::rmc::structures::connection_data::ConnectionData;
|
||||
use rnex_core::rmc::structures::qresult::QResult;
|
||||
use rnex_core::rmc::structures::RmcSerialize;
|
||||
use rnex_core::rmc::response::RMCResponse;
|
||||
use std::io::Cursor;
|
||||
|
||||
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
|
||||
return;
|
||||
let stuff = hex::decode("200100000a0106000000028000000100010051b3995774000000a6321c7f78847c1c5e9fb825eb26bd91841f1a40d92fc694159666119cb13527f1463ac48ad42a63e6613ede67041554b1770978112e6f1f3e177a2bfc75933216dbe38f70133a1eb28e2ae32a4b5c4b0c3e3efd4c02907992e259b257270b57a9dbe7792f4721b07f8fafb9e32d50f2555c616a015c0000004b007072756470733a2f5049443d323b7369643d313b73747265616d3d31303b747970653d323b616464726573733d322e3234332e39352e3131333b706f72743d31303030313b4349443d3100000000000100002c153ba51f00000033006272616e63683a6f726967696e2f70726f6a6563742f7775702d61676d6a206275696c643a335f385f31355f323030345f3000").unwrap();
|
||||
let stuff = RMCResponse::new(&mut Cursor::new(stuff)).unwrap();
|
||||
|
||||
let rnex_core::rmc::response::RMCResponseResult::Success { .. } = stuff.response_result else {
|
||||
let rnex_core::rmc::response::RMCResponseResult::Success { .. } = stuff.response_result
|
||||
else {
|
||||
panic!()
|
||||
};
|
||||
|
||||
|
||||
|
||||
// let stuff = hex::decode("0100010051B399577400000085F1736FCFBE93660275A3FE36FED6C2EFC57222AC99A9219CF54170A415B02DF1463AC48AD42A6307813FDE67041554B177097832ED000F892D9551A09F88E9CB0388DC1BC9527CC7384556A3287B2A349ABBF7E34A5A3EC14C2287CC7F78DA616BC3B03A035347FBD2E9A505C8EF42447CD809015F0000004E007072756470733A2F73747265616D3D31303B747970653D323B616464726573733D3139322E3136382E3137382E3132303B706F72743D31303030313B4349443D313B5049443D323B7369643D310000000000010000CDF53AA51F00000033006272616E63683A6F726967696E2F70726F6A6563742F7775702D61676D6A206275696C643A335F385F31355F323030345F3000").unwrap();
|
||||
let stuff = hex::decode("0100010051b399577400000037d3d4814d2b16dd546c94a75d32637b45f856b5abe73cf26cfaa235c5f2c1cef1463ac48ad42a637d873fde67041554b177097880cfa7e10bb810eaf686bfb0a0cf3d65b1f476ebc046d0855327986f557dca14fbb8594883c186b863f2206f22baa0309dbcc81da2f883cb2cdc12628ec7fced015c0000004b007072756470733a2f5049443d323b7369643d313b73747265616d3d31303b747970653d323b616464726573733d322e3234332e39352e3131333b706f72743d31303030313b4349443d310000000000010000b7f33aa51f00000033006272616e63683a6f726967696e2f70726f6a6563742f7775702d61676d6a206275696c643a335f385f31355f323030345f3000").unwrap();
|
||||
|
||||
let data = <(QResult, u32, Vec<u8>, ConnectionData, String) as RmcSerialize>::deserialize(
|
||||
&mut Cursor::new(stuff),
|
||||
).unwrap();
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
println!("data: {:?}", data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,40 +1,48 @@
|
|||
use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::sync::atomic::AtomicU32;
|
||||
use std::sync::atomic::Ordering::Relaxed;
|
||||
use std::time::Duration;
|
||||
use log::info;
|
||||
use rand::random;
|
||||
use tokio::sync::{Mutex, RwLock};
|
||||
use tokio::time::sleep;
|
||||
use rnex_core::kerberos::KerberosDateTime;
|
||||
use crate::nex::user::User;
|
||||
use crate::rmc::protocols::notifications::{NotificationEvent, RemoteNotification};
|
||||
use rnex_core::rmc::protocols::notifications::notification_types::{HOST_CHANGED, OWNERSHIP_CHANGED};
|
||||
use log::info;
|
||||
use rand::random;
|
||||
use rnex_core::kerberos::KerberosDateTime;
|
||||
use rnex_core::rmc::protocols::notifications::notification_types::{
|
||||
HOST_CHANGED, OWNERSHIP_CHANGED,
|
||||
};
|
||||
use rnex_core::rmc::response::ErrorCode;
|
||||
use rnex_core::rmc::response::ErrorCode::{Core_InvalidArgument, RendezVous_SessionVoid};
|
||||
use rnex_core::rmc::structures::matchmake::{Gathering, MatchmakeParam, MatchmakeSession, MatchmakeSessionSearchCriteria};
|
||||
use rnex_core::rmc::structures::matchmake::gathering_flags::PERSISTENT_GATHERING;
|
||||
use rnex_core::rmc::structures::matchmake::{
|
||||
Gathering, MatchmakeParam, MatchmakeSession, MatchmakeSessionSearchCriteria,
|
||||
};
|
||||
use rnex_core::rmc::structures::variant::Variant;
|
||||
use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
use std::sync::atomic::AtomicU32;
|
||||
use std::sync::atomic::Ordering::Relaxed;
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::time::Duration;
|
||||
use tokio::sync::{Mutex, RwLock};
|
||||
use tokio::time::sleep;
|
||||
|
||||
pub struct MatchmakeManager{
|
||||
pub gid_counter: AtomicU32,
|
||||
pub struct MatchmakeManager {
|
||||
//pub gid_counter: AtomicU32,
|
||||
pub sessions: RwLock<HashMap<u32, Arc<Mutex<ExtendedMatchmakeSession>>>>,
|
||||
pub rv_cid_counter: AtomicU32,
|
||||
pub users: RwLock<HashMap<u32, Weak<User>>>
|
||||
pub users: RwLock<HashMap<u32, Weak<User>>>,
|
||||
}
|
||||
|
||||
impl MatchmakeManager{
|
||||
pub fn next_gid(&self) -> u32{
|
||||
self.gid_counter.fetch_add(1, Relaxed)
|
||||
impl MatchmakeManager {
|
||||
pub fn next_gid(&self) -> u32 {
|
||||
random()
|
||||
//self.gid_counter.fetch_add(1, Relaxed)
|
||||
}
|
||||
|
||||
pub fn next_cid(&self) -> u32{
|
||||
pub fn next_cid(&self) -> u32 {
|
||||
self.rv_cid_counter.fetch_add(1, Relaxed)
|
||||
}
|
||||
|
||||
pub async fn get_session(&self, gid: u32) -> Result<Arc<Mutex<ExtendedMatchmakeSession>>, ErrorCode>{
|
||||
pub async fn get_session(
|
||||
&self,
|
||||
gid: u32,
|
||||
) -> Result<Arc<Mutex<ExtendedMatchmakeSession>>, ErrorCode> {
|
||||
let sessions = self.sessions.read().await;
|
||||
|
||||
let Some(session) = sessions.get(&gid) else {
|
||||
|
|
@ -47,7 +55,7 @@ impl MatchmakeManager{
|
|||
Ok(session)
|
||||
}
|
||||
|
||||
async fn garbage_collect(&self){
|
||||
async fn garbage_collect(&self) {
|
||||
info!("running rnex garbage collector over all sessions and users");
|
||||
|
||||
let mut idx = 0;
|
||||
|
|
@ -61,12 +69,12 @@ impl MatchmakeManager{
|
|||
let sessions = self.sessions.read().await;
|
||||
let session_pair = sessions.iter().nth(idx).map(|s| (*s.0, s.1.clone()));
|
||||
drop(sessions);
|
||||
|
||||
|
||||
session_pair
|
||||
}{
|
||||
} {
|
||||
let session = session.lock().await;
|
||||
|
||||
if !session.is_reachable(){
|
||||
if !session.is_reachable() {
|
||||
to_be_deleted_gids.push(gid);
|
||||
}
|
||||
|
||||
|
|
@ -75,14 +83,14 @@ impl MatchmakeManager{
|
|||
|
||||
let mut sessions = self.sessions.write().await;
|
||||
|
||||
for gid in to_be_deleted_gids{
|
||||
for gid in to_be_deleted_gids {
|
||||
sessions.remove(&gid);
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn initialize_garbage_collect_thread(this: Weak<Self>){
|
||||
pub async fn initialize_garbage_collect_thread(this: Weak<Self>) {
|
||||
tokio::spawn(async move {
|
||||
while let Some(this) = this.upgrade(){
|
||||
while let Some(this) = this.upgrade() {
|
||||
this.garbage_collect().await;
|
||||
|
||||
// every 30 minutes
|
||||
|
|
@ -92,51 +100,62 @@ impl MatchmakeManager{
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct ExtendedMatchmakeSession{
|
||||
pub struct ExtendedMatchmakeSession {
|
||||
pub session: MatchmakeSession,
|
||||
pub connected_players: Vec<Weak<User>>,
|
||||
}
|
||||
|
||||
fn read_bounds_string<T: FromStr>(str: &str) -> Option<(T,T)>{
|
||||
fn read_bounds_string<T: FromStr>(str: &str) -> Option<(T, T)> {
|
||||
let bounds = str.split_once(",")?;
|
||||
|
||||
Some((T::from_str(bounds.0).ok()?, T::from_str(bounds.1).ok()?))
|
||||
}
|
||||
|
||||
fn check_bounds_str<T: FromStr + PartialOrd>(compare: T, str: &str) -> Option<bool>{
|
||||
fn check_bounds_str<T: FromStr + PartialOrd>(compare: T, str: &str) -> Option<bool> {
|
||||
let bounds: (T, T) = read_bounds_string(str)?;
|
||||
|
||||
Some(bounds.0 <= compare && compare <= bounds.1)
|
||||
}
|
||||
|
||||
pub async fn broadcast_notification<T: AsRef<User>>(players: &[T], notification_event: &NotificationEvent){
|
||||
for player in players{
|
||||
pub async fn broadcast_notification<T: AsRef<User>>(
|
||||
players: &[T],
|
||||
notification_event: &NotificationEvent,
|
||||
) {
|
||||
for player in players {
|
||||
let player = player.as_ref();
|
||||
player.remote.process_notification_event(notification_event.clone()).await;
|
||||
player
|
||||
.remote
|
||||
.process_notification_event(notification_event.clone())
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
impl ExtendedMatchmakeSession{
|
||||
impl ExtendedMatchmakeSession {
|
||||
#[inline(always)]
|
||||
pub fn get_active_players(&self) -> Vec<Arc<User>>{
|
||||
self.connected_players.iter().filter_map(|u| u.upgrade()).collect()
|
||||
pub fn get_active_players(&self) -> Vec<Arc<User>> {
|
||||
self.connected_players
|
||||
.iter()
|
||||
.filter_map(|u| u.upgrade())
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub async fn broadcast_notification(&self, notification_event: &NotificationEvent){
|
||||
pub async fn broadcast_notification(&self, notification_event: &NotificationEvent) {
|
||||
broadcast_notification(&self.get_active_players(), notification_event).await;
|
||||
}
|
||||
|
||||
pub async fn from_matchmake_session(gid: u32, session: MatchmakeSession, host: &Weak<User>) -> Self{
|
||||
let Some(host) = host.upgrade() else{
|
||||
pub async fn from_matchmake_session(
|
||||
gid: u32,
|
||||
session: MatchmakeSession,
|
||||
host: &Weak<User>,
|
||||
) -> Self {
|
||||
let Some(host) = host.upgrade() else {
|
||||
return Default::default();
|
||||
};
|
||||
|
||||
|
||||
let mm_session = MatchmakeSession{
|
||||
gathering: Gathering{
|
||||
let mm_session = MatchmakeSession {
|
||||
gathering: Gathering {
|
||||
self_gid: gid,
|
||||
owner_pid: host.pid,
|
||||
host_pid: host.pid,
|
||||
|
|
@ -144,25 +163,25 @@ impl ExtendedMatchmakeSession{
|
|||
},
|
||||
datetime: KerberosDateTime::now(),
|
||||
session_key: (0..32).map(|_| random()).collect(),
|
||||
matchmake_param: MatchmakeParam{
|
||||
matchmake_param: MatchmakeParam {
|
||||
params: vec![
|
||||
("@SR".to_owned(), Variant::Bool(true)),
|
||||
("@GIR".to_owned(), Variant::SInt64(3))
|
||||
]
|
||||
("@GIR".to_owned(), Variant::SInt64(3)),
|
||||
],
|
||||
},
|
||||
system_password_enabled: false,
|
||||
..session
|
||||
};
|
||||
|
||||
Self{
|
||||
Self {
|
||||
session: mm_session,
|
||||
connected_players: Default::default()
|
||||
connected_players: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn add_players(&mut self, conns: &[Weak<User>], join_msg: String) {
|
||||
let Some(initiating_user) = conns[0].upgrade() else {
|
||||
return
|
||||
return;
|
||||
};
|
||||
|
||||
let initiating_pid = initiating_user.pid;
|
||||
|
|
@ -173,36 +192,42 @@ impl ExtendedMatchmakeSession{
|
|||
}
|
||||
self.session.participation_count = self.connected_players.len() as u32;
|
||||
|
||||
for other_connection in &conns[1..]{
|
||||
for other_connection in &conns[1..] {
|
||||
let Some(other_conn) = other_connection.upgrade() else {
|
||||
continue;
|
||||
};
|
||||
|
||||
|
||||
let other_pid = other_conn.pid;
|
||||
/*if other_pid == self.session.gathering.owner_pid &&
|
||||
joining_pid == self.session.gathering.owner_pid{
|
||||
continue;
|
||||
}*/
|
||||
|
||||
other_conn.remote.process_notification_event(NotificationEvent{
|
||||
pid_source: initiating_pid,
|
||||
notif_type: 122000,
|
||||
param_1: self.session.gathering.self_gid,
|
||||
param_2: other_pid,
|
||||
str_param: "".into(),
|
||||
param_3: 0
|
||||
}).await;
|
||||
other_conn
|
||||
.remote
|
||||
.process_notification_event(NotificationEvent {
|
||||
pid_source: initiating_pid,
|
||||
notif_type: 122000,
|
||||
param_1: self.session.gathering.self_gid,
|
||||
param_2: other_pid,
|
||||
str_param: "".into(),
|
||||
param_3: 0,
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
let list_of_connected_pids: Vec<_> = self.connected_players.iter().filter_map(|p| p.upgrade()).map(|p| p.pid).collect();
|
||||
let list_of_connected_pids: Vec<_> = self
|
||||
.connected_players
|
||||
.iter()
|
||||
.filter_map(|p| p.upgrade())
|
||||
.map(|p| p.pid)
|
||||
.collect();
|
||||
|
||||
for other_connection in conns{
|
||||
for other_connection in conns {
|
||||
let Some(other_conn) = other_connection.upgrade() else {
|
||||
continue;
|
||||
};
|
||||
|
||||
|
||||
// let other_pid = other_conn.pid;
|
||||
/*if other_pid == self.session.gathering.owner_pid &&
|
||||
joining_pid == self.session.gathering.owner_pid{
|
||||
|
|
@ -210,44 +235,52 @@ impl ExtendedMatchmakeSession{
|
|||
}*/
|
||||
|
||||
for pid in &list_of_connected_pids {
|
||||
other_conn.remote.process_notification_event(NotificationEvent {
|
||||
pid_source: initiating_pid,
|
||||
notif_type: 3001,
|
||||
param_1: self.session.gathering.self_gid,
|
||||
param_2: *pid,
|
||||
str_param: join_msg.clone(),
|
||||
param_3: self.connected_players.len() as _
|
||||
}).await;
|
||||
other_conn
|
||||
.remote
|
||||
.process_notification_event(NotificationEvent {
|
||||
pid_source: initiating_pid,
|
||||
notif_type: 3001,
|
||||
param_1: self.session.gathering.self_gid,
|
||||
param_2: *pid,
|
||||
str_param: join_msg.clone(),
|
||||
param_3: self.connected_players.len() as _,
|
||||
})
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
for old_conns in &old_particip{
|
||||
for old_conns in &old_particip {
|
||||
let Some(old_conns) = old_conns.upgrade() else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let older_pid = old_conns.pid;
|
||||
|
||||
|
||||
|
||||
initiating_user.remote.process_notification_event(NotificationEvent{
|
||||
pid_source: initiating_pid,
|
||||
notif_type: 3001,
|
||||
param_1: self.session.gathering.self_gid,
|
||||
param_2: older_pid,
|
||||
str_param: join_msg.clone(),
|
||||
param_3: self.connected_players.len() as _
|
||||
}).await;
|
||||
initiating_user
|
||||
.remote
|
||||
.process_notification_event(NotificationEvent {
|
||||
pid_source: initiating_pid,
|
||||
notif_type: 3001,
|
||||
param_1: self.session.gathering.self_gid,
|
||||
param_2: older_pid,
|
||||
str_param: join_msg.clone(),
|
||||
param_3: self.connected_players.len() as _,
|
||||
})
|
||||
.await;
|
||||
}
|
||||
}
|
||||
pub fn has_active_players(&self) -> bool{
|
||||
self.connected_players.iter().filter(|v| v.upgrade().is_some()).count() != 0
|
||||
pub fn has_active_players(&self) -> bool {
|
||||
self.connected_players
|
||||
.iter()
|
||||
.filter(|v| v.upgrade().is_some())
|
||||
.count()
|
||||
!= 0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_reachable(&self) -> bool{
|
||||
(if self.session.gathering.flags & PERSISTENT_GATHERING != 0{
|
||||
if self.has_active_players(){
|
||||
pub fn is_reachable(&self) -> bool {
|
||||
(if self.session.gathering.flags & PERSISTENT_GATHERING != 0 {
|
||||
if self.has_active_players() {
|
||||
true
|
||||
} else {
|
||||
self.session.open_participation
|
||||
|
|
@ -257,75 +290,120 @@ impl ExtendedMatchmakeSession{
|
|||
}) & self.has_active_players()
|
||||
}
|
||||
#[inline]
|
||||
pub fn is_joinable(&self) -> bool{
|
||||
pub fn is_joinable(&self) -> bool {
|
||||
self.is_reachable() && self.session.open_participation
|
||||
}
|
||||
|
||||
pub fn matches_criteria(&self, search_criteria: &MatchmakeSessionSearchCriteria) -> Result<bool, ErrorCode>{
|
||||
pub fn matches_criteria(
|
||||
&self,
|
||||
search_criteria: &MatchmakeSessionSearchCriteria,
|
||||
) -> Result<bool, ErrorCode> {
|
||||
// todo: implement the rest of the search criteria
|
||||
|
||||
if search_criteria.vacant_only {
|
||||
if (self.connected_players.len() as u16 + search_criteria.vacant_participants) > self.session.gathering.maximum_participants{
|
||||
if (self.connected_players.len() as u16 + search_criteria.vacant_participants)
|
||||
> self.session.gathering.maximum_participants
|
||||
{
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
|
||||
if search_criteria.exclude_locked{
|
||||
if !self.session.open_participation{
|
||||
if search_criteria.exclude_locked {
|
||||
if !self.session.open_participation {
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
|
||||
if search_criteria.exclude_system_password_set{
|
||||
if self.session.system_password_enabled{
|
||||
if search_criteria.exclude_system_password_set {
|
||||
if self.session.system_password_enabled {
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
|
||||
if search_criteria.exclude_user_password_set{
|
||||
if self.session.user_password_enabled{
|
||||
if search_criteria.exclude_user_password_set {
|
||||
if self.session.user_password_enabled {
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
|
||||
if !check_bounds_str(self.session.gathering.minimum_participants, &search_criteria.minimum_participants).ok_or(Core_InvalidArgument)? {
|
||||
if !check_bounds_str(
|
||||
self.session.gathering.minimum_participants,
|
||||
&search_criteria.minimum_participants,
|
||||
)
|
||||
.ok_or(Core_InvalidArgument)?
|
||||
{
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
if !check_bounds_str(self.session.gathering.maximum_participants, &search_criteria.maximum_participants).ok_or(Core_InvalidArgument)? {
|
||||
if !check_bounds_str(
|
||||
self.session.gathering.maximum_participants,
|
||||
&search_criteria.maximum_participants,
|
||||
)
|
||||
.ok_or(Core_InvalidArgument)?
|
||||
{
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
let game_mode: u32 = search_criteria.game_mode.parse().map_err(|_| Core_InvalidArgument)?;
|
||||
let game_mode: u32 = search_criteria
|
||||
.game_mode
|
||||
.parse()
|
||||
.map_err(|_| Core_InvalidArgument)?;
|
||||
|
||||
if self.session.gamemode != game_mode{
|
||||
if self.session.gamemode != game_mode {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
let mm_sys_type: u32 = search_criteria.matchmake_system_type.parse().map_err(|_| Core_InvalidArgument)?;
|
||||
let mm_sys_type: u32 = search_criteria
|
||||
.matchmake_system_type
|
||||
.parse()
|
||||
.map_err(|_| Core_InvalidArgument)?;
|
||||
|
||||
if self.session.matchmake_system_type != mm_sys_type{
|
||||
if self.session.matchmake_system_type != mm_sys_type {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
|
||||
if search_criteria.attribs.get(0).map(|str| str.parse().ok()).flatten() != self.session.attributes.get(0).map(|v| *v){
|
||||
if search_criteria
|
||||
.attribs
|
||||
.get(0)
|
||||
.map(|str| str.parse().ok())
|
||||
.flatten()
|
||||
!= self.session.attributes.get(0).map(|v| *v)
|
||||
{
|
||||
return Ok(false);
|
||||
}
|
||||
if search_criteria.attribs.get(2).map(|str| str.parse().ok()).flatten() != self.session.attributes.get(2).map(|v| *v){
|
||||
if search_criteria
|
||||
.attribs
|
||||
.get(2)
|
||||
.map(|str| str.parse().ok())
|
||||
.flatten()
|
||||
!= self.session.attributes.get(2).map(|v| *v)
|
||||
{
|
||||
return Ok(false);
|
||||
}
|
||||
if search_criteria.attribs.get(3).map(|str| str.parse().ok()).flatten() != self.session.attributes.get(3).map(|v| *v){
|
||||
if search_criteria
|
||||
.attribs
|
||||
.get(3)
|
||||
.map(|str| str.parse().ok())
|
||||
.flatten()
|
||||
!= self.session.attributes.get(3).map(|v| *v)
|
||||
{
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
pub async fn migrate_ownership(&mut self, initiator_pid: u32) -> Result<(), ErrorCode>{
|
||||
let players: Vec<_> = self.connected_players.iter().filter_map(|p| p.upgrade()).collect();
|
||||
pub async fn migrate_ownership(&mut self, initiator_pid: u32) -> Result<(), ErrorCode> {
|
||||
let players: Vec<_> = self
|
||||
.connected_players
|
||||
.iter()
|
||||
.filter_map(|p| p.upgrade())
|
||||
.collect();
|
||||
|
||||
let Some(new_owner) = players.iter().find(|p| p.pid != self.session.gathering.owner_pid) else {
|
||||
let Some(new_owner) = players
|
||||
.iter()
|
||||
.find(|p| p.pid != self.session.gathering.owner_pid)
|
||||
else {
|
||||
self.session.gathering.owner_pid = 0;
|
||||
|
||||
return Ok(());
|
||||
|
|
@ -333,36 +411,44 @@ impl ExtendedMatchmakeSession{
|
|||
|
||||
self.session.gathering.owner_pid = new_owner.pid;
|
||||
|
||||
self.broadcast_notification(&NotificationEvent{
|
||||
self.broadcast_notification(&NotificationEvent {
|
||||
pid_source: initiator_pid,
|
||||
notif_type: OWNERSHIP_CHANGED,
|
||||
param_1: self.session.gathering.self_gid,
|
||||
param_2: new_owner.pid,
|
||||
..Default::default()
|
||||
}).await;
|
||||
})
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn migrate_host(&mut self, initiator_pid: u32) -> Result<(), ErrorCode>{
|
||||
pub async fn migrate_host(&mut self, initiator_pid: u32) -> Result<(), ErrorCode> {
|
||||
// let players: Vec<_> = self.connected_players.iter().filter_map(|p| p.upgrade()).collect();
|
||||
|
||||
self.session.gathering.host_pid = self.session.gathering.owner_pid;
|
||||
|
||||
self.broadcast_notification(&NotificationEvent{
|
||||
self.broadcast_notification(&NotificationEvent {
|
||||
pid_source: initiator_pid,
|
||||
notif_type: HOST_CHANGED,
|
||||
param_1: self.session.gathering.self_gid,
|
||||
..Default::default()
|
||||
}).await;
|
||||
})
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn remove_player_from_session(&mut self, pid: u32, message: &str) -> Result<(), ErrorCode>{
|
||||
self.connected_players.retain(|u| u.upgrade().is_some_and(|u| u.pid != pid));
|
||||
pub async fn remove_player_from_session(
|
||||
&mut self,
|
||||
pid: u32,
|
||||
message: &str,
|
||||
) -> Result<(), ErrorCode> {
|
||||
self.connected_players
|
||||
.retain(|u| u.upgrade().is_some_and(|u| u.pid != pid));
|
||||
|
||||
self.session.participation_count = (self.connected_players.len() & u32::MAX as usize) as u32;
|
||||
self.session.participation_count =
|
||||
(self.connected_players.len() & u32::MAX as usize) as u32;
|
||||
|
||||
if pid == self.session.gathering.owner_pid {
|
||||
self.migrate_ownership(pid).await?;
|
||||
|
|
@ -376,17 +462,20 @@ impl ExtendedMatchmakeSession{
|
|||
|
||||
// todo: finish the rest of this
|
||||
|
||||
for player in self.connected_players.iter().filter_map(|p| p.upgrade()){
|
||||
player.remote.process_notification_event(NotificationEvent{
|
||||
notif_type: 3008,
|
||||
pid_source: pid,
|
||||
param_1: self.session.gathering.self_gid,
|
||||
param_2: pid,
|
||||
str_param: message.to_owned(),
|
||||
.. Default::default()
|
||||
}).await;
|
||||
for player in self.connected_players.iter().filter_map(|p| p.upgrade()) {
|
||||
player
|
||||
.remote
|
||||
.process_notification_event(NotificationEvent {
|
||||
notif_type: 3008,
|
||||
pid_source: pid,
|
||||
param_1: self.session.gathering.self_gid,
|
||||
param_2: pid,
|
||||
str_param: message.to_owned(),
|
||||
..Default::default()
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,33 +1,41 @@
|
|||
use crate::define_rmc_proto;
|
||||
use crate::nex::matchmake::{ExtendedMatchmakeSession, MatchmakeManager};
|
||||
use crate::nex::remote_console::RemoteConsole;
|
||||
use rnex_core::prudp::station_url::StationUrl;
|
||||
use rnex_core::prudp::station_url::UrlOptions::{
|
||||
Address, NatFiltering, NatMapping, NatType, Port, PrincipalID, RVConnectionID,
|
||||
|
||||
};
|
||||
use crate::rmc::protocols::matchmake::{
|
||||
Matchmake, RawMatchmake, RawMatchmakeInfo, RemoteMatchmake,
|
||||
};
|
||||
use rnex_core::rmc::protocols::ranking::{Ranking, RawRanking, RawRankingInfo, RemoteRanking};
|
||||
use crate::rmc::protocols::nat_traversal::{
|
||||
NatTraversal, RawNatTraversal, RawNatTraversalInfo, RemoteNatTraversal,
|
||||
RemoteNatTraversalConsole,
|
||||
};
|
||||
use rnex_core::prudp::station_url::StationUrl;
|
||||
use rnex_core::prudp::station_url::UrlOptions::{
|
||||
Address, NatFiltering, NatMapping, NatType, Port, PrincipalID, RVConnectionID,
|
||||
};
|
||||
use rnex_core::rmc::protocols::matchmake_ext::{
|
||||
MatchmakeExt, RawMatchmakeExt, RawMatchmakeExtInfo, RemoteMatchmakeExt,
|
||||
};
|
||||
use rnex_core::rmc::protocols::matchmake_extension::{
|
||||
MatchmakeExtension, RawMatchmakeExtension, RawMatchmakeExtensionInfo, RemoteMatchmakeExtension,
|
||||
};
|
||||
use crate::rmc::protocols::nat_traversal::{NatTraversal, RawNatTraversal, RawNatTraversalInfo, RemoteNatTraversal, RemoteNatTraversalConsole};
|
||||
use rnex_core::rmc::protocols::ranking::{Ranking, RawRanking, RawRankingInfo, RemoteRanking};
|
||||
use rnex_core::rmc::protocols::secure::{RawSecure, RawSecureInfo, RemoteSecure, Secure};
|
||||
use rnex_core::rmc::protocols::matchmake_ext::{MatchmakeExt, RawMatchmakeExt, RawMatchmakeExtInfo, RemoteMatchmakeExt};
|
||||
use rnex_core::rmc::response::ErrorCode;
|
||||
use rnex_core::rmc::structures::matchmake::{AutoMatchmakeParam, CreateMatchmakeSessionParam, JoinMatchmakeSessionParam, MatchmakeSession};
|
||||
use rnex_core::rmc::structures::matchmake::{
|
||||
AutoMatchmakeParam, CreateMatchmakeSessionParam, JoinMatchmakeSessionParam, MatchmakeSession,
|
||||
};
|
||||
|
||||
use rnex_core::rmc::structures::qresult::QResult;
|
||||
use macros::rmc_struct;
|
||||
use std::sync::{Arc, Weak};
|
||||
use crate::rmc::protocols::notifications::{NotificationEvent, RemoteNotification};
|
||||
use log::info;
|
||||
use tokio::sync::{Mutex, RwLock};
|
||||
use macros::rmc_struct;
|
||||
use rnex_core::prudp::socket_addr::PRUDPSockAddr;
|
||||
use rnex_core::prudp::station_url::nat_types::PUBLIC;
|
||||
use crate::rmc::protocols::notifications::{NotificationEvent, RemoteNotification};
|
||||
use rnex_core::rmc::response::ErrorCode::{Core_Exception, Core_InvalidArgument, RendezVous_AccountExpired};
|
||||
use rnex_core::rmc::response::ErrorCode::{
|
||||
Core_Exception, Core_InvalidArgument, RendezVous_AccountExpired,
|
||||
};
|
||||
use rnex_core::rmc::structures::qresult::QResult;
|
||||
use std::sync::{Arc, Weak};
|
||||
use tokio::sync::{Mutex, RwLock};
|
||||
|
||||
define_rmc_proto!(
|
||||
proto UserProtocol{
|
||||
|
|
@ -78,14 +86,14 @@ impl Secure for User {
|
|||
|
||||
let Some(nat_filtering) = station.options.iter().find_map(|v| match v {
|
||||
NatFiltering(v) => Some(v),
|
||||
_ => None
|
||||
_ => None,
|
||||
}) else {
|
||||
return Err(Core_Exception);
|
||||
};
|
||||
|
||||
let Some(nat_mapping) = station.options.iter().find_map(|v| match v {
|
||||
NatMapping(v) => Some(v),
|
||||
_ => None
|
||||
_ => None,
|
||||
}) else {
|
||||
return Err(Core_Exception);
|
||||
};
|
||||
|
|
@ -108,15 +116,17 @@ impl Secure for User {
|
|||
} else {
|
||||
let mut public_station = private_station.clone();
|
||||
|
||||
public_station.options.retain(|v| {
|
||||
match v {
|
||||
Address(_) | Port(_) | NatFiltering(_) | NatMapping(_) | NatType(_) => false,
|
||||
_ => true
|
||||
}
|
||||
public_station.options.retain(|v| match v {
|
||||
Address(_) | Port(_) | NatFiltering(_) | NatMapping(_) | NatType(_) => false,
|
||||
_ => true,
|
||||
});
|
||||
|
||||
public_station.options.push(Address(*self.ip.regular_socket_addr.ip()));
|
||||
public_station.options.push(Port(self.ip.regular_socket_addr.port()));
|
||||
public_station
|
||||
.options
|
||||
.push(Address(*self.ip.regular_socket_addr.ip()));
|
||||
public_station
|
||||
.options
|
||||
.push(Port(self.ip.regular_socket_addr.port()));
|
||||
public_station.options.push(NatFiltering(0));
|
||||
public_station.options.push(NatMapping(0));
|
||||
public_station.options.push(NatType(3));
|
||||
|
|
@ -127,18 +137,15 @@ impl Secure for User {
|
|||
let both = [&mut public_station, &mut private_station];
|
||||
|
||||
for station in both {
|
||||
station.options.retain(|v| {
|
||||
match v {
|
||||
PrincipalID(_) | RVConnectionID(_) => false,
|
||||
_ => true
|
||||
}
|
||||
station.options.retain(|v| match v {
|
||||
PrincipalID(_) | RVConnectionID(_) => false,
|
||||
_ => true,
|
||||
});
|
||||
|
||||
station.options.push(PrincipalID(self.pid));
|
||||
station.options.push(RVConnectionID(cid));
|
||||
}
|
||||
|
||||
|
||||
let mut lock = self.station_url.write().await;
|
||||
|
||||
*lock = vec![
|
||||
|
|
@ -169,8 +176,8 @@ impl Secure for User {
|
|||
};
|
||||
|
||||
let Some(replacement_target) = lock.iter_mut().find(|url| {
|
||||
url.options.iter().any(|o| o == target_addr) &&
|
||||
url.options.iter().any(|o| o == target_port)
|
||||
url.options.iter().any(|o| o == target_addr)
|
||||
&& url.options.iter().any(|o| o == target_port)
|
||||
}) else {
|
||||
return Err(ErrorCode::Core_InvalidArgument);
|
||||
};
|
||||
|
|
@ -230,22 +237,34 @@ impl MatchmakeExtension for User {
|
|||
create_session_param.matchmake_session,
|
||||
&self.this.clone(),
|
||||
)
|
||||
.await;
|
||||
.await;
|
||||
|
||||
let mut joining_players = vec![self.this.clone()];
|
||||
|
||||
let users = self.matchmake_manager.users.read().await;
|
||||
|
||||
if let Ok(old_gathering) = self.matchmake_manager.get_session(create_session_param.gid_for_participation_check).await {
|
||||
if let Ok(old_gathering) = self
|
||||
.matchmake_manager
|
||||
.get_session(create_session_param.gid_for_participation_check)
|
||||
.await
|
||||
{
|
||||
let old_gathering = old_gathering.lock().await;
|
||||
|
||||
let players = old_gathering.connected_players.iter().filter_map(|v| v.upgrade()).filter(|u| create_session_param.additional_participants.iter().any(|p| *p == u.pid));
|
||||
let players = old_gathering
|
||||
.connected_players
|
||||
.iter()
|
||||
.filter_map(|v| v.upgrade())
|
||||
.filter(|u| {
|
||||
create_session_param
|
||||
.additional_participants
|
||||
.iter()
|
||||
.any(|p| *p == u.pid)
|
||||
});
|
||||
for player in players {
|
||||
joining_players.push(Arc::downgrade(&player));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
drop(users);
|
||||
|
||||
new_session.session.participation_count = create_session_param.participation_count as u32;
|
||||
|
|
@ -266,26 +285,43 @@ impl MatchmakeExtension for User {
|
|||
&self,
|
||||
join_session_param: JoinMatchmakeSessionParam,
|
||||
) -> Result<MatchmakeSession, ErrorCode> {
|
||||
let session = self.matchmake_manager.get_session(join_session_param.gid).await?;
|
||||
let session = self
|
||||
.matchmake_manager
|
||||
.get_session(join_session_param.gid)
|
||||
.await?;
|
||||
|
||||
let mut session = session.lock().await;
|
||||
|
||||
if session.session.user_password_enabled{
|
||||
if join_session_param.user_password != session.session.user_password{
|
||||
return Err(ErrorCode::RendezVous_InvalidPassword)
|
||||
}
|
||||
if session.session.user_password_enabled {
|
||||
if join_session_param.user_password != session.session.user_password {
|
||||
return Err(ErrorCode::RendezVous_InvalidPassword);
|
||||
}
|
||||
}
|
||||
|
||||
session.connected_players.retain(|v| v.upgrade().is_some_and(|v| v.pid != self.pid));
|
||||
session
|
||||
.connected_players
|
||||
.retain(|v| v.upgrade().is_some_and(|v| v.pid != self.pid));
|
||||
|
||||
let mut joining_players = vec![self.this.clone()];
|
||||
|
||||
let users = self.matchmake_manager.users.read().await;
|
||||
|
||||
if let Ok(old_gathering) = self.matchmake_manager.get_session(join_session_param.gid_for_participation_check).await {
|
||||
if let Ok(old_gathering) = self
|
||||
.matchmake_manager
|
||||
.get_session(join_session_param.gid_for_participation_check)
|
||||
.await
|
||||
{
|
||||
let old_gathering = old_gathering.lock().await;
|
||||
|
||||
let players = old_gathering.connected_players.iter().filter_map(|v| v.upgrade()).filter(|u| join_session_param.additional_participants.iter().any(|p| *p == u.pid));
|
||||
let players = old_gathering
|
||||
.connected_players
|
||||
.iter()
|
||||
.filter_map(|v| v.upgrade())
|
||||
.filter(|u| {
|
||||
join_session_param
|
||||
.additional_participants
|
||||
.iter()
|
||||
.any(|p| *p == u.pid)
|
||||
});
|
||||
for player in players {
|
||||
joining_players.push(Arc::downgrade(&player));
|
||||
}
|
||||
|
|
@ -302,17 +338,28 @@ impl MatchmakeExtension for User {
|
|||
Ok(mm_session)
|
||||
}
|
||||
|
||||
async fn auto_matchmake_with_param_postpone(&self, param: AutoMatchmakeParam) -> Result<MatchmakeSession, ErrorCode> {
|
||||
async fn auto_matchmake_with_param_postpone(
|
||||
&self,
|
||||
param: AutoMatchmakeParam,
|
||||
) -> Result<MatchmakeSession, ErrorCode> {
|
||||
println!("{:?}", param);
|
||||
|
||||
let mut joining_players = vec![self.this.clone()];
|
||||
|
||||
let users = self.matchmake_manager.users.read().await;
|
||||
|
||||
if let Ok(old_gathering) = self.matchmake_manager.get_session(param.gid_for_participation_check).await {
|
||||
if let Ok(old_gathering) = self
|
||||
.matchmake_manager
|
||||
.get_session(param.gid_for_participation_check)
|
||||
.await
|
||||
{
|
||||
let old_gathering = old_gathering.lock().await;
|
||||
|
||||
let players = old_gathering.connected_players.iter().filter_map(|v| v.upgrade()).filter(|u| param.additional_participants.iter().any(|p| *p == u.pid));
|
||||
let players = old_gathering
|
||||
.connected_players
|
||||
.iter()
|
||||
.filter_map(|v| v.upgrade())
|
||||
.filter(|u| param.additional_participants.iter().any(|p| *p == u.pid));
|
||||
for player in players {
|
||||
joining_players.push(Arc::downgrade(&player));
|
||||
}
|
||||
|
|
@ -339,7 +386,9 @@ impl MatchmakeExtension for User {
|
|||
}
|
||||
|
||||
if bool_matched_criteria {
|
||||
session.add_players(&joining_players, param.join_message).await;
|
||||
session
|
||||
.add_players(&joining_players, param.join_message)
|
||||
.await;
|
||||
|
||||
return Ok(session.session.clone());
|
||||
}
|
||||
|
|
@ -365,17 +414,26 @@ impl MatchmakeExtension for User {
|
|||
create_matchmake_session_option: 0,
|
||||
matchmake_session,
|
||||
additional_participants,
|
||||
}).await
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn find_matchmake_session_by_gathering_id_detail(&self, gid: u32) -> Result<MatchmakeSession, ErrorCode> {
|
||||
async fn find_matchmake_session_by_gathering_id_detail(
|
||||
&self,
|
||||
gid: u32,
|
||||
) -> Result<MatchmakeSession, ErrorCode> {
|
||||
let session = self.matchmake_manager.get_session(gid).await?;
|
||||
let session = session.lock().await;
|
||||
|
||||
Ok(session.session.clone())
|
||||
}
|
||||
|
||||
async fn modify_current_game_attribute(&self, gid: u32, attrib_index: u32, attrib_val: u32) -> Result<(), ErrorCode> {
|
||||
async fn modify_current_game_attribute(
|
||||
&self,
|
||||
gid: u32,
|
||||
attrib_index: u32,
|
||||
attrib_val: u32,
|
||||
) -> Result<(), ErrorCode> {
|
||||
let session = self.matchmake_manager.get_session(gid).await?;
|
||||
let mut session = session.lock().await;
|
||||
|
||||
|
|
@ -394,30 +452,30 @@ impl Matchmake for User {
|
|||
|
||||
let session = session.lock().await;
|
||||
|
||||
let urls: Vec<_> =
|
||||
session
|
||||
.connected_players
|
||||
.iter()
|
||||
.filter_map(|v| v.upgrade())
|
||||
.filter(|u| u.pid == session.session.gathering.host_pid)
|
||||
.map(|u| async move {
|
||||
u.station_url.read().await.clone()
|
||||
})
|
||||
.next()
|
||||
.ok_or(ErrorCode::RendezVous_SessionClosed)?
|
||||
.await;
|
||||
|
||||
let urls: Vec<_> = session
|
||||
.connected_players
|
||||
.iter()
|
||||
.filter_map(|v| v.upgrade())
|
||||
.filter(|u| u.pid == session.session.gathering.host_pid)
|
||||
.map(|u| async move { u.station_url.read().await.clone() })
|
||||
.next()
|
||||
.ok_or(ErrorCode::RendezVous_SessionClosed)?
|
||||
.await;
|
||||
|
||||
println!("{:?}", urls);
|
||||
|
||||
if urls.is_empty(){
|
||||
return Err(ErrorCode::RendezVous_NotParticipatedGathering)
|
||||
|
||||
if urls.is_empty() {
|
||||
return Err(ErrorCode::RendezVous_NotParticipatedGathering);
|
||||
}
|
||||
|
||||
Ok(urls)
|
||||
}
|
||||
|
||||
async fn update_session_host(&self, gid: u32, change_session_owner: bool) -> Result<(), ErrorCode> {
|
||||
async fn update_session_host(
|
||||
&self,
|
||||
gid: u32,
|
||||
change_session_owner: bool,
|
||||
) -> Result<(), ErrorCode> {
|
||||
let session = self.matchmake_manager.get_session(gid).await?;
|
||||
let mut session = session.lock().await;
|
||||
|
||||
|
|
@ -428,40 +486,50 @@ impl Matchmake for User {
|
|||
continue;
|
||||
};
|
||||
|
||||
player.remote.process_notification_event(NotificationEvent {
|
||||
notif_type: 110000,
|
||||
pid_source: self.pid,
|
||||
param_1: gid,
|
||||
param_2: self.pid,
|
||||
param_3: 0,
|
||||
str_param: "".to_string(),
|
||||
}).await;
|
||||
player
|
||||
.remote
|
||||
.process_notification_event(NotificationEvent {
|
||||
notif_type: 110000,
|
||||
pid_source: self.pid,
|
||||
param_1: gid,
|
||||
param_2: self.pid,
|
||||
param_3: 0,
|
||||
str_param: "".to_string(),
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
if change_session_owner {
|
||||
session.session.gathering.owner_pid = self.pid;
|
||||
|
||||
|
||||
for player in &session.connected_players {
|
||||
let Some(player) = player.upgrade() else {
|
||||
continue;
|
||||
};
|
||||
|
||||
player.remote.process_notification_event(NotificationEvent {
|
||||
notif_type: 4000,
|
||||
pid_source: self.pid,
|
||||
param_1: gid,
|
||||
param_2: self.pid,
|
||||
param_3: 0,
|
||||
str_param: "".to_string(),
|
||||
}).await;
|
||||
player
|
||||
.remote
|
||||
.process_notification_event(NotificationEvent {
|
||||
notif_type: 4000,
|
||||
pid_source: self.pid,
|
||||
param_1: gid,
|
||||
param_2: self.pid,
|
||||
param_3: 0,
|
||||
str_param: "".to_string(),
|
||||
})
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn migrate_gathering_ownership(&self, gid: u32, candidates: Vec<u32>, _participants_only: bool) -> Result<(), ErrorCode> {
|
||||
async fn migrate_gathering_ownership(
|
||||
&self,
|
||||
gid: u32,
|
||||
candidates: Vec<u32>,
|
||||
_participants_only: bool,
|
||||
) -> Result<(), ErrorCode> {
|
||||
let session = self.matchmake_manager.get_session(gid).await?;
|
||||
let mut session = session.lock().await;
|
||||
|
||||
|
|
@ -474,14 +542,17 @@ impl Matchmake for User {
|
|||
continue;
|
||||
};
|
||||
|
||||
player.remote.process_notification_event(NotificationEvent {
|
||||
notif_type: 4000,
|
||||
pid_source: self.pid,
|
||||
param_1: gid,
|
||||
param_2: *candidate,
|
||||
param_3: 0,
|
||||
str_param: "".to_string(),
|
||||
}).await;
|
||||
player
|
||||
.remote
|
||||
.process_notification_event(NotificationEvent {
|
||||
notif_type: 4000,
|
||||
pid_source: self.pid,
|
||||
param_1: gid,
|
||||
param_2: *candidate,
|
||||
param_3: 0,
|
||||
str_param: "".to_string(),
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
@ -493,12 +564,12 @@ impl MatchmakeExt for User {
|
|||
let session = self.matchmake_manager.get_session(gid).await?;
|
||||
let mut session = session.lock().await;
|
||||
|
||||
session.remove_player_from_session(self.pid, &message).await?;
|
||||
session
|
||||
.remove_player_from_session(self.pid, &message)
|
||||
.await?;
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
impl NatTraversal for User {
|
||||
|
|
@ -513,7 +584,7 @@ impl NatTraversal for User {
|
|||
for station_url in urls.iter_mut() {
|
||||
station_url.options.retain(|o| match o {
|
||||
NatMapping(_) | NatFiltering(_) => false,
|
||||
_ => true
|
||||
_ => true,
|
||||
});
|
||||
|
||||
station_url.options.push(NatMapping(nat_mapping as u8));
|
||||
|
|
@ -523,7 +594,12 @@ impl NatTraversal for User {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn report_nat_traversal_result(&self, _cid: u32, _result: bool, _rtt: u32) -> Result<(), ErrorCode> {
|
||||
async fn report_nat_traversal_result(
|
||||
&self,
|
||||
_cid: u32,
|
||||
_result: bool,
|
||||
_rtt: u32,
|
||||
) -> Result<(), ErrorCode> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -532,17 +608,28 @@ impl NatTraversal for User {
|
|||
Err(RendezVous_AccountExpired)
|
||||
}
|
||||
|
||||
async fn request_probe_initialization_ext(&self, target_list: Vec<String>, station_to_probe: String) -> Result<(), ErrorCode> {
|
||||
async fn request_probe_initialization_ext(
|
||||
&self,
|
||||
target_list: Vec<String>,
|
||||
station_to_probe: String,
|
||||
) -> Result<(), ErrorCode> {
|
||||
let users = self.matchmake_manager.users.read().await;
|
||||
|
||||
println!("requesting station probe for {:?} to {:?}", target_list, station_to_probe);
|
||||
println!(
|
||||
"requesting station probe for {:?} to {:?}",
|
||||
target_list, station_to_probe
|
||||
);
|
||||
|
||||
for target in target_list {
|
||||
let Ok(url) = StationUrl::try_from(target.as_ref()) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let Some(RVConnectionID(v)) = url.options.into_iter().find(|o| { matches!(o, &RVConnectionID(_)) }) else {
|
||||
let Some(RVConnectionID(v)) = url
|
||||
.options
|
||||
.into_iter()
|
||||
.find(|o| matches!(o, &RVConnectionID(_)))
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
|
||||
|
|
@ -554,7 +641,9 @@ impl NatTraversal for User {
|
|||
continue;
|
||||
};
|
||||
|
||||
user.remote.request_probe_initiation(station_to_probe.clone()).await;
|
||||
user.remote
|
||||
.request_probe_initiation(station_to_probe.clone())
|
||||
.await;
|
||||
}
|
||||
|
||||
info!("finished probing");
|
||||
|
|
@ -563,6 +652,4 @@ impl NatTraversal for User {
|
|||
}
|
||||
}
|
||||
|
||||
impl Ranking for User{
|
||||
|
||||
}
|
||||
impl Ranking for User {}
|
||||
|
|
|
|||
20
rnex-core/src/prudp/encryption.rs
Normal file
20
rnex-core/src/prudp/encryption.rs
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
use std::sync::LazyLock;
|
||||
|
||||
use rc4::{Key, StreamCipher};
|
||||
use typenum::U5;
|
||||
|
||||
pub struct EncryptionPair<T: StreamCipher + Send> {
|
||||
pub send: T,
|
||||
pub recv: T,
|
||||
}
|
||||
|
||||
impl<T: StreamCipher + Send> EncryptionPair<T> {
|
||||
pub fn init_both<F: Fn() -> T>(func: F) -> Self {
|
||||
Self {
|
||||
recv: func(),
|
||||
send: func(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub static DEFAULT_KEY: LazyLock<Key<U5>> = LazyLock::new(|| Key::from(*b"CD&ML"));
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
pub mod virtual_port;
|
||||
pub mod encryption;
|
||||
pub mod socket_addr;
|
||||
pub mod station_url;
|
||||
pub mod socket_addr;
|
||||
pub mod types_flags;
|
||||
pub mod virtual_port;
|
||||
|
|
|
|||
64
rnex-core/src/prudp/types_flags.rs
Normal file
64
rnex-core/src/prudp/types_flags.rs
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
use std::fmt::{Debug, Formatter};
|
||||
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use v_byte_helpers::SwapEndian;
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Copy, Clone, Pod, Zeroable, SwapEndian, Default, Eq, PartialEq)]
|
||||
pub struct TypesFlags(pub u16);
|
||||
|
||||
impl TypesFlags {
|
||||
#[inline]
|
||||
pub const fn get_types(self) -> u8 {
|
||||
(self.0 & 0x000F) as u8
|
||||
}
|
||||
#[inline]
|
||||
pub const fn get_flags(self) -> u16 {
|
||||
(self.0 & 0xFFF0) >> 4
|
||||
}
|
||||
#[inline]
|
||||
pub const fn types(self, val: u8) -> Self {
|
||||
Self((self.0 & 0xFFF0) | (val as u16 & 0x000F))
|
||||
}
|
||||
#[inline]
|
||||
pub const fn flags(self, val: u16) -> Self {
|
||||
Self((self.0 & 0x000F) | ((val << 4) & 0xFFF0))
|
||||
}
|
||||
#[inline]
|
||||
pub const fn set_flag(&mut self, val: u16) {
|
||||
self.0 |= (val & 0xFFF) << 4;
|
||||
}
|
||||
#[inline]
|
||||
pub const fn set_types(&mut self, val: u8) {
|
||||
self.0 |= val as u16 & 0x0F;
|
||||
}
|
||||
}
|
||||
impl Debug for TypesFlags {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
let stream_type = self.get_types();
|
||||
let port_number = self.get_flags();
|
||||
write!(
|
||||
f,
|
||||
"TypesFlags{{ types: {}, flags: {} }}",
|
||||
stream_type, port_number
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub mod flags {
|
||||
pub const ACK: u16 = 0x001;
|
||||
pub const RELIABLE: u16 = 0x002;
|
||||
pub const NEED_ACK: u16 = 0x004;
|
||||
pub const HAS_SIZE: u16 = 0x008;
|
||||
pub const MULTI_ACK: u16 = 0x200;
|
||||
}
|
||||
|
||||
pub mod types {
|
||||
pub const SYN: u8 = 0x0;
|
||||
pub const CONNECT: u8 = 0x1;
|
||||
pub const DATA: u8 = 0x2;
|
||||
pub const DISCONNECT: u8 = 0x3;
|
||||
pub const PING: u8 = 0x4;
|
||||
/// no idea what user is supposed to mean
|
||||
pub const USER: u8 = 0x5;
|
||||
}
|
||||
|
|
@ -1,5 +1,8 @@
|
|||
use std::fmt::{Debug, Formatter};
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use std::{
|
||||
fmt::{Debug, Formatter},
|
||||
slice,
|
||||
};
|
||||
use v_byte_helpers::SwapEndian;
|
||||
|
||||
#[repr(transparent)]
|
||||
|
|
@ -7,7 +10,6 @@ use v_byte_helpers::SwapEndian;
|
|||
pub struct VirtualPort(pub u8);
|
||||
|
||||
impl VirtualPort {
|
||||
|
||||
#[inline]
|
||||
pub const fn get_stream_type(self) -> u8 {
|
||||
(self.0 & 0xF0) >> 4
|
||||
|
|
@ -38,12 +40,21 @@ impl VirtualPort {
|
|||
pub fn new(port: u8, stream_type: u8) -> Self {
|
||||
Self(0).stream_type(stream_type).port_number(port)
|
||||
}
|
||||
#[inline(always)]
|
||||
pub fn parse(data: &str) -> Option<Self> {
|
||||
let (p1, p2) = data.split_once(':')?;
|
||||
Some(Self::new(p1.parse().ok()?, p2.parse().ok()?))
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for VirtualPort {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
let stream_type = self.get_stream_type();
|
||||
let port_number = self.get_port_number();
|
||||
write!(f, "VirtualPort{{ stream_type: {}, port_number: {} }}", stream_type, port_number)
|
||||
write!(
|
||||
f,
|
||||
"VirtualPort{{ stream_type: {}, port_number: {} }}",
|
||||
stream_type, port_number
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
use crate::define_rmc_proto;
|
||||
use crate::rmc::structures::RmcSerialize;
|
||||
use macros::{RmcSerialize, method_id, rmc_proto};
|
||||
use rnex_core::rmc::response::ErrorCode;
|
||||
use std::io;
|
||||
use std::net::SocketAddrV4;
|
||||
use macros::{method_id, rmc_proto, RmcSerialize};
|
||||
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
|
||||
use crate::define_rmc_proto;
|
||||
use rnex_core::rmc::response::ErrorCode;
|
||||
use crate::rmc::structures::RmcSerialize;
|
||||
|
||||
pub trait UnitPacketRead: AsyncRead + Unpin{
|
||||
async fn read_buffer(&mut self) -> Result<Vec<u8>, io::Error>{
|
||||
pub trait UnitPacketRead: AsyncRead + Unpin {
|
||||
async fn read_buffer(&mut self) -> Result<Vec<u8>, io::Error> {
|
||||
let mut len_raw: [u8; 4] = [0; 4];
|
||||
|
||||
self.read_exact(&mut len_raw).await?;
|
||||
|
|
@ -22,12 +22,13 @@ pub trait UnitPacketRead: AsyncRead + Unpin{
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: AsyncRead + Unpin> UnitPacketRead for T{}
|
||||
pub trait UnitPacketWrite: AsyncWrite + Unpin{
|
||||
impl<T: AsyncRead + Unpin> UnitPacketRead for T {}
|
||||
pub trait UnitPacketWrite: AsyncWrite + Unpin {
|
||||
async fn send_buffer(&mut self, data: &[u8]) -> Result<(), io::Error> {
|
||||
let mut dest_data = Vec::new();
|
||||
|
||||
data.serialize(&mut dest_data).expect("ran out of memory or something");
|
||||
data.serialize(&mut dest_data)
|
||||
.expect("ran out of memory or something");
|
||||
|
||||
self.write_all(&dest_data[..]).await?;
|
||||
|
||||
|
|
@ -37,9 +38,7 @@ pub trait UnitPacketWrite: AsyncWrite + Unpin{
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: AsyncWrite + Unpin> UnitPacketWrite for T{}
|
||||
|
||||
|
||||
impl<T: AsyncWrite + Unpin> UnitPacketWrite for T {}
|
||||
|
||||
#[rmc_proto(1)]
|
||||
pub trait EdgeNodeManagement {
|
||||
|
|
@ -55,7 +54,7 @@ define_rmc_proto!(
|
|||
|
||||
#[derive(RmcSerialize, Debug)]
|
||||
#[repr(u32)]
|
||||
pub enum EdgeNodeHolderConnectOption{
|
||||
pub enum EdgeNodeHolderConnectOption {
|
||||
DontRegister = 0,
|
||||
Register(SocketAddrV4) = 1
|
||||
Register(SocketAddrV4) = 1,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,20 +1,21 @@
|
|||
#![allow(async_fn_in_trait)]
|
||||
|
||||
pub mod auth;
|
||||
pub mod secure;
|
||||
pub mod notifications;
|
||||
pub mod matchmake;
|
||||
pub mod matchmake_ext;
|
||||
pub mod matchmake_extension;
|
||||
pub mod nat_traversal;
|
||||
pub mod matchmake_ext;
|
||||
pub mod notifications;
|
||||
pub mod ranking;
|
||||
pub mod secure;
|
||||
|
||||
use crate::util::{SendingBufferConnection, SplittableBufferConnection};
|
||||
use crate::result::ResultExtension;
|
||||
use crate::rmc::message::RMCMessage;
|
||||
use crate::rmc::protocols::RemoteCallError::ConnectionBroke;
|
||||
use crate::rmc::response::{ErrorCode, RMCResponse, RMCResponseResult};
|
||||
use crate::rmc::structures;
|
||||
use crate::rmc::structures::RmcSerialize;
|
||||
use crate::util::{SendingBufferConnection, SplittableBufferConnection};
|
||||
use log::{error, info};
|
||||
use std::collections::HashMap;
|
||||
use std::future::Future;
|
||||
|
|
@ -24,8 +25,7 @@ use std::sync::Arc;
|
|||
use std::time::Duration;
|
||||
use thiserror::Error;
|
||||
use tokio::sync::{Mutex, Notify};
|
||||
use tokio::time::{sleep, sleep_until, Instant};
|
||||
use crate::result::ResultExtension;
|
||||
use tokio::time::{Instant, sleep, sleep_until};
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum RemoteCallError {
|
||||
|
|
@ -68,7 +68,7 @@ impl RmcConnection {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn disconnect(&self){
|
||||
pub async fn disconnect(&self) {
|
||||
self.0.disconnect().await;
|
||||
}
|
||||
}
|
||||
|
|
@ -92,15 +92,11 @@ impl RmcResponseReceiver {
|
|||
let mut locked = self.1.lock().await;
|
||||
|
||||
if let Some(v) = locked.remove(&call_id) {
|
||||
match v.response_result{
|
||||
RMCResponseResult::Success {
|
||||
data,
|
||||
..
|
||||
} => return Ok(data),
|
||||
RMCResponseResult::Error {
|
||||
error_code,
|
||||
..
|
||||
} => return Err(RemoteCallError::ServerError(error_code))
|
||||
match v.response_result {
|
||||
RMCResponseResult::Success { data, .. } => return Ok(data),
|
||||
RMCResponseResult::Error { error_code, .. } => {
|
||||
return Err(RemoteCallError::ServerError(error_code));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -167,10 +163,14 @@ macro_rules! define_rmc_proto {
|
|||
|
||||
pub struct [<Remote $name>](rnex_core::rmc::protocols::RmcConnection);
|
||||
|
||||
impl rnex_core::rmc::protocols::RemoteInstantiatable for [<Remote $name>]{
|
||||
impl rnex_core::rmc::protocols::RmcPureRemoteObject for [<Remote $name>]{
|
||||
fn new(conn: rnex_core::rmc::protocols::RmcConnection) -> Self{
|
||||
Self(conn)
|
||||
}
|
||||
}
|
||||
|
||||
impl rnex_core::rmc::protocols::RemoteDisconnectable for [<Remote $name>]{
|
||||
|
||||
async fn disconnect(&self){
|
||||
self.0.disconnect().await;
|
||||
}
|
||||
|
|
@ -203,14 +203,23 @@ impl RmcCallable for () {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait RemoteInstantiatable{
|
||||
pub trait RmcPureRemoteObject {
|
||||
fn new(conn: RmcConnection) -> Self;
|
||||
}
|
||||
|
||||
pub trait RemoteDisconnectable {
|
||||
async fn disconnect(&self);
|
||||
}
|
||||
|
||||
pub struct OnlyRemote<T: RemoteInstantiatable>(T);
|
||||
pub struct OnlyRemote<T: RemoteDisconnectable>(T);
|
||||
|
||||
impl<T: RemoteInstantiatable> Deref for OnlyRemote<T>{
|
||||
impl<T: RemoteDisconnectable + RmcPureRemoteObject> OnlyRemote<T> {
|
||||
pub fn new(conn: RmcConnection) -> Self {
|
||||
Self(T::new(conn))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: RemoteDisconnectable> Deref for OnlyRemote<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
|
|
@ -218,20 +227,23 @@ impl<T: RemoteInstantiatable> Deref for OnlyRemote<T>{
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: RemoteInstantiatable> OnlyRemote<T>{
|
||||
pub fn new(conn: RmcConnection) -> Self{
|
||||
Self(T::new(conn))
|
||||
}
|
||||
|
||||
impl<T: RemoteDisconnectable> OnlyRemote<T> {
|
||||
pub async fn disconnect(&self) {
|
||||
self.0.disconnect().await;
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: RemoteInstantiatable> RmcCallable for OnlyRemote<T>{
|
||||
fn rmc_call(&self, _responder: &SendingBufferConnection, _protocol_id: u16, _method_id: u32, _call_id: u32, _rest: Vec<u8>) -> impl Future<Output = ()> + Send {
|
||||
impl<T: RemoteDisconnectable> RmcCallable for OnlyRemote<T> {
|
||||
fn rmc_call(
|
||||
&self,
|
||||
_responder: &SendingBufferConnection,
|
||||
_protocol_id: u16,
|
||||
_method_id: u32,
|
||||
_call_id: u32,
|
||||
_rest: Vec<u8>,
|
||||
) -> impl Future<Output = ()> + Send {
|
||||
// maybe respond with not implemented or something
|
||||
async{}
|
||||
async {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -243,23 +255,23 @@ async fn handle_incoming<T: RmcCallable + Send + Sync + 'static>(
|
|||
) {
|
||||
let sending_conn = connection.duplicate_sender();
|
||||
|
||||
while let Some(v) = connection.recv().await{
|
||||
while let Some(v) = connection.recv().await {
|
||||
let Some(proto_id) = v.get(4) else {
|
||||
error!("received too small rmc message.");
|
||||
error!("ending rmc gateway.");
|
||||
return
|
||||
return;
|
||||
};
|
||||
|
||||
// protocol 0 is hardcoded to be the no protocol protocol aka keepalive protocol
|
||||
if *proto_id == 0{
|
||||
if *proto_id == 0 {
|
||||
println!("got keepalive");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (proto_id & 0x80) == 0{
|
||||
if (proto_id & 0x80) == 0 {
|
||||
let Some(response) = RMCResponse::new(&mut Cursor::new(v)).display_err_or_some() else {
|
||||
error!("ending rmc gateway.");
|
||||
return
|
||||
return;
|
||||
};
|
||||
|
||||
info!("got rmc response");
|
||||
|
|
@ -271,28 +283,34 @@ async fn handle_incoming<T: RmcCallable + Send + Sync + 'static>(
|
|||
} else {
|
||||
let Some(message) = RMCMessage::new(&mut Cursor::new(v)).display_err_or_some() else {
|
||||
error!("ending rmc gateway.");
|
||||
return
|
||||
return;
|
||||
};
|
||||
|
||||
let RMCMessage{
|
||||
let RMCMessage {
|
||||
protocol_id,
|
||||
method_id,
|
||||
call_id,
|
||||
rest_of_data
|
||||
rest_of_data,
|
||||
} = message;
|
||||
|
||||
info!("RMC REQUEST: Proto: {}; Method: {};", protocol_id, method_id);
|
||||
info!(
|
||||
"RMC REQUEST: Proto: {}; Method: {};",
|
||||
protocol_id, method_id
|
||||
);
|
||||
|
||||
remote.rmc_call(&sending_conn, protocol_id, method_id, call_id, rest_of_data).await;
|
||||
|
||||
|
||||
remote
|
||||
.rmc_call(&sending_conn, protocol_id, method_id, call_id, rest_of_data)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
info!("rmc disconnected")
|
||||
}
|
||||
|
||||
pub fn new_rmc_gateway_connection<T: RmcCallable + Sync + Send + 'static,F>(conn: SplittableBufferConnection, create_internal: F) -> Arc<T>
|
||||
pub fn new_rmc_gateway_connection<T: RmcCallable + Sync + Send + 'static, F>(
|
||||
conn: SplittableBufferConnection,
|
||||
create_internal: F,
|
||||
) -> Arc<T>
|
||||
where
|
||||
F: FnOnce(RmcConnection) -> Arc<T>,
|
||||
{
|
||||
|
|
@ -312,18 +330,12 @@ where
|
|||
{
|
||||
let exposed_object = exposed_object.clone();
|
||||
tokio::spawn(async move {
|
||||
handle_incoming(
|
||||
conn,
|
||||
exposed_object,
|
||||
notify,
|
||||
incoming
|
||||
).await;
|
||||
handle_incoming(conn, exposed_object, notify, incoming).await;
|
||||
});
|
||||
|
||||
|
||||
tokio::spawn(async move {
|
||||
while sending_conn.is_alive(){
|
||||
sending_conn.send([0,0,0,0,0].to_vec()).await;
|
||||
while sending_conn.is_alive() {
|
||||
sending_conn.send([0, 0, 0, 0, 0].to_vec()).await;
|
||||
sleep(Duration::from_secs(10)).await;
|
||||
}
|
||||
});
|
||||
|
|
@ -332,12 +344,20 @@ where
|
|||
exposed_object
|
||||
}
|
||||
|
||||
impl<T: RmcCallable> RmcCallable for Arc<T>{
|
||||
fn rmc_call(&self, responder: &SendingBufferConnection, protocol_id: u16, method_id: u32, call_id: u32, rest: Vec<u8>) -> impl Future<Output=()> + Send {
|
||||
self.as_ref().rmc_call(responder, protocol_id, method_id, call_id, rest)
|
||||
impl<T: RmcCallable> RmcCallable for Arc<T> {
|
||||
fn rmc_call(
|
||||
&self,
|
||||
responder: &SendingBufferConnection,
|
||||
protocol_id: u16,
|
||||
method_id: u32,
|
||||
call_id: u32,
|
||||
rest: Vec<u8>,
|
||||
) -> impl Future<Output = ()> + Send {
|
||||
self.as_ref()
|
||||
.rmc_call(responder, protocol_id, method_id, call_id, rest)
|
||||
}
|
||||
}
|
||||
|
||||
define_rmc_proto! {
|
||||
proto NoProto{}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,54 +4,60 @@ use rnex_core::rmc::structures::qbuffer::QBuffer;
|
|||
|
||||
#[derive(RmcSerialize, Debug)]
|
||||
#[rmc_struct(0)]
|
||||
struct UploadCompetitionData{
|
||||
winning_team/*?*/: u32,
|
||||
splatfest_id/*?*/: u32,
|
||||
unk_2/*?*/: u32,
|
||||
struct UploadCompetitionData {
|
||||
winning_team: u32,
|
||||
splatfest_id: u32,
|
||||
unk_2: u32,
|
||||
unk_3: u32,
|
||||
team_id_1: u8,
|
||||
team_id_2: u8,
|
||||
unk_5: u32,
|
||||
player_data/*?*/: QBuffer,
|
||||
player_data: QBuffer,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Pod, Zeroable)]
|
||||
#[repr(C)]
|
||||
struct UserData{
|
||||
struct UserData {
|
||||
name: [u16; 0x10],
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test{
|
||||
use std::io::Cursor;
|
||||
use bytemuck::from_bytes;
|
||||
mod test {
|
||||
use crate::rmc::structures::ranking::{UploadCompetitionData, UserData};
|
||||
use bytemuck::from_bytes;
|
||||
use rnex_core::rmc::structures::RmcSerialize;
|
||||
use std::io::Cursor;
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
return;
|
||||
let data: [u8; 0xBD] = [
|
||||
0x00, 0xB8, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFC, 0x03, 0x00, 0x00, 0x02, 0x00, 0x00,
|
||||
0x00, 0x1F, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x00, 0x00, 0x49, 0x00,
|
||||
0x7A, 0x00, 0x7A, 0x00, 0x79, 0x00, 0x53, 0x00, 0x50, 0x00, 0x46, 0x00, 0x4E, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0xF2, 0x00, 0x00, 0x00,
|
||||
0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x1F, 0x5E, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x90, 0x00, 0x00, 0x00,
|
||||
0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x0A, 0x00, 0x00, 0x14, 0x87, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x00, 0x00, 0x00,
|
||||
0x00, 0xB8, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFC, 0x03, 0x00, 0x00, 0x02,
|
||||
0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0xA0,
|
||||
0x00, 0x00, 0x49, 0x00, 0x7A, 0x00, 0x7A, 0x00, 0x79, 0x00, 0x53, 0x00, 0x50, 0x00,
|
||||
0x46, 0x00, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0xF2, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x1F, 0x5E, 0x00, 0x00, 0x00, 0x01, 0x00,
|
||||
0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x90, 0x00,
|
||||
0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x14, 0x87, 0x00, 0x00, 0x00, 0x01, 0x00,
|
||||
0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
|
||||
0x00, 0x00, 0x00, 0x4C, 0x00, 0x00, 0x00,
|
||||
];
|
||||
|
||||
let mut cursor = Cursor::new(data);
|
||||
|
||||
let data = UploadCompetitionData::deserialize(&mut cursor).expect("unable to deserialize data");
|
||||
let data =
|
||||
UploadCompetitionData::deserialize(&mut cursor).expect("unable to deserialize data");
|
||||
|
||||
let user_data: &UserData = from_bytes(&data.player_data.0[..size_of::<UserData>()]);
|
||||
|
||||
let pos = user_data.name.iter()
|
||||
let pos = user_data
|
||||
.name
|
||||
.iter()
|
||||
.position(|v| *v == 0x0000)
|
||||
.unwrap_or(0x10);
|
||||
|
||||
|
|
@ -65,4 +71,4 @@ mod test{
|
|||
|
||||
assert!(u8::deserialize(&mut cursor).is_err())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue