mirror of
https://git.ngram.ca/OpenJam/rc-servers
synced 2026-08-23 23:08:52 +00:00
Add basic chat plugin harness (no plugin loading implemented)
This commit is contained in:
9
Cargo.lock
generated
9
Cargo.lock
generated
@@ -2469,10 +2469,12 @@ dependencies = [
|
|||||||
"chrono",
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
|
"futures",
|
||||||
"git-version",
|
"git-version",
|
||||||
"log",
|
"log",
|
||||||
"oj_polariton_auth",
|
"oj_polariton_auth",
|
||||||
"oj_rc_core",
|
"oj_rc_core",
|
||||||
|
"oj_rc_plugins",
|
||||||
"oj_serdes",
|
"oj_serdes",
|
||||||
"polariton",
|
"polariton",
|
||||||
"polariton_server",
|
"polariton_server",
|
||||||
@@ -2602,6 +2604,13 @@ dependencies = [
|
|||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "oj_rc_plugins"
|
||||||
|
version = "1.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oj_rc_services"
|
name = "oj_rc_services"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ members = [
|
|||||||
"rc_lobby", "rc_lobby_room",
|
"rc_lobby", "rc_lobby_room",
|
||||||
"rc_core", "rc_database", "rc_factory",
|
"rc_core", "rc_database", "rc_factory",
|
||||||
"rc_multiplayer",
|
"rc_multiplayer",
|
||||||
|
"rc_plugins",
|
||||||
]
|
]
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
|
|||||||
@@ -23,3 +23,5 @@ async-trait.workspace = true
|
|||||||
git-version.workspace = true
|
git-version.workspace = true
|
||||||
chrono.workspace = true
|
chrono.workspace = true
|
||||||
oj_serdes.workspace = true
|
oj_serdes.workspace = true
|
||||||
|
oj_rc_plugins = { version = "*", path = "../rc_plugins" }
|
||||||
|
futures.workspace = true
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ mod cli;
|
|||||||
mod state;
|
mod state;
|
||||||
mod op_handler;
|
mod op_handler;
|
||||||
pub use op_handler::SimpleChatFunc;
|
pub use op_handler::SimpleChatFunc;
|
||||||
|
mod plugin_wrapper;
|
||||||
|
pub use plugin_wrapper::{PluginWrapper, ProviderWrapper};
|
||||||
|
|
||||||
mod data;
|
mod data;
|
||||||
mod operations;
|
mod operations;
|
||||||
|
|||||||
53
rc_chat_room/src/plugin_wrapper.rs
Normal file
53
rc_chat_room/src/plugin_wrapper.rs
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
pub struct PluginWrapper {
|
||||||
|
plugins: Vec<std::sync::Arc<Box<dyn oj_rc_plugins::chat::ChatPlugin>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PluginWrapper {
|
||||||
|
pub fn new(plugins: impl IntoIterator<Item=Box<dyn oj_rc_plugins::chat::ChatPlugin>>) -> Self {
|
||||||
|
Self {
|
||||||
|
plugins: plugins.into_iter().map(std::sync::Arc::new).collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_provider(&self, provider: std::sync::Arc<Box<dyn oj_rc_plugins::chat::ChatProvider>>) {
|
||||||
|
for plugin in self.plugins.iter() {
|
||||||
|
plugin.set_provider(provider.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn on_message(&self, message: &str, channel: &str, username: &str) {
|
||||||
|
let mut futures = Vec::with_capacity(self.plugins.len());
|
||||||
|
for plugin in self.plugins.iter() {
|
||||||
|
let owned_plugin = plugin.to_owned();
|
||||||
|
let owned_message = message.to_owned();
|
||||||
|
let owned_channel = channel.to_owned();
|
||||||
|
let owned_username = username.to_owned();
|
||||||
|
let handle = tokio::task::spawn_blocking(move || owned_plugin.on_message(&owned_message, &owned_channel, &owned_username));
|
||||||
|
futures.push(handle);
|
||||||
|
}
|
||||||
|
futures::future::join_all(futures).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ProviderWrapper {
|
||||||
|
provider: std::sync::Arc<tokio::sync::RwLock<crate::state::chat::ChatSystem>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProviderWrapper {
|
||||||
|
pub fn new(provider: std::sync::Arc<tokio::sync::RwLock<crate::state::chat::ChatSystem>>) -> Self {
|
||||||
|
Self {
|
||||||
|
provider,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn do_send_message(provider: std::sync::Arc<tokio::sync::RwLock<crate::state::chat::ChatSystem>>, message: String, channel: String, username: String) {
|
||||||
|
provider.read().await
|
||||||
|
.send_fake_message(message, channel, username).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl oj_rc_plugins::chat::ChatProvider for ProviderWrapper {
|
||||||
|
fn send_message(&self, message: &str, channel: &str, username: &str) {
|
||||||
|
tokio::task::spawn(Self::do_send_message(self.provider.clone(), message.to_owned(), channel.to_owned(), username.to_owned()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,12 +19,18 @@ impl ChatProvider {
|
|||||||
pub async fn system_mut(&self) -> tokio::sync::RwLockWriteGuard<'_, crate::state::chat::ChatSystem> {
|
pub async fn system_mut(&self) -> tokio::sync::RwLockWriteGuard<'_, crate::state::chat::ChatSystem> {
|
||||||
self.chat_system.write().await
|
self.chat_system.write().await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn init_provider(&self) {
|
||||||
|
let provider = crate::ProviderWrapper::new(self.chat_system.clone());
|
||||||
|
self.chat_system.read().await.plugin.set_provider(std::sync::Arc::new(Box::new(provider)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ChatSystem {
|
pub struct ChatSystem {
|
||||||
chats: HashMap<String, super::ChatRoom>,
|
chats: HashMap<String, super::ChatRoom>,
|
||||||
online_users: HashMap<String, super::UserHandle>,
|
online_users: HashMap<String, super::UserHandle>,
|
||||||
config: super::ChatSystemConfig,
|
config: super::ChatSystemConfig,
|
||||||
|
plugin: crate::PluginWrapper,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChatSystem {
|
impl ChatSystem {
|
||||||
@@ -53,6 +59,10 @@ impl ChatSystem {
|
|||||||
total_removed_users + to_be_removed.len()
|
total_removed_users + to_be_removed.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_channel(&self, channel: &str) -> Option<&super::ChatRoom> {
|
||||||
|
self.chats.get(&channel.to_lowercase())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn connect_user(&mut self, display_name: String, channels: Vec<String>, event_tx: tokio::sync::mpsc::UnboundedSender<polariton_server::ToSend>) {
|
pub fn connect_user(&mut self, display_name: String, channels: Vec<String>, event_tx: tokio::sync::mpsc::UnboundedSender<polariton_server::ToSend>) {
|
||||||
self.cleanup();
|
self.cleanup();
|
||||||
let handle = super::UserHandle::from_strong_sender(event_tx, display_name.clone());
|
let handle = super::UserHandle::from_strong_sender(event_tx, display_name.clone());
|
||||||
@@ -92,11 +102,11 @@ impl ChatSystem {
|
|||||||
if let Some(user_handle) = self.online_users.get(user.public_id()) {
|
if let Some(user_handle) = self.online_users.get(user.public_id()) {
|
||||||
self.handle_public_command(user, text, user_handle, channel, channel_ty).await;
|
self.handle_public_command(user, text, user_handle, channel, channel_ty).await;
|
||||||
}
|
}
|
||||||
} else if let Some(room) = self.chats.get(&channel.to_lowercase()) {
|
} else if let Some(room) = self.get_channel(&channel) {
|
||||||
let event_params = crate::events::chat_message::PublicMessage {
|
let event_params = crate::events::chat_message::PublicMessage {
|
||||||
sender_name: user.public_id().to_owned(),
|
sender_name: user.public_id().to_owned(),
|
||||||
sender_display_name: user.display_name().to_owned(),
|
sender_display_name: user.display_name().to_owned(),
|
||||||
text,
|
text: text.clone(),
|
||||||
is_dev: user.is_dev(),
|
is_dev: user.is_dev(),
|
||||||
is_mod: user.is_mod(),
|
is_mod: user.is_mod(),
|
||||||
is_admin: user.is_admin(),
|
is_admin: user.is_admin(),
|
||||||
@@ -104,11 +114,32 @@ impl ChatSystem {
|
|||||||
channel_ty,
|
channel_ty,
|
||||||
};
|
};
|
||||||
room.send_public_message(event_params);
|
room.send_public_message(event_params);
|
||||||
|
self.plugin.on_message(&text, &room.canon_name(), user.display_name()).await;
|
||||||
} else {
|
} else {
|
||||||
log::warn!("Got message for non-existent chat room {} (variant: {:?})", channel, channel_ty);
|
log::warn!("Got message for non-existent chat room {} (variant: {:?})", channel, channel_ty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn send_fake_message(&self, message: String, channel: String, username: String) -> bool {
|
||||||
|
if let Some(room) = self.get_channel(&channel) {
|
||||||
|
let event_params = crate::events::chat_message::PublicMessage {
|
||||||
|
sender_name: username.clone(),
|
||||||
|
sender_display_name: username.clone(),
|
||||||
|
text: message.clone(),
|
||||||
|
is_dev: false,
|
||||||
|
is_mod: false,
|
||||||
|
is_admin: false,
|
||||||
|
channel_name: room.canon_name(),
|
||||||
|
channel_ty: crate::data::channel::ChatChannelType::Public,
|
||||||
|
};
|
||||||
|
room.send_public_message(event_params);
|
||||||
|
self.plugin.on_message(&message, &room.canon_name(), &username).await;
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async fn handle_public_command(&self, user: &dyn oj_rc_core::persist::user::User<()>, text: String, handle: &super::UserHandle, channel: String, channel_ty: crate::data::channel::ChatChannelType) {
|
async fn handle_public_command(&self, user: &dyn oj_rc_core::persist::user::User<()>, text: String, handle: &super::UserHandle, channel: String, channel_ty: crate::data::channel::ChatChannelType) {
|
||||||
let event_params = crate::events::chat_message::PublicMessage {
|
let event_params = crate::events::chat_message::PublicMessage {
|
||||||
sender_name: self.config.command_username().to_owned(),
|
sender_name: self.config.command_username().to_owned(),
|
||||||
@@ -172,6 +203,7 @@ impl ChatSystem {
|
|||||||
chats: HashMap::new(),
|
chats: HashMap::new(),
|
||||||
online_users: HashMap::new(),
|
online_users: HashMap::new(),
|
||||||
config: super::ChatSystemConfig::from_persist(config)?,
|
config: super::ChatSystemConfig::from_persist(config)?,
|
||||||
|
plugin: crate::PluginWrapper::new(vec![]), // TODO construct plugins
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
11
rc_plugins/Cargo.toml
Normal file
11
rc_plugins/Cargo.toml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
[package]
|
||||||
|
name = "oj_rc_plugins"
|
||||||
|
version.workspace = true
|
||||||
|
edition.workspace = true
|
||||||
|
repository.workspace = true
|
||||||
|
license.workspace = true
|
||||||
|
authors.workspace = true
|
||||||
|
readme.workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
log.workspace = true
|
||||||
2
rc_plugins/src/chat/mod.rs
Normal file
2
rc_plugins/src/chat/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
mod plugin;
|
||||||
|
pub use plugin::{ChatProvider, ChatPlugin};
|
||||||
8
rc_plugins/src/chat/plugin.rs
Normal file
8
rc_plugins/src/chat/plugin.rs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
pub trait ChatPlugin: crate::Plugin {
|
||||||
|
fn set_provider(&self, provider: std::sync::Arc<Box<dyn ChatProvider>>);
|
||||||
|
fn on_message(&self, message: &str, channel: &str, username: &str);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ChatProvider: Send + Sync {
|
||||||
|
fn send_message(&self, message: &str, channel: &str, username: &str);
|
||||||
|
}
|
||||||
3
rc_plugins/src/lib.rs
Normal file
3
rc_plugins/src/lib.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
pub mod chat;
|
||||||
|
|
||||||
|
pub trait Plugin: Send + Sync {}
|
||||||
Reference in New Issue
Block a user