From 7d81fe02595e933f058ac36797f8035ce63b4b4c Mon Sep 17 00:00:00 2001 From: Maple Nebel Date: Fri, 19 Jun 2026 11:40:43 +0200 Subject: [PATCH] hopefully improve performance of rate_objects --- rnex-core/src/nex/datastore.rs | 129 +++++++++++------- rnex-core/src/nex/user.rs | 10 +- .../src/rmc/protocols/message_delivery.rs | 9 ++ rnex-core/src/rmc/protocols/mod.rs | 1 + 4 files changed, 98 insertions(+), 51 deletions(-) create mode 100644 rnex-core/src/rmc/protocols/message_delivery.rs diff --git a/rnex-core/src/nex/datastore.rs b/rnex-core/src/nex/datastore.rs index 32f4980..d6944a7 100644 --- a/rnex-core/src/nex/datastore.rs +++ b/rnex-core/src/nex/datastore.rs @@ -1,6 +1,12 @@ -use crate::rmc::protocols::datastore::{DataStoreFileServerObjectInfo, DataStoreGetCourseRecordParam, DataStoreGetCourseRecordResult, DataStoreUploadCourseRecordParam}; +use std::convert; + +use crate::rmc::protocols::datastore::{ + DataStoreFileServerObjectInfo, DataStoreGetCourseRecordParam, DataStoreGetCourseRecordResult, + DataStoreUploadCourseRecordParam, +}; use chrono::{NaiveDateTime, Utc}; use futures::TryStreamExt; +use futures::future::join_all; use rnex_core::PID; use rnex_core::executables::common::{ RNEX_DATASTORE_S3_BUCKET, RNEX_DATASTORE_S3_ENDPOINT, get_db, @@ -161,6 +167,8 @@ pub async fn get_object_info_by_data_id( let ratings = get_object_ratings(data_id, password).await?; + // lots of ugly unwraps please fix the db eventually to correctly represent what states it can and cant be in + Ok(map_row_to_meta_info( row.data_id, row.owner.unwrap_or(0), @@ -298,8 +306,9 @@ async fn verify_object_permission( Err(ErrorCode::DataStore_PermissionDenied) } } - 3 => Err(ErrorCode::DataStore_PermissionDenied), // Owner only, redundant - _ => Err(ErrorCode::DataStore_InvalidArgument), // ??? haxx0r + 3 => Err(ErrorCode::DataStore_PermissionDenied), // Owner only, redundant (maple: we should still check if its + // the owner and return true if it is, otherwise the owner would be unable to access their own objects) + _ => Err(ErrorCode::DataStore_InvalidArgument), // ??? haxx0r } } @@ -702,12 +711,12 @@ pub async fn insert_buffer(dataid: i64, slot: i32, buffer: &QBuffer) { db_now, buffer.0 ) - .execute(get_db()) - .await - .map_err(|e| { - log::error!("DB Error: {:?}", e); - ErrorCode::DataStore_NotFound - }); + .execute(get_db()) + .await + .map_err(|e| { + log::error!("DB Error: {:?}", e); + ErrorCode::DataStore_NotFound + }); } impl DataStore for User { @@ -1295,39 +1304,55 @@ impl DataStore for User { _transactional: bool, fetch_ratings: bool, ) -> Result<(Vec, Vec), ErrorCode> { - let mut ratings: Vec = vec![]; let results: Vec = vec![]; - // SMM seems to work fine with this, no clue for other DTSR games - if targets.len() != params.len() { + // this might be good to keep as a sanity check but as long as we zip the two vecs together + // we already avoid crashes which can be caused by this + // (previous comment) SMM seems to work fine with this, no clue for other DTSR games + /*if targets.len() != params.len() { return Err(ErrorCode::DataStore_OperationNotAllowed); - } + }*/ - for (i, target) in targets.into_iter().enumerate() { - let param = ¶ms[i]; + let actions = + targets + .into_iter() + .zip(params.into_iter()) + .map(|(target, param)| async move { + log::info!("Data ID: {:?}", target.dataid); + log::info!("Slot: {:?}", target.slot); + log::info!("Access Password: {:?}", param.access_password); - log::info!("Data ID: {:?}", target.dataid); - log::info!("Slot: {:?}", target.slot); - log::info!("Access Password: {:?}", param.access_password); + let object_info = + get_object_info_by_data_id(target.dataid, param.access_password).await?; + log::info!("object info get complete"); + verify_object_permission(object_info.owner, self.pid, &object_info.permission) + .await?; + log::info!("object permission complete"); - let object_info = - get_object_info_by_data_id(target.dataid, param.access_password).await?; - log::info!("object info get complete"); - verify_object_permission(object_info.owner, self.pid, &object_info.permission).await?; - log::info!("object permission complete"); - let rating = rate_object( - target.dataid, - target.slot, - param.rating_value, - param.access_password, - ) - .await?; - log::info!("rating complete"); + if fetch_ratings { + let rating = rate_object( + target.dataid, + target.slot, + param.rating_value, + param.access_password, + ) + .await?; + log::info!("rating complete"); + Result::, ErrorCode>::Ok(Some(rating)) + } else { + Result::, ErrorCode>::Ok(None) + } + }); - if fetch_ratings { - ratings.push(rating) - } - } + let ratings: Result, ErrorCode> = join_all(actions).await.into_iter().collect(); + let ratings = ratings?; + + let ratings = if fetch_ratings { + ratings.into_iter().filter_map(convert::identity).collect() + } else { + // skip collecting, we already know the vector is empty + vec![] + }; Ok((ratings, results)) } @@ -1609,7 +1634,10 @@ impl DataStore for User { Ok(results) } - async fn get_object_infos(&self, dataids: Vec) -> Result, ErrorCode> { + async fn get_object_infos( + &self, + dataids: Vec, + ) -> Result, ErrorCode> { let mut list = Vec::with_capacity(dataids.len()); for dataid in dataids.into_iter() { let object_info = get_object_info_by_data_id(dataid, 0).await?; @@ -1618,29 +1646,30 @@ impl DataStore for User { &format!("https://{}", *RNEX_DATASTORE_S3_ENDPOINT), format!("{}", *RNEX_DATASTORE_S3_BUCKET), ) - .await; + .await; let key = format!("data/{}.bin", dataid); let download_url = presigner.generate_presigned_get(&key); - list.push( - DataStoreFileServerObjectInfo { + list.push(DataStoreFileServerObjectInfo { + dataid, + get_info: DataStoreReqGetInfo { + url: download_url, + request_headers: vec![], + size: object_info.size, + root_ca_cert: vec![], dataid, - get_info: DataStoreReqGetInfo { - url: download_url, - request_headers: vec![], - size: object_info.size, - root_ca_cert: vec![], - dataid - } - } - ); - }; + }, + }); + } Ok(list) } - async fn check_rate_custom_ranking_counter(&self, application_id: u32) -> Result { + async fn check_rate_custom_ranking_counter( + &self, + application_id: u32, + ) -> Result { // official servers always return true? application ID is always 0 as far as i know. maybe a check is warranted for the app id? Ok(true) } diff --git a/rnex-core/src/nex/user.rs b/rnex-core/src/nex/user.rs index f955fca..723cab3 100644 --- a/rnex-core/src/nex/user.rs +++ b/rnex-core/src/nex/user.rs @@ -40,6 +40,9 @@ use cfg_if::cfg_if; use log::{error, info}; use macros::rmc_struct; use rnex_core::prudp::socket_addr::PRUDPSockAddr; +use rnex_core::rmc::protocols::message_delivery::{ + MessageDelivery, RawMessageDelivery, RawMessageDeliveryInfo, RemoteMessageDelivery, +}; use rnex_core::rmc::protocols::notifications::{NotificationEvent, RemoteNotification}; use rnex_core::rmc::protocols::ranking::{ CompetitionRankingGetParam, CompetitionRankingScoreData, CompetitionRankingScoreInfo, @@ -65,7 +68,8 @@ cfg_if! { NatTraversal, Ranking, Utility, - DataStore + DataStore, + MessageDelivery } ); } else { @@ -922,3 +926,7 @@ impl Ranking for User { Ok(true) } } + +impl MessageDelivery for User { + async fn deliver_message(&self, message: Any) {} +} diff --git a/rnex-core/src/rmc/protocols/message_delivery.rs b/rnex-core/src/rmc/protocols/message_delivery.rs new file mode 100644 index 0000000..f1a11a7 --- /dev/null +++ b/rnex-core/src/rmc/protocols/message_delivery.rs @@ -0,0 +1,9 @@ +use macros::{method_id, rmc_proto}; + +use crate::rmc::{response::ErrorCode, structures::any::Any}; + +#[rmc_proto(27, NoReturn)] +pub trait MessageDelivery { + #[method_id(1)] + async fn deliver_message(&self, message: Any); +} diff --git a/rnex-core/src/rmc/protocols/mod.rs b/rnex-core/src/rmc/protocols/mod.rs index 6f14323..d9e8482 100644 --- a/rnex-core/src/rmc/protocols/mod.rs +++ b/rnex-core/src/rmc/protocols/mod.rs @@ -8,6 +8,7 @@ pub mod friends_wiiu; pub mod matchmake; pub mod matchmake_ext; pub mod matchmake_extension; +pub mod message_delivery; pub mod nat_traversal; pub mod nintendo_notification; pub mod notifications;