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
1079
Cargo.lock
generated
1079
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -13,6 +13,8 @@ prudpv1 = { path = "../prudpv1", optional = true }
|
||||||
proxy-common = { path = "../proxy-common" }
|
proxy-common = { path = "../proxy-common" }
|
||||||
cfg-if = "1.0.4"
|
cfg-if = "1.0.4"
|
||||||
rnex-prudp = { path = "../rnex-prudp" }
|
rnex-prudp = { path = "../rnex-prudp" }
|
||||||
|
rnex-server = { path = "../rnex-server" }
|
||||||
|
tracing = "0.1.44"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
prudpv0 = ["dep:prudpv0"]
|
prudpv0 = ["dep:prudpv0"]
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use proxy::edge_node_dc_callback;
|
use proxy::edge_node_dc_callback;
|
||||||
use proxy_common::{ProxyStartupParam, setup_edge_node_connection};
|
use proxy_common::{ProxyStartupParam, setup_edge_node_connection};
|
||||||
use rnex_core::common::with_setup;
|
use rnex_server::with_setup;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
|
|
@ -11,6 +11,7 @@ async fn main() {
|
||||||
setup_edge_node_connection(¶m, edge_node_dc_callback).await;
|
setup_edge_node_connection(¶m, edge_node_dc_callback).await;
|
||||||
|
|
||||||
proxy::start_insecure(param).await;
|
proxy::start_insecure(param).await;
|
||||||
|
Ok(())
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use std::process::abort;
|
use std::process::abort;
|
||||||
|
|
||||||
use cfg_if::cfg_if;
|
use cfg_if::cfg_if;
|
||||||
use log::error;
|
use tracing::error;
|
||||||
|
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(feature = "prudpv0")]{
|
if #[cfg(feature = "prudpv0")]{
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use proxy::edge_node_dc_callback;
|
use proxy::edge_node_dc_callback;
|
||||||
use proxy_common::{ProxyStartupParam, setup_edge_node_connection};
|
use proxy_common::{ProxyStartupParam, setup_edge_node_connection};
|
||||||
use rnex_core::common::with_setup;
|
use rnex_server::with_setup;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
|
|
@ -10,6 +10,7 @@ async fn main() {
|
||||||
|
|
||||||
setup_edge_node_connection(¶m, edge_node_dc_callback).await;
|
setup_edge_node_connection(¶m, edge_node_dc_callback).await;
|
||||||
proxy::start_secure(param).await;
|
proxy::start_secure(param).await;
|
||||||
|
Ok(())
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,14 +8,17 @@ workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rnex-prudp = { path = "../rnex-prudp" }
|
rnex-prudp = { path = "../rnex-prudp" }
|
||||||
|
rnex-util = { path = "../rnex-util" }
|
||||||
|
rnex-rmc = { path = "../rnex-rmc" }
|
||||||
tokio = { version = "1.47.0", features = ["full"] }
|
tokio = { version = "1.47.0", features = ["full"] }
|
||||||
bytemuck = { version = "1.23.1", features = ["derive"] }
|
bytemuck = { version = "1.23.1", features = ["derive"] }
|
||||||
typenum = "1.18.0"
|
typenum = "1.18.0"
|
||||||
rc4 = "0.1.0"
|
rc4 = "0.2.0"
|
||||||
cfg-if = "1.0.4"
|
cfg-if = "1.0.4"
|
||||||
proxy-common = {path = "../proxy-common"}
|
proxy-common = {path = "../proxy-common"}
|
||||||
hmac = "0.12.1"
|
hmac = "0.13.0"
|
||||||
md-5 = "^0.10.6"
|
md-5 = "0.11.0"
|
||||||
|
tracing = "0.1.44"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
prudpv0 = []
|
prudpv0 = []
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,11 @@ use std::io::Write;
|
||||||
use hmac::Mac;
|
use hmac::Mac;
|
||||||
use md5::{Digest, Md5};
|
use md5::{Digest, Md5};
|
||||||
use rc4::{KeyInit, Rc4, StreamCipher};
|
use rc4::{KeyInit, Rc4, StreamCipher};
|
||||||
use rnex_core::{
|
use rnex_prudp::{
|
||||||
PID,
|
encryption::{DEFAULT_KEY, EncryptionPair},
|
||||||
prudp::{
|
types_flags::{TypesFlags, types::DATA},
|
||||||
encryption::{DEFAULT_KEY, EncryptionPair},
|
|
||||||
types_flags::{TypesFlags, types::DATA},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
use rnex_util::PID;
|
||||||
use typenum::U5;
|
use typenum::U5;
|
||||||
|
|
||||||
use crate::crypto::{
|
use crate::crypto::{
|
||||||
|
|
@ -19,7 +17,7 @@ use crate::crypto::{
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct InsecureInstance {
|
pub struct InsecureInstance {
|
||||||
pair: EncryptionPair<Rc4<U5>>,
|
pair: EncryptionPair<Rc4>,
|
||||||
self_signat: [u8; 4],
|
self_signat: [u8; 4],
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
remote_signat: [u8; 4],
|
remote_signat: [u8; 4],
|
||||||
|
|
@ -41,8 +39,8 @@ impl CryptoInstance for InsecureInstance {
|
||||||
[0x78, 0x56, 0x34, 0x12]
|
[0x78, 0x56, 0x34, 0x12]
|
||||||
} else {
|
} else {
|
||||||
let mut hash = Md5::new();
|
let mut hash = Md5::new();
|
||||||
hash.write(ACCESS_KEY.as_bytes()).unwrap();
|
hash.update(ACCESS_KEY.as_bytes());
|
||||||
let mut hmac = <HmacMd5 as Mac>::new_from_slice(&hash.finalize().as_slice())
|
let mut hmac = HmacMd5::new_from_slice(&hash.finalize().as_slice())
|
||||||
.expect("unable to create hmac md5");
|
.expect("unable to create hmac md5");
|
||||||
hmac.update(data);
|
hmac.update(data);
|
||||||
hmac.finalize().into_bytes()[0..4].try_into().unwrap()
|
hmac.finalize().into_bytes()[0..4].try_into().unwrap()
|
||||||
|
|
@ -57,7 +55,7 @@ pub struct Insecure();
|
||||||
|
|
||||||
impl Crypto for Insecure {
|
impl Crypto for Insecure {
|
||||||
type Instance = InsecureInstance;
|
type Instance = InsecureInstance;
|
||||||
fn new() -> Self {
|
async fn new() -> Self {
|
||||||
Self()
|
Self()
|
||||||
}
|
}
|
||||||
fn calculate_checksum(&self, data: &[u8]) -> u8 {
|
fn calculate_checksum(&self, data: &[u8]) -> u8 {
|
||||||
|
|
@ -72,7 +70,9 @@ impl Crypto for Insecure {
|
||||||
) -> Option<(Self::Instance, Vec<u8>)> {
|
) -> Option<(Self::Instance, Vec<u8>)> {
|
||||||
Some((
|
Some((
|
||||||
InsecureInstance {
|
InsecureInstance {
|
||||||
pair: EncryptionPair::init_both(|| Rc4::new(&DEFAULT_KEY)),
|
pair: EncryptionPair::init_both(|| {
|
||||||
|
Rc4::new_from_slice(DEFAULT_KEY).expect("incorrect key size")
|
||||||
|
}),
|
||||||
self_signat,
|
self_signat,
|
||||||
remote_signat,
|
remote_signat,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,13 @@
|
||||||
use hmac::Mac;
|
use hmac::Mac;
|
||||||
use md5::{Digest, Md5};
|
use md5::{Digest, Md5};
|
||||||
use rc4::{KeyInit, Rc4, StreamCipher};
|
use rc4::{KeyInit, Rc4, StreamCipher};
|
||||||
use rnex_core::{
|
use rnex_prudp::{
|
||||||
PID,
|
encryption::EncryptionPair,
|
||||||
executables::common::SECURE_SERVER_ACCOUNT,
|
ticket::read_secure_connection_data,
|
||||||
nex::account::Account,
|
types_flags::{TypesFlags, types::DATA},
|
||||||
prudp::{
|
|
||||||
encryption::EncryptionPair,
|
|
||||||
ticket::read_secure_connection_data,
|
|
||||||
types_flags::{TypesFlags, types::DATA},
|
|
||||||
},
|
|
||||||
rmc::structures::RmcSerialize,
|
|
||||||
};
|
};
|
||||||
|
use rnex_rmc::serialization::RmcSerialize;
|
||||||
|
use rnex_util::{PID, account::Account};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use typenum::U16;
|
use typenum::U16;
|
||||||
|
|
||||||
|
|
@ -22,7 +18,7 @@ use crate::crypto::{
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct SecureInstance {
|
pub struct SecureInstance {
|
||||||
pair: EncryptionPair<Rc4<U16>>,
|
pair: EncryptionPair<Rc4>,
|
||||||
uid: PID,
|
uid: PID,
|
||||||
self_signat: [u8; 4],
|
self_signat: [u8; 4],
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
|
@ -45,8 +41,8 @@ impl CryptoInstance for SecureInstance {
|
||||||
[0x78, 0x56, 0x34, 0x12]
|
[0x78, 0x56, 0x34, 0x12]
|
||||||
} else {
|
} else {
|
||||||
let mut hash = Md5::new();
|
let mut hash = Md5::new();
|
||||||
hash.write(ACCESS_KEY.as_bytes()).unwrap();
|
hash.update(ACCESS_KEY.as_bytes());
|
||||||
let mut hmac = <HmacMd5 as Mac>::new_from_slice(&hash.finalize().as_slice())
|
let mut hmac = HmacMd5::new_from_slice(&hash.finalize().as_slice())
|
||||||
.expect("unable to create hmac md5");
|
.expect("unable to create hmac md5");
|
||||||
hmac.update(data);
|
hmac.update(data);
|
||||||
hmac.finalize().into_bytes()[0..4].try_into().unwrap()
|
hmac.finalize().into_bytes()[0..4].try_into().unwrap()
|
||||||
|
|
@ -57,12 +53,16 @@ impl CryptoInstance for SecureInstance {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Secure(&'static Account);
|
pub struct Secure(Account);
|
||||||
|
|
||||||
impl Crypto for Secure {
|
impl Crypto for Secure {
|
||||||
type Instance = SecureInstance;
|
type Instance = SecureInstance;
|
||||||
fn new() -> Self {
|
async fn new() -> Self {
|
||||||
Self(&SECURE_SERVER_ACCOUNT)
|
Self(
|
||||||
|
Account::from_nexact(2, "Quazal Rendez-Vous")
|
||||||
|
.await
|
||||||
|
.expect("unable to get account info"),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
fn calculate_checksum(&self, data: &[u8]) -> u8 {
|
fn calculate_checksum(&self, data: &[u8]) -> u8 {
|
||||||
common_checksum(ACCESS_KEY, data)
|
common_checksum(ACCESS_KEY, data)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use cfg_if::cfg_if;
|
use cfg_if::cfg_if;
|
||||||
use rnex_core::{PID, prudp::types_flags::TypesFlags};
|
use rnex_prudp::types_flags::TypesFlags;
|
||||||
|
use rnex_util::PID;
|
||||||
|
|
||||||
mod common_crypto;
|
mod common_crypto;
|
||||||
|
|
||||||
|
|
@ -12,7 +13,7 @@ pub trait CryptoInstance: Send + 'static {
|
||||||
|
|
||||||
pub trait Crypto: Send + Sync + 'static {
|
pub trait Crypto: Send + Sync + 'static {
|
||||||
type Instance: CryptoInstance;
|
type Instance: CryptoInstance;
|
||||||
fn new() -> Self;
|
async fn new() -> Self;
|
||||||
fn calculate_checksum(&self, data: &[u8]) -> u8;
|
fn calculate_checksum(&self, data: &[u8]) -> u8;
|
||||||
fn instantiate(
|
fn instantiate(
|
||||||
&self,
|
&self,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use cfg_if::cfg_if;
|
use cfg_if::cfg_if;
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(feature = "prudpv0")] {
|
if #[cfg(feature = "prudpv0")] {
|
||||||
use log::info;
|
use tracing::info;
|
||||||
use proxy_common::ProxyStartupParam;
|
use proxy_common::ProxyStartupParam;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::net::SocketAddrV4;
|
use std::net::SocketAddrV4;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
use bytemuck::{Pod, Zeroable, try_from_bytes, try_from_bytes_mut};
|
use bytemuck::{Pod, Zeroable, try_from_bytes, try_from_bytes_mut};
|
||||||
use log::{info, warn};
|
use rnex_prudp::{
|
||||||
use rnex_core::prudp::{
|
|
||||||
types_flags::{
|
types_flags::{
|
||||||
TypesFlags,
|
TypesFlags,
|
||||||
flags::HAS_SIZE,
|
flags::HAS_SIZE,
|
||||||
|
|
@ -8,6 +7,7 @@ use rnex_core::prudp::{
|
||||||
},
|
},
|
||||||
virtual_port::VirtualPort,
|
virtual_port::VirtualPort,
|
||||||
};
|
};
|
||||||
|
use tracing::{info, warn};
|
||||||
|
|
||||||
use crate::crypto::{Crypto, CryptoInstance};
|
use crate::crypto::{Crypto, CryptoInstance};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,24 +5,22 @@ use std::{
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
use log::{error, info, warn};
|
|
||||||
use proxy_common::{ProxyStartupParam, new_backend_connection};
|
use proxy_common::{ProxyStartupParam, new_backend_connection};
|
||||||
use rnex_core::{
|
use rnex_prudp::{
|
||||||
prudp::{
|
socket_addr::PRUDPSockAddr,
|
||||||
socket_addr::PRUDPSockAddr,
|
types_flags::{
|
||||||
types_flags::{
|
flags::{ACK, NEED_ACK, RELIABLE},
|
||||||
flags::{ACK, NEED_ACK, RELIABLE},
|
types::{CONNECT, DATA, DISCONNECT, PING, SYN},
|
||||||
types::{CONNECT, DATA, DISCONNECT, PING, SYN},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
util::{SendingBufferConnection, SplittableBufferConnection},
|
|
||||||
};
|
};
|
||||||
|
use rnex_util::{SendingBufferConnection, SplittableBufferConnection};
|
||||||
use tokio::{
|
use tokio::{
|
||||||
net::UdpSocket,
|
net::UdpSocket,
|
||||||
spawn,
|
spawn,
|
||||||
sync::{Mutex, RwLock},
|
sync::{Mutex, RwLock},
|
||||||
time::{Instant, sleep},
|
time::{Instant, sleep},
|
||||||
};
|
};
|
||||||
|
use tracing::{error, info, warn};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
crypto::{Crypto, CryptoInstance},
|
crypto::{Crypto, CryptoInstance},
|
||||||
|
|
@ -528,7 +526,7 @@ impl<C: Crypto> Server<C> {
|
||||||
.expect("unable to bind socket");
|
.expect("unable to bind socket");
|
||||||
Self {
|
Self {
|
||||||
socket,
|
socket,
|
||||||
crypto: C::new(),
|
crypto: C::new().await,
|
||||||
connections: RwLock::new(HashMap::new()),
|
connections: RwLock::new(HashMap::new()),
|
||||||
param,
|
param,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,6 @@
|
||||||
#![allow(async_fn_in_trait)]
|
#![allow(async_fn_in_trait)]
|
||||||
//#![warn(missing_docs)]
|
//#![warn(missing_docs)]
|
||||||
|
|
||||||
#[cfg(feature = "big_pid")]
|
|
||||||
pub type PID = i64;
|
|
||||||
#[cfg(not(feature = "big_pid"))]
|
|
||||||
pub type PID = i32;
|
|
||||||
|
|
||||||
pub use ctor::ctor;
|
pub use ctor::ctor;
|
||||||
|
|
||||||
pub mod prudp;
|
pub mod prudp;
|
||||||
|
|
|
||||||
|
|
@ -8,5 +8,8 @@ ctor = "1.0.8"
|
||||||
rnex-rmc = { path = "../../rnex-rmc" }
|
rnex-rmc = { path = "../../rnex-rmc" }
|
||||||
rnex-base-protos = { path = "../base-protos" }
|
rnex-base-protos = { path = "../base-protos" }
|
||||||
|
|
||||||
|
[feature]
|
||||||
|
datastore = []
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
|
||||||
|
|
@ -22,14 +22,14 @@ pub struct Permission {
|
||||||
pub recipient_ids: Vec<PID>,
|
pub recipient_ids: Vec<PID>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(RmcSerialize, Clone, Default)]
|
#[derive(RmcSerialize, Clone, Default, Debug)]
|
||||||
#[rmc_struct(0)]
|
#[rmc_struct(0)]
|
||||||
pub struct RatingInfoWithSlot {
|
pub struct RatingInfoWithSlot {
|
||||||
pub slot: i8,
|
pub slot: i8,
|
||||||
pub rating: RatingInfo,
|
pub rating: RatingInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(RmcSerialize, Clone, Default)]
|
#[derive(RmcSerialize, Clone, Default, Debug)]
|
||||||
#[rmc_struct(0)]
|
#[rmc_struct(0)]
|
||||||
pub struct RatingInfo {
|
pub struct RatingInfo {
|
||||||
pub total_value: i64,
|
pub total_value: i64,
|
||||||
|
|
@ -46,7 +46,7 @@ pub struct GetMetaParam {
|
||||||
pub access_password: i64,
|
pub access_password: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(RmcSerialize, Clone, Default)]
|
#[derive(RmcSerialize, Clone, Default, Debug)]
|
||||||
#[rmc_struct(0)]
|
#[rmc_struct(0)]
|
||||||
pub struct GetMetaInfo {
|
pub struct GetMetaInfo {
|
||||||
pub dataid: i64,
|
pub dataid: i64,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#![allow(async_fn_in_trait)]
|
#![allow(async_fn_in_trait)]
|
||||||
|
#![cfg(feature = "datastore")]
|
||||||
|
|
||||||
pub mod datastore;
|
pub mod datastore;
|
||||||
use datastore::{DataStore, RawDataStore, RawDataStoreInfo, RemoteDataStore};
|
use datastore::{DataStore, RawDataStore, RawDataStoreInfo, RemoteDataStore};
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
#[cfg(not(feature = "rmc_struct_header"))]
|
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::{
|
use std::{
|
||||||
fmt::Arguments,
|
fmt::Arguments,
|
||||||
|
|
@ -102,7 +101,7 @@ pub fn read_struct<T: Sized, R: Read + ?Sized>(
|
||||||
version: u8,
|
version: u8,
|
||||||
pred: impl FnOnce(&mut SubRead<R>) -> Result<T>,
|
pred: impl FnOnce(&mut SubRead<R>) -> Result<T>,
|
||||||
) -> Result<T> {
|
) -> Result<T> {
|
||||||
use crate::rmc::structures::Error::VersionMismatch;
|
use crate::serialization::Error::VersionMismatch;
|
||||||
use v_byte_helpers::IS_BIG_ENDIAN;
|
use v_byte_helpers::IS_BIG_ENDIAN;
|
||||||
use v_byte_helpers::ReadExtensions;
|
use v_byte_helpers::ReadExtensions;
|
||||||
let ver: u8 = reader.read_struct(IS_BIG_ENDIAN)?;
|
let ver: u8 = reader.read_struct(IS_BIG_ENDIAN)?;
|
||||||
|
|
|
||||||
|
|
@ -122,13 +122,7 @@ impl Secure for BaseUser {
|
||||||
println!("{:?}", station_urls);
|
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?;
|
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-base-protos = { path = "../../rnex-protocols/base-protos" }
|
||||||
rnex-ds-protos = { path = "../../rnex-protocols/ds-protos" }
|
rnex-ds-protos = { path = "../../rnex-protocols/ds-protos" }
|
||||||
rnex-server = { path = "../../rnex-server" }
|
rnex-server = { path = "../../rnex-server" }
|
||||||
sqlx = "0.9.0"
|
sqlx = { version = "0.9.0", features = ["chrono"] }
|
||||||
tracing = "0.1.44"
|
tracing = "0.1.44"
|
||||||
thiserror = "2.0.18"
|
thiserror = "2.0.18"
|
||||||
chrono = "0.4.45"
|
chrono = "0.4.45"
|
||||||
aws-sdk-s3 = "1.138.0"
|
|
||||||
aws-config = "1.9.0"
|
|
||||||
sha2 = "0.11.0"
|
sha2 = "0.11.0"
|
||||||
hmac = "0.13.0"
|
hmac = "0.13.0"
|
||||||
base64 = "0.22.1"
|
base64 = "0.22.1"
|
||||||
|
|
@ -24,5 +22,8 @@ hex = "0.4.3"
|
||||||
urlencoding = "2.1.3"
|
urlencoding = "2.1.3"
|
||||||
futures = "0.3.32"
|
futures = "0.3.32"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
datastore = []
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use futures::future::join_all;
|
use futures::{TryStreamExt, future::join_all};
|
||||||
use rnex_base::user::BaseUser;
|
use rnex_base::user::BaseUser;
|
||||||
use rnex_ds_protos::{
|
use rnex_ds_protos::{
|
||||||
LocalDatastoreProtocol,
|
LocalDatastoreProtocol,
|
||||||
|
|
@ -11,8 +11,8 @@ use rnex_ds_protos::{
|
||||||
DataStorePrepareGetParam, DataStoreRateObjectParam, DataStoreRatingTarget,
|
DataStorePrepareGetParam, DataStoreRateObjectParam, DataStoreRatingTarget,
|
||||||
DataStoreReportCourseParam, DataStoreReqGetInfo, DataStoreSearchParam,
|
DataStoreReportCourseParam, DataStoreReqGetInfo, DataStoreSearchParam,
|
||||||
DataStoreUploadCourseRecordParam, GetMetaInfo, GetMetaParam, KeyValue, Permission,
|
DataStoreUploadCourseRecordParam, GetMetaInfo, GetMetaParam, KeyValue, Permission,
|
||||||
PersistenceTarget, PreparePostParam, RatingInfo, RatingInfoWithSlot,
|
PersistenceTarget, PreparePostParam, RateCustomRankingParam, RatingInfo,
|
||||||
RatingInitParamWithSlot, ReqPostInfo,
|
RatingInfoWithSlot, RatingInitParamWithSlot, ReqPostInfo,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use rnex_rmc::{qbuffer::QBuffer, qresult::QResult, response::ErrorCode, rmc_struct};
|
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 rnex_util::{PID, date_time::DateTime};
|
||||||
use sqlx::query;
|
use sqlx::query;
|
||||||
use std::convert;
|
use std::convert;
|
||||||
use tracing::{error, info, warn};
|
use tracing::{error, info, instrument, warn};
|
||||||
|
|
||||||
use crate::{DatastoreManager, s3presigner::S3Presigner};
|
use crate::{DatastoreManager, s3presigner::S3Presigner};
|
||||||
// todo: refactor this further to make some of the helper functions attached to the user and some to
|
// 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
|
// the manager and also move the usages of pid into the helper functions attached to user
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
#[rmc_struct(DatastoreProtocol)]
|
#[rmc_struct(DatastoreProtocol)]
|
||||||
pub struct DatastoreUser {
|
pub struct DatastoreUser {
|
||||||
pub base: PassthroughInitModule<BaseUser>,
|
pub base: PassthroughInitModule<BaseUser>,
|
||||||
|
|
@ -33,6 +34,7 @@ pub struct DatastoreUser {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DatastoreUser {
|
impl DatastoreUser {
|
||||||
|
#[instrument]
|
||||||
fn map_row_to_meta_info(
|
fn map_row_to_meta_info(
|
||||||
&self,
|
&self,
|
||||||
row_data_id: i64,
|
row_data_id: i64,
|
||||||
|
|
@ -88,6 +90,7 @@ impl DatastoreUser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument]
|
||||||
pub async fn check_object_availability(
|
pub async fn check_object_availability(
|
||||||
&self,
|
&self,
|
||||||
data_id: i64,
|
data_id: i64,
|
||||||
|
|
@ -121,6 +124,7 @@ impl DatastoreUser {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument]
|
||||||
pub async fn get_object_ratings(
|
pub async fn get_object_ratings(
|
||||||
&self,
|
&self,
|
||||||
data_id: i64,
|
data_id: i64,
|
||||||
|
|
@ -158,6 +162,7 @@ impl DatastoreUser {
|
||||||
Ok(ratings)
|
Ok(ratings)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument]
|
||||||
pub async fn get_object_info_by_data_id(
|
pub async fn get_object_info_by_data_id(
|
||||||
&self,
|
&self,
|
||||||
data_id: i64,
|
data_id: i64,
|
||||||
|
|
@ -210,6 +215,7 @@ impl DatastoreUser {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument]
|
||||||
async fn get_object_info_by_persistence_target(
|
async fn get_object_info_by_persistence_target(
|
||||||
&self,
|
&self,
|
||||||
target: PersistenceTarget,
|
target: PersistenceTarget,
|
||||||
|
|
@ -271,6 +277,7 @@ impl DatastoreUser {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument]
|
||||||
async fn get_buffer_queues_by_data_id_and_slot(
|
async fn get_buffer_queues_by_data_id_and_slot(
|
||||||
&self,
|
&self,
|
||||||
data_id: i64,
|
data_id: i64,
|
||||||
|
|
@ -300,13 +307,13 @@ impl DatastoreUser {
|
||||||
Ok(buffer_queues)
|
Ok(buffer_queues)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument]
|
||||||
fn verify_object_permission(
|
fn verify_object_permission(
|
||||||
&self,
|
&self,
|
||||||
owner_id: PID,
|
owner_id: PID,
|
||||||
viewer_id: PID,
|
|
||||||
permission: &Permission,
|
permission: &Permission,
|
||||||
) -> Result<(), ErrorCode> {
|
) -> Result<(), ErrorCode> {
|
||||||
if owner_id == viewer_id {
|
if owner_id == self.base.pid {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -315,7 +322,7 @@ impl DatastoreUser {
|
||||||
1 => Err(ErrorCode::DataStore_PermissionDenied), // Friends only, unimplemented
|
1 => Err(ErrorCode::DataStore_PermissionDenied), // Friends only, unimplemented
|
||||||
2 => {
|
2 => {
|
||||||
// Recipient IDs can read
|
// Recipient IDs can read
|
||||||
if permission.recipient_ids.contains(&viewer_id) {
|
if permission.recipient_ids.contains(&self.base.pid) {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(ErrorCode::DataStore_PermissionDenied)
|
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) {
|
fn filter_properties_by_result_option(&self, meta_info: &mut GetMetaInfo, result_option: u8) {
|
||||||
if (result_option & 0x01) == 0 {
|
if (result_option & 0x01) == 0 {
|
||||||
meta_info.meta_binary = QBuffer(Vec::new());
|
meta_info.meta_binary = QBuffer(Vec::new());
|
||||||
|
|
@ -339,6 +347,7 @@ impl DatastoreUser {
|
||||||
// No idea what the other things do. :shrug:
|
// No idea what the other things do. :shrug:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument]
|
||||||
async fn init_object_rating_slot(&self, data_id: i64, rating_param: RatingInitParamWithSlot) {
|
async fn init_object_rating_slot(&self, data_id: i64, rating_param: RatingInitParamWithSlot) {
|
||||||
info!("running init object rating slot");
|
info!("running init object rating slot");
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
|
|
@ -376,11 +385,12 @@ impl DatastoreUser {
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
error!("DB Error: {:?}", e);
|
error!("DB Error: {:?}", e);
|
||||||
ErrorCode::DataStore_NotFound
|
ErrorCode::DataStore_NotFound
|
||||||
});
|
})?;
|
||||||
info!("done running");
|
info!("done running");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dawg...
|
// Dawg...
|
||||||
|
#[instrument]
|
||||||
async fn get_custom_rankings_by_data_ids(
|
async fn get_custom_rankings_by_data_ids(
|
||||||
&self,
|
&self,
|
||||||
application_id: u32,
|
application_id: u32,
|
||||||
|
|
@ -431,6 +441,7 @@ impl DatastoreUser {
|
||||||
results
|
results
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument]
|
||||||
async fn get_user_course_object_ids(&self, owner_pid: PID) -> Result<Vec<i64>, ErrorCode> {
|
async fn get_user_course_object_ids(&self, owner_pid: PID) -> Result<Vec<i64>, ErrorCode> {
|
||||||
let rows = sqlx::query!(
|
let rows = sqlx::query!(
|
||||||
r#"
|
r#"
|
||||||
|
|
@ -459,6 +470,7 @@ impl DatastoreUser {
|
||||||
Ok(valid_ids)
|
Ok(valid_ids)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument]
|
||||||
fn get_blacklist_1(&self) -> Vec<String> {
|
fn get_blacklist_1(&self) -> Vec<String> {
|
||||||
vec![
|
vec![
|
||||||
"けされ",
|
"けされ",
|
||||||
|
|
@ -533,6 +545,7 @@ impl DatastoreUser {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument]
|
||||||
fn get_blacklist_2(&self) -> Vec<String> {
|
fn get_blacklist_2(&self) -> Vec<String> {
|
||||||
vec![
|
vec![
|
||||||
"ゼロから",
|
"ゼロから",
|
||||||
|
|
@ -548,6 +561,7 @@ impl DatastoreUser {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument]
|
||||||
fn get_blacklist_3(&self) -> Vec<String> {
|
fn get_blacklist_3(&self) -> Vec<String> {
|
||||||
vec![
|
vec![
|
||||||
"いいね",
|
"いいね",
|
||||||
|
|
@ -617,6 +631,7 @@ impl DatastoreUser {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument]
|
||||||
// couldn't find a better way to do this im going crazyy
|
// couldn't find a better way to do this im going crazyy
|
||||||
async fn rate_object(
|
async fn rate_object(
|
||||||
&self,
|
&self,
|
||||||
|
|
@ -651,6 +666,7 @@ impl DatastoreUser {
|
||||||
Ok(rating)
|
Ok(rating)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument]
|
||||||
async fn change_meta_object_check(
|
async fn change_meta_object_check(
|
||||||
&self,
|
&self,
|
||||||
param: &DataStoreChangeMetaParam,
|
param: &DataStoreChangeMetaParam,
|
||||||
|
|
@ -679,6 +695,7 @@ impl DatastoreUser {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument]
|
||||||
async fn get_rating_with_slot_data_id(
|
async fn get_rating_with_slot_data_id(
|
||||||
&self,
|
&self,
|
||||||
dataid: i64,
|
dataid: i64,
|
||||||
|
|
@ -713,6 +730,7 @@ impl DatastoreUser {
|
||||||
Ok(ratings)
|
Ok(ratings)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument]
|
||||||
pub async fn insert_buffer(&self, dataid: i64, slot: i32, buffer: &QBuffer) {
|
pub async fn insert_buffer(&self, dataid: i64, slot: i32, buffer: &QBuffer) {
|
||||||
let db_now = Utc::now().naive_utc();
|
let db_now = Utc::now().naive_utc();
|
||||||
|
|
||||||
|
|
@ -756,8 +774,7 @@ impl DataStore for DatastoreUser {
|
||||||
.await?
|
.await?
|
||||||
};
|
};
|
||||||
|
|
||||||
let current_pid = self.pid;
|
self.verify_object_permission(meta_info.owner, &meta_info.permission)?;
|
||||||
self.verify_object_permission(meta_info.owner, current_pid, &meta_info.permission)?;
|
|
||||||
|
|
||||||
self.filter_properties_by_result_option(&mut meta_info, metaparam.result_option);
|
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
|
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17
|
||||||
) RETURNING data_id
|
) RETURNING data_id
|
||||||
"#,
|
"#,
|
||||||
self.pid as i32,
|
self.base.pid as i32,
|
||||||
postparam.size as i32,
|
postparam.size as i32,
|
||||||
postparam.name,
|
postparam.name,
|
||||||
postparam.data_type as i32,
|
postparam.data_type as i32,
|
||||||
|
|
@ -815,7 +832,7 @@ impl DataStore for DatastoreUser {
|
||||||
.fetch_one(&self.dm.db_pool)
|
.fetch_one(&self.dm.db_pool)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
log::error!("DB Error: {:?}", e);
|
error!("DB Error: {:?}", e);
|
||||||
ErrorCode::DataStore_NotFound
|
ErrorCode::DataStore_NotFound
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
|
@ -998,7 +1015,7 @@ impl DataStore for DatastoreUser {
|
||||||
],
|
],
|
||||||
10 => vec![35, 75, 96, 40, 5, 6],
|
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);
|
return Err(ErrorCode::DataStore_Unknown);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -1081,7 +1098,7 @@ impl DataStore for DatastoreUser {
|
||||||
};
|
};
|
||||||
|
|
||||||
info!("verifying object permission");
|
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 key = format!("data/{}.bin", meta_info.dataid);
|
||||||
let download_url = self.dm.s3_presigner.generate_presigned_get(&key);
|
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();
|
res.meta_info.ratings = Vec::new();
|
||||||
}
|
}
|
||||||
if course_search_param.result_option & 0x4 == 0 {
|
if course_search_param.result_option & 0x4 == 0 {
|
||||||
res.meta_info.meta_binary =
|
res.meta_info.meta_binary = QBuffer(Vec::new());
|
||||||
rnex_core::rmc::structures::qbuffer::QBuffer(Vec::new());
|
|
||||||
}
|
}
|
||||||
if course_search_param.result_option & 0x20 == 0 {
|
if course_search_param.result_option & 0x20 == 0 {
|
||||||
res.score = 0;
|
res.score = 0;
|
||||||
|
|
@ -1180,9 +1196,7 @@ impl DataStore for DatastoreUser {
|
||||||
|
|
||||||
match info_result {
|
match info_result {
|
||||||
Ok(mut meta) => {
|
Ok(mut meta) => {
|
||||||
if let Err(e) =
|
if let Err(e) = self.verify_object_permission(meta.owner, &meta.permission) {
|
||||||
self.verify_object_permission(meta.owner, self.base.pid, &meta.permission)
|
|
||||||
{
|
|
||||||
metas.push(GetMetaInfo::default());
|
metas.push(GetMetaInfo::default());
|
||||||
results.push(QResult::error(e));
|
results.push(QResult::error(e));
|
||||||
} else {
|
} 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
|
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17
|
||||||
) RETURNING data_id
|
) RETURNING data_id
|
||||||
"#,
|
"#,
|
||||||
self.pid as i32,
|
self.base.pid as i32,
|
||||||
param.post_param.size as i32,
|
param.post_param.size as i32,
|
||||||
param.post_param.name,
|
param.post_param.name,
|
||||||
param.post_param.data_type as i32,
|
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)
|
.get_object_info_by_data_id(target.dataid, param.access_password)
|
||||||
.await?;
|
.await?;
|
||||||
info!("object info get complete");
|
info!("object info get complete");
|
||||||
self.verify_object_permission(
|
self.verify_object_permission(object_info.owner, &object_info.permission)?;
|
||||||
object_info.owner,
|
|
||||||
self.base.pid,
|
|
||||||
&object_info.permission,
|
|
||||||
)?;
|
|
||||||
info!("object permission complete");
|
info!("object permission complete");
|
||||||
|
|
||||||
if fetch_ratings {
|
if fetch_ratings {
|
||||||
|
|
@ -1386,11 +1396,11 @@ impl DataStore for DatastoreUser {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn change_meta(&self, param: DataStoreChangeMetaParam) -> Result<(), ErrorCode> {
|
async fn change_meta(&self, param: DataStoreChangeMetaParam) -> Result<(), ErrorCode> {
|
||||||
let object_info = get_object_info_by_data_id(param.dataid, 0).await?;
|
let object_info = self.get_object_info_by_data_id(param.dataid, 0).await?;
|
||||||
verify_object_permission(object_info.owner, self.pid, &object_info.permission).await?;
|
self.verify_object_permission(object_info.owner, &object_info.permission)?;
|
||||||
|
|
||||||
if param.modifies_flag & 0x08 != 0 {
|
if param.modifies_flag & 0x08 != 0 {
|
||||||
change_meta_object_check(¶m).await?;
|
self.change_meta_object_check(¶m).await?;
|
||||||
|
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
r#"UPDATE datastore.objects SET period=$1 WHERE data_id=$2"#,
|
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 {
|
if param.modifies_flag & 0x10 != 0 {
|
||||||
change_meta_object_check(¶m).await?;
|
self.change_meta_object_check(¶m).await?;
|
||||||
|
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
r#"UPDATE datastore.objects SET meta_binary=$1 WHERE data_id=$2"#,
|
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 {
|
if param.modifies_flag & 0x80 != 0 {
|
||||||
change_meta_object_check(¶m).await?;
|
self.change_meta_object_check(¶m).await?;
|
||||||
|
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
r#"UPDATE datastore.objects SET data_type=$1 WHERE data_id=$2"#,
|
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.dataid,
|
||||||
upload_course_record_param.slot as i16,
|
upload_course_record_param.slot as i16,
|
||||||
self.pid,
|
self.base.pid,
|
||||||
self.pid,
|
self.base.pid,
|
||||||
upload_course_record_param.score,
|
upload_course_record_param.score,
|
||||||
now,
|
now,
|
||||||
now
|
now
|
||||||
|
|
@ -1641,7 +1651,7 @@ impl DataStore for DatastoreUser {
|
||||||
) -> Result<Vec<QResult>, ErrorCode> {
|
) -> Result<Vec<QResult>, ErrorCode> {
|
||||||
let mut results = Vec::new();
|
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()) {
|
for (param, buffer) in bufferparam.iter().zip(buffers.iter()) {
|
||||||
if param.slot == 0 {
|
if param.slot == 0 {
|
||||||
|
|
@ -1713,7 +1723,7 @@ impl DataStore for DatastoreUser {
|
||||||
)
|
)
|
||||||
"#,
|
"#,
|
||||||
report_course_param.dataid,
|
report_course_param.dataid,
|
||||||
self.pid,
|
self.base.pid,
|
||||||
report_course_param.report_category as i16,
|
report_course_param.report_category as i16,
|
||||||
report_course_param.report_reason
|
report_course_param.report_reason
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
#![cfg(feature = "datastore")]
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
use rnex_server::{ConnectionInitData, RnexManager, RnexModule};
|
use rnex_server::{ConnectionInitData, RnexManager, RnexModule};
|
||||||
|
|
@ -9,20 +10,21 @@ use crate::{datastore::DatastoreUser, s3presigner::S3Presigner};
|
||||||
pub mod datastore;
|
pub mod datastore;
|
||||||
pub(crate) mod s3presigner;
|
pub(crate) mod s3presigner;
|
||||||
|
|
||||||
struct DatastoreManager {
|
#[derive(Debug)]
|
||||||
|
pub struct DatastoreManager {
|
||||||
db_pool: PgPool,
|
db_pool: PgPool,
|
||||||
s3_presigner: S3Presigner,
|
s3_presigner: S3Presigner,
|
||||||
}
|
}
|
||||||
struct DatastoreModule;
|
pub struct DatastoreModule;
|
||||||
impl RnexManager for DatastoreManager {
|
impl RnexManager for DatastoreManager {
|
||||||
type User = DatastoreUser;
|
type User = DatastoreUser;
|
||||||
type InitData = ConnectionInitData;
|
type InitData = ConnectionInitData;
|
||||||
async fn init_new_user(
|
async fn init_new_user(
|
||||||
this: rnex_server::PassthroughInitModule<Self>,
|
this: rnex_server::PassthroughInitModule<Self>,
|
||||||
mod_holder: &rnex_server::ModuleHolder,
|
mod_holder: &rnex_server::ModuleHolder,
|
||||||
remote: &rnex_rmc::RmcConnection,
|
_: &rnex_rmc::RmcConnection,
|
||||||
init_data: &Self::InitData,
|
_: &Self::InitData,
|
||||||
weak_user: rnex_server::WeakPassthroughInitModule<Self::User>,
|
_: rnex_server::WeakPassthroughInitModule<Self::User>,
|
||||||
) -> Self::User {
|
) -> Self::User {
|
||||||
DatastoreUser {
|
DatastoreUser {
|
||||||
dm: this,
|
dm: this,
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ use hmac::{Hmac, KeyInit, Mac};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest, Sha256};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct S3Presigner {
|
pub struct S3Presigner {
|
||||||
endpoint: String,
|
endpoint: String,
|
||||||
bucket: String,
|
bucket: String,
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,22 @@ version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[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]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
|
||||||
|
|
@ -1,92 +1,38 @@
|
||||||
use std::collections::HashMap;
|
use std::{
|
||||||
use std::sync::{Arc, atomic::AtomicU32};
|
collections::HashMap,
|
||||||
use std::sync::{LazyLock, Weak};
|
mem,
|
||||||
use std::time::Duration;
|
sync::{Arc, Weak},
|
||||||
use std::{env, mem};
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::rmc::protocols::account_management::{
|
|
||||||
AccountExtraInfo, AccountManagement, RawAccountManagement, RawAccountManagementInfo,
|
|
||||||
RemoteAccountManagement,
|
|
||||||
};
|
|
||||||
use crate::rmc::protocols::friends_3ds::{
|
|
||||||
Friends3DS, RawFriends3DS, RawFriends3DSInfo, RemoteFriends3DS,
|
|
||||||
};
|
|
||||||
use crate::rmc::protocols::friends_wiiu::{
|
|
||||||
FriendsWiiU, RawFriendsWiiU, RawFriendsWiiUInfo, RemoteFriendsWiiU,
|
|
||||||
};
|
|
||||||
use crate::rmc::protocols::nintendo_notification::{
|
|
||||||
NintendoNotification, RawNintendoNotification, RawNintendoNotificationInfo,
|
|
||||||
RemoteNintendoNotification,
|
|
||||||
};
|
|
||||||
use crate::rmc::protocols::secure::{RawSecure, RawSecureInfo, RemoteSecure, Secure};
|
|
||||||
use crate::{
|
|
||||||
define_rmc_proto,
|
|
||||||
kerberos::KerberosDateTime,
|
|
||||||
nex::common::get_station_urls,
|
|
||||||
prudp::{socket_addr::PRUDPSockAddr, station_url::StationUrl},
|
|
||||||
rmc::{
|
|
||||||
protocols::friends_wiiu::{
|
|
||||||
BlacklistedPrincipal, Comment, FriendInfo, FriendRequest, NNAInfo, NintendoPresenceV2,
|
|
||||||
PersistentNotification, PrincipalPreference, PrincipalRequestBlockSetting,
|
|
||||||
},
|
|
||||||
response::ErrorCode,
|
|
||||||
structures::{any::Any, qresult::QResult},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
use bytemuck::{Pod, Zeroable};
|
use bytemuck::{Pod, Zeroable};
|
||||||
use chrono::{TimeZone, Utc};
|
use chrono::{TimeZone, Utc};
|
||||||
use rnex_rmc::rmc_struct;
|
use nex_account::{derive_pid_hmac, grpc::ActCreateInfo, grpc_client};
|
||||||
use sqlx::query;
|
use rnex_fpd_protos::{
|
||||||
use std::sync::atomic::Ordering::Relaxed;
|
LocalFriendsGuest, LocalFriendsUser, RemoteFriendRemote,
|
||||||
use tokio::spawn;
|
account_management::{AccountExtraInfo, AccountManagement, NintendoCreateAccountData},
|
||||||
use tokio::sync::RwLock;
|
friends_3ds::{
|
||||||
use tokio::time::sleep;
|
self, FriendComment, FriendMii, FriendMiiList, FriendPersistentInfo, FriendPicture,
|
||||||
use tracing::warn;
|
FriendPresence, FriendRelationship, Friends3DS, Mii, MiiList, MyProfile, NintendoPresence,
|
||||||
use tracing::{error, info};
|
PlayedGame,
|
||||||
|
},
|
||||||
use crate::rmc::protocols::friends_wiiu::{GameKey, MiiV2, PrincipalBasicInfo};
|
friends_wiiu::{
|
||||||
|
self, BlacklistedPrincipal, Comment, FriendRequest, FriendRequestMessage, FriendsWiiU,
|
||||||
use crate::PID;
|
MiiV2, NNAInfo, NintendoPresenceV2, PersistentNotification, PrincipalBasicInfo,
|
||||||
|
PrincipalPreference, PrincipalRequestBlockSetting,
|
||||||
use crate::rmc::protocols::account_management::NintendoCreateAccountData;
|
},
|
||||||
use crate::rmc::protocols::nintendo_notification::NintendoNotificationEvent;
|
nintendo_notification::{
|
||||||
|
NintendoNotificationEvent, NintendoNotificationEventGeneral, RemoteNintendoNotification,
|
||||||
use crate::rmc::structures::data::Data;
|
},
|
||||||
|
|
||||||
use crate::executables::common::get_db;
|
|
||||||
|
|
||||||
use crate::rmc::protocols::friends_3ds::{
|
|
||||||
FriendComment, FriendMii, FriendMiiList, FriendPersistentInfo, FriendPicture, FriendPresence,
|
|
||||||
FriendRelationship, Mii, MiiList, MyProfile, NintendoPresence, PlayedGame,
|
|
||||||
};
|
};
|
||||||
use crate::rmc::protocols::friends_wiiu::FriendRequestMessage;
|
use rnex_rmc::{any::Any, data::Data, qbuffer::QBuffer, response::ErrorCode, rmc_struct};
|
||||||
use crate::rmc::protocols::nintendo_notification::NintendoNotificationEventGeneral;
|
use rnex_server::{PassthroughInitModule, WeakPassthroughInitModule};
|
||||||
use crate::rmc::response::ErrorCode::FPD_InvalidArgument;
|
use rnex_util::{PID, date_time::DateTime};
|
||||||
use crate::rmc::structures::qbuffer::QBuffer;
|
use sqlx::query;
|
||||||
use nex_account::grpc::ActCreateInfo;
|
use tokio::{spawn, sync::RwLock, time::sleep};
|
||||||
use nex_account::{derive_pid_hmac, grpc_client};
|
use tracing::{error, info, warn};
|
||||||
|
|
||||||
define_rmc_proto!(
|
use crate::FriendsManager;
|
||||||
proto FriendsUser{
|
|
||||||
Secure,
|
|
||||||
FriendsWiiU,
|
|
||||||
Friends3DS
|
|
||||||
}
|
|
||||||
);
|
|
||||||
define_rmc_proto!(
|
|
||||||
proto FriendRemote{
|
|
||||||
NintendoNotification
|
|
||||||
}
|
|
||||||
);
|
|
||||||
define_rmc_proto!(
|
|
||||||
proto FriendsGuest{
|
|
||||||
Secure,
|
|
||||||
AccountManagement
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
static NEX_ACCOUNT_URL: LazyLock<String> =
|
|
||||||
LazyLock::new(|| env::var("NEX_ACCOUNT_ENDPOINT").expect("NEX_ACCOUNT_ENDPOINT not set"));
|
|
||||||
|
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
#[derive(Pod, Zeroable, Copy, Clone, Debug)]
|
#[derive(Pod, Zeroable, Copy, Clone, Debug)]
|
||||||
|
|
@ -96,10 +42,11 @@ pub struct NascToken {
|
||||||
pub pwd_hash: [u8; 4],
|
pub pwd_hash: [u8; 4],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
#[rmc_struct(FriendsUser)]
|
#[rmc_struct(FriendsUser)]
|
||||||
pub struct FriendsUser {
|
pub struct FriendsUser {
|
||||||
pub fm: Arc<FriendsManager>,
|
pub fm: PassthroughInitModule<FriendsManager>,
|
||||||
pub addr: PRUDPSockAddr,
|
//pub addr: PRUDPSockAddr,
|
||||||
pub pid: PID,
|
pub pid: PID,
|
||||||
pub friend_pids: RwLock<Vec<PID>>,
|
pub friend_pids: RwLock<Vec<PID>>,
|
||||||
pub maybe_remote_friend: RwLock<HashMap<PID, Weak<FriendsUser>>>,
|
pub maybe_remote_friend: RwLock<HashMap<PID, Weak<FriendsUser>>>,
|
||||||
|
|
@ -108,27 +55,14 @@ pub struct FriendsUser {
|
||||||
pub remote: RemoteFriendRemote,
|
pub remote: RemoteFriendRemote,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
#[rmc_struct(FriendsGuest)]
|
#[rmc_struct(FriendsGuest)]
|
||||||
pub struct FriendsGuest {
|
pub struct FriendsGuest;
|
||||||
pub fm: Arc<FriendsManager>,
|
|
||||||
pub addr: PRUDPSockAddr,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct FriendsManager {
|
|
||||||
pub cid_counter: AtomicU32,
|
|
||||||
pub users: RwLock<HashMap<PID, Weak<FriendsUser>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FriendsManager {
|
|
||||||
pub fn next_cid(&self) -> u32 {
|
|
||||||
self.cid_counter.fetch_add(1, Relaxed)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FriendsManager {
|
impl FriendsManager {
|
||||||
async fn denies_friend_requests(&self, pid: PID) -> Result<bool, ErrorCode> {
|
async fn denies_friend_requests(&self, pid: PID) -> Result<bool, ErrorCode> {
|
||||||
query!("select principal_preference_block_friend_requests from nintendo_network_accounts where pid = $1", pid)
|
query!("select principal_preference_block_friend_requests from nintendo_network_accounts where pid = $1", pid)
|
||||||
.fetch_one(get_db())
|
.fetch_one(&self.db)
|
||||||
.await
|
.await
|
||||||
.map_err(|_| ErrorCode::FPD_InvalidAccount)
|
.map_err(|_| ErrorCode::FPD_InvalidAccount)
|
||||||
.map(|v| v.principal_preference_block_friend_requests)
|
.map(|v| v.principal_preference_block_friend_requests)
|
||||||
|
|
@ -165,7 +99,7 @@ impl Friends3DS for FriendsUser {
|
||||||
|
|
||||||
async fn get_friend_mii(
|
async fn get_friend_mii(
|
||||||
&self,
|
&self,
|
||||||
_friends: Vec<crate::rmc::protocols::friends_3ds::FriendInfo>,
|
_friends: Vec<friends_3ds::FriendInfo>,
|
||||||
) -> Result<Vec<FriendMii>, ErrorCode> {
|
) -> Result<Vec<FriendMii>, ErrorCode> {
|
||||||
// sorry for the copying pretendo but i don't have a mii on hand rn
|
// sorry for the copying pretendo but i don't have a mii on hand rn
|
||||||
let data: Vec<u8> = vec![
|
let data: Vec<u8> = vec![
|
||||||
|
|
@ -196,7 +130,7 @@ impl Friends3DS for FriendsUser {
|
||||||
|
|
||||||
async fn get_friend_mii_list(
|
async fn get_friend_mii_list(
|
||||||
&self,
|
&self,
|
||||||
_friends: Vec<crate::rmc::protocols::friends_3ds::FriendInfo>,
|
_friends: Vec<friends_3ds::FriendInfo>,
|
||||||
) -> Result<Vec<FriendMiiList>, ErrorCode> {
|
) -> Result<Vec<FriendMiiList>, ErrorCode> {
|
||||||
Err(ErrorCode::Core_NotImplemented)
|
Err(ErrorCode::Core_NotImplemented)
|
||||||
}
|
}
|
||||||
|
|
@ -204,7 +138,7 @@ impl Friends3DS for FriendsUser {
|
||||||
async fn is_active_game(
|
async fn is_active_game(
|
||||||
&self,
|
&self,
|
||||||
_unk: Vec<u32>,
|
_unk: Vec<u32>,
|
||||||
_game_key: crate::rmc::protocols::friends_3ds::GameKey,
|
_game_key: friends_3ds::GameKey,
|
||||||
) -> Result<Vec<u32>, ErrorCode> {
|
) -> Result<Vec<u32>, ErrorCode> {
|
||||||
Err(ErrorCode::Core_NotImplemented)
|
Err(ErrorCode::Core_NotImplemented)
|
||||||
}
|
}
|
||||||
|
|
@ -298,9 +232,9 @@ impl Friends3DS for FriendsUser {
|
||||||
|
|
||||||
async fn update_favorite_game_key(
|
async fn update_favorite_game_key(
|
||||||
&self,
|
&self,
|
||||||
game_key: rnex_core::rmc::protocols::friends_3ds::GameKey,
|
game_key: friends_3ds::GameKey,
|
||||||
) -> Result<(), ErrorCode> {
|
) -> Result<(), ErrorCode> {
|
||||||
log::info!("favorite game key: {:?}", game_key);
|
info!("favorite game key: {:?}", game_key);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -314,7 +248,7 @@ impl Friends3DS for FriendsUser {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_friend_presence(&self, unk: Vec<u32>) -> Result<Vec<FriendPresence>, ErrorCode> {
|
async fn get_friend_presence(&self, unk: Vec<u32>) -> Result<Vec<FriendPresence>, ErrorCode> {
|
||||||
log::info!("pids: {:?}", unk);
|
info!("pids: {:?}", unk);
|
||||||
|
|
||||||
let presence = FriendPresence {
|
let presence = FriendPresence {
|
||||||
data: Data {},
|
data: Data {},
|
||||||
|
|
@ -322,7 +256,7 @@ impl Friends3DS for FriendsUser {
|
||||||
presence: NintendoPresence {
|
presence: NintendoPresence {
|
||||||
data: Data {},
|
data: Data {},
|
||||||
changed_bit_flag: 0xFFFF_FFFF,
|
changed_bit_flag: 0xFFFF_FFFF,
|
||||||
game_key: rnex_core::rmc::protocols::friends_3ds::GameKey {
|
game_key: friends_3ds::GameKey {
|
||||||
data: Data {},
|
data: Data {},
|
||||||
title_id: 1_125_899_907_457_280,
|
title_id: 1_125_899_907_457_280,
|
||||||
version: 2064,
|
version: 2064,
|
||||||
|
|
@ -343,7 +277,7 @@ impl Friends3DS for FriendsUser {
|
||||||
|
|
||||||
async fn get_friend_comment(
|
async fn get_friend_comment(
|
||||||
&self,
|
&self,
|
||||||
_unk: Vec<crate::rmc::protocols::friends_3ds::FriendInfo>,
|
_unk: Vec<friends_3ds::FriendInfo>,
|
||||||
) -> Result<Vec<FriendComment>, ErrorCode> {
|
) -> Result<Vec<FriendComment>, ErrorCode> {
|
||||||
Err(ErrorCode::Core_NotImplemented)
|
Err(ErrorCode::Core_NotImplemented)
|
||||||
}
|
}
|
||||||
|
|
@ -364,15 +298,15 @@ impl Friends3DS for FriendsUser {
|
||||||
area: 0,
|
area: 0,
|
||||||
language: 0,
|
language: 0,
|
||||||
platform: 0,
|
platform: 0,
|
||||||
game_key: rnex_core::rmc::protocols::friends_3ds::GameKey {
|
game_key: friends_3ds::GameKey {
|
||||||
data: Data {},
|
data: Data {},
|
||||||
title_id: 1_125_899_907_457_280,
|
title_id: 1_125_899_907_457_280,
|
||||||
version: 2064,
|
version: 2064,
|
||||||
},
|
},
|
||||||
message: "yo whats up".to_string(),
|
message: "yo whats up".to_string(),
|
||||||
msg_updated_at: KerberosDateTime::now(),
|
msg_updated_at: DateTime::now(),
|
||||||
friended_at: KerberosDateTime::now(),
|
friended_at: DateTime::now(),
|
||||||
last_online: KerberosDateTime::now(),
|
last_online: DateTime::now(),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(vec![dummypersistentinfo])
|
Ok(vec![dummypersistentinfo])
|
||||||
|
|
@ -399,7 +333,7 @@ macro_rules! basic_principal_from_record {
|
||||||
nnid: $record.nnid.clone(),
|
nnid: $record.nnid.clone(),
|
||||||
mii: MiiV2 {
|
mii: MiiV2 {
|
||||||
data: Data {},
|
data: Data {},
|
||||||
date_time: KerberosDateTime(bytemuck::cast($record.mii_unk_datetime)),
|
date_time: DateTime(bytemuck::cast($record.mii_unk_datetime)),
|
||||||
mii_data: $record.mii_ffl_data.clone(),
|
mii_data: $record.mii_ffl_data.clone(),
|
||||||
name: QBuffer($record.mii_name.clone()),
|
name: QBuffer($record.mii_name.clone()),
|
||||||
unk: mii_unk1,
|
unk: mii_unk1,
|
||||||
|
|
@ -424,7 +358,7 @@ macro_rules! nna_info_from_record {
|
||||||
|
|
||||||
macro_rules! game_key_from_record {
|
macro_rules! game_key_from_record {
|
||||||
($record:expr) => {
|
($record:expr) => {
|
||||||
GameKey {
|
friends_wiiu::GameKey {
|
||||||
data: Data {},
|
data: Data {},
|
||||||
tid: $record.game_key_tid,
|
tid: $record.game_key_tid,
|
||||||
version: $record.game_key_version,
|
version: $record.game_key_version,
|
||||||
|
|
@ -440,7 +374,7 @@ macro_rules! friend_request_from_record {
|
||||||
basic_info: basic_principal_from_record!($record),
|
basic_info: basic_principal_from_record!($record),
|
||||||
request_message: FriendRequestMessage {
|
request_message: FriendRequestMessage {
|
||||||
data: Data {},
|
data: Data {},
|
||||||
expires_on: KerberosDateTime::from_naive(
|
expires_on: DateTime::from_naive(
|
||||||
Utc.timestamp_opt(Utc::now().timestamp() + 2592000, 0)
|
Utc.timestamp_opt(Utc::now().timestamp() + 2592000, 0)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.naive_utc(),
|
.naive_utc(),
|
||||||
|
|
@ -452,9 +386,9 @@ macro_rules! friend_request_from_record {
|
||||||
unk,
|
unk,
|
||||||
unk2,
|
unk2,
|
||||||
unk3: $record.unk_2,
|
unk3: $record.unk_2,
|
||||||
unk4: KerberosDateTime(bytemuck::cast($record.unk_3)),
|
unk4: DateTime(bytemuck::cast($record.unk_3)),
|
||||||
},
|
},
|
||||||
sent_on: KerberosDateTime::from_naive($record.creation_time),
|
sent_on: DateTime::from_naive($record.creation_time),
|
||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
@ -464,12 +398,12 @@ impl FriendsWiiU for FriendsUser {
|
||||||
&self,
|
&self,
|
||||||
info: NNAInfo,
|
info: NNAInfo,
|
||||||
presence: NintendoPresenceV2,
|
presence: NintendoPresenceV2,
|
||||||
birthday: KerberosDateTime,
|
birthday: DateTime,
|
||||||
) -> Result<
|
) -> Result<
|
||||||
(
|
(
|
||||||
PrincipalPreference,
|
PrincipalPreference,
|
||||||
Comment,
|
Comment,
|
||||||
Vec<FriendInfo>,
|
Vec<friends_wiiu::FriendInfo>,
|
||||||
Vec<FriendRequest>,
|
Vec<FriendRequest>,
|
||||||
Vec<FriendRequest>,
|
Vec<FriendRequest>,
|
||||||
Vec<BlacklistedPrincipal>,
|
Vec<BlacklistedPrincipal>,
|
||||||
|
|
@ -512,7 +446,7 @@ impl FriendsWiiU for FriendsUser {
|
||||||
smoosh_to_i16(info.unk, info.unk2),
|
smoosh_to_i16(info.unk, info.unk2),
|
||||||
bytemuck::cast::<_, i64>(birthday)
|
bytemuck::cast::<_, i64>(birthday)
|
||||||
)
|
)
|
||||||
.fetch_one(get_db())
|
.fetch_one(&self.fm.db)
|
||||||
.await else {
|
.await else {
|
||||||
println!("psql failed(unable to update user)");
|
println!("psql failed(unable to update user)");
|
||||||
return Err(ErrorCode::Core_SystemError)
|
return Err(ErrorCode::Core_SystemError)
|
||||||
|
|
@ -528,7 +462,7 @@ impl FriendsWiiU for FriendsUser {
|
||||||
",
|
",
|
||||||
self.pid
|
self.pid
|
||||||
)
|
)
|
||||||
.fetch_all(get_db())
|
.fetch_all(&self.fm.db)
|
||||||
.await
|
.await
|
||||||
.map(|v| {
|
.map(|v| {
|
||||||
v.into_iter()
|
v.into_iter()
|
||||||
|
|
@ -549,7 +483,7 @@ impl FriendsWiiU for FriendsUser {
|
||||||
",
|
",
|
||||||
self.pid
|
self.pid
|
||||||
)
|
)
|
||||||
.fetch_all(get_db())
|
.fetch_all(&self.fm.db)
|
||||||
.await
|
.await
|
||||||
.map(|v| {
|
.map(|v| {
|
||||||
v.into_iter()
|
v.into_iter()
|
||||||
|
|
@ -580,7 +514,7 @@ impl FriendsWiiU for FriendsUser {
|
||||||
inner join nintendo_network_accounts on friendships.pid = nintendo_network_accounts.pid",
|
inner join nintendo_network_accounts on friendships.pid = nintendo_network_accounts.pid",
|
||||||
self.pid
|
self.pid
|
||||||
)
|
)
|
||||||
.fetch_all(get_db())
|
.fetch_all(&self.fm.db)
|
||||||
.await
|
.await
|
||||||
else {
|
else {
|
||||||
println!("error whilest getting friends");
|
println!("error whilest getting friends");
|
||||||
|
|
@ -624,7 +558,7 @@ impl FriendsWiiU for FriendsUser {
|
||||||
drop(remo_friends);
|
drop(remo_friends);
|
||||||
}
|
}
|
||||||
|
|
||||||
friends.push(FriendInfo {
|
friends.push(friends_wiiu::FriendInfo {
|
||||||
data: Data {},
|
data: Data {},
|
||||||
nna_info: nna_info_from_record!(friend),
|
nna_info: nna_info_from_record!(friend),
|
||||||
presence,
|
presence,
|
||||||
|
|
@ -632,10 +566,10 @@ impl FriendsWiiU for FriendsUser {
|
||||||
data: Data {},
|
data: Data {},
|
||||||
unk: (bytemuck::cast::<_, u16>(friend.comment_unk) & 0xFF) as u8,
|
unk: (bytemuck::cast::<_, u16>(friend.comment_unk) & 0xFF) as u8,
|
||||||
message: friend.comment_message,
|
message: friend.comment_message,
|
||||||
last_changed: KerberosDateTime::from_naive(friend.comment_lastchanged),
|
last_changed: DateTime::from_naive(friend.comment_lastchanged),
|
||||||
},
|
},
|
||||||
became_friends: KerberosDateTime::from_naive(friend_since),
|
became_friends: DateTime::from_naive(friend_since),
|
||||||
last_online: KerberosDateTime::from_naive(friend.last_online),
|
last_online: DateTime::from_naive(friend.last_online),
|
||||||
unk: 0,
|
unk: 0,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -650,13 +584,13 @@ impl FriendsWiiU for FriendsUser {
|
||||||
",
|
",
|
||||||
self.pid
|
self.pid
|
||||||
)
|
)
|
||||||
.fetch_all(get_db())
|
.fetch_all(&self.fm.db)
|
||||||
.await
|
.await
|
||||||
.map(|v| {
|
.map(|v| {
|
||||||
v.into_iter()
|
v.into_iter()
|
||||||
.map(|v| BlacklistedPrincipal {
|
.map(|v| BlacklistedPrincipal {
|
||||||
basic_info: basic_principal_from_record!(v),
|
basic_info: basic_principal_from_record!(v),
|
||||||
since: KerberosDateTime::from_naive(v.since),
|
since: DateTime::from_naive(v.since),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
|
|
@ -681,7 +615,7 @@ impl FriendsWiiU for FriendsUser {
|
||||||
},
|
},
|
||||||
Comment {
|
Comment {
|
||||||
data: Data {},
|
data: Data {},
|
||||||
last_changed: KerberosDateTime::from_naive(query.comment_lastchanged),
|
last_changed: DateTime::from_naive(query.comment_lastchanged),
|
||||||
message: query.comment_message,
|
message: query.comment_message,
|
||||||
unk: (bytemuck::cast::<_, u16>(query.comment_unk) & 0xFF) as u8,
|
unk: (bytemuck::cast::<_, u16>(query.comment_unk) & 0xFF) as u8,
|
||||||
},
|
},
|
||||||
|
|
@ -697,15 +631,18 @@ impl FriendsWiiU for FriendsUser {
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn add_friend(&self, friend: PID) -> Result<(FriendRequest, FriendInfo), ErrorCode> {
|
async fn add_friend(
|
||||||
|
&self,
|
||||||
|
friend: PID,
|
||||||
|
) -> Result<(FriendRequest, friends_wiiu::FriendInfo), ErrorCode> {
|
||||||
self.add_friend_request(
|
self.add_friend_request(
|
||||||
friend,
|
friend,
|
||||||
0,
|
0,
|
||||||
"".into(),
|
"".into(),
|
||||||
0,
|
0,
|
||||||
"".into(),
|
"".into(),
|
||||||
GameKey::default(),
|
friends_wiiu::GameKey::default(),
|
||||||
KerberosDateTime::now(),
|
DateTime::now(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
@ -713,12 +650,12 @@ impl FriendsWiiU for FriendsUser {
|
||||||
async fn add_friend_by_name(
|
async fn add_friend_by_name(
|
||||||
&self,
|
&self,
|
||||||
name: String,
|
name: String,
|
||||||
) -> Result<(FriendRequest, FriendInfo), ErrorCode> {
|
) -> Result<(FriendRequest, friends_wiiu::FriendInfo), ErrorCode> {
|
||||||
let Ok(pid) = query!(
|
let Ok(pid) = query!(
|
||||||
"select pid from nintendo_network_accounts where nnid = $1",
|
"select pid from nintendo_network_accounts where nnid = $1",
|
||||||
name
|
name
|
||||||
)
|
)
|
||||||
.fetch_optional(get_db())
|
.fetch_optional(&self.fm.db)
|
||||||
.await
|
.await
|
||||||
else {
|
else {
|
||||||
println!("db error when trying to look up nnid");
|
println!("db error when trying to look up nnid");
|
||||||
|
|
@ -737,7 +674,7 @@ impl FriendsWiiU for FriendsUser {
|
||||||
self.pid,
|
self.pid,
|
||||||
friend
|
friend
|
||||||
)
|
)
|
||||||
.execute(get_db())
|
.execute(&self.fm.db)
|
||||||
.await
|
.await
|
||||||
else {
|
else {
|
||||||
return Err(ErrorCode::FPD_InvalidMessageID);
|
return Err(ErrorCode::FPD_InvalidMessageID);
|
||||||
|
|
@ -790,9 +727,9 @@ impl FriendsWiiU for FriendsUser {
|
||||||
message: String,
|
message: String,
|
||||||
_unk2: u8,
|
_unk2: u8,
|
||||||
unk3: String,
|
unk3: String,
|
||||||
game_key: GameKey,
|
game_key: friends_wiiu::GameKey,
|
||||||
unk4: KerberosDateTime,
|
unk4: DateTime,
|
||||||
) -> Result<(FriendRequest, FriendInfo), ErrorCode> {
|
) -> Result<(FriendRequest, friends_wiiu::FriendInfo), ErrorCode> {
|
||||||
let unk1 = 0;
|
let unk1 = 0;
|
||||||
let unk2 = 1;
|
let unk2 = 1;
|
||||||
|
|
||||||
|
|
@ -805,12 +742,12 @@ impl FriendsWiiU for FriendsUser {
|
||||||
"insert into friendships (pid_a, pid_b) values(99, $1)",
|
"insert into friendships (pid_a, pid_b) values(99, $1)",
|
||||||
self.pid
|
self.pid
|
||||||
)
|
)
|
||||||
.execute(get_db())
|
.execute(&self.fm.db)
|
||||||
.await
|
.await
|
||||||
.ok();
|
.ok();
|
||||||
|
|
||||||
let Ok(v) = query!("select * from nintendo_network_accounts where pid = 99")
|
let Ok(v) = query!("select * from nintendo_network_accounts where pid = 99")
|
||||||
.fetch_one(get_db())
|
.fetch_one(&self.fm.db)
|
||||||
.await
|
.await
|
||||||
else {
|
else {
|
||||||
return Err(ErrorCode::Core_Exception);
|
return Err(ErrorCode::Core_Exception);
|
||||||
|
|
@ -829,22 +766,22 @@ impl FriendsWiiU for FriendsUser {
|
||||||
drop(friends);
|
drop(friends);
|
||||||
|
|
||||||
let Ok(r) = query!("select * from nintendo_network_accounts where pid = 99")
|
let Ok(r) = query!("select * from nintendo_network_accounts where pid = 99")
|
||||||
.fetch_one(get_db())
|
.fetch_one(&this.fm.db)
|
||||||
.await
|
.await
|
||||||
else {
|
else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let data = Any::new(&FriendInfo {
|
let data = Any::new(&friends_wiiu::FriendInfo {
|
||||||
data: Data {},
|
data: Data {},
|
||||||
nna_info: nna_info_from_record!(r),
|
nna_info: nna_info_from_record!(r),
|
||||||
became_friends: KerberosDateTime::now(),
|
became_friends: DateTime::now(),
|
||||||
comment: Comment {
|
comment: Comment {
|
||||||
data: Data {},
|
data: Data {},
|
||||||
last_changed: KerberosDateTime::from_naive(r.comment_lastchanged),
|
last_changed: DateTime::from_naive(r.comment_lastchanged),
|
||||||
message: r.comment_message,
|
message: r.comment_message,
|
||||||
unk: (bytemuck::cast::<_, u16>(r.comment_unk) & 0xFF) as u8,
|
unk: (bytemuck::cast::<_, u16>(r.comment_unk) & 0xFF) as u8,
|
||||||
},
|
},
|
||||||
last_online: KerberosDateTime::now(),
|
last_online: DateTime::now(),
|
||||||
presence: NintendoPresenceV2::default(),
|
presence: NintendoPresenceV2::default(),
|
||||||
unk: 0,
|
unk: 0,
|
||||||
})
|
})
|
||||||
|
|
@ -870,21 +807,21 @@ impl FriendsWiiU for FriendsUser {
|
||||||
unk2: 1,
|
unk2: 1,
|
||||||
unk3: "Dummy".into(),
|
unk3: "Dummy".into(),
|
||||||
game_key,
|
game_key,
|
||||||
unk4: KerberosDateTime::now(),
|
unk4: DateTime::now(),
|
||||||
expires_on: KerberosDateTime::now(),
|
expires_on: DateTime::now(),
|
||||||
},
|
},
|
||||||
data: Data {},
|
data: Data {},
|
||||||
sent_on: KerberosDateTime::now(),
|
sent_on: DateTime::now(),
|
||||||
},
|
},
|
||||||
FriendInfo {
|
friends_wiiu::FriendInfo {
|
||||||
became_friends: KerberosDateTime::now(),
|
became_friends: DateTime::now(),
|
||||||
comment: Comment {
|
comment: Comment {
|
||||||
data: Data {},
|
data: Data {},
|
||||||
unk: bytemuck::cast::<_, u16>(v.comment_unk & 0xFF) as u8,
|
unk: bytemuck::cast::<_, u16>(v.comment_unk & 0xFF) as u8,
|
||||||
message: v.comment_message,
|
message: v.comment_message,
|
||||||
last_changed: KerberosDateTime::from_naive(v.comment_lastchanged),
|
last_changed: DateTime::from_naive(v.comment_lastchanged),
|
||||||
},
|
},
|
||||||
last_online: KerberosDateTime::now(),
|
last_online: DateTime::now(),
|
||||||
nna_info: nna_info_from_record!(v),
|
nna_info: nna_info_from_record!(v),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
|
@ -896,7 +833,7 @@ impl FriendsWiiU for FriendsUser {
|
||||||
friend,
|
friend,
|
||||||
self.pid
|
self.pid
|
||||||
)
|
)
|
||||||
.fetch_optional(get_db())
|
.fetch_optional(&self.fm.db)
|
||||||
.await
|
.await
|
||||||
else {
|
else {
|
||||||
return Err(ErrorCode::Authentication_AccountLibraryError);
|
return Err(ErrorCode::Authentication_AccountLibraryError);
|
||||||
|
|
@ -911,7 +848,7 @@ impl FriendsWiiU for FriendsUser {
|
||||||
"select count(recipient) from friend_requests where sender = $1",
|
"select count(recipient) from friend_requests where sender = $1",
|
||||||
self.pid
|
self.pid
|
||||||
)
|
)
|
||||||
.fetch_one(get_db())
|
.fetch_one(&self.fm.db)
|
||||||
.await
|
.await
|
||||||
else {
|
else {
|
||||||
println!("friend request count check failed to execute on database");
|
println!("friend request count check failed to execute on database");
|
||||||
|
|
@ -924,7 +861,7 @@ impl FriendsWiiU for FriendsUser {
|
||||||
"select count(recipient) from friend_requests where recipient = $1",
|
"select count(recipient) from friend_requests where recipient = $1",
|
||||||
friend
|
friend
|
||||||
)
|
)
|
||||||
.fetch_one(get_db())
|
.fetch_one(&self.fm.db)
|
||||||
.await
|
.await
|
||||||
else {
|
else {
|
||||||
println!("friend request count check failed to execute on database");
|
println!("friend request count check failed to execute on database");
|
||||||
|
|
@ -955,7 +892,7 @@ impl FriendsWiiU for FriendsUser {
|
||||||
game_key.tid,
|
game_key.tid,
|
||||||
game_key.version
|
game_key.version
|
||||||
)
|
)
|
||||||
.fetch_one(get_db())
|
.fetch_one(&self.fm.db)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let query = match query {
|
let query = match query {
|
||||||
|
|
@ -993,7 +930,7 @@ impl FriendsWiiU for FriendsUser {
|
||||||
"select * from nintendo_network_accounts where pid = $1",
|
"select * from nintendo_network_accounts where pid = $1",
|
||||||
self.pid
|
self.pid
|
||||||
)
|
)
|
||||||
.fetch_one(get_db())
|
.fetch_one(&self.fm.db)
|
||||||
.await
|
.await
|
||||||
else {
|
else {
|
||||||
println!("failed to acquire account info after adding friend");
|
println!("failed to acquire account info after adding friend");
|
||||||
|
|
@ -1012,7 +949,7 @@ impl FriendsWiiU for FriendsUser {
|
||||||
|
|
||||||
dbg!(Ok((
|
dbg!(Ok((
|
||||||
fr,
|
fr,
|
||||||
FriendInfo {
|
friends_wiiu::FriendInfo {
|
||||||
presence: NintendoPresenceV2 {
|
presence: NintendoPresenceV2 {
|
||||||
game_key,
|
game_key,
|
||||||
app_data: vec![0x00],
|
app_data: vec![0x00],
|
||||||
|
|
@ -1029,7 +966,7 @@ impl FriendsWiiU for FriendsUser {
|
||||||
bytemuck::cast::<_, i64>(id),
|
bytemuck::cast::<_, i64>(id),
|
||||||
self.pid
|
self.pid
|
||||||
)
|
)
|
||||||
.fetch_one(get_db())
|
.fetch_one(&self.fm.db)
|
||||||
.await
|
.await
|
||||||
else {
|
else {
|
||||||
return Err(ErrorCode::FPD_InvalidMessageID);
|
return Err(ErrorCode::FPD_InvalidMessageID);
|
||||||
|
|
@ -1055,8 +992,8 @@ impl FriendsWiiU for FriendsUser {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn accept_friend_request(&self, id: u64) -> Result<FriendInfo, ErrorCode> {
|
async fn accept_friend_request(&self, id: u64) -> Result<friends_wiiu::FriendInfo, ErrorCode> {
|
||||||
let Ok(mut tx) = get_db().begin().await else {
|
let Ok(mut tx) = self.fm.db.begin().await else {
|
||||||
return Err(ErrorCode::Core_Exception);
|
return Err(ErrorCode::Core_Exception);
|
||||||
};
|
};
|
||||||
let Ok(query) = query!(
|
let Ok(query) = query!(
|
||||||
|
|
@ -1120,17 +1057,17 @@ impl FriendsWiiU for FriendsUser {
|
||||||
println!("internal server error whilest getting nna info");
|
println!("internal server error whilest getting nna info");
|
||||||
return Err(ErrorCode::Core_Exception);
|
return Err(ErrorCode::Core_Exception);
|
||||||
};
|
};
|
||||||
let data = Any::new(&FriendInfo {
|
let data = Any::new(&friends_wiiu::FriendInfo {
|
||||||
data: Data {},
|
data: Data {},
|
||||||
nna_info: nna_info_from_record!(r),
|
nna_info: nna_info_from_record!(r),
|
||||||
became_friends: KerberosDateTime::now(),
|
became_friends: DateTime::now(),
|
||||||
comment: Comment {
|
comment: Comment {
|
||||||
data: Data {},
|
data: Data {},
|
||||||
last_changed: KerberosDateTime::from_naive(r.comment_lastchanged),
|
last_changed: DateTime::from_naive(r.comment_lastchanged),
|
||||||
message: r.comment_message,
|
message: r.comment_message,
|
||||||
unk: (bytemuck::cast::<_, u16>(r.comment_unk) & 0xFF) as u8,
|
unk: (bytemuck::cast::<_, u16>(r.comment_unk) & 0xFF) as u8,
|
||||||
},
|
},
|
||||||
last_online: KerberosDateTime::now(),
|
last_online: DateTime::now(),
|
||||||
presence: self.presence.read().await.clone().unwrap_or_default(),
|
presence: self.presence.read().await.clone().unwrap_or_default(),
|
||||||
unk: 0,
|
unk: 0,
|
||||||
})
|
})
|
||||||
|
|
@ -1155,18 +1092,18 @@ impl FriendsWiiU for FriendsUser {
|
||||||
|
|
||||||
tx.commit().await.ok();
|
tx.commit().await.ok();
|
||||||
|
|
||||||
Ok(FriendInfo {
|
Ok(friends_wiiu::FriendInfo {
|
||||||
data: Data {},
|
data: Data {},
|
||||||
nna_info: nna_info_from_record!(query),
|
nna_info: nna_info_from_record!(query),
|
||||||
presence,
|
presence,
|
||||||
comment: Comment {
|
comment: Comment {
|
||||||
data: Data {},
|
data: Data {},
|
||||||
last_changed: KerberosDateTime::from_naive(query.comment_lastchanged),
|
last_changed: DateTime::from_naive(query.comment_lastchanged),
|
||||||
message: query.comment_message,
|
message: query.comment_message,
|
||||||
unk: (bytemuck::cast::<_, u16>(query.comment_unk) & 0xFF) as u8,
|
unk: (bytemuck::cast::<_, u16>(query.comment_unk) & 0xFF) as u8,
|
||||||
},
|
},
|
||||||
became_friends: KerberosDateTime::now(),
|
became_friends: DateTime::now(),
|
||||||
last_online: KerberosDateTime::from_naive(query.last_online),
|
last_online: DateTime::from_naive(query.last_online),
|
||||||
unk: 0,
|
unk: 0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -1176,7 +1113,7 @@ impl FriendsWiiU for FriendsUser {
|
||||||
"delete from friend_requests where id = $1 returning sender, recipient",
|
"delete from friend_requests where id = $1 returning sender, recipient",
|
||||||
bytemuck::cast::<_, i64>(id),
|
bytemuck::cast::<_, i64>(id),
|
||||||
)
|
)
|
||||||
.fetch_one(get_db())
|
.fetch_one(&self.fm.db)
|
||||||
.await
|
.await
|
||||||
else {
|
else {
|
||||||
return Err(ErrorCode::FPD_InvalidMessageID);
|
return Err(ErrorCode::FPD_InvalidMessageID);
|
||||||
|
|
@ -1216,7 +1153,7 @@ impl FriendsWiiU for FriendsUser {
|
||||||
bytemuck::cast::<_, i64>(id),
|
bytemuck::cast::<_, i64>(id),
|
||||||
self.pid
|
self.pid
|
||||||
)
|
)
|
||||||
.fetch_one(get_db())
|
.fetch_one(&self.fm.db)
|
||||||
.await
|
.await
|
||||||
else {
|
else {
|
||||||
return Err(ErrorCode::FPD_InvalidMessageID);
|
return Err(ErrorCode::FPD_InvalidMessageID);
|
||||||
|
|
@ -1235,7 +1172,7 @@ impl FriendsWiiU for FriendsUser {
|
||||||
self.pid,
|
self.pid,
|
||||||
query.sender
|
query.sender
|
||||||
)
|
)
|
||||||
.execute(get_db())
|
.execute(&self.fm.db)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
println!("{}", e);
|
println!("{}", e);
|
||||||
|
|
@ -1264,18 +1201,18 @@ impl FriendsWiiU for FriendsUser {
|
||||||
"select * from nintendo_network_accounts where pid = $1",
|
"select * from nintendo_network_accounts where pid = $1",
|
||||||
query.sender
|
query.sender
|
||||||
)
|
)
|
||||||
.fetch_one(get_db())
|
.fetch_one(&self.fm.db)
|
||||||
.await
|
.await
|
||||||
else {
|
else {
|
||||||
println!("attempt to get invalid user which is in friend request");
|
println!("attempt to get invalid user which is in friend request");
|
||||||
return Err(FPD_InvalidArgument);
|
return Err(ErrorCode::FPD_InvalidArgument);
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(BlacklistedPrincipal {
|
Ok(BlacklistedPrincipal {
|
||||||
data: Data {},
|
data: Data {},
|
||||||
basic_info: basic_principal_from_record!(user),
|
basic_info: basic_principal_from_record!(user),
|
||||||
game_key: GameKey::default(),
|
game_key: friends_wiiu::GameKey::default(),
|
||||||
since: KerberosDateTime::now(),
|
since: DateTime::now(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1285,7 +1222,7 @@ impl FriendsWiiU for FriendsUser {
|
||||||
"update friend_requests set is_recieved = true where id = $1",
|
"update friend_requests set is_recieved = true where id = $1",
|
||||||
bytemuck::cast::<_, i64>(id)
|
bytemuck::cast::<_, i64>(id)
|
||||||
)
|
)
|
||||||
.execute(get_db())
|
.execute(&self.fm.db)
|
||||||
.await
|
.await
|
||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
|
|
@ -1301,7 +1238,7 @@ impl FriendsWiiU for FriendsUser {
|
||||||
self.pid,
|
self.pid,
|
||||||
principal.basic_info.pid
|
principal.basic_info.pid
|
||||||
)
|
)
|
||||||
.execute(get_db())
|
.execute(&self.fm.db)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
println!("{}", e);
|
println!("{}", e);
|
||||||
|
|
@ -1312,18 +1249,18 @@ impl FriendsWiiU for FriendsUser {
|
||||||
"select * from nintendo_network_accounts where pid = $1",
|
"select * from nintendo_network_accounts where pid = $1",
|
||||||
principal.basic_info.pid
|
principal.basic_info.pid
|
||||||
)
|
)
|
||||||
.fetch_one(get_db())
|
.fetch_one(&self.fm.db)
|
||||||
.await
|
.await
|
||||||
else {
|
else {
|
||||||
println!("attempt to get invalid user which is in friend request");
|
println!("attempt to get invalid user which is in friend request");
|
||||||
return Err(FPD_InvalidArgument);
|
return Err(ErrorCode::FPD_InvalidArgument);
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(BlacklistedPrincipal {
|
Ok(BlacklistedPrincipal {
|
||||||
data: Data {},
|
data: Data {},
|
||||||
basic_info: basic_principal_from_record!(user),
|
basic_info: basic_principal_from_record!(user),
|
||||||
game_key: GameKey::default(),
|
game_key: friends_wiiu::GameKey::default(),
|
||||||
since: KerberosDateTime::now(),
|
since: DateTime::now(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1333,7 +1270,7 @@ impl FriendsWiiU for FriendsUser {
|
||||||
self.pid,
|
self.pid,
|
||||||
id
|
id
|
||||||
)
|
)
|
||||||
.execute(get_db())
|
.execute(&self.fm.db)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
println!("{}", e);
|
println!("{}", e);
|
||||||
|
|
@ -1343,16 +1280,16 @@ impl FriendsWiiU for FriendsUser {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn update_presence(&self, mut presence: NintendoPresenceV2) -> Result<(), ErrorCode> {
|
async fn update_presence(&self, mut presence: NintendoPresenceV2) -> Result<(), ErrorCode> {
|
||||||
if !query!("select principal_preference_show_currently_playing_title from nintendo_network_accounts where pid = $1", self.pid).fetch_one(get_db()).await.map_err(|_| ErrorCode::FPD_InvalidAccount)?.principal_preference_show_currently_playing_title{
|
if !query!("select principal_preference_show_currently_playing_title from nintendo_network_accounts where pid = $1", self.pid).fetch_one(&self.fm.db).await.map_err(|_| ErrorCode::FPD_InvalidAccount)?.principal_preference_show_currently_playing_title{
|
||||||
presence.game_server_id = 0;
|
presence.game_server_id = 0;
|
||||||
presence.game_key = GameKey::default();
|
presence.game_key = friends_wiiu::GameKey::default();
|
||||||
presence.app_data = vec![];
|
presence.app_data = vec![];
|
||||||
}
|
}
|
||||||
if !query!(
|
if !query!(
|
||||||
"select principal_preference_show_online from nintendo_network_accounts where pid = $1",
|
"select principal_preference_show_online from nintendo_network_accounts where pid = $1",
|
||||||
self.pid
|
self.pid
|
||||||
)
|
)
|
||||||
.fetch_one(get_db())
|
.fetch_one(&self.fm.db)
|
||||||
.await
|
.await
|
||||||
.map_err(|_| ErrorCode::FPD_InvalidAccount)?
|
.map_err(|_| ErrorCode::FPD_InvalidAccount)?
|
||||||
.principal_preference_show_online
|
.principal_preference_show_online
|
||||||
|
|
@ -1380,7 +1317,7 @@ impl FriendsWiiU for FriendsUser {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn update_mii(&self, mii: MiiV2) -> Result<KerberosDateTime, ErrorCode> {
|
async fn update_mii(&self, mii: MiiV2) -> Result<DateTime, ErrorCode> {
|
||||||
if let Err(e) = query!(
|
if let Err(e) = query!(
|
||||||
"
|
"
|
||||||
update nintendo_network_accounts
|
update nintendo_network_accounts
|
||||||
|
|
@ -1392,7 +1329,7 @@ impl FriendsWiiU for FriendsUser {
|
||||||
bytemuck::cast::<_, i64>(mii.date_time.0),
|
bytemuck::cast::<_, i64>(mii.date_time.0),
|
||||||
self.pid
|
self.pid
|
||||||
)
|
)
|
||||||
.execute(get_db())
|
.execute(&self.fm.db)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
println!("internal server error whilest updating mii: {}", e);
|
println!("internal server error whilest updating mii: {}", e);
|
||||||
|
|
@ -1403,7 +1340,7 @@ impl FriendsWiiU for FriendsUser {
|
||||||
"select * from nintendo_network_accounts where pid = $1",
|
"select * from nintendo_network_accounts where pid = $1",
|
||||||
self.pid
|
self.pid
|
||||||
)
|
)
|
||||||
.fetch_one(get_db())
|
.fetch_one(&self.fm.db)
|
||||||
.await
|
.await
|
||||||
else {
|
else {
|
||||||
println!("internal server error whilest getting nna info");
|
println!("internal server error whilest getting nna info");
|
||||||
|
|
@ -1425,10 +1362,10 @@ impl FriendsWiiU for FriendsUser {
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(KerberosDateTime::now())
|
Ok(DateTime::now())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn update_comment(&self, comment: Comment) -> Result<KerberosDateTime, ErrorCode> {
|
async fn update_comment(&self, comment: Comment) -> Result<DateTime, ErrorCode> {
|
||||||
if let Err(e) = query!(
|
if let Err(e) = query!(
|
||||||
"
|
"
|
||||||
update nintendo_network_accounts
|
update nintendo_network_accounts
|
||||||
|
|
@ -1438,7 +1375,7 @@ impl FriendsWiiU for FriendsUser {
|
||||||
comment.message.clone(),
|
comment.message.clone(),
|
||||||
self.pid
|
self.pid
|
||||||
)
|
)
|
||||||
.execute(get_db())
|
.execute(&self.fm.db)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
println!("internal server error whilest updating mii: {}", e);
|
println!("internal server error whilest updating mii: {}", e);
|
||||||
|
|
@ -1463,7 +1400,7 @@ impl FriendsWiiU for FriendsUser {
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(KerberosDateTime::now())
|
Ok(DateTime::now())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn update_preference(&self, preference: PrincipalPreference) -> Result<(), ErrorCode> {
|
async fn update_preference(&self, preference: PrincipalPreference) -> Result<(), ErrorCode> {
|
||||||
|
|
@ -1480,7 +1417,7 @@ impl FriendsWiiU for FriendsUser {
|
||||||
preference.block_friend_request,
|
preference.block_friend_request,
|
||||||
self.pid
|
self.pid
|
||||||
)
|
)
|
||||||
.execute(get_db())
|
.execute(&self.fm.db)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
println!("internal server error whilest updating mii: {e}");
|
println!("internal server error whilest updating mii: {e}");
|
||||||
|
|
@ -1494,14 +1431,14 @@ impl FriendsWiiU for FriendsUser {
|
||||||
|
|
||||||
if !preference.show_playing_title {
|
if !preference.show_playing_title {
|
||||||
presence.game_server_id = 0;
|
presence.game_server_id = 0;
|
||||||
presence.game_key = GameKey::default();
|
presence.game_key = friends_wiiu::GameKey::default();
|
||||||
presence.app_data = vec![];
|
presence.app_data = vec![];
|
||||||
}
|
}
|
||||||
query!(
|
query!(
|
||||||
"update nintendo_network_accounts set last_online = now() where pid = $1",
|
"update nintendo_network_accounts set last_online = now() where pid = $1",
|
||||||
self.pid
|
self.pid
|
||||||
)
|
)
|
||||||
.execute(get_db())
|
.execute(&self.fm.db)
|
||||||
.await
|
.await
|
||||||
.ok();
|
.ok();
|
||||||
let friends = self.maybe_remote_friend.read().await;
|
let friends = self.maybe_remote_friend.read().await;
|
||||||
|
|
@ -1530,7 +1467,7 @@ impl FriendsWiiU for FriendsUser {
|
||||||
event_type: 10,
|
event_type: 10,
|
||||||
sender: self.pid,
|
sender: self.pid,
|
||||||
data: Any::new(&NintendoNotificationEventGeneral {
|
data: Any::new(&NintendoNotificationEventGeneral {
|
||||||
param3: KerberosDateTime::now().0,
|
param3: DateTime::now().0,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.expect("type error"),
|
.expect("type error"),
|
||||||
|
|
@ -1551,7 +1488,7 @@ impl FriendsWiiU for FriendsUser {
|
||||||
"select * from nintendo_network_accounts where pid = $1",
|
"select * from nintendo_network_accounts where pid = $1",
|
||||||
pid
|
pid
|
||||||
)
|
)
|
||||||
.fetch_one(get_db())
|
.fetch_one(&self.fm.db)
|
||||||
.await
|
.await
|
||||||
else {
|
else {
|
||||||
return Err(ErrorCode::FPD_NotFriend);
|
return Err(ErrorCode::FPD_NotFriend);
|
||||||
|
|
@ -1591,7 +1528,7 @@ impl FriendsWiiU for FriendsUser {
|
||||||
pid,
|
pid,
|
||||||
self.pid
|
self.pid
|
||||||
)
|
)
|
||||||
.fetch_optional(get_db())
|
.fetch_optional(&self.fm.db)
|
||||||
.await
|
.await
|
||||||
else {
|
else {
|
||||||
warn!("user requested request setting of invalid user");
|
warn!("user requested request setting of invalid user");
|
||||||
|
|
@ -1619,61 +1556,12 @@ impl FriendsWiiU for FriendsUser {
|
||||||
|
|
||||||
type HMacMd5 = hmac::Hmac<md5::Md5>;
|
type HMacMd5 = hmac::Hmac<md5::Md5>;
|
||||||
|
|
||||||
impl Secure for FriendsUser {
|
|
||||||
async fn register(
|
|
||||||
&self,
|
|
||||||
station_urls: Vec<StationUrl>,
|
|
||||||
) -> Result<(QResult, u32, StationUrl), ErrorCode> {
|
|
||||||
let cid = self.fm.next_cid();
|
|
||||||
Ok((
|
|
||||||
QResult::success(ErrorCode::Core_Unknown),
|
|
||||||
cid,
|
|
||||||
get_station_urls(&station_urls, self.addr, self.pid, cid).await?[0].clone(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
async fn register_ex(
|
|
||||||
&self,
|
|
||||||
station_urls: Vec<StationUrl>,
|
|
||||||
_data: Any,
|
|
||||||
) -> Result<(QResult, u32, StationUrl), ErrorCode> {
|
|
||||||
info!("register");
|
|
||||||
self.register(station_urls).await
|
|
||||||
}
|
|
||||||
async fn replace_url(&self, _target: StationUrl, _dest: StationUrl) -> Result<(), ErrorCode> {
|
|
||||||
Err(ErrorCode::Core_NotImplemented)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Secure for FriendsGuest {
|
|
||||||
async fn register(
|
|
||||||
&self,
|
|
||||||
station_urls: Vec<StationUrl>,
|
|
||||||
) -> Result<(QResult, u32, StationUrl), ErrorCode> {
|
|
||||||
let cid = self.fm.next_cid();
|
|
||||||
Ok((
|
|
||||||
QResult::success(ErrorCode::Core_Unknown),
|
|
||||||
cid,
|
|
||||||
get_station_urls(&station_urls, self.addr, 100, cid).await?[0].clone(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
async fn register_ex(
|
|
||||||
&self,
|
|
||||||
station_urls: Vec<StationUrl>,
|
|
||||||
_data: Any,
|
|
||||||
) -> Result<(QResult, u32, StationUrl), ErrorCode> {
|
|
||||||
info!("register");
|
|
||||||
self.register(station_urls).await
|
|
||||||
}
|
|
||||||
async fn replace_url(&self, _target: StationUrl, _dest: StationUrl) -> Result<(), ErrorCode> {
|
|
||||||
Err(ErrorCode::Core_NotImplemented)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for FriendsUser {
|
impl Drop for FriendsUser {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let friends = mem::take(&mut self.maybe_remote_friend);
|
let friends = mem::take(&mut self.maybe_remote_friend);
|
||||||
let users = friends.into_inner();
|
let users = friends.into_inner();
|
||||||
let pid = self.pid;
|
let pid = self.pid;
|
||||||
|
let fm = self.fm.clone();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
for user in users {
|
for user in users {
|
||||||
let Some(user) = user.1.upgrade() else {
|
let Some(user) = user.1.upgrade() else {
|
||||||
|
|
@ -1685,7 +1573,7 @@ impl Drop for FriendsUser {
|
||||||
event_type: 10,
|
event_type: 10,
|
||||||
sender: pid,
|
sender: pid,
|
||||||
data: Any::new(&NintendoNotificationEventGeneral {
|
data: Any::new(&NintendoNotificationEventGeneral {
|
||||||
param3: KerberosDateTime::now().0,
|
param3: DateTime::now().0,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.expect("type error"),
|
.expect("type error"),
|
||||||
|
|
@ -1696,7 +1584,7 @@ impl Drop for FriendsUser {
|
||||||
"update nintendo_network_accounts set last_online = now() where pid = $1",
|
"update nintendo_network_accounts set last_online = now() where pid = $1",
|
||||||
pid
|
pid
|
||||||
)
|
)
|
||||||
.execute(get_db())
|
.execute(&fm.db)
|
||||||
.await
|
.await
|
||||||
.ok();
|
.ok();
|
||||||
});
|
});
|
||||||
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"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[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]
|
[lints]
|
||||||
workspace = true
|
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> {
|
async fn deliver_message(&self, mut message: Any<UserMessage>) -> Result<(), ErrorCode> {
|
||||||
let mut msg = message.get()?;
|
let mut msg = message.get()?;
|
||||||
|
|
||||||
let _users = match msg.recipient_type {
|
let _users = match msg.recipient_type {
|
||||||
1 => {
|
1 => {
|
||||||
let Some(user) = self
|
let Some(user) = self
|
||||||
.matchmake_manager
|
.msgm
|
||||||
.users_by_pid
|
.users_by_pid
|
||||||
.read()
|
.read()
|
||||||
.await
|
.await
|
||||||
.get(&msg.recipient_id)
|
.get(&msg.recipient_id)
|
||||||
.map(Weak::upgrade)
|
.map(WeakPassthroughInitModule::upgrade)
|
||||||
.flatten()
|
.flatten()
|
||||||
else {
|
else {
|
||||||
return Err(ErrorCode::Core_InvalidArgument);
|
return Err(ErrorCode::Core_InvalidArgument);
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,15 @@ version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[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]
|
[lints]
|
||||||
workspace = true
|
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)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct CompetitionPostResults {
|
pub struct CompetitionPostResults {
|
||||||
pub splatfest_id: u32,
|
pub splatfest_id: u32,
|
||||||
|
|
@ -7,50 +29,20 @@ pub struct CompetitionPostResults {
|
||||||
pub user: PID,
|
pub user: PID,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Seperate function because I cannot give a fuck right now
|
impl Ranking for RankingUser {
|
||||||
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 {
|
|
||||||
async fn competition_ranking_get_param(
|
async fn competition_ranking_get_param(
|
||||||
&self,
|
&self,
|
||||||
param: CompetitionRankingGetParam,
|
param: CompetitionRankingGetParam,
|
||||||
) -> Result<Vec<CompetitionRankingScoreInfo>, ErrorCode> {
|
) -> Result<Vec<CompetitionRankingScoreInfo>, ErrorCode> {
|
||||||
let fest_id = param.festival_ids.get(0).copied().unwrap_or(0);
|
let fest_id = param.festival_ids.get(0).copied().unwrap_or(0);
|
||||||
|
|
||||||
let endpoint_results = env::var("RNEX_SPLATOON_RESULTS_GET").map_err(|_| {
|
let url_results = format!("{}?splatfest_id={}", self.rm.rnex_result_get, fest_id);
|
||||||
error!("RNEX_SPLATOON_RESULTS_GET not set");
|
let Ok(response_results) =
|
||||||
ErrorCode::RendezVous_InvalidConfiguration
|
tokio::task::spawn_blocking(move || ureq::get(&url_results).call()).await
|
||||||
})?;
|
else {
|
||||||
|
error!("failed to join task");
|
||||||
let url_results = format!("{}?splatfest_id={}", endpoint_results, fest_id);
|
return Err(ErrorCode::Core_Exception);
|
||||||
let response_results = ureq::get(&url_results).call();
|
};
|
||||||
|
|
||||||
let results: Vec<CompetitionPostResults> = match response_results {
|
let results: Vec<CompetitionPostResults> = match response_results {
|
||||||
Ok(mut res) => res.body_mut().read_json().map_err(|e| {
|
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 start = offset.min(results.len());
|
||||||
let end = (start + size).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];
|
let mut wins = vec![0u32, 0u32];
|
||||||
for r in &results {
|
for r in &results {
|
||||||
let won_team = (r.team_id ^ (!r.team_win)) & 1;
|
let won_team = (r.team_id ^ (!r.team_win)) & 1;
|
||||||
|
|
@ -84,7 +76,7 @@ impl Ranking for User {
|
||||||
unk: 1,
|
unk: 1,
|
||||||
pid: r.user,
|
pid: r.user,
|
||||||
score: r.score,
|
score: r.score,
|
||||||
modified: KerberosDateTime::now(),
|
modified: DateTime::now(),
|
||||||
unk2: 1,
|
unk2: 1,
|
||||||
appdata: QBuffer(vec![]),
|
appdata: QBuffer(vec![]),
|
||||||
})
|
})
|
||||||
|
|
@ -113,14 +105,6 @@ impl Ranking for User {
|
||||||
info!("team id: {:?}", param.team_id);
|
info!("team id: {:?}", param.team_id);
|
||||||
info!("did current team win: {:?}", param.team_win);
|
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 {
|
let payload = CompetitionPostResults {
|
||||||
splatfest_id: param.splatfest_id,
|
splatfest_id: param.splatfest_id,
|
||||||
score: param.score,
|
score: param.score,
|
||||||
|
|
@ -137,9 +121,18 @@ impl Ranking for User {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let response = ureq::post(&endpoint)
|
let rm = self.rm.clone();
|
||||||
.header("Content-Type", "application/json")
|
|
||||||
.send(json_body);
|
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 {
|
match response {
|
||||||
Ok(res) => {
|
Ok(res) => {
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ chrono = "0.4.39"
|
||||||
bytemuck = { version = "1.25.0", features = ["derive"] }
|
bytemuck = { version = "1.25.0", features = ["derive"] }
|
||||||
md-5 = "0.11.0"
|
md-5 = "0.11.0"
|
||||||
thiserror = "2.0.18"
|
thiserror = "2.0.18"
|
||||||
|
nex-account = { version = "0.2.4", registry = "spbr" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
nx = []
|
nx = []
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use md5::{Digest, Md5};
|
use md5::{Digest, Md5};
|
||||||
|
use nex_account::{grpc::Pid, grpc_client};
|
||||||
|
|
||||||
use crate::PID;
|
use crate::PID;
|
||||||
|
|
||||||
|
|
@ -44,4 +45,17 @@ impl Account {
|
||||||
pub fn get_login_data(&self) -> (PID, [u8; 16]) {
|
pub fn get_login_data(&self) -> (PID, [u8; 16]) {
|
||||||
(self.pid, self.nex_key)
|
(self.pid, self.nex_key)
|
||||||
}
|
}
|
||||||
|
pub async fn from_nexact(pid: PID, username: &str) -> Option<Self> {
|
||||||
|
let key: [u8; 16] = grpc_client()
|
||||||
|
.await
|
||||||
|
.ok()?
|
||||||
|
.get_nex_key_by_pid(Pid { pid })
|
||||||
|
.await
|
||||||
|
.ok()?
|
||||||
|
.into_inner()
|
||||||
|
.key
|
||||||
|
.try_into()
|
||||||
|
.ok()?;
|
||||||
|
Some(Self::new_raw_key(pid, username, key))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue