progress
Some checks failed
Build and Test / puyopuyo (push) Failing after 26s
Build and Test / splatoon-testfire (push) Failing after 27s
Build and Test / minecraft-wiiu (push) Failing after 2m34s
Build and Test / fast-racing-neo (push) Failing after 2m36s
Build and Test / mario-tennis (push) Failing after 2m38s
Build and Test / splatoon (push) Failing after 2m38s
Build and Test / wii-u-chat (push) Failing after 5m25s
Build and Test / friends (push) Successful in 6m34s
Build and Test / super-mario-maker (push) Failing after 6m43s
Build and Test / sonic-transformed (push) Failing after 6m58s
Build and Test / wii-sports-club (push) Failing after 7m9s
Some checks failed
Build and Test / puyopuyo (push) Failing after 26s
Build and Test / splatoon-testfire (push) Failing after 27s
Build and Test / minecraft-wiiu (push) Failing after 2m34s
Build and Test / fast-racing-neo (push) Failing after 2m36s
Build and Test / mario-tennis (push) Failing after 2m38s
Build and Test / splatoon (push) Failing after 2m38s
Build and Test / wii-u-chat (push) Failing after 5m25s
Build and Test / friends (push) Successful in 6m34s
Build and Test / super-mario-maker (push) Failing after 6m43s
Build and Test / sonic-transformed (push) Failing after 6m58s
Build and Test / wii-sports-club (push) Failing after 7m9s
This commit is contained in:
parent
3f07e45f08
commit
f1d16e40a1
36 changed files with 730 additions and 1392 deletions
|
|
@ -122,13 +122,7 @@ impl Secure for BaseUser {
|
|||
println!("{:?}", station_urls);
|
||||
|
||||
/*
|
||||
let mut users = self.matchmake_manager.users.write().await;
|
||||
users.insert(cid, self.this.clone());
|
||||
drop(users);
|
||||
let mut users = self.matchmake_manager.users_by_pid.write().await;
|
||||
users.insert(self.pid, self.this.clone());
|
||||
drop(users);
|
||||
*/
|
||||
*/
|
||||
|
||||
let stations = get_station_urls(&station_urls, self.addr, self.pid, cid).await?;
|
||||
|
||||
|
|
|
|||
|
|
@ -10,12 +10,10 @@ rnex-base = { path = "../rnex-base" }
|
|||
rnex-base-protos = { path = "../../rnex-protocols/base-protos" }
|
||||
rnex-ds-protos = { path = "../../rnex-protocols/ds-protos" }
|
||||
rnex-server = { path = "../../rnex-server" }
|
||||
sqlx = "0.9.0"
|
||||
sqlx = { version = "0.9.0", features = ["chrono"] }
|
||||
tracing = "0.1.44"
|
||||
thiserror = "2.0.18"
|
||||
chrono = "0.4.45"
|
||||
aws-sdk-s3 = "1.138.0"
|
||||
aws-config = "1.9.0"
|
||||
sha2 = "0.11.0"
|
||||
hmac = "0.13.0"
|
||||
base64 = "0.22.1"
|
||||
|
|
@ -24,5 +22,8 @@ hex = "0.4.3"
|
|||
urlencoding = "2.1.3"
|
||||
futures = "0.3.32"
|
||||
|
||||
[features]
|
||||
datastore = []
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use chrono::Utc;
|
||||
use futures::future::join_all;
|
||||
use futures::{TryStreamExt, future::join_all};
|
||||
use rnex_base::user::BaseUser;
|
||||
use rnex_ds_protos::{
|
||||
LocalDatastoreProtocol,
|
||||
|
|
@ -11,8 +11,8 @@ use rnex_ds_protos::{
|
|||
DataStorePrepareGetParam, DataStoreRateObjectParam, DataStoreRatingTarget,
|
||||
DataStoreReportCourseParam, DataStoreReqGetInfo, DataStoreSearchParam,
|
||||
DataStoreUploadCourseRecordParam, GetMetaInfo, GetMetaParam, KeyValue, Permission,
|
||||
PersistenceTarget, PreparePostParam, RatingInfo, RatingInfoWithSlot,
|
||||
RatingInitParamWithSlot, ReqPostInfo,
|
||||
PersistenceTarget, PreparePostParam, RateCustomRankingParam, RatingInfo,
|
||||
RatingInfoWithSlot, RatingInitParamWithSlot, ReqPostInfo,
|
||||
},
|
||||
};
|
||||
use rnex_rmc::{qbuffer::QBuffer, qresult::QResult, response::ErrorCode, rmc_struct};
|
||||
|
|
@ -20,12 +20,13 @@ use rnex_server::PassthroughInitModule;
|
|||
use rnex_util::{PID, date_time::DateTime};
|
||||
use sqlx::query;
|
||||
use std::convert;
|
||||
use tracing::{error, info, warn};
|
||||
use tracing::{error, info, instrument, warn};
|
||||
|
||||
use crate::{DatastoreManager, s3presigner::S3Presigner};
|
||||
// todo: refactor this further to make some of the helper functions attached to the user and some to
|
||||
// the manager and also move the usages of pid into the helper functions attached to user
|
||||
|
||||
#[derive(Debug)]
|
||||
#[rmc_struct(DatastoreProtocol)]
|
||||
pub struct DatastoreUser {
|
||||
pub base: PassthroughInitModule<BaseUser>,
|
||||
|
|
@ -33,6 +34,7 @@ pub struct DatastoreUser {
|
|||
}
|
||||
|
||||
impl DatastoreUser {
|
||||
#[instrument]
|
||||
fn map_row_to_meta_info(
|
||||
&self,
|
||||
row_data_id: i64,
|
||||
|
|
@ -88,6 +90,7 @@ impl DatastoreUser {
|
|||
}
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
pub async fn check_object_availability(
|
||||
&self,
|
||||
data_id: i64,
|
||||
|
|
@ -121,6 +124,7 @@ impl DatastoreUser {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
pub async fn get_object_ratings(
|
||||
&self,
|
||||
data_id: i64,
|
||||
|
|
@ -158,6 +162,7 @@ impl DatastoreUser {
|
|||
Ok(ratings)
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
pub async fn get_object_info_by_data_id(
|
||||
&self,
|
||||
data_id: i64,
|
||||
|
|
@ -210,6 +215,7 @@ impl DatastoreUser {
|
|||
))
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
async fn get_object_info_by_persistence_target(
|
||||
&self,
|
||||
target: PersistenceTarget,
|
||||
|
|
@ -271,6 +277,7 @@ impl DatastoreUser {
|
|||
))
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
async fn get_buffer_queues_by_data_id_and_slot(
|
||||
&self,
|
||||
data_id: i64,
|
||||
|
|
@ -300,13 +307,13 @@ impl DatastoreUser {
|
|||
Ok(buffer_queues)
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
fn verify_object_permission(
|
||||
&self,
|
||||
owner_id: PID,
|
||||
viewer_id: PID,
|
||||
permission: &Permission,
|
||||
) -> Result<(), ErrorCode> {
|
||||
if owner_id == viewer_id {
|
||||
if owner_id == self.base.pid {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
|
@ -315,7 +322,7 @@ impl DatastoreUser {
|
|||
1 => Err(ErrorCode::DataStore_PermissionDenied), // Friends only, unimplemented
|
||||
2 => {
|
||||
// Recipient IDs can read
|
||||
if permission.recipient_ids.contains(&viewer_id) {
|
||||
if permission.recipient_ids.contains(&self.base.pid) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ErrorCode::DataStore_PermissionDenied)
|
||||
|
|
@ -327,6 +334,7 @@ impl DatastoreUser {
|
|||
}
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
fn filter_properties_by_result_option(&self, meta_info: &mut GetMetaInfo, result_option: u8) {
|
||||
if (result_option & 0x01) == 0 {
|
||||
meta_info.meta_binary = QBuffer(Vec::new());
|
||||
|
|
@ -339,6 +347,7 @@ impl DatastoreUser {
|
|||
// No idea what the other things do. :shrug:
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
async fn init_object_rating_slot(&self, data_id: i64, rating_param: RatingInitParamWithSlot) {
|
||||
info!("running init object rating slot");
|
||||
sqlx::query!(
|
||||
|
|
@ -376,11 +385,12 @@ impl DatastoreUser {
|
|||
.map_err(|e| {
|
||||
error!("DB Error: {:?}", e);
|
||||
ErrorCode::DataStore_NotFound
|
||||
});
|
||||
})?;
|
||||
info!("done running");
|
||||
}
|
||||
|
||||
// Dawg...
|
||||
#[instrument]
|
||||
async fn get_custom_rankings_by_data_ids(
|
||||
&self,
|
||||
application_id: u32,
|
||||
|
|
@ -431,6 +441,7 @@ impl DatastoreUser {
|
|||
results
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
async fn get_user_course_object_ids(&self, owner_pid: PID) -> Result<Vec<i64>, ErrorCode> {
|
||||
let rows = sqlx::query!(
|
||||
r#"
|
||||
|
|
@ -459,6 +470,7 @@ impl DatastoreUser {
|
|||
Ok(valid_ids)
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
fn get_blacklist_1(&self) -> Vec<String> {
|
||||
vec![
|
||||
"けされ",
|
||||
|
|
@ -533,6 +545,7 @@ impl DatastoreUser {
|
|||
.collect()
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
fn get_blacklist_2(&self) -> Vec<String> {
|
||||
vec![
|
||||
"ゼロから",
|
||||
|
|
@ -548,6 +561,7 @@ impl DatastoreUser {
|
|||
.collect()
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
fn get_blacklist_3(&self) -> Vec<String> {
|
||||
vec![
|
||||
"いいね",
|
||||
|
|
@ -617,6 +631,7 @@ impl DatastoreUser {
|
|||
.collect()
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
// couldn't find a better way to do this im going crazyy
|
||||
async fn rate_object(
|
||||
&self,
|
||||
|
|
@ -651,6 +666,7 @@ impl DatastoreUser {
|
|||
Ok(rating)
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
async fn change_meta_object_check(
|
||||
&self,
|
||||
param: &DataStoreChangeMetaParam,
|
||||
|
|
@ -679,6 +695,7 @@ impl DatastoreUser {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
async fn get_rating_with_slot_data_id(
|
||||
&self,
|
||||
dataid: i64,
|
||||
|
|
@ -713,6 +730,7 @@ impl DatastoreUser {
|
|||
Ok(ratings)
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
pub async fn insert_buffer(&self, dataid: i64, slot: i32, buffer: &QBuffer) {
|
||||
let db_now = Utc::now().naive_utc();
|
||||
|
||||
|
|
@ -756,8 +774,7 @@ impl DataStore for DatastoreUser {
|
|||
.await?
|
||||
};
|
||||
|
||||
let current_pid = self.pid;
|
||||
self.verify_object_permission(meta_info.owner, current_pid, &meta_info.permission)?;
|
||||
self.verify_object_permission(meta_info.owner, &meta_info.permission)?;
|
||||
|
||||
self.filter_properties_by_result_option(&mut meta_info, metaparam.result_option);
|
||||
|
||||
|
|
@ -794,7 +811,7 @@ impl DataStore for DatastoreUser {
|
|||
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17
|
||||
) RETURNING data_id
|
||||
"#,
|
||||
self.pid as i32,
|
||||
self.base.pid as i32,
|
||||
postparam.size as i32,
|
||||
postparam.name,
|
||||
postparam.data_type as i32,
|
||||
|
|
@ -815,7 +832,7 @@ impl DataStore for DatastoreUser {
|
|||
.fetch_one(&self.dm.db_pool)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
log::error!("DB Error: {:?}", e);
|
||||
error!("DB Error: {:?}", e);
|
||||
ErrorCode::DataStore_NotFound
|
||||
})?;
|
||||
|
||||
|
|
@ -998,7 +1015,7 @@ impl DataStore for DatastoreUser {
|
|||
],
|
||||
10 => vec![35, 75, 96, 40, 5, 6],
|
||||
_ => {
|
||||
log::error!("unknown SMM app id: {}", appid);
|
||||
error!("unknown SMM app id: {}", appid);
|
||||
return Err(ErrorCode::DataStore_Unknown);
|
||||
}
|
||||
};
|
||||
|
|
@ -1081,7 +1098,7 @@ impl DataStore for DatastoreUser {
|
|||
};
|
||||
|
||||
info!("verifying object permission");
|
||||
self.verify_object_permission(meta_info.owner, self.base.pid, &meta_info.permission)?;
|
||||
self.verify_object_permission(meta_info.owner, &meta_info.permission)?;
|
||||
|
||||
let key = format!("data/{}.bin", meta_info.dataid);
|
||||
let download_url = self.dm.s3_presigner.generate_presigned_get(&key);
|
||||
|
|
@ -1123,8 +1140,7 @@ impl DataStore for DatastoreUser {
|
|||
res.meta_info.ratings = Vec::new();
|
||||
}
|
||||
if course_search_param.result_option & 0x4 == 0 {
|
||||
res.meta_info.meta_binary =
|
||||
rnex_core::rmc::structures::qbuffer::QBuffer(Vec::new());
|
||||
res.meta_info.meta_binary = QBuffer(Vec::new());
|
||||
}
|
||||
if course_search_param.result_option & 0x20 == 0 {
|
||||
res.score = 0;
|
||||
|
|
@ -1180,9 +1196,7 @@ impl DataStore for DatastoreUser {
|
|||
|
||||
match info_result {
|
||||
Ok(mut meta) => {
|
||||
if let Err(e) =
|
||||
self.verify_object_permission(meta.owner, self.base.pid, &meta.permission)
|
||||
{
|
||||
if let Err(e) = self.verify_object_permission(meta.owner, &meta.permission) {
|
||||
metas.push(GetMetaInfo::default());
|
||||
results.push(QResult::error(e));
|
||||
} else {
|
||||
|
|
@ -1255,7 +1269,7 @@ impl DataStore for DatastoreUser {
|
|||
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17
|
||||
) RETURNING data_id
|
||||
"#,
|
||||
self.pid as i32,
|
||||
self.base.pid as i32,
|
||||
param.post_param.size as i32,
|
||||
param.post_param.name,
|
||||
param.post_param.data_type as i32,
|
||||
|
|
@ -1349,11 +1363,7 @@ impl DataStore for DatastoreUser {
|
|||
.get_object_info_by_data_id(target.dataid, param.access_password)
|
||||
.await?;
|
||||
info!("object info get complete");
|
||||
self.verify_object_permission(
|
||||
object_info.owner,
|
||||
self.base.pid,
|
||||
&object_info.permission,
|
||||
)?;
|
||||
self.verify_object_permission(object_info.owner, &object_info.permission)?;
|
||||
info!("object permission complete");
|
||||
|
||||
if fetch_ratings {
|
||||
|
|
@ -1386,11 +1396,11 @@ impl DataStore for DatastoreUser {
|
|||
}
|
||||
|
||||
async fn change_meta(&self, param: DataStoreChangeMetaParam) -> Result<(), ErrorCode> {
|
||||
let object_info = get_object_info_by_data_id(param.dataid, 0).await?;
|
||||
verify_object_permission(object_info.owner, self.pid, &object_info.permission).await?;
|
||||
let object_info = self.get_object_info_by_data_id(param.dataid, 0).await?;
|
||||
self.verify_object_permission(object_info.owner, &object_info.permission)?;
|
||||
|
||||
if param.modifies_flag & 0x08 != 0 {
|
||||
change_meta_object_check(¶m).await?;
|
||||
self.change_meta_object_check(¶m).await?;
|
||||
|
||||
sqlx::query!(
|
||||
r#"UPDATE datastore.objects SET period=$1 WHERE data_id=$2"#,
|
||||
|
|
@ -1406,7 +1416,7 @@ impl DataStore for DatastoreUser {
|
|||
}
|
||||
|
||||
if param.modifies_flag & 0x10 != 0 {
|
||||
change_meta_object_check(¶m).await?;
|
||||
self.change_meta_object_check(¶m).await?;
|
||||
|
||||
sqlx::query!(
|
||||
r#"UPDATE datastore.objects SET meta_binary=$1 WHERE data_id=$2"#,
|
||||
|
|
@ -1422,7 +1432,7 @@ impl DataStore for DatastoreUser {
|
|||
}
|
||||
|
||||
if param.modifies_flag & 0x80 != 0 {
|
||||
change_meta_object_check(¶m).await?;
|
||||
self.change_meta_object_check(¶m).await?;
|
||||
|
||||
sqlx::query!(
|
||||
r#"UPDATE datastore.objects SET data_type=$1 WHERE data_id=$2"#,
|
||||
|
|
@ -1583,8 +1593,8 @@ impl DataStore for DatastoreUser {
|
|||
"#,
|
||||
upload_course_record_param.dataid,
|
||||
upload_course_record_param.slot as i16,
|
||||
self.pid,
|
||||
self.pid,
|
||||
self.base.pid,
|
||||
self.base.pid,
|
||||
upload_course_record_param.score,
|
||||
now,
|
||||
now
|
||||
|
|
@ -1641,7 +1651,7 @@ impl DataStore for DatastoreUser {
|
|||
) -> Result<Vec<QResult>, ErrorCode> {
|
||||
let mut results = Vec::new();
|
||||
|
||||
let client_pid = self.pid;
|
||||
let client_pid = self.base.pid;
|
||||
|
||||
for (param, buffer) in bufferparam.iter().zip(buffers.iter()) {
|
||||
if param.slot == 0 {
|
||||
|
|
@ -1713,7 +1723,7 @@ impl DataStore for DatastoreUser {
|
|||
)
|
||||
"#,
|
||||
report_course_param.dataid,
|
||||
self.pid,
|
||||
self.base.pid,
|
||||
report_course_param.report_category as i16,
|
||||
report_course_param.report_reason
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#![cfg(feature = "datastore")]
|
||||
use std::env;
|
||||
|
||||
use rnex_server::{ConnectionInitData, RnexManager, RnexModule};
|
||||
|
|
@ -9,20 +10,21 @@ use crate::{datastore::DatastoreUser, s3presigner::S3Presigner};
|
|||
pub mod datastore;
|
||||
pub(crate) mod s3presigner;
|
||||
|
||||
struct DatastoreManager {
|
||||
#[derive(Debug)]
|
||||
pub struct DatastoreManager {
|
||||
db_pool: PgPool,
|
||||
s3_presigner: S3Presigner,
|
||||
}
|
||||
struct DatastoreModule;
|
||||
pub struct DatastoreModule;
|
||||
impl RnexManager for DatastoreManager {
|
||||
type User = DatastoreUser;
|
||||
type InitData = ConnectionInitData;
|
||||
async fn init_new_user(
|
||||
this: rnex_server::PassthroughInitModule<Self>,
|
||||
mod_holder: &rnex_server::ModuleHolder,
|
||||
remote: &rnex_rmc::RmcConnection,
|
||||
init_data: &Self::InitData,
|
||||
weak_user: rnex_server::WeakPassthroughInitModule<Self::User>,
|
||||
_: &rnex_rmc::RmcConnection,
|
||||
_: &Self::InitData,
|
||||
_: rnex_server::WeakPassthroughInitModule<Self::User>,
|
||||
) -> Self::User {
|
||||
DatastoreUser {
|
||||
dm: this,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use hmac::{Hmac, KeyInit, Mac};
|
|||
use serde_json::json;
|
||||
use sha2::{Digest, Sha256};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct S3Presigner {
|
||||
endpoint: String,
|
||||
bucket: String,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,22 @@ version = "0.1.0"
|
|||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
bytemuck = { version = "1.25.1", features = ["derive"] }
|
||||
rnex-rmc = { path = "../../rnex-rmc" }
|
||||
rnex-util = { path = "../../rnex-util" }
|
||||
rnex-fpd-protos = { path = "../../rnex-protocols/fpd-protos" }
|
||||
rnex-base = { path = "../rnex-base" }
|
||||
rnex-server = { path = "../../rnex-server" }
|
||||
tokio = { version = "1.52.3", features = ["sync"] }
|
||||
rand = "0.10.2"
|
||||
tracing = "0.1.44"
|
||||
sqlx = { version = "0.9.0", features = ["chrono"] }
|
||||
chrono = "0.4.45"
|
||||
hmac = "0.13.0"
|
||||
md-5 = "0.11.0"
|
||||
nex-account = { version = "0.2.4", registry = "spbr" }
|
||||
hex = "0.4.3"
|
||||
thiserror = "2.0.18"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
|
|
|||
1649
rnex-server-nex-modules/rnex-fpd/src/friends_handler.rs
Normal file
1649
rnex-server-nex-modules/rnex-fpd/src/friends_handler.rs
Normal file
File diff suppressed because it is too large
Load diff
102
rnex-server-nex-modules/rnex-fpd/src/lib.rs
Normal file
102
rnex-server-nex-modules/rnex-fpd/src/lib.rs
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
use crate::friends_handler::{FriendsGuest, FriendsUser};
|
||||
use nex_account::GUEST_PID;
|
||||
use rnex_fpd_protos::RemoteFriendRemote;
|
||||
use rnex_rmc::{RmcCallable, RmcPureRemoteObject};
|
||||
use rnex_server::{ConnectionInitData, RnexManager, RnexModule, WeakPassthroughInitModule};
|
||||
use rnex_util::PID;
|
||||
use sqlx::PgPool;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
env,
|
||||
sync::{Arc, Weak, atomic::AtomicU32},
|
||||
};
|
||||
use thiserror::Error;
|
||||
use tokio::sync::RwLock;
|
||||
pub mod friends_handler;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum ModuleInitError {
|
||||
#[error(transparent)]
|
||||
Sqlx(#[from] sqlx::Error),
|
||||
#[error(transparent)]
|
||||
Env(#[from] env::VarError),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum FriendsMaybeGuest {
|
||||
Guest(FriendsGuest),
|
||||
User(Arc<FriendsUser>),
|
||||
}
|
||||
|
||||
impl RmcCallable for FriendsMaybeGuest {
|
||||
async fn rmc_call(
|
||||
&self,
|
||||
responder: &rnex_util::SendingBufferConnection,
|
||||
protocol_id: u16,
|
||||
method_id: u32,
|
||||
call_id: u32,
|
||||
rest: &[u8],
|
||||
) -> bool {
|
||||
match self {
|
||||
FriendsMaybeGuest::Guest(friends_guest) => {
|
||||
friends_guest
|
||||
.rmc_call(responder, protocol_id, method_id, call_id, rest)
|
||||
.await
|
||||
}
|
||||
FriendsMaybeGuest::User(friends_user) => {
|
||||
friends_user
|
||||
.rmc_call(responder, protocol_id, method_id, call_id, rest)
|
||||
.await
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FriendsManager {
|
||||
pub users: RwLock<HashMap<PID, Weak<FriendsUser>>>,
|
||||
pub db: PgPool,
|
||||
}
|
||||
|
||||
pub struct FriendsModule;
|
||||
|
||||
impl RnexManager for FriendsManager {
|
||||
type InitData = ConnectionInitData;
|
||||
type User = FriendsMaybeGuest;
|
||||
|
||||
async fn init_new_user(
|
||||
mgr: rnex_server::PassthroughInitModule<Self>,
|
||||
mod_holder: &rnex_server::ModuleHolder,
|
||||
remote: &rnex_rmc::RmcConnection,
|
||||
init_data: &Self::InitData,
|
||||
weak_user: WeakPassthroughInitModule<Self::User>,
|
||||
) -> Self::User {
|
||||
if init_data.pid == GUEST_PID {
|
||||
return FriendsMaybeGuest::Guest(FriendsGuest);
|
||||
}
|
||||
FriendsMaybeGuest::User(Arc::new_cyclic(|this| FriendsUser {
|
||||
fm: mgr,
|
||||
pid: init_data.pid,
|
||||
friend_pids: Default::default(),
|
||||
maybe_remote_friend: Default::default(),
|
||||
presence: Default::default(),
|
||||
this: this.clone(),
|
||||
remote: RemoteFriendRemote::new(remote.clone()),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl RnexModule for FriendsModule {
|
||||
type Manager = FriendsManager;
|
||||
|
||||
type InitError = ModuleInitError;
|
||||
|
||||
async fn create_manager(
|
||||
mod_holder: &rnex_server::ModuleHolder,
|
||||
) -> Result<Self::Manager, Self::InitError> {
|
||||
Ok(FriendsManager {
|
||||
users: Default::default(),
|
||||
db: PgPool::connect(&env::var("RNEX_DATASTORE_DATABASE")?).await?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
||||
|
|
@ -4,6 +4,9 @@ version = "0.1.0"
|
|||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
|
||||
rnex-rmc = { path = "../../rnex-rmc" }
|
||||
rnex-msg-protos = { path = "../../rnex-protocols/msg-protos" }
|
||||
rnex-server = { path = "../../rnex-server" }
|
||||
tokio = { version = "1.52.3", features = ["sync"] }
|
||||
[lints]
|
||||
workspace = true
|
||||
|
|
|
|||
40
rnex-server-nex-modules/rnex-msg/src/lib.rs
Normal file
40
rnex-server-nex-modules/rnex-msg/src/lib.rs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use rnex_msg_protos::RemoteMessagingClient;
|
||||
use rnex_rmc::{RmcPureRemoteObject, util::PID};
|
||||
use rnex_server::{ConnectionInitData, RnexManager, WeakPassthroughInitModule};
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use crate::user::MessagingUser;
|
||||
|
||||
pub mod user;
|
||||
|
||||
pub struct MessagingManager {
|
||||
users_by_pid: RwLock<HashMap<PID, WeakPassthroughInitModule<MessagingUser>>>,
|
||||
}
|
||||
|
||||
pub struct MessagingModule;
|
||||
|
||||
impl RnexManager for MessagingManager {
|
||||
type User = MessagingUser;
|
||||
|
||||
type InitData = ConnectionInitData;
|
||||
|
||||
async fn init_new_user(
|
||||
this: rnex_server::PassthroughInitModule<Self>,
|
||||
mod_holder: &rnex_server::ModuleHolder,
|
||||
remote: &rnex_rmc::RmcConnection,
|
||||
init_data: &Self::InitData,
|
||||
weak_user: rnex_server::WeakPassthroughInitModule<Self::User>,
|
||||
) -> Self::User {
|
||||
this.users_by_pid
|
||||
.write()
|
||||
.await
|
||||
.insert(init_data.pid, weak_user);
|
||||
MessagingUser {
|
||||
msgm: this,
|
||||
pid: init_data.pid,
|
||||
remote: RemoteMessagingClient::new(remote.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
||||
|
|
@ -1,16 +1,32 @@
|
|||
impl MessageDelivery for User {
|
||||
use crate::MessagingManager;
|
||||
use rnex_msg_protos::message_delivery::RemoteMessageDeliveryNoResponse;
|
||||
use rnex_msg_protos::{
|
||||
LocalMessagingProtocol, RemoteMessagingClient, message_delivery::MessageDelivery,
|
||||
messaging::UserMessage,
|
||||
};
|
||||
use rnex_rmc::{any::Any, response::ErrorCode, rmc_struct, util::PID};
|
||||
use rnex_server::{PassthroughInitModule, WeakPassthroughInitModule};
|
||||
|
||||
#[rmc_struct(MessagingProtocol)]
|
||||
pub struct MessagingUser {
|
||||
pub msgm: PassthroughInitModule<MessagingManager>,
|
||||
pub pid: PID,
|
||||
pub remote: RemoteMessagingClient,
|
||||
}
|
||||
|
||||
impl MessageDelivery for MessagingUser {
|
||||
async fn deliver_message(&self, mut message: Any<UserMessage>) -> Result<(), ErrorCode> {
|
||||
let mut msg = message.get()?;
|
||||
|
||||
let _users = match msg.recipient_type {
|
||||
1 => {
|
||||
let Some(user) = self
|
||||
.matchmake_manager
|
||||
.msgm
|
||||
.users_by_pid
|
||||
.read()
|
||||
.await
|
||||
.get(&msg.recipient_id)
|
||||
.map(Weak::upgrade)
|
||||
.map(WeakPassthroughInitModule::upgrade)
|
||||
.flatten()
|
||||
else {
|
||||
return Err(ErrorCode::Core_InvalidArgument);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,15 @@ version = "0.1.0"
|
|||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
rnex-rmc = { path = "../../rnex-rmc" }
|
||||
rnex-util = { path = "../../rnex-util" }
|
||||
rnex-rk-protos = { path = "../../rnex-protocols/rk-protos" }
|
||||
rnex-server = { path = "../../rnex-server" }
|
||||
serde = { version = "1.0.228", features = ["derive"] }
|
||||
tracing = "0.1.44"
|
||||
ureq = { version = "3.3.0", features = ["json"] }
|
||||
tokio = { version = "1.52.3", features = ["rt"] }
|
||||
serde_json = "1.0.150"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
|
|
|||
86
rnex-server-nex-modules/rnex-rk/src/lib.rs
Normal file
86
rnex-server-nex-modules/rnex-rk/src/lib.rs
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
use std::env::{self, VarError};
|
||||
|
||||
use rnex_rmc::response::ErrorCode;
|
||||
use rnex_server::{ConnectionInitData, RnexManager, RnexModule};
|
||||
use std::str::FromStr;
|
||||
use tracing::error;
|
||||
|
||||
use crate::user::RankingUser;
|
||||
|
||||
pub mod user;
|
||||
|
||||
pub struct RankingManager {
|
||||
rnex_result_get: String,
|
||||
rnex_result_votes_get: String,
|
||||
rnex_result_post: String,
|
||||
}
|
||||
|
||||
pub struct RankingModule;
|
||||
|
||||
impl RankingManager {
|
||||
// Seperate function because I cannot give a fuck right now
|
||||
async fn fetch_team_votes(&self, fest_id: u32) -> Result<Vec<u32>, ErrorCode> {
|
||||
let url_votes = format!("{}?splatfest_id={}", self.rnex_result_votes_get, fest_id);
|
||||
let Ok(response) = tokio::task::spawn_blocking(move || {
|
||||
ureq::get(&url_votes).call().map_err(|e| {
|
||||
error!("GET for votes failed: {:?}", e);
|
||||
ErrorCode::RendezVous_InvalidConfiguration
|
||||
})
|
||||
})
|
||||
.await
|
||||
else {
|
||||
error!("failed to make request");
|
||||
return Err(ErrorCode::Core_Exception);
|
||||
};
|
||||
|
||||
let mut response = response?;
|
||||
|
||||
let body = response.body_mut().read_to_string().map_err(|e| {
|
||||
error!("failed to read votes body: {:?}", e);
|
||||
ErrorCode::RendezVous_InvalidConfiguration
|
||||
})?;
|
||||
|
||||
let body = body.trim().trim_start_matches('[').trim_end_matches(']');
|
||||
let votes: Result<Vec<u32>, _> = body.split(',').map(|s| u32::from_str(s.trim())).collect();
|
||||
|
||||
votes.map_err(|e| {
|
||||
error!("failed to parse votes: {:?}", e);
|
||||
ErrorCode::RendezVous_InvalidConfiguration
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl RnexManager for RankingManager {
|
||||
type User = RankingUser;
|
||||
|
||||
type InitData = ConnectionInitData;
|
||||
|
||||
async fn init_new_user(
|
||||
this: rnex_server::PassthroughInitModule<Self>,
|
||||
mod_holder: &rnex_server::ModuleHolder,
|
||||
remote: &rnex_rmc::RmcConnection,
|
||||
init_data: &Self::InitData,
|
||||
weak_user: rnex_server::WeakPassthroughInitModule<Self::User>,
|
||||
) -> Self::User {
|
||||
RankingUser {
|
||||
rm: this,
|
||||
pid: init_data.pid,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RnexModule for RankingModule {
|
||||
type Manager = RankingManager;
|
||||
|
||||
type InitError = VarError;
|
||||
|
||||
async fn create_manager(
|
||||
_: &rnex_server::ModuleHolder,
|
||||
) -> Result<Self::Manager, Self::InitError> {
|
||||
Ok(RankingManager {
|
||||
rnex_result_votes_get: env::var("RNEX_SPLATOON_RESULTS_VOTES_GET")?,
|
||||
rnex_result_post: env::var("RNEX_SPLATOON_RESULTS_POST")?,
|
||||
rnex_result_get: env::var("RNEX_SPLATOON_RESULTS_GET")?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
||||
|
|
@ -1,3 +1,25 @@
|
|||
use rnex_rk_protos::{
|
||||
LocalRankingProtocol,
|
||||
ranking::{
|
||||
CompetitionRankingGetParam, CompetitionRankingScoreData, CompetitionRankingScoreInfo,
|
||||
Ranking, UploadCompetitionData,
|
||||
},
|
||||
};
|
||||
use rnex_rmc::{qbuffer::QBuffer, response::ErrorCode, rmc_struct};
|
||||
use rnex_server::PassthroughInitModule;
|
||||
use rnex_util::{PID, date_time::DateTime};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{env, str::FromStr};
|
||||
use tracing::{error, info};
|
||||
|
||||
use crate::RankingManager;
|
||||
|
||||
#[rmc_struct(RankingProtocol)]
|
||||
pub struct RankingUser {
|
||||
pub rm: PassthroughInitModule<RankingManager>,
|
||||
pub pid: PID,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct CompetitionPostResults {
|
||||
pub splatfest_id: u32,
|
||||
|
|
@ -7,50 +29,20 @@ pub struct CompetitionPostResults {
|
|||
pub user: PID,
|
||||
}
|
||||
|
||||
// Seperate function because I cannot give a fuck right now
|
||||
async fn fetch_team_votes(fest_id: u32) -> Result<Vec<u32>, ErrorCode> {
|
||||
let endpoint_votes = env::var("RNEX_SPLATOON_RESULTS_VOTES_GET").map_err(|_| {
|
||||
error!("RNEX_SPLATOON_RESULTS_VOTES_GET not set");
|
||||
ErrorCode::RendezVous_InvalidConfiguration
|
||||
})?;
|
||||
|
||||
let url_votes = format!("{}?splatfest_id={}", endpoint_votes, fest_id);
|
||||
let mut response = tokio::task::spawn_blocking(|| {
|
||||
ureq::get(&url_votes).call().map_err(|e| {
|
||||
error!("GET for votes failed: {:?}", e);
|
||||
ErrorCode::RendezVous_InvalidConfiguration
|
||||
})
|
||||
})
|
||||
.await?;
|
||||
|
||||
let body = response.body_mut().read_to_string().map_err(|e| {
|
||||
error!("failed to read votes body: {:?}", e);
|
||||
ErrorCode::RendezVous_InvalidConfiguration
|
||||
})?;
|
||||
|
||||
let body = body.trim().trim_start_matches('[').trim_end_matches(']');
|
||||
let votes: Result<Vec<u32>, _> = body.split(',').map(|s| u32::from_str(s.trim())).collect();
|
||||
|
||||
votes.map_err(|e| {
|
||||
error!("failed to parse votes: {:?}", e);
|
||||
ErrorCode::RendezVous_InvalidConfiguration
|
||||
})
|
||||
}
|
||||
|
||||
impl Ranking for User {
|
||||
impl Ranking for RankingUser {
|
||||
async fn competition_ranking_get_param(
|
||||
&self,
|
||||
param: CompetitionRankingGetParam,
|
||||
) -> Result<Vec<CompetitionRankingScoreInfo>, ErrorCode> {
|
||||
let fest_id = param.festival_ids.get(0).copied().unwrap_or(0);
|
||||
|
||||
let endpoint_results = env::var("RNEX_SPLATOON_RESULTS_GET").map_err(|_| {
|
||||
error!("RNEX_SPLATOON_RESULTS_GET not set");
|
||||
ErrorCode::RendezVous_InvalidConfiguration
|
||||
})?;
|
||||
|
||||
let url_results = format!("{}?splatfest_id={}", endpoint_results, fest_id);
|
||||
let response_results = ureq::get(&url_results).call();
|
||||
let url_results = format!("{}?splatfest_id={}", self.rm.rnex_result_get, fest_id);
|
||||
let Ok(response_results) =
|
||||
tokio::task::spawn_blocking(move || ureq::get(&url_results).call()).await
|
||||
else {
|
||||
error!("failed to join task");
|
||||
return Err(ErrorCode::Core_Exception);
|
||||
};
|
||||
|
||||
let results: Vec<CompetitionPostResults> = match response_results {
|
||||
Ok(mut res) => res.body_mut().read_json().map_err(|e| {
|
||||
|
|
@ -69,7 +61,7 @@ impl Ranking for User {
|
|||
let start = offset.min(results.len());
|
||||
let end = (start + size).min(results.len());
|
||||
|
||||
let team_votes = fetch_team_votes(fest_id)?;
|
||||
let team_votes = self.rm.fetch_team_votes(fest_id).await?;
|
||||
let mut wins = vec![0u32, 0u32];
|
||||
for r in &results {
|
||||
let won_team = (r.team_id ^ (!r.team_win)) & 1;
|
||||
|
|
@ -84,7 +76,7 @@ impl Ranking for User {
|
|||
unk: 1,
|
||||
pid: r.user,
|
||||
score: r.score,
|
||||
modified: KerberosDateTime::now(),
|
||||
modified: DateTime::now(),
|
||||
unk2: 1,
|
||||
appdata: QBuffer(vec![]),
|
||||
})
|
||||
|
|
@ -113,14 +105,6 @@ impl Ranking for User {
|
|||
info!("team id: {:?}", param.team_id);
|
||||
info!("did current team win: {:?}", param.team_win);
|
||||
|
||||
let endpoint = match env::var("RNEX_SPLATOON_RESULTS_POST") {
|
||||
Ok(url) => url,
|
||||
Err(_) => {
|
||||
error!("RNEX_SPLATOON_RESULTS_POST not set");
|
||||
return Ok(false);
|
||||
}
|
||||
};
|
||||
|
||||
let payload = CompetitionPostResults {
|
||||
splatfest_id: param.splatfest_id,
|
||||
score: param.score,
|
||||
|
|
@ -137,9 +121,18 @@ impl Ranking for User {
|
|||
}
|
||||
};
|
||||
|
||||
let response = ureq::post(&endpoint)
|
||||
.header("Content-Type", "application/json")
|
||||
.send(json_body);
|
||||
let rm = self.rm.clone();
|
||||
|
||||
let Ok(response) = tokio::task::spawn_blocking(move || {
|
||||
ureq::post(&rm.rnex_result_post)
|
||||
.header("Content-Type", "application/json")
|
||||
.send(json_body)
|
||||
})
|
||||
.await
|
||||
else {
|
||||
error!("unable to spawn blocking");
|
||||
return Err(ErrorCode::Core_Exception);
|
||||
};
|
||||
|
||||
match response {
|
||||
Ok(res) => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue