mirror of
https://git.ngram.ca/OpenJam/rc-servers
synced 2026-08-23 23:08:52 +00:00
Move chat system into core, merge configs, save to database
This commit is contained in:
85
rc_core/src/data/channel.rs
Normal file
85
rc_core/src/data/channel.rs
Normal file
@@ -0,0 +1,85 @@
|
||||
use polariton::operation::{Typed, Arr};
|
||||
|
||||
pub struct ChatChannelInfo {
|
||||
pub channel_name: String,
|
||||
pub members: Vec<ChatChannelMember>,
|
||||
pub channel_ty: ChatChannelType,
|
||||
}
|
||||
|
||||
impl ChatChannelInfo {
|
||||
pub fn as_transmissible(&self) -> Typed {
|
||||
Typed::HashMap(vec![
|
||||
(Typed::Str("channelName".into()), Typed::Str(self.channel_name.clone().into())),
|
||||
(Typed::Str("members".into()), Typed::Arr(Arr {
|
||||
ty: polariton::serdes::TypePrefix::HashMap, // hashtable
|
||||
items: self.members.iter().map(|x| x.as_transmissible()).collect(),
|
||||
})),
|
||||
(Typed::Str("channelType".into()), Typed::Int(self.channel_ty as _)),
|
||||
].into())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ChatChannelMember {
|
||||
pub name: String,
|
||||
pub use_custom_avatar: bool,
|
||||
pub state: ChatPlayerState,
|
||||
pub custom_avatar: Vec<u8>, // always PNG?
|
||||
pub avatar_id: i32,
|
||||
}
|
||||
|
||||
impl ChatChannelMember {
|
||||
pub fn as_transmissible(&self) -> Typed {
|
||||
Typed::HashMap(vec![
|
||||
(Typed::Str("name".into()), Typed::Str(self.name.clone().into())),
|
||||
(Typed::Str("useCustomAvatar".into()), Typed::Bool(self.use_custom_avatar.into())),
|
||||
(Typed::Str("state".into()), Typed::Int(self.state as _)),
|
||||
if self.use_custom_avatar {
|
||||
(Typed::Str("customAvatar".into()), Typed::Bytes(self.custom_avatar.clone().into()))
|
||||
} else {
|
||||
(Typed::Str("avatarId".into()), Typed::Int(self.avatar_id))
|
||||
},
|
||||
].into())
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[repr(u8)]
|
||||
#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
|
||||
pub enum ChatChannelType {
|
||||
None = 0,
|
||||
Public = 1,
|
||||
Battle = 2,
|
||||
BattleTeam = 3,
|
||||
Platoon = 4,
|
||||
Custom = 5,
|
||||
Clan = 6,
|
||||
Private = 7,
|
||||
CustomGame = 8,
|
||||
}
|
||||
|
||||
impl ChatChannelType {
|
||||
pub fn from_u8(num: u8) -> Result<Self, i16> {
|
||||
match num {
|
||||
0 => Ok(Self::None),
|
||||
1 => Ok(Self::Public),
|
||||
2 => Ok(Self::Battle),
|
||||
3 => Ok(Self::BattleTeam),
|
||||
4 => Ok(Self::Platoon),
|
||||
5 => Ok(Self::Custom),
|
||||
6 => Ok(Self::Clan),
|
||||
7 => Ok(Self::Private),
|
||||
8 => Ok(Self::CustomGame),
|
||||
_ => Err(crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[repr(u8)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum ChatPlayerState {
|
||||
Idk0 = 0,
|
||||
Idk1 = 1,
|
||||
Idk2 = 2,
|
||||
// FIXME
|
||||
}
|
||||
@@ -11,6 +11,7 @@ pub mod voting;
|
||||
pub mod weapon_list;
|
||||
pub mod weapon_upgrade;
|
||||
pub mod crf;
|
||||
pub mod channel;
|
||||
|
||||
pub mod error_codes;
|
||||
|
||||
|
||||
@@ -4,8 +4,34 @@ use serde::{Serialize, Deserialize};
|
||||
pub struct ChatConfig {
|
||||
#[serde(default = "default_pub_channs")]
|
||||
pub public_channels: Vec<String>,
|
||||
#[serde(default = "default_command_chann")]
|
||||
pub command_channel: String,
|
||||
pub commands: Vec<ChatCommand>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct ChatCommand {
|
||||
pub regex: String,
|
||||
pub op: ChatOperation,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(tag = "type")]
|
||||
pub enum ChatOperation {
|
||||
BuiltIn(BuiltInChatOperation),
|
||||
Custom,
|
||||
#[serde(alias = "No-op")]
|
||||
Nop,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(tag = "built_in")]
|
||||
pub enum BuiltInChatOperation {
|
||||
OnlineUsers,
|
||||
TotalUsers,
|
||||
}
|
||||
|
||||
|
||||
fn default_pub_channs() -> Vec<String> {
|
||||
vec![
|
||||
"main".to_owned(),
|
||||
@@ -13,3 +39,8 @@ fn default_pub_channs() -> Vec<String> {
|
||||
"openjam_worship".to_owned(),
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
fn default_command_chann() -> String {
|
||||
"sys".to_owned()
|
||||
}
|
||||
|
||||
@@ -281,4 +281,11 @@ impl <C: Clone> super::ConfigProvider<C> for CubeConfig {
|
||||
fn cubes(&self) -> &'_ std::collections::HashMap<String, crate::persist::Cube> {
|
||||
&self.cubes
|
||||
}
|
||||
|
||||
fn chat_system_config(&self) -> super::ChatSystemConfig {
|
||||
super::ChatSystemConfig {
|
||||
command_channel: self.chat.command_channel.clone(),
|
||||
commands: self.chat.commands.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ mod cubes_json;
|
||||
pub use cubes_json::CubeConfig;
|
||||
|
||||
mod traits;
|
||||
pub use traits::{ConfigProvider, CompleteCampaignProvider, DevMessageProvider, ServerConfig, GarageUpgrades, GarageUpgradeIncrement};
|
||||
pub use traits::{ConfigProvider, CompleteCampaignProvider, DevMessageProvider, ServerConfig, GarageUpgrades, GarageUpgradeIncrement, ChatSystemConfig};
|
||||
|
||||
pub type ConfigImpl = CubeConfig;
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ pub trait ConfigProvider<C: Clone> {
|
||||
fn garage_upgrades(&self) -> GarageUpgrades;
|
||||
async fn factory(&self) -> Result<crate::factory::Factory, Box<dyn std::error::Error + 'static>>;
|
||||
fn cubes(&self) -> &'_ std::collections::HashMap<String, crate::persist::Cube>;
|
||||
fn chat_system_config(&self) -> ChatSystemConfig;
|
||||
}
|
||||
|
||||
pub struct CompleteCampaignProvider {
|
||||
@@ -121,3 +122,9 @@ impl GarageUpgrades {
|
||||
].into())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ChatSystemConfig {
|
||||
pub command_channel: String,
|
||||
pub commands: Vec<crate::persist::ChatCommand>,
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ mod settings;
|
||||
pub use settings::Settings;
|
||||
|
||||
mod chat;
|
||||
pub use chat::ChatConfig;
|
||||
pub use chat::{ChatConfig, ChatCommand, ChatOperation, BuiltInChatOperation};
|
||||
|
||||
mod vehicle_factory;
|
||||
pub use vehicle_factory::{FactoryConfig, AdapterSettings, ArcFactorySettings};
|
||||
|
||||
@@ -527,3 +527,78 @@ impl <C: Clone> super::User<C> for UserData {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl super::ChatUser for UserData {
|
||||
async fn subscribed_channels(&self) -> Result<polariton::operation::Typed<()>, i16> {
|
||||
let channels = self.subscribed_channels_strings().await?;
|
||||
Ok(polariton::operation::Typed::Arr(polariton::operation::Arr {
|
||||
ty: polariton::serdes::TypePrefix::HashMap, // hashtable
|
||||
items: channels.iter().map(|name| crate::data::channel::ChatChannelInfo {
|
||||
channel_name: name.to_owned(),
|
||||
members: Vec::default(),
|
||||
channel_ty: crate::data::channel::ChatChannelType::Public,
|
||||
}.as_transmissible()).collect()
|
||||
}))
|
||||
}
|
||||
|
||||
async fn subscribed_channels_strings(&self) -> Result<Vec<String>, i16> {
|
||||
let channels = self.db.user_aux_by_user_id_and_descriptor(self.account.id, rc_database::schema::user_aux::Descriptor::SubscribedChannels).await.map_err(|e| {
|
||||
log::error!("Failed to retrieve SubscribedChannels (user_aux) for user_id {}: {}", self.account.id, e);
|
||||
crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16
|
||||
})?.ok_or_else(|| {
|
||||
log::error!("Failed to find SubscribedChannels (user_aux) for user_id {}", self.account.id);
|
||||
crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16
|
||||
})?;
|
||||
let channels = serde_json::from_str::<Vec<String>>(&channels.data).map_err(|e| {
|
||||
log::error!("Failed to parse SubscribedChannels (user_aux) for user_id {}: {}", self.account.id, e);
|
||||
crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16
|
||||
})?;
|
||||
Ok(channels)
|
||||
}
|
||||
|
||||
async fn add_subscribed_channel(&self, channel: String, channel_ty: crate::data::channel::ChatChannelType) -> Result<polariton::operation::Typed<()>, i16> {
|
||||
if let crate::data::channel::ChatChannelType::Public = channel_ty {
|
||||
let mut sub_channels = self.subscribed_channels_strings().await?;
|
||||
sub_channels.push(channel.clone());
|
||||
let new_data = serde_json::to_string(&sub_channels).map_err(|e| {
|
||||
log::error!("Failed to convert to JSON SubscribedChannels (user_aux) for user_id {}: {}", self.account.id, e);
|
||||
crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16
|
||||
})?;
|
||||
self.db.update_user_aux_by_user_id_and_descriptor(rc_database::schema::user_aux::ActiveModel {
|
||||
data: rc_database::sea_orm::ActiveValue::Set(new_data),
|
||||
..Default::default()
|
||||
}, self.account.id, rc_database::schema::user_aux::Descriptor::SubscribedChannels).await.map_err(|e| {
|
||||
log::error!("Failed to update SubscribedChannels (user_aux) for user_id {}: {}", self.account.id, e);
|
||||
crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16
|
||||
})?;
|
||||
}
|
||||
|
||||
Ok(crate::data::channel::ChatChannelInfo {
|
||||
channel_name: channel,
|
||||
members: Vec::default(),
|
||||
channel_ty,
|
||||
}.as_transmissible())
|
||||
}
|
||||
|
||||
async fn remove_subscribed_channel(&self, channel: String, channel_ty: crate::data::channel::ChatChannelType) -> Result<(), i16> {
|
||||
if let crate::data::channel::ChatChannelType::Public = channel_ty {
|
||||
let mut sub_channels = self.subscribed_channels_strings().await?;
|
||||
if let Some(index) = sub_channels.iter().position(|chann| chann == &channel) {
|
||||
sub_channels.swap_remove(index);
|
||||
let new_data = serde_json::to_string(&sub_channels).map_err(|e| {
|
||||
log::error!("Failed to convert to JSON SubscribedChannels (user_aux) for user_id {}: {}", self.account.id, e);
|
||||
crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16
|
||||
})?;
|
||||
self.db.update_user_aux_by_user_id_and_descriptor(rc_database::schema::user_aux::ActiveModel {
|
||||
data: rc_database::sea_orm::ActiveValue::Set(new_data),
|
||||
..Default::default()
|
||||
}, self.account.id, rc_database::schema::user_aux::Descriptor::SubscribedChannels).await.map_err(|e| {
|
||||
log::error!("Failed to update SubscribedChannels (user_aux) for user_id {}: {}", self.account.id, e);
|
||||
crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16
|
||||
})?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,25 +69,26 @@ fn default_user_data(info: &super::RegistrationInfo) -> rc_database::schema::use
|
||||
}
|
||||
|
||||
fn default_user_aux_data(user_id: u32) -> Vec<rc_database::schema::user_aux::ActiveModel> {
|
||||
let current_time = current_unix_time();
|
||||
vec![
|
||||
rc_database::schema::user_aux::ActiveModel {
|
||||
id: Default::default(),
|
||||
user_id: rc_database::sea_orm::ActiveValue::Set(user_id),
|
||||
creation_time: rc_database::sea_orm::ActiveValue::Set(current_unix_time()),
|
||||
creation_time: rc_database::sea_orm::ActiveValue::Set(current_time),
|
||||
descriptor: rc_database::sea_orm::ActiveValue::Set(rc_database::schema::user_aux::Descriptor::UserXP),
|
||||
data: rc_database::sea_orm::ActiveValue::Set("0".to_owned()),
|
||||
},
|
||||
rc_database::schema::user_aux::ActiveModel {
|
||||
id: Default::default(),
|
||||
user_id: rc_database::sea_orm::ActiveValue::Set(user_id),
|
||||
creation_time: rc_database::sea_orm::ActiveValue::Set(current_unix_time()),
|
||||
creation_time: rc_database::sea_orm::ActiveValue::Set(current_time),
|
||||
descriptor: rc_database::sea_orm::ActiveValue::Set(rc_database::schema::user_aux::Descriptor::PremiumExpiry),
|
||||
data: rc_database::sea_orm::ActiveValue::Set(current_unix_time().to_string()),
|
||||
data: rc_database::sea_orm::ActiveValue::Set(current_time.to_string()),
|
||||
},
|
||||
rc_database::schema::user_aux::ActiveModel {
|
||||
id: Default::default(),
|
||||
user_id: rc_database::sea_orm::ActiveValue::Set(user_id),
|
||||
creation_time: rc_database::sea_orm::ActiveValue::Set(current_unix_time()),
|
||||
creation_time: rc_database::sea_orm::ActiveValue::Set(current_time),
|
||||
descriptor: rc_database::sea_orm::ActiveValue::Set(rc_database::schema::user_aux::Descriptor::UnlockedParts),
|
||||
data: rc_database::sea_orm::ActiveValue::Set(
|
||||
r#"{
|
||||
@@ -98,37 +99,44 @@ r#"{
|
||||
rc_database::schema::user_aux::ActiveModel {
|
||||
id: Default::default(),
|
||||
user_id: rc_database::sea_orm::ActiveValue::Set(user_id),
|
||||
creation_time: rc_database::sea_orm::ActiveValue::Set(current_unix_time()),
|
||||
creation_time: rc_database::sea_orm::ActiveValue::Set(current_time),
|
||||
descriptor: rc_database::sea_orm::ActiveValue::Set(rc_database::schema::user_aux::Descriptor::TechPoints),
|
||||
data: rc_database::sea_orm::ActiveValue::Set("1337".to_owned()),
|
||||
},
|
||||
rc_database::schema::user_aux::ActiveModel {
|
||||
id: Default::default(),
|
||||
user_id: rc_database::sea_orm::ActiveValue::Set(user_id),
|
||||
creation_time: rc_database::sea_orm::ActiveValue::Set(current_unix_time()),
|
||||
creation_time: rc_database::sea_orm::ActiveValue::Set(current_time),
|
||||
descriptor: rc_database::sea_orm::ActiveValue::Set(rc_database::schema::user_aux::Descriptor::UserRank),
|
||||
data: rc_database::sea_orm::ActiveValue::Set("1".to_owned()),
|
||||
},
|
||||
rc_database::schema::user_aux::ActiveModel {
|
||||
id: Default::default(),
|
||||
user_id: rc_database::sea_orm::ActiveValue::Set(user_id),
|
||||
creation_time: rc_database::sea_orm::ActiveValue::Set(current_unix_time()),
|
||||
creation_time: rc_database::sea_orm::ActiveValue::Set(current_time),
|
||||
descriptor: rc_database::sea_orm::ActiveValue::Set(rc_database::schema::user_aux::Descriptor::UserFreeCurrency),
|
||||
data: rc_database::sea_orm::ActiveValue::Set("10000".to_owned()),
|
||||
},
|
||||
rc_database::schema::user_aux::ActiveModel {
|
||||
id: Default::default(),
|
||||
user_id: rc_database::sea_orm::ActiveValue::Set(user_id),
|
||||
creation_time: rc_database::sea_orm::ActiveValue::Set(current_unix_time()),
|
||||
creation_time: rc_database::sea_orm::ActiveValue::Set(current_time),
|
||||
descriptor: rc_database::sea_orm::ActiveValue::Set(rc_database::schema::user_aux::Descriptor::UserPaidCurrency),
|
||||
data: rc_database::sea_orm::ActiveValue::Set("1000".to_owned()),
|
||||
},
|
||||
rc_database::schema::user_aux::ActiveModel {
|
||||
id: Default::default(),
|
||||
user_id: rc_database::sea_orm::ActiveValue::Set(user_id),
|
||||
creation_time: rc_database::sea_orm::ActiveValue::Set(current_unix_time()),
|
||||
creation_time: rc_database::sea_orm::ActiveValue::Set(current_time),
|
||||
descriptor: rc_database::sea_orm::ActiveValue::Set(rc_database::schema::user_aux::Descriptor::GarageSlotOrder),
|
||||
data: rc_database::sea_orm::ActiveValue::Set("[0]".to_owned()),
|
||||
},
|
||||
rc_database::schema::user_aux::ActiveModel {
|
||||
id: Default::default(),
|
||||
user_id: rc_database::sea_orm::ActiveValue::Set(user_id),
|
||||
creation_time: rc_database::sea_orm::ActiveValue::Set(current_time),
|
||||
descriptor: rc_database::sea_orm::ActiveValue::Set(rc_database::schema::user_aux::Descriptor::SubscribedChannels),
|
||||
data: rc_database::sea_orm::ActiveValue::Set("[\"sys\"]".to_owned()),
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ mod inventory;
|
||||
pub use inventory::UnlockedParts;
|
||||
|
||||
mod traits;
|
||||
pub use traits::{UserProvider, User, UserToken, UserSlots, UserSlotData, VehicleData, UserInfo, UserLoginInfo, ExtraUserInfo, UserAuthenticator, NewSlotData, UserId, RegistrationInfo, VehicleUploadData};
|
||||
pub use traits::{UserProvider, User, UserToken, UserSlots, UserSlotData, VehicleData, UserInfo, UserLoginInfo, ExtraUserInfo, UserAuthenticator, NewSlotData, UserId, RegistrationInfo, VehicleUploadData, ChatUser};
|
||||
|
||||
pub const TOKEN_SECRET_FILENAME: &str = "token_secret.key";
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ pub trait UserAuthenticator {
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
pub trait User<C> {
|
||||
pub trait User<C>: ChatUser {
|
||||
fn ext(&self, ty: std::any::TypeId) -> Option<&'_ (dyn std::any::Any + Send + Sync + 'static)>;
|
||||
fn token(&self) -> &'_ super::UserToken;
|
||||
fn is_mod(&self) -> bool;
|
||||
@@ -121,3 +121,14 @@ pub struct VehicleUploadData {
|
||||
pub description: String,
|
||||
pub thumbnail: Vec<u8>,
|
||||
}
|
||||
|
||||
use polariton::operation::Typed;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
pub trait ChatUser {
|
||||
async fn subscribed_channels(&self) -> Result<Typed<()>, i16>;
|
||||
async fn subscribed_channels_strings(&self) -> Result<Vec<String>, i16>;
|
||||
async fn add_subscribed_channel(&self, channel: String, channel_ty: crate::data::channel::ChatChannelType) -> Result<Typed<()>, i16>;
|
||||
async fn remove_subscribed_channel(&self, channel: String, channel_ty: crate::data::channel::ChatChannelType) -> Result<(), i16>;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user