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:
@@ -14447,6 +14447,22 @@
|
|||||||
"main",
|
"main",
|
||||||
"sys",
|
"sys",
|
||||||
"jam_club"
|
"jam_club"
|
||||||
|
],
|
||||||
|
"commands": [
|
||||||
|
{
|
||||||
|
"regex": "\\?online",
|
||||||
|
"op": {
|
||||||
|
"type": "BuiltIn",
|
||||||
|
"built_in": "OnlineUsers"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"regex": "\\?users",
|
||||||
|
"op": {
|
||||||
|
"type": "BuiltIn",
|
||||||
|
"built_in": "TotalUsers"
|
||||||
|
}
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"factory": {
|
"factory": {
|
||||||
@@ -14515,4 +14531,4 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1 +1 @@
|
|||||||
pub mod channel;
|
pub use rc_core::data::channel;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#![forbid(unsafe_code)]
|
#![forbid(unsafe_code)]
|
||||||
mod cli;
|
mod cli;
|
||||||
mod state;
|
mod state;
|
||||||
mod persist;
|
|
||||||
mod op_handler;
|
mod op_handler;
|
||||||
pub use op_handler::SimpleChatFunc;
|
pub use op_handler::SimpleChatFunc;
|
||||||
|
|
||||||
@@ -10,6 +9,7 @@ mod operations;
|
|||||||
mod events;
|
mod events;
|
||||||
|
|
||||||
use polariton_auth::Handshake;
|
use polariton_auth::Handshake;
|
||||||
|
use rc_core::ConfigProvider;
|
||||||
use tokio::net;
|
use tokio::net;
|
||||||
|
|
||||||
use polariton::packet::{Data, Message, Packet, StandardMessage};
|
use polariton::packet::{Data, Message, Packet, StandardMessage};
|
||||||
@@ -26,9 +26,9 @@ async fn main() -> std::io::Result<()> {
|
|||||||
let cubes = rc_core::persist::config::ConfigImpl::load(&args.assets).expect("Bad config data");
|
let cubes = rc_core::persist::config::ConfigImpl::load(&args.assets).expect("Bad config data");
|
||||||
let users = std::sync::Arc::new(rc_core::persist::user::UserImpl::load(&args.data, &cubes).await.expect("Bad user data"));
|
let users = std::sync::Arc::new(rc_core::persist::user::UserImpl::load(&args.data, &cubes).await.expect("Bad user data"));
|
||||||
|
|
||||||
let chat_system = state::chat::ChatImpl::new(&args.assets, &args.data).expect("Bad chat config data");
|
let chat_system = state::chat::ChatImpl::new(<rc_core::ConfigImpl as ConfigProvider<()>>::chat_system_config(&cubes)).expect("Bad chat config data");
|
||||||
|
|
||||||
let server = std::sync::Arc::new(polariton_server::Server::new(operations::handler(chat_system, &args.data, &cubes), polariton_server::events::EventsHandler::new()));
|
let server = std::sync::Arc::new(polariton_server::Server::new(operations::handler(chat_system, &cubes), polariton_server::events::EventsHandler::new()));
|
||||||
|
|
||||||
let ip_addr: std::net::IpAddr = args.ip.parse().expect("Invalid IP address");
|
let ip_addr: std::net::IpAddr = args.ip.parse().expect("Invalid IP address");
|
||||||
|
|
||||||
|
|||||||
@@ -1,61 +1,35 @@
|
|||||||
use crate::SimpleChatFunc;
|
//use rc_core::persist::user::ChatUser;
|
||||||
use crate::persist::chat_user::ChatUser;
|
use polariton::operation::{ParameterTable, OperationResponse};
|
||||||
use polariton::operation::ParameterTable;
|
|
||||||
|
const CODE: u8 = 11;
|
||||||
|
|
||||||
const PARAM_KEY: u8 = 18;
|
const PARAM_KEY: u8 = 18;
|
||||||
|
|
||||||
pub(super) fn all_channels_provider(chat_system: crate::state::ChatImpl) -> SimpleChatFunc<11, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy, &crate::state::ChatImpl) -> Result<ParameterTable, i16>) + Sync + Sync> {
|
async fn do_handling(params: ParameterTable<()>, user: &crate::UserTy) -> Result<ParameterTable, i16> {
|
||||||
SimpleChatFunc::new(|params, user: &crate::UserTy, _chat_system: &crate::state::ChatImpl| {
|
let mut params = params.to_dict();
|
||||||
let mut params = params.to_dict();
|
let user_info = user.user()?;
|
||||||
let user_trait = user.user()?;
|
params.insert(PARAM_KEY, user_info.subscribed_channels().await?);
|
||||||
let chat_user = super::get_chat_user(user_trait.as_ref().as_ref());
|
Ok(params.into())
|
||||||
//let chat_user: &ChatUserImpl = user_trait.ext(std::any::TypeId::of::<ChatUserImpl>()).unwrap().downcast_ref().unwrap();
|
}
|
||||||
params.insert(PARAM_KEY, chat_user.subscribed_channels());
|
|
||||||
/*params.insert(PARAM_KEY, Typed::Arr(Arr {
|
pub struct JoinedChannelsProvider;
|
||||||
ty: polariton::serdes::TypePrefix::HashMap, // hashtable
|
|
||||||
items: vec![
|
#[async_trait::async_trait]
|
||||||
ChatChannelInfo {
|
impl polariton_server::operations::Operation<()> for JoinedChannelsProvider {
|
||||||
channel_name: "RE_public_channel0".to_owned(),
|
type User = crate::UserTy;
|
||||||
members: vec![
|
|
||||||
ChatChannelMember {
|
async fn handle_async(&self, params: ParameterTable<()>, user: &Self::User) -> OperationResponse<()> {
|
||||||
name: "RE_chat0_username0".to_owned(),
|
polariton_server::operations::result_to_op_resp::<CODE, ()>(do_handling(params, user).await)
|
||||||
use_custom_avatar: false,
|
}
|
||||||
state: ChatPlayerState::Idk1,
|
}
|
||||||
custom_avatar: Vec::default(),
|
|
||||||
avatar_id: 2,
|
impl polariton_server::operations::OperationCode for JoinedChannelsProvider {
|
||||||
},
|
fn op_code() -> u8 {
|
||||||
ChatChannelMember {
|
CODE
|
||||||
name: "RE_chat0_username1".to_owned(),
|
}
|
||||||
use_custom_avatar: false,
|
}
|
||||||
state: ChatPlayerState::Idk2,
|
|
||||||
custom_avatar: Vec::default(),
|
|
||||||
avatar_id: 3,
|
pub(super) fn all_channels_provider() -> JoinedChannelsProvider {
|
||||||
},
|
JoinedChannelsProvider
|
||||||
],
|
|
||||||
channel_ty: ChatChannelType::Public,
|
|
||||||
}.as_transmissible(),
|
|
||||||
ChatChannelInfo {
|
|
||||||
channel_name: "RE_custom_channel1".to_owned(),
|
|
||||||
members: vec![
|
|
||||||
ChatChannelMember {
|
|
||||||
name: "RE_chat1_username0".to_owned(),
|
|
||||||
use_custom_avatar: false,
|
|
||||||
state: ChatPlayerState::Idk0,
|
|
||||||
custom_avatar: Vec::default(),
|
|
||||||
avatar_id: 2,
|
|
||||||
},
|
|
||||||
ChatChannelMember {
|
|
||||||
name: "RE_chat1_username1".to_owned(),
|
|
||||||
use_custom_avatar: false,
|
|
||||||
state: ChatPlayerState::Idk1,
|
|
||||||
custom_avatar: Vec::default(),
|
|
||||||
avatar_id: 3,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
channel_ty: ChatChannelType::Custom,
|
|
||||||
}.as_transmissible(),
|
|
||||||
],
|
|
||||||
}));*/
|
|
||||||
Ok(params.into())
|
|
||||||
}, chat_system)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,41 +1,85 @@
|
|||||||
use crate::{persist::chat_user::ChatUser, SimpleChatFunc};
|
use polariton::operation::{ParameterTable, Typed, OperationResponse};
|
||||||
use polariton::operation::{ParameterTable, Typed};
|
|
||||||
|
const JOIN_CODE: u8 = 1;
|
||||||
|
const LEAVE_CODE: u8 = 5;
|
||||||
|
|
||||||
const CHANNEL_NAME_PARAM_KEY: u8 = 3; // str; in
|
const CHANNEL_NAME_PARAM_KEY: u8 = 3; // str; in
|
||||||
const CHANNEL_TYPE_PARAM_KEY: u8 = 1; // int; in
|
const CHANNEL_TYPE_PARAM_KEY: u8 = 1; // int; in
|
||||||
const CHANNEL_PASSWORD_PARAM_KEY: u8 = 16; // str; in
|
const CHANNEL_PASSWORD_PARAM_KEY: u8 = 16; // str; in
|
||||||
const CHANNEL_INFO_PARAM_KEY: u8 = 17; // hashtable; out
|
const CHANNEL_INFO_PARAM_KEY: u8 = 17; // hashtable; out
|
||||||
|
|
||||||
pub(super) fn join_channel_provider(chat_system: crate::state::ChatImpl) -> SimpleChatFunc<1, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy, &crate::state::ChatImpl) -> Result<ParameterTable, i16>) + Sync + Sync> {
|
pub struct JoinChannelProvider {
|
||||||
SimpleChatFunc::new(|params, user: &crate::UserTy, chat_system| {
|
chat_system: crate::state::ChatImpl,
|
||||||
let mut params = params.to_dict();
|
|
||||||
if let Some(Typed::Str(chann_name)) = params.remove(&CHANNEL_NAME_PARAM_KEY) {
|
|
||||||
if let Some(Typed::Int(chann_ty)) = params.remove(&CHANNEL_TYPE_PARAM_KEY) {
|
|
||||||
if let Some(Typed::Str(channel_pwd)) = params.remove(&CHANNEL_PASSWORD_PARAM_KEY) {
|
|
||||||
log::warn!("Received channel password {} which is unsupported", channel_pwd.string);
|
|
||||||
}
|
|
||||||
let user_info = user.user()?;
|
|
||||||
let chat_user = super::get_chat_user(user_info.as_ref().as_ref());
|
|
||||||
chat_system.system_mut().join_channel(user_info.token().uuid.clone(), chann_name.string.clone());
|
|
||||||
let response = chat_user.add_subscribed_channel(chann_name.string, crate::data::channel::ChatChannelType::from_u8(chann_ty as _)?);
|
|
||||||
params.insert(CHANNEL_INFO_PARAM_KEY, response);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(params.into())
|
|
||||||
}, chat_system)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn leave_channel_provider(chat_system: crate::state::ChatImpl) -> SimpleChatFunc<5, crate::UserTy, impl (Fn(ParameterTable, &crate::UserTy, &crate::state::ChatImpl) -> Result<ParameterTable, i16>) + Sync + Sync> {
|
pub(super) fn join_channel_provider(chat_system: crate::state::ChatImpl) -> JoinChannelProvider {
|
||||||
SimpleChatFunc::new(|params, user: &crate::UserTy, chat_system| {
|
JoinChannelProvider { chat_system }
|
||||||
let mut params = params.to_dict();
|
}
|
||||||
if let Some(Typed::Str(chann_name)) = params.remove(&CHANNEL_NAME_PARAM_KEY) {
|
|
||||||
if let Some(Typed::Int(chann_ty)) = params.remove(&CHANNEL_TYPE_PARAM_KEY) {
|
async fn do_join_handling(params: ParameterTable<()>, user: &crate::UserTy, chat_system: &crate::state::ChatImpl) -> Result<ParameterTable, i16> {
|
||||||
let user_info = user.user()?;
|
let mut params = params.to_dict();
|
||||||
let chat_user = super::get_chat_user(user_info.as_ref().as_ref());
|
if let Some(Typed::Str(chann_name)) = params.remove(&CHANNEL_NAME_PARAM_KEY) {
|
||||||
chat_system.system_mut().leave_channel(user_info.token().uuid.clone(), chann_name.string.clone());
|
if let Some(Typed::Int(chann_ty)) = params.remove(&CHANNEL_TYPE_PARAM_KEY) {
|
||||||
chat_user.remove_subscribed_channel(chann_name.string, crate::data::channel::ChatChannelType::from_u8(chann_ty as _)?);
|
if let Some(Typed::Str(channel_pwd)) = params.remove(&CHANNEL_PASSWORD_PARAM_KEY) {
|
||||||
|
log::warn!("Received channel password {} which is unsupported", channel_pwd.string);
|
||||||
}
|
}
|
||||||
|
let user_info = user.user()?;
|
||||||
|
//let chat_user = super::get_chat_user(user_info.as_ref().as_ref());
|
||||||
|
chat_system.system_mut().join_channel(user_info.token().uuid.clone(), chann_name.string.clone());
|
||||||
|
let response = user_info.add_subscribed_channel(chann_name.string, crate::data::channel::ChatChannelType::from_u8(chann_ty as _)?).await?;
|
||||||
|
params.insert(CHANNEL_INFO_PARAM_KEY, response);
|
||||||
}
|
}
|
||||||
Ok(params.into())
|
}
|
||||||
}, chat_system)
|
Ok(params.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl polariton_server::operations::Operation<()> for JoinChannelProvider {
|
||||||
|
type User = crate::UserTy;
|
||||||
|
|
||||||
|
async fn handle_async(&self, params: ParameterTable<()>, user: &Self::User) -> OperationResponse<()> {
|
||||||
|
polariton_server::operations::result_to_op_resp::<JOIN_CODE, ()>(do_join_handling(params, user, &self.chat_system).await)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl polariton_server::operations::OperationCode for JoinChannelProvider {
|
||||||
|
fn op_code() -> u8 {
|
||||||
|
JOIN_CODE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LeaveChannelProvider {
|
||||||
|
chat_system: crate::state::ChatImpl,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn leave_channel_provider(chat_system: crate::state::ChatImpl) -> LeaveChannelProvider {
|
||||||
|
LeaveChannelProvider { chat_system }
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn do_leave_handling(params: ParameterTable<()>, user: &crate::UserTy, chat_system: &crate::state::ChatImpl) -> Result<ParameterTable, i16> {
|
||||||
|
let mut params = params.to_dict();
|
||||||
|
if let Some(Typed::Str(chann_name)) = params.remove(&CHANNEL_NAME_PARAM_KEY) {
|
||||||
|
if let Some(Typed::Int(chann_ty)) = params.remove(&CHANNEL_TYPE_PARAM_KEY) {
|
||||||
|
let user_info = user.user()?;
|
||||||
|
//let chat_user = super::get_chat_user(user_info.as_ref().as_ref());
|
||||||
|
chat_system.system_mut().leave_channel(user_info.token().uuid.clone(), chann_name.string.clone());
|
||||||
|
user_info.remove_subscribed_channel(chann_name.string, crate::data::channel::ChatChannelType::from_u8(chann_ty as _)?).await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(params.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl polariton_server::operations::Operation<()> for LeaveChannelProvider {
|
||||||
|
type User = crate::UserTy;
|
||||||
|
|
||||||
|
async fn handle_async(&self, params: ParameterTable<()>, user: &Self::User) -> OperationResponse<()> {
|
||||||
|
polariton_server::operations::result_to_op_resp::<LEAVE_CODE, ()>(do_leave_handling(params, user, &self.chat_system).await)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl polariton_server::operations::OperationCode for LeaveChannelProvider {
|
||||||
|
fn op_code() -> u8 {
|
||||||
|
LEAVE_CODE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,26 +6,24 @@ mod send_message;
|
|||||||
mod public_channels;
|
mod public_channels;
|
||||||
mod join_channel;
|
mod join_channel;
|
||||||
mod user_online;
|
mod user_online;
|
||||||
|
mod subscribed_channels;
|
||||||
|
|
||||||
use polariton_server::operations::OperationsHandler;
|
use polariton_server::operations::OperationsHandler;
|
||||||
|
|
||||||
pub fn handler(chat_system: crate::state::chat::ChatImpl, data_root: impl AsRef<std::path::Path>, conf: &rc_core::persist::config::ConfigImpl) -> OperationsHandler<crate::UserTy> {
|
pub fn handler(chat_system: crate::state::chat::ChatImpl, conf: &rc_core::persist::config::ConfigImpl) -> OperationsHandler<crate::UserTy> {
|
||||||
OperationsHandler::new()
|
OperationsHandler::new()
|
||||||
.modify(rc_core::polariton::OpIdCopy)
|
.modify(rc_core::polariton::OpIdCopy)
|
||||||
.add(more_auth::MoreLobbyAuth::new(chat_system.clone(), data_root))
|
.add(more_auth::MoreLobbyAuth::new(chat_system.clone()))
|
||||||
.add(chat_ignores::ignores_provider())
|
.add(chat_ignores::ignores_provider())
|
||||||
.add(pending_sanctions::pending_sanctions_checker())
|
.add(pending_sanctions::pending_sanctions_checker())
|
||||||
.add(all_joined_channels::all_channels_provider(chat_system.clone()))
|
.add(all_joined_channels::all_channels_provider())
|
||||||
.add(polariton_server::operations::Ack::<12, _>::default())
|
//.add(polariton_server::operations::Ack::<12, _>::default())
|
||||||
.add(send_message::send_public_message_handler(chat_system.clone()))
|
.add(send_message::send_public_message_handler(chat_system.clone()))
|
||||||
.add(public_channels::public_channels_provider(conf))
|
.add(public_channels::public_channels_provider(conf))
|
||||||
.add(join_channel::join_channel_provider(chat_system.clone()))
|
.add(join_channel::join_channel_provider(chat_system.clone()))
|
||||||
.add(user_online::is_online_provider(chat_system.clone()))
|
.add(user_online::is_online_provider(chat_system.clone()))
|
||||||
.add(send_message::send_private_message_handler(chat_system.clone()))
|
.add(send_message::send_private_message_handler(chat_system.clone()))
|
||||||
.add(join_channel::leave_channel_provider(chat_system.clone()))
|
.add(join_channel::leave_channel_provider(chat_system.clone()))
|
||||||
|
.add(subscribed_channels::all_subbed_channels_provider())
|
||||||
//.add(polariton_server::operations::Ack::<00000, _>::default())
|
//.add(polariton_server::operations::Ack::<00000, _>::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(self) fn get_chat_user<'a, C>(user: &'a dyn rc_core::persist::user::User<C>) -> &'a crate::persist::chat_user::ChatUserImpl {
|
|
||||||
user.ext(std::any::TypeId::of::<crate::persist::chat_user::ChatUserImpl>()).unwrap().downcast_ref().unwrap()
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,24 +1,23 @@
|
|||||||
use polariton::operation::Typed;
|
use polariton::operation::Typed;
|
||||||
use polariton_server::operations::{Operation, OperationCode};
|
use polariton_server::operations::{Operation, OperationCode};
|
||||||
|
|
||||||
use crate::persist::chat_user::{ChatUser, ChatUserImpl};
|
//use crate::persist::chat_user::{ChatUser, ChatUserImpl};
|
||||||
|
//use rc_core::persist::user::ChatUser;
|
||||||
|
|
||||||
pub struct MoreLobbyAuth {
|
pub struct MoreLobbyAuth {
|
||||||
chat_system: crate::state::chat::ChatImpl,
|
chat_system: crate::state::chat::ChatImpl,
|
||||||
root: std::path::PathBuf,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MoreLobbyAuth {
|
impl MoreLobbyAuth {
|
||||||
const AUTH_PAYLOAD_KEY: u8 = 245;
|
const AUTH_PAYLOAD_KEY: u8 = 245;
|
||||||
|
|
||||||
pub fn new(chat_system: crate::state::chat::ChatImpl, root: impl AsRef<std::path::Path>) -> Self {
|
pub fn new(chat_system: crate::state::chat::ChatImpl) -> Self {
|
||||||
Self {
|
Self {
|
||||||
chat_system,
|
chat_system,
|
||||||
root: root.as_ref().to_path_buf(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_ext_map(&self, token: &rc_core::persist::user::UserToken) -> Option<std::collections::HashMap<std::any::TypeId, Box<dyn std::any::Any + Send + Sync + 'static>>> {
|
/*fn build_ext_map(&self, token: &rc_core::persist::user::UserToken) -> Option<std::collections::HashMap<std::any::TypeId, Box<dyn std::any::Any + Send + Sync + 'static>>> {
|
||||||
let user_dir = self.root.join(rc_core::persist::user::USERS_DIR).join(&token.uuid);
|
let user_dir = self.root.join(rc_core::persist::user::USERS_DIR).join(&token.uuid);
|
||||||
let data = if let Ok(data) = ChatUserImpl::load(&user_dir) {
|
let data = if let Ok(data) = ChatUserImpl::load(&user_dir) {
|
||||||
data
|
data
|
||||||
@@ -29,15 +28,15 @@ impl MoreLobbyAuth {
|
|||||||
let mut map = std::collections::HashMap::with_capacity(1);
|
let mut map = std::collections::HashMap::with_capacity(1);
|
||||||
map.insert(std::any::TypeId::of::<ChatUserImpl>(), Box::new(data) as _);
|
map.insert(std::any::TypeId::of::<ChatUserImpl>(), Box::new(data) as _);
|
||||||
Some(map)
|
Some(map)
|
||||||
}
|
}*/
|
||||||
|
|
||||||
async fn do_auth<C>(&self, params: std::collections::HashMap<u8, Typed<C>>, user: &crate::UserTy) -> Result<polariton::operation::ParameterTable<C>, i16> {
|
async fn do_auth<C>(&self, params: std::collections::HashMap<u8, Typed<C>>, user: &crate::UserTy) -> Result<polariton::operation::ParameterTable<C>, i16> {
|
||||||
if let Some(Typed::Str(auth_payload)) = params.get(&Self::AUTH_PAYLOAD_KEY) {
|
if let Some(Typed::Str(auth_payload)) = params.get(&Self::AUTH_PAYLOAD_KEY) {
|
||||||
if user.update_with_auth_ext(&auth_payload.string, |t| self.build_ext_map(t)).await {
|
if user.update_with_auth(&auth_payload.string).await {
|
||||||
let user_impl = user.user()?;
|
let user_impl = user.user()?;
|
||||||
let name = user_impl.token().uuid.clone();
|
let name = user_impl.token().uuid.clone();
|
||||||
let chat_user = super::get_chat_user(user_impl.as_ref().as_ref());
|
//let chat_user = super::get_chat_user(user_impl.as_ref().as_ref());
|
||||||
let channels = chat_user.subscribed_channels_strings();
|
let channels = user_impl.subscribed_channels_strings().await?;
|
||||||
let event_tx = user.event_sender();
|
let event_tx = user.event_sender();
|
||||||
self.chat_system.system_mut().connect_user(name, channels, event_tx);
|
self.chat_system.system_mut().connect_user(name, channels, event_tx);
|
||||||
let mut resp_params = std::collections::HashMap::new();
|
let mut resp_params = std::collections::HashMap::new();
|
||||||
|
|||||||
35
rc_chat_room/src/operations/subscribed_channels.rs
Normal file
35
rc_chat_room/src/operations/subscribed_channels.rs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
//use rc_core::persist::user::ChatUser;
|
||||||
|
use polariton::operation::{ParameterTable, OperationResponse};
|
||||||
|
|
||||||
|
const CODE: u8 = 12;
|
||||||
|
|
||||||
|
const PARAM_KEY: u8 = 18;
|
||||||
|
|
||||||
|
async fn do_handling(params: ParameterTable<()>, user: &crate::UserTy) -> Result<ParameterTable, i16> {
|
||||||
|
let mut params = params.to_dict();
|
||||||
|
let user_info = user.user()?;
|
||||||
|
params.insert(PARAM_KEY, user_info.subscribed_channels().await?);
|
||||||
|
Ok(params.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SubscribedChannelsProvider;
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl polariton_server::operations::Operation<()> for SubscribedChannelsProvider {
|
||||||
|
type User = crate::UserTy;
|
||||||
|
|
||||||
|
async fn handle_async(&self, params: ParameterTable<()>, user: &Self::User) -> OperationResponse<()> {
|
||||||
|
polariton_server::operations::result_to_op_resp::<CODE, ()>(do_handling(params, user).await)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl polariton_server::operations::OperationCode for SubscribedChannelsProvider {
|
||||||
|
fn op_code() -> u8 {
|
||||||
|
CODE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub(super) fn all_subbed_channels_provider() -> SubscribedChannelsProvider {
|
||||||
|
SubscribedChannelsProvider
|
||||||
|
}
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
use serde::{Serialize, Deserialize};
|
|
||||||
use polariton::operation::{Typed, Arr};
|
|
||||||
|
|
||||||
use crate::data::channel::{ChatChannelInfo, ChatChannelType};
|
|
||||||
|
|
||||||
pub struct ChatUserInfo {
|
|
||||||
data: std::sync::RwLock<ChatUserData>,
|
|
||||||
root: std::path::PathBuf,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ChatUserInfo {
|
|
||||||
pub fn load(root: impl AsRef<std::path::Path>) -> std::io::Result<Self> {
|
|
||||||
let data = ChatUserData::load(root.as_ref())?;
|
|
||||||
Ok(Self {
|
|
||||||
data: std::sync::RwLock::new(data),
|
|
||||||
root: root.as_ref().to_path_buf(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/*pub fn save(&self) -> std::io::Result<()> {
|
|
||||||
self.data.read().unwrap().save(&self.root)
|
|
||||||
}*/
|
|
||||||
|
|
||||||
pub fn default_load(root: impl AsRef<std::path::Path>) -> Self {
|
|
||||||
let data = ChatUserData::default_load();
|
|
||||||
if let Err(e) = data.save(root.as_ref()) {
|
|
||||||
log::error!("Failed to save default chat data to {}: {}", root.as_ref().display(), e);
|
|
||||||
}
|
|
||||||
Self {
|
|
||||||
data: std::sync::RwLock::new(data),
|
|
||||||
root: root.as_ref().to_path_buf(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
|
||||||
pub struct ChatUserData {
|
|
||||||
subscribed_channels: Vec<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ChatUserData {
|
|
||||||
fn load(root: impl AsRef<std::path::Path>) -> std::io::Result<Self> {
|
|
||||||
let file = std::fs::File::open(root.as_ref().join(super::CHAT_USER_FILE))?;
|
|
||||||
let buffered = std::io::BufReader::new(file);
|
|
||||||
let result = serde_json::from_reader(buffered)?;
|
|
||||||
Ok(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn save(&self, root: impl AsRef<std::path::Path>) -> std::io::Result<()> {
|
|
||||||
let file = std::fs::File::create(root.as_ref().join(super::CHAT_USER_FILE))?;
|
|
||||||
let buffered = std::io::BufWriter::new(file);
|
|
||||||
serde_json::to_writer_pretty(buffered, self)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn default_load() -> Self {
|
|
||||||
Self {
|
|
||||||
subscribed_channels: vec![
|
|
||||||
"main".to_owned(),
|
|
||||||
"sys".to_owned(),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl super::ChatUser for ChatUserInfo {
|
|
||||||
fn subscribed_channels(&self) -> polariton::operation::Typed<()> {
|
|
||||||
Typed::Arr(Arr {
|
|
||||||
ty: polariton::serdes::TypePrefix::HashMap, // hashtable
|
|
||||||
items: self.data.read().unwrap().subscribed_channels.iter().map(|name| ChatChannelInfo {
|
|
||||||
channel_name: name.to_owned(),
|
|
||||||
members: Vec::default(),
|
|
||||||
channel_ty: ChatChannelType::Public,
|
|
||||||
}.as_transmissible()).collect()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subscribed_channels_strings(&self) -> Vec<String> {
|
|
||||||
self.data.read().unwrap().subscribed_channels.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_subscribed_channel(&self, channel: String, channel_ty: crate::data::channel::ChatChannelType) -> Typed<()> {
|
|
||||||
if let crate::data::channel::ChatChannelType::Public = channel_ty {
|
|
||||||
let mut lock = self.data.write().unwrap();
|
|
||||||
lock.subscribed_channels.push(channel.clone());
|
|
||||||
if let Err(e) = lock.save(&self.root) {
|
|
||||||
log::error!("Failed to save chat data to {}: {}", self.root.display(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
crate::data::channel::ChatChannelInfo {
|
|
||||||
channel_name: channel,
|
|
||||||
members: Vec::default(),
|
|
||||||
channel_ty,
|
|
||||||
}.as_transmissible()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn remove_subscribed_channel(&self, channel: String, channel_ty: crate::data::channel::ChatChannelType) -> bool {
|
|
||||||
if let crate::data::channel::ChatChannelType::Public = channel_ty {
|
|
||||||
let mut lock = self.data.write().unwrap();
|
|
||||||
if let Some(index) = lock.subscribed_channels.iter().position(|chann| chann == &channel) {
|
|
||||||
lock.subscribed_channels.swap_remove(index);
|
|
||||||
if let Err(e) = lock.save(&self.root) {
|
|
||||||
log::error!("Failed to save chat data to {}: {}", self.root.display(), e);
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
mod chat_json;
|
|
||||||
pub use chat_json::ChatUserInfo;
|
|
||||||
|
|
||||||
mod traits;
|
|
||||||
pub use traits::ChatUser;
|
|
||||||
|
|
||||||
pub const CHAT_USER_FILE: &str = "chat.json";
|
|
||||||
pub type ChatUserImpl = ChatUserInfo;
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
use polariton::operation::Typed;
|
|
||||||
|
|
||||||
pub trait ChatUser {
|
|
||||||
fn subscribed_channels(&self) -> Typed<()>;
|
|
||||||
fn subscribed_channels_strings(&self) -> Vec<String>;
|
|
||||||
fn add_subscribed_channel(&self, channel: String, channel_ty: crate::data::channel::ChatChannelType) -> Typed<()>;
|
|
||||||
fn remove_subscribed_channel(&self, channel: String, channel_ty: crate::data::channel::ChatChannelType) -> bool;
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
use serde::{Serialize, Deserialize};
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
|
||||||
pub struct ChatSystemConfig {
|
|
||||||
#[serde(default = "default_command_chann")]
|
|
||||||
pub command_channel: String,
|
|
||||||
pub commands: Vec<ChatCommand>,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn default_command_chann() -> String {
|
|
||||||
"sys".to_owned()
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ChatSystemConfig {
|
|
||||||
pub fn load(asset_root: impl AsRef<std::path::Path>) -> std::io::Result<Self> {
|
|
||||||
let file = std::fs::File::open(asset_root.as_ref().join(super::CHAT_CONFIG_FILE))?;
|
|
||||||
let buffered = std::io::BufReader::new(file);
|
|
||||||
let config = serde_json::from_reader(buffered)?;
|
|
||||||
Ok(config)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[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,
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
mod chat;
|
|
||||||
pub use chat::{ChatSystemConfig, ChatCommand, ChatOperation, BuiltInChatOperation};
|
|
||||||
|
|
||||||
pub const CHAT_CONFIG_FILE: &str = "chat.json";
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
pub mod chat_user;
|
|
||||||
pub mod config;
|
|
||||||
@@ -6,9 +6,9 @@ pub struct ChatProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ChatProvider {
|
impl ChatProvider {
|
||||||
pub fn new(asset_root: impl AsRef<std::path::Path>, data_root: impl AsRef<std::path::Path>) -> std::io::Result<Self> {
|
pub fn new(conf: rc_core::persist::config::ChatSystemConfig) -> std::io::Result<Self> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
chat_system: std::sync::Arc::new(std::sync::RwLock::new(crate::state::chat::ChatSystem::new(asset_root, data_root)?)),
|
chat_system: std::sync::Arc::new(std::sync::RwLock::new(crate::state::chat::ChatSystem::new(conf)?)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,12 +161,11 @@ impl ChatSystem {
|
|||||||
handle.send_private_message(response);
|
handle.send_private_message(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(asset_root: impl AsRef<std::path::Path>, data_root: impl AsRef<std::path::Path>) -> std::io::Result<Self> {
|
pub fn new(config: rc_core::persist::config::ChatSystemConfig) -> std::io::Result<Self> {
|
||||||
let config_persist = crate::persist::config::ChatSystemConfig::load(&asset_root)?;
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
chats: HashMap::new(),
|
chats: HashMap::new(),
|
||||||
online_users: HashMap::new(),
|
online_users: HashMap::new(),
|
||||||
config: super::ChatSystemConfig::from_persist(config_persist, asset_root.as_ref().to_path_buf(), data_root.as_ref().to_path_buf())?,
|
config: super::ChatSystemConfig::from_persist(config)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +1,17 @@
|
|||||||
pub struct ChatSystemConfig {
|
pub struct ChatSystemConfig {
|
||||||
command_channel: String,
|
command_channel: String,
|
||||||
commands: Vec<ChatCommand>,
|
commands: Vec<ChatCommand>,
|
||||||
asset_root: std::path::PathBuf,
|
|
||||||
data_root: std::path::PathBuf,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
struct CommandContext<'a, 'b, 'c> {
|
struct CommandContext<'a, 'b> {
|
||||||
chat_system: &'a super::ChatSystem,
|
chat_system: &'a super::ChatSystem,
|
||||||
user: &'b dyn rc_core::persist::user::User<()>,
|
user: &'b dyn rc_core::persist::user::User<()>,
|
||||||
asset_root: &'c std::path::PathBuf,
|
|
||||||
data_root: &'c std::path::PathBuf,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChatSystemConfig {
|
impl ChatSystemConfig {
|
||||||
pub fn from_persist(config: crate::persist::config::ChatSystemConfig, asset_root: std::path::PathBuf, data_root: std::path::PathBuf) -> std::io::Result<Self> {
|
pub fn from_persist(config: rc_core::persist::config::ChatSystemConfig) -> std::io::Result<Self> {
|
||||||
let mut compiled_commands = Vec::with_capacity(config.commands.len());
|
let mut compiled_commands = Vec::with_capacity(config.commands.len());
|
||||||
for (i, cmd) in config.commands.into_iter().enumerate() {
|
for (i, cmd) in config.commands.into_iter().enumerate() {
|
||||||
let compiled_command = ChatCommand::compile_command(cmd).map_err(|e| {
|
let compiled_command = ChatCommand::compile_command(cmd).map_err(|e| {
|
||||||
@@ -27,8 +23,6 @@ impl ChatSystemConfig {
|
|||||||
Ok(Self {
|
Ok(Self {
|
||||||
command_channel: config.command_channel,
|
command_channel: config.command_channel,
|
||||||
commands: compiled_commands,
|
commands: compiled_commands,
|
||||||
asset_root,
|
|
||||||
data_root,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,8 +30,6 @@ impl ChatSystemConfig {
|
|||||||
let ctx = CommandContext {
|
let ctx = CommandContext {
|
||||||
chat_system,
|
chat_system,
|
||||||
user,
|
user,
|
||||||
asset_root: &self.asset_root,
|
|
||||||
data_root: &self.data_root,
|
|
||||||
};
|
};
|
||||||
for cmd in self.commands.iter() {
|
for cmd in self.commands.iter() {
|
||||||
if let Some(result) = cmd.perform_if_match(text, ctx) {
|
if let Some(result) = cmd.perform_if_match(text, ctx) {
|
||||||
@@ -66,7 +58,7 @@ pub struct ChatCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ChatCommand {
|
impl ChatCommand {
|
||||||
fn compile_command(command: crate::persist::config::ChatCommand) -> Result<Self, regex::Error> {
|
fn compile_command(command: rc_core::persist::ChatCommand) -> Result<Self, regex::Error> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
regex: regex::RegexBuilder::new(&command.regex).build()?,
|
regex: regex::RegexBuilder::new(&command.regex).build()?,
|
||||||
op: ChatOperation::from_persist(command.op)
|
op: ChatOperation::from_persist(command.op)
|
||||||
@@ -89,11 +81,11 @@ enum ChatOperation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ChatOperation {
|
impl ChatOperation {
|
||||||
fn from_persist(op: crate::persist::config::ChatOperation) -> Self {
|
fn from_persist(op: rc_core::persist::ChatOperation) -> Self {
|
||||||
match op {
|
match op {
|
||||||
crate::persist::config::ChatOperation::BuiltIn(b_in) => Self::BuiltIn(BuiltIn::from_persist(b_in)),
|
rc_core::persist::ChatOperation::BuiltIn(b_in) => Self::BuiltIn(BuiltIn::from_persist(b_in)),
|
||||||
crate::persist::config::ChatOperation::Custom => Self::Custom,
|
rc_core::persist::ChatOperation::Custom => Self::Custom,
|
||||||
crate::persist::config::ChatOperation::Nop => Self::Nop,
|
rc_core::persist::ChatOperation::Nop => Self::Nop,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,10 +104,10 @@ enum BuiltIn {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl BuiltIn {
|
impl BuiltIn {
|
||||||
fn from_persist(b_in: crate::persist::config::BuiltInChatOperation) -> Self {
|
fn from_persist(b_in: rc_core::persist::BuiltInChatOperation) -> Self {
|
||||||
match b_in {
|
match b_in {
|
||||||
crate::persist::config::BuiltInChatOperation::OnlineUsers => Self::OnlineUsers,
|
rc_core::persist::BuiltInChatOperation::OnlineUsers => Self::OnlineUsers,
|
||||||
crate::persist::config::BuiltInChatOperation::TotalUsers => Self::TotalUsers,
|
rc_core::persist::BuiltInChatOperation::TotalUsers => Self::TotalUsers,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,14 +122,7 @@ impl BuiltIn {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
Self::TotalUsers => {
|
Self::TotalUsers => {
|
||||||
let user_path = ctx.data_root.join(rc_core::persist::user::USERS_DIR);
|
format!("User count is not supported")
|
||||||
let user_count = user_path.read_dir().map_or(0, |dir| dir.count()).clamp(1, usize::MAX) - 1;
|
|
||||||
if user_count == 1 {
|
|
||||||
"1 user exists".to_owned()
|
|
||||||
} else {
|
|
||||||
format!("{} users exist", user_count)
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ impl ChatChannelType {
|
|||||||
6 => Ok(Self::Clan),
|
6 => Ok(Self::Clan),
|
||||||
7 => Ok(Self::Private),
|
7 => Ok(Self::Private),
|
||||||
8 => Ok(Self::CustomGame),
|
8 => Ok(Self::CustomGame),
|
||||||
_ => Err(rc_core::data::error_codes::ChatErrorCodes::UnexpectedError as i16)
|
_ => Err(crate::data::error_codes::ChatErrorCodes::UnexpectedError as i16)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -11,6 +11,7 @@ pub mod voting;
|
|||||||
pub mod weapon_list;
|
pub mod weapon_list;
|
||||||
pub mod weapon_upgrade;
|
pub mod weapon_upgrade;
|
||||||
pub mod crf;
|
pub mod crf;
|
||||||
|
pub mod channel;
|
||||||
|
|
||||||
pub mod error_codes;
|
pub mod error_codes;
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,34 @@ use serde::{Serialize, Deserialize};
|
|||||||
pub struct ChatConfig {
|
pub struct ChatConfig {
|
||||||
#[serde(default = "default_pub_channs")]
|
#[serde(default = "default_pub_channs")]
|
||||||
pub public_channels: Vec<String>,
|
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> {
|
fn default_pub_channs() -> Vec<String> {
|
||||||
vec![
|
vec![
|
||||||
"main".to_owned(),
|
"main".to_owned(),
|
||||||
@@ -13,3 +39,8 @@ fn default_pub_channs() -> Vec<String> {
|
|||||||
"openjam_worship".to_owned(),
|
"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> {
|
fn cubes(&self) -> &'_ std::collections::HashMap<String, crate::persist::Cube> {
|
||||||
&self.cubes
|
&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;
|
pub use cubes_json::CubeConfig;
|
||||||
|
|
||||||
mod traits;
|
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;
|
pub type ConfigImpl = CubeConfig;
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ pub trait ConfigProvider<C: Clone> {
|
|||||||
fn garage_upgrades(&self) -> GarageUpgrades;
|
fn garage_upgrades(&self) -> GarageUpgrades;
|
||||||
async fn factory(&self) -> Result<crate::factory::Factory, Box<dyn std::error::Error + 'static>>;
|
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 cubes(&self) -> &'_ std::collections::HashMap<String, crate::persist::Cube>;
|
||||||
|
fn chat_system_config(&self) -> ChatSystemConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CompleteCampaignProvider {
|
pub struct CompleteCampaignProvider {
|
||||||
@@ -121,3 +122,9 @@ impl GarageUpgrades {
|
|||||||
].into())
|
].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;
|
pub use settings::Settings;
|
||||||
|
|
||||||
mod chat;
|
mod chat;
|
||||||
pub use chat::ChatConfig;
|
pub use chat::{ChatConfig, ChatCommand, ChatOperation, BuiltInChatOperation};
|
||||||
|
|
||||||
mod vehicle_factory;
|
mod vehicle_factory;
|
||||||
pub use vehicle_factory::{FactoryConfig, AdapterSettings, ArcFactorySettings};
|
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> {
|
fn default_user_aux_data(user_id: u32) -> Vec<rc_database::schema::user_aux::ActiveModel> {
|
||||||
|
let current_time = current_unix_time();
|
||||||
vec![
|
vec![
|
||||||
rc_database::schema::user_aux::ActiveModel {
|
rc_database::schema::user_aux::ActiveModel {
|
||||||
id: Default::default(),
|
id: Default::default(),
|
||||||
user_id: rc_database::sea_orm::ActiveValue::Set(user_id),
|
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),
|
descriptor: rc_database::sea_orm::ActiveValue::Set(rc_database::schema::user_aux::Descriptor::UserXP),
|
||||||
data: rc_database::sea_orm::ActiveValue::Set("0".to_owned()),
|
data: rc_database::sea_orm::ActiveValue::Set("0".to_owned()),
|
||||||
},
|
},
|
||||||
rc_database::schema::user_aux::ActiveModel {
|
rc_database::schema::user_aux::ActiveModel {
|
||||||
id: Default::default(),
|
id: Default::default(),
|
||||||
user_id: rc_database::sea_orm::ActiveValue::Set(user_id),
|
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),
|
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 {
|
rc_database::schema::user_aux::ActiveModel {
|
||||||
id: Default::default(),
|
id: Default::default(),
|
||||||
user_id: rc_database::sea_orm::ActiveValue::Set(user_id),
|
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),
|
descriptor: rc_database::sea_orm::ActiveValue::Set(rc_database::schema::user_aux::Descriptor::UnlockedParts),
|
||||||
data: rc_database::sea_orm::ActiveValue::Set(
|
data: rc_database::sea_orm::ActiveValue::Set(
|
||||||
r#"{
|
r#"{
|
||||||
@@ -98,37 +99,44 @@ r#"{
|
|||||||
rc_database::schema::user_aux::ActiveModel {
|
rc_database::schema::user_aux::ActiveModel {
|
||||||
id: Default::default(),
|
id: Default::default(),
|
||||||
user_id: rc_database::sea_orm::ActiveValue::Set(user_id),
|
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),
|
descriptor: rc_database::sea_orm::ActiveValue::Set(rc_database::schema::user_aux::Descriptor::TechPoints),
|
||||||
data: rc_database::sea_orm::ActiveValue::Set("1337".to_owned()),
|
data: rc_database::sea_orm::ActiveValue::Set("1337".to_owned()),
|
||||||
},
|
},
|
||||||
rc_database::schema::user_aux::ActiveModel {
|
rc_database::schema::user_aux::ActiveModel {
|
||||||
id: Default::default(),
|
id: Default::default(),
|
||||||
user_id: rc_database::sea_orm::ActiveValue::Set(user_id),
|
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),
|
descriptor: rc_database::sea_orm::ActiveValue::Set(rc_database::schema::user_aux::Descriptor::UserRank),
|
||||||
data: rc_database::sea_orm::ActiveValue::Set("1".to_owned()),
|
data: rc_database::sea_orm::ActiveValue::Set("1".to_owned()),
|
||||||
},
|
},
|
||||||
rc_database::schema::user_aux::ActiveModel {
|
rc_database::schema::user_aux::ActiveModel {
|
||||||
id: Default::default(),
|
id: Default::default(),
|
||||||
user_id: rc_database::sea_orm::ActiveValue::Set(user_id),
|
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),
|
descriptor: rc_database::sea_orm::ActiveValue::Set(rc_database::schema::user_aux::Descriptor::UserFreeCurrency),
|
||||||
data: rc_database::sea_orm::ActiveValue::Set("10000".to_owned()),
|
data: rc_database::sea_orm::ActiveValue::Set("10000".to_owned()),
|
||||||
},
|
},
|
||||||
rc_database::schema::user_aux::ActiveModel {
|
rc_database::schema::user_aux::ActiveModel {
|
||||||
id: Default::default(),
|
id: Default::default(),
|
||||||
user_id: rc_database::sea_orm::ActiveValue::Set(user_id),
|
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),
|
descriptor: rc_database::sea_orm::ActiveValue::Set(rc_database::schema::user_aux::Descriptor::UserPaidCurrency),
|
||||||
data: rc_database::sea_orm::ActiveValue::Set("1000".to_owned()),
|
data: rc_database::sea_orm::ActiveValue::Set("1000".to_owned()),
|
||||||
},
|
},
|
||||||
rc_database::schema::user_aux::ActiveModel {
|
rc_database::schema::user_aux::ActiveModel {
|
||||||
id: Default::default(),
|
id: Default::default(),
|
||||||
user_id: rc_database::sea_orm::ActiveValue::Set(user_id),
|
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),
|
descriptor: rc_database::sea_orm::ActiveValue::Set(rc_database::schema::user_aux::Descriptor::GarageSlotOrder),
|
||||||
data: rc_database::sea_orm::ActiveValue::Set("[0]".to_owned()),
|
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;
|
pub use inventory::UnlockedParts;
|
||||||
|
|
||||||
mod traits;
|
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";
|
pub const TOKEN_SECRET_FILENAME: &str = "token_secret.key";
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ pub trait UserAuthenticator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[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 ext(&self, ty: std::any::TypeId) -> Option<&'_ (dyn std::any::Any + Send + Sync + 'static)>;
|
||||||
fn token(&self) -> &'_ super::UserToken;
|
fn token(&self) -> &'_ super::UserToken;
|
||||||
fn is_mod(&self) -> bool;
|
fn is_mod(&self) -> bool;
|
||||||
@@ -121,3 +121,14 @@ pub struct VehicleUploadData {
|
|||||||
pub description: String,
|
pub description: String,
|
||||||
pub thumbnail: Vec<u8>,
|
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>;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ pub enum Descriptor {
|
|||||||
UserRank, // u32
|
UserRank, // u32
|
||||||
UserFreeCurrency, // u64
|
UserFreeCurrency, // u64
|
||||||
UserPaidCurrency, // u64
|
UserPaidCurrency, // u64
|
||||||
GarageSlotOrder, // Vec<u32>,
|
GarageSlotOrder, // Vec<u32>, CSV
|
||||||
LastSeen, // u64, seconds since Unix epoch
|
LastSeen, // u64, seconds since Unix epoch
|
||||||
|
SubscribedChannels, // Vec<String>, JSON
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -454,6 +454,22 @@ def main(asset_in, cubes=None, weapons=None, movement=None):
|
|||||||
"sys",
|
"sys",
|
||||||
"jam_club",
|
"jam_club",
|
||||||
],
|
],
|
||||||
|
"commands": [
|
||||||
|
{
|
||||||
|
"regex": "\\?online",
|
||||||
|
"op": {
|
||||||
|
"type": "BuiltIn",
|
||||||
|
"built_in": "OnlineUsers"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"regex": "\\?users",
|
||||||
|
"op": {
|
||||||
|
"type": "BuiltIn",
|
||||||
|
"built_in": "TotalUsers"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"factory": {
|
"factory": {
|
||||||
"adapter": {
|
"adapter": {
|
||||||
|
|||||||
Reference in New Issue
Block a user