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:
@@ -1,85 +0,0 @@
|
||||
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(rc_core::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
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
pub mod channel;
|
||||
pub use rc_core::data::channel;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#![forbid(unsafe_code)]
|
||||
mod cli;
|
||||
mod state;
|
||||
mod persist;
|
||||
mod op_handler;
|
||||
pub use op_handler::SimpleChatFunc;
|
||||
|
||||
@@ -10,6 +9,7 @@ mod operations;
|
||||
mod events;
|
||||
|
||||
use polariton_auth::Handshake;
|
||||
use rc_core::ConfigProvider;
|
||||
use tokio::net;
|
||||
|
||||
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 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");
|
||||
|
||||
|
||||
@@ -1,61 +1,35 @@
|
||||
use crate::SimpleChatFunc;
|
||||
use crate::persist::chat_user::ChatUser;
|
||||
use polariton::operation::ParameterTable;
|
||||
//use rc_core::persist::user::ChatUser;
|
||||
use polariton::operation::{ParameterTable, OperationResponse};
|
||||
|
||||
const CODE: u8 = 11;
|
||||
|
||||
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> {
|
||||
SimpleChatFunc::new(|params, user: &crate::UserTy, _chat_system: &crate::state::ChatImpl| {
|
||||
let mut params = params.to_dict();
|
||||
let user_trait = user.user()?;
|
||||
let chat_user = super::get_chat_user(user_trait.as_ref().as_ref());
|
||||
//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 {
|
||||
ty: polariton::serdes::TypePrefix::HashMap, // hashtable
|
||||
items: vec![
|
||||
ChatChannelInfo {
|
||||
channel_name: "RE_public_channel0".to_owned(),
|
||||
members: vec![
|
||||
ChatChannelMember {
|
||||
name: "RE_chat0_username0".to_owned(),
|
||||
use_custom_avatar: false,
|
||||
state: ChatPlayerState::Idk1,
|
||||
custom_avatar: Vec::default(),
|
||||
avatar_id: 2,
|
||||
},
|
||||
ChatChannelMember {
|
||||
name: "RE_chat0_username1".to_owned(),
|
||||
use_custom_avatar: false,
|
||||
state: ChatPlayerState::Idk2,
|
||||
custom_avatar: Vec::default(),
|
||||
avatar_id: 3,
|
||||
},
|
||||
],
|
||||
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)
|
||||
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 JoinedChannelsProvider;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl polariton_server::operations::Operation<()> for JoinedChannelsProvider {
|
||||
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 JoinedChannelsProvider {
|
||||
fn op_code() -> u8 {
|
||||
CODE
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub(super) fn all_channels_provider() -> JoinedChannelsProvider {
|
||||
JoinedChannelsProvider
|
||||
}
|
||||
|
||||
@@ -1,41 +1,85 @@
|
||||
use crate::{persist::chat_user::ChatUser, SimpleChatFunc};
|
||||
use polariton::operation::{ParameterTable, Typed};
|
||||
use polariton::operation::{ParameterTable, Typed, OperationResponse};
|
||||
|
||||
const JOIN_CODE: u8 = 1;
|
||||
const LEAVE_CODE: u8 = 5;
|
||||
|
||||
const CHANNEL_NAME_PARAM_KEY: u8 = 3; // str; in
|
||||
const CHANNEL_TYPE_PARAM_KEY: u8 = 1; // int; in
|
||||
const CHANNEL_PASSWORD_PARAM_KEY: u8 = 16; // str; in
|
||||
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> {
|
||||
SimpleChatFunc::new(|params, user: &crate::UserTy, 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) {
|
||||
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 struct JoinChannelProvider {
|
||||
chat_system: crate::state::ChatImpl,
|
||||
}
|
||||
|
||||
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> {
|
||||
SimpleChatFunc::new(|params, user: &crate::UserTy, 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) {
|
||||
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());
|
||||
chat_user.remove_subscribed_channel(chann_name.string, crate::data::channel::ChatChannelType::from_u8(chann_ty as _)?);
|
||||
pub(super) fn join_channel_provider(chat_system: crate::state::ChatImpl) -> JoinChannelProvider {
|
||||
JoinChannelProvider { chat_system }
|
||||
}
|
||||
|
||||
async fn do_join_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) {
|
||||
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 join_channel;
|
||||
mod user_online;
|
||||
mod subscribed_channels;
|
||||
|
||||
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()
|
||||
.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(pending_sanctions::pending_sanctions_checker())
|
||||
.add(all_joined_channels::all_channels_provider(chat_system.clone()))
|
||||
.add(polariton_server::operations::Ack::<12, _>::default())
|
||||
.add(all_joined_channels::all_channels_provider())
|
||||
//.add(polariton_server::operations::Ack::<12, _>::default())
|
||||
.add(send_message::send_public_message_handler(chat_system.clone()))
|
||||
.add(public_channels::public_channels_provider(conf))
|
||||
.add(join_channel::join_channel_provider(chat_system.clone()))
|
||||
.add(user_online::is_online_provider(chat_system.clone()))
|
||||
.add(send_message::send_private_message_handler(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())
|
||||
}
|
||||
|
||||
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_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 {
|
||||
chat_system: crate::state::chat::ChatImpl,
|
||||
root: std::path::PathBuf,
|
||||
}
|
||||
|
||||
impl MoreLobbyAuth {
|
||||
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 {
|
||||
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 data = if let Ok(data) = ChatUserImpl::load(&user_dir) {
|
||||
data
|
||||
@@ -29,15 +28,15 @@ impl MoreLobbyAuth {
|
||||
let mut map = std::collections::HashMap::with_capacity(1);
|
||||
map.insert(std::any::TypeId::of::<ChatUserImpl>(), Box::new(data) as _);
|
||||
Some(map)
|
||||
}
|
||||
}*/
|
||||
|
||||
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 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 name = user_impl.token().uuid.clone();
|
||||
let chat_user = super::get_chat_user(user_impl.as_ref().as_ref());
|
||||
let channels = chat_user.subscribed_channels_strings();
|
||||
//let chat_user = super::get_chat_user(user_impl.as_ref().as_ref());
|
||||
let channels = user_impl.subscribed_channels_strings().await?;
|
||||
let event_tx = user.event_sender();
|
||||
self.chat_system.system_mut().connect_user(name, channels, event_tx);
|
||||
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 {
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
|
||||
pub fn new(asset_root: impl AsRef<std::path::Path>, data_root: impl AsRef<std::path::Path>) -> std::io::Result<Self> {
|
||||
let config_persist = crate::persist::config::ChatSystemConfig::load(&asset_root)?;
|
||||
pub fn new(config: rc_core::persist::config::ChatSystemConfig) -> std::io::Result<Self> {
|
||||
Ok(Self {
|
||||
chats: 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 {
|
||||
command_channel: String,
|
||||
commands: Vec<ChatCommand>,
|
||||
asset_root: std::path::PathBuf,
|
||||
data_root: std::path::PathBuf,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Clone, Copy)]
|
||||
struct CommandContext<'a, 'b, 'c> {
|
||||
struct CommandContext<'a, 'b> {
|
||||
chat_system: &'a super::ChatSystem,
|
||||
user: &'b dyn rc_core::persist::user::User<()>,
|
||||
asset_root: &'c std::path::PathBuf,
|
||||
data_root: &'c std::path::PathBuf,
|
||||
}
|
||||
|
||||
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());
|
||||
for (i, cmd) in config.commands.into_iter().enumerate() {
|
||||
let compiled_command = ChatCommand::compile_command(cmd).map_err(|e| {
|
||||
@@ -27,8 +23,6 @@ impl ChatSystemConfig {
|
||||
Ok(Self {
|
||||
command_channel: config.command_channel,
|
||||
commands: compiled_commands,
|
||||
asset_root,
|
||||
data_root,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -36,8 +30,6 @@ impl ChatSystemConfig {
|
||||
let ctx = CommandContext {
|
||||
chat_system,
|
||||
user,
|
||||
asset_root: &self.asset_root,
|
||||
data_root: &self.data_root,
|
||||
};
|
||||
for cmd in self.commands.iter() {
|
||||
if let Some(result) = cmd.perform_if_match(text, ctx) {
|
||||
@@ -66,7 +58,7 @@ pub struct 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 {
|
||||
regex: regex::RegexBuilder::new(&command.regex).build()?,
|
||||
op: ChatOperation::from_persist(command.op)
|
||||
@@ -89,11 +81,11 @@ enum ChatOperation {
|
||||
}
|
||||
|
||||
impl ChatOperation {
|
||||
fn from_persist(op: crate::persist::config::ChatOperation) -> Self {
|
||||
fn from_persist(op: rc_core::persist::ChatOperation) -> Self {
|
||||
match op {
|
||||
crate::persist::config::ChatOperation::BuiltIn(b_in) => Self::BuiltIn(BuiltIn::from_persist(b_in)),
|
||||
crate::persist::config::ChatOperation::Custom => Self::Custom,
|
||||
crate::persist::config::ChatOperation::Nop => Self::Nop,
|
||||
rc_core::persist::ChatOperation::BuiltIn(b_in) => Self::BuiltIn(BuiltIn::from_persist(b_in)),
|
||||
rc_core::persist::ChatOperation::Custom => Self::Custom,
|
||||
rc_core::persist::ChatOperation::Nop => Self::Nop,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,10 +104,10 @@ enum 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 {
|
||||
crate::persist::config::BuiltInChatOperation::OnlineUsers => Self::OnlineUsers,
|
||||
crate::persist::config::BuiltInChatOperation::TotalUsers => Self::TotalUsers,
|
||||
rc_core::persist::BuiltInChatOperation::OnlineUsers => Self::OnlineUsers,
|
||||
rc_core::persist::BuiltInChatOperation::TotalUsers => Self::TotalUsers,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,14 +122,7 @@ impl BuiltIn {
|
||||
}
|
||||
},
|
||||
Self::TotalUsers => {
|
||||
let user_path = ctx.data_root.join(rc_core::persist::user::USERS_DIR);
|
||||
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)
|
||||
}
|
||||
|
||||
format!("User count is not supported")
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user