mirror of
https://git.ngram.ca/OpenJam/rc-servers
synced 2026-08-23 23:08:52 +00:00
Add some basic commands for sysadmins and permission system for them
This commit is contained in:
@@ -14454,21 +14454,24 @@
|
|||||||
"op": {
|
"op": {
|
||||||
"type": "BuiltIn",
|
"type": "BuiltIn",
|
||||||
"built_in": "OnlineUsers"
|
"built_in": "OnlineUsers"
|
||||||
}
|
},
|
||||||
|
"permission": "Player"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"regex": "\\?users",
|
"regex": "\\?users",
|
||||||
"op": {
|
"op": {
|
||||||
"type": "BuiltIn",
|
"type": "BuiltIn",
|
||||||
"built_in": "TotalUsers"
|
"built_in": "TotalUsers"
|
||||||
}
|
},
|
||||||
|
"permission": "Player"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"regex": "\\?version",
|
"regex": "\\?version",
|
||||||
"op": {
|
"op": {
|
||||||
"type": "BuiltIn",
|
"type": "BuiltIn",
|
||||||
"built_in": "Version"
|
"built_in": "Version"
|
||||||
}
|
},
|
||||||
|
"permission": "Player"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"regex": "\\?banner",
|
"regex": "\\?banner",
|
||||||
@@ -14476,14 +14479,34 @@
|
|||||||
"type": "BuiltIn",
|
"type": "BuiltIn",
|
||||||
"built_in": "Intercom",
|
"built_in": "Intercom",
|
||||||
"intercom": "DevMessage"
|
"intercom": "DevMessage"
|
||||||
}
|
},
|
||||||
|
"permission": "Player"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"regex": "\\?maintenance",
|
||||||
|
"op": {
|
||||||
|
"type": "BuiltIn",
|
||||||
|
"built_in": "Intercom",
|
||||||
|
"intercom": "Maintenance"
|
||||||
|
},
|
||||||
|
"permission": "Developer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"regex": "\\?broadcast",
|
||||||
|
"op": {
|
||||||
|
"type": "BuiltIn",
|
||||||
|
"built_in": "Intercom",
|
||||||
|
"intercom": "DevBroadcast"
|
||||||
|
},
|
||||||
|
"permission": "Developer"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"regex": "\\?help",
|
"regex": "\\?help",
|
||||||
"op": {
|
"op": {
|
||||||
"type": "BuiltIn",
|
"type": "BuiltIn",
|
||||||
"built_in": "Help"
|
"built_in": "Help"
|
||||||
}
|
},
|
||||||
|
"permission": "Player"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -6,3 +6,12 @@ pub use services::{services_ws, service_msg};
|
|||||||
|
|
||||||
mod user_registry;
|
mod user_registry;
|
||||||
pub use user_registry::Users;
|
pub use user_registry::Users;
|
||||||
|
|
||||||
|
enum IntercomOp {
|
||||||
|
Message(oj_rc_core::persist::user::intercom::IntercomWebServiceUserMessage),
|
||||||
|
Info(IntercomInfo),
|
||||||
|
}
|
||||||
|
|
||||||
|
enum IntercomInfo {
|
||||||
|
Close,
|
||||||
|
}
|
||||||
|
|||||||
@@ -18,13 +18,29 @@ pub async fn services_ws(req: HttpRequest, stream: Payload, auth: Data<super::In
|
|||||||
|
|
||||||
// start task but don't wait for it
|
// start task but don't wait for it
|
||||||
rt::spawn(async move {
|
rt::spawn(async move {
|
||||||
while let Some(msg) = rx.recv().await {
|
let mut is_ok = false;
|
||||||
if let Err(e) = session.text(serde_json::to_string(&msg).unwrap()).await {
|
while let Some(op) = rx.recv().await {
|
||||||
log::warn!("Failed to send services intercom to user {}: {}", name, e);
|
match op {
|
||||||
break;
|
super::IntercomOp::Message(msg) => {
|
||||||
|
if let Err(e) = session.text(serde_json::to_string(&msg).unwrap()).await {
|
||||||
|
log::warn!("Failed to send services intercom to user {}: {}", name, e);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
super::IntercomOp::Info(info) => {
|
||||||
|
match info {
|
||||||
|
super::IntercomInfo::Close => {
|
||||||
|
is_ok = true;
|
||||||
|
break;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if !is_ok {
|
||||||
|
reg.remove_service(name.clone()).await;
|
||||||
}
|
}
|
||||||
reg.remove_service(name.clone()).await;
|
|
||||||
rx.close();
|
rx.close();
|
||||||
session.close(Some(actix_ws::CloseReason {
|
session.close(Some(actix_ws::CloseReason {
|
||||||
code: actix_ws::CloseCode::Normal,
|
code: actix_ws::CloseCode::Normal,
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
use oj_rc_core::persist::user::intercom::IntercomWebServiceUserMessage;
|
|
||||||
|
|
||||||
pub struct Users {
|
pub struct Users {
|
||||||
service_listeners: tokio::sync::RwLock<std::collections::HashMap<String, tokio::sync::mpsc::Sender<IntercomWebServiceUserMessage>>>,
|
service_listeners: tokio::sync::RwLock<std::collections::HashMap<String, tokio::sync::mpsc::Sender<super::IntercomOp>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Users {
|
impl Users {
|
||||||
@@ -11,11 +9,12 @@ impl Users {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn register_service(&self, public_id: String, sender: tokio::sync::mpsc::Sender<IntercomWebServiceUserMessage>) {
|
pub(super) async fn register_service(&self, public_id: String, sender: tokio::sync::mpsc::Sender<super::IntercomOp>) {
|
||||||
let mut write_lock = self.service_listeners.write().await;
|
let mut write_lock = self.service_listeners.write().await;
|
||||||
if let Some(old_sender) = write_lock.insert(public_id.clone(), sender) {
|
if let Some(old_sender) = write_lock.insert(public_id.clone(), sender) {
|
||||||
if !old_sender.is_closed() {
|
if !old_sender.is_closed() {
|
||||||
log::warn!("Replaced web services intercom channel for user {} (why duplicate!?)", public_id);
|
log::warn!("Replaced web services intercom channel for user {} (why duplicate!?)", public_id);
|
||||||
|
old_sender.send(super::IntercomOp::Info(super::IntercomInfo::Close)).await.unwrap_or_default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -29,13 +28,22 @@ impl Users {
|
|||||||
|
|
||||||
pub async fn broadcast_service_message(&self, msg: oj_rc_core::persist::user::intercom::IntercomWebServiceMessage) {
|
pub async fn broadcast_service_message(&self, msg: oj_rc_core::persist::user::intercom::IntercomWebServiceMessage) {
|
||||||
let read_lock = self.service_listeners.read().await;
|
let read_lock = self.service_listeners.read().await;
|
||||||
for public_id in msg.public_ids {
|
if msg.everyone {
|
||||||
if let Some(tx) = read_lock.get(&public_id) {
|
if !msg.public_ids.is_empty() { return; } // invalid
|
||||||
if let Err(e) = tx.send(msg.data.clone()).await {
|
for (public_id, tx) in read_lock.iter() {
|
||||||
|
if let Err(e) = tx.send(super::IntercomOp::Message(msg.data.clone())).await {
|
||||||
log::error!("Failed to send web service intercom message to {}: {}", public_id, e);
|
log::error!("Failed to send web service intercom message to {}: {}", public_id, e);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
log::warn!("Not sending web service intercom message to user {}; no listener found", public_id);
|
} else {
|
||||||
|
for public_id in msg.public_ids {
|
||||||
|
if let Some(tx) = read_lock.get(&public_id) {
|
||||||
|
if let Err(e) = tx.send(super::IntercomOp::Message(msg.data.clone())).await {
|
||||||
|
log::error!("Failed to send web service intercom message to {}: {}", public_id, e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log::warn!("Not sending web service intercom message to user {}; no listener found", public_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,19 +55,26 @@ impl ChatSystemConfig {
|
|||||||
pub struct ChatCommand {
|
pub struct ChatCommand {
|
||||||
regex: regex::Regex,
|
regex: regex::Regex,
|
||||||
op: ChatOperation,
|
op: ChatOperation,
|
||||||
|
perms: ExecutePermission,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChatCommand {
|
impl ChatCommand {
|
||||||
fn compile_command(command: oj_rc_core::persist::ChatCommand) -> Result<Self, regex::Error> {
|
fn compile_command(command: oj_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),
|
||||||
|
perms: ExecutePermission::from_persist(command.permission),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn perform_if_match<'b, 'c>(&self, text: &str, ctx: CommandContext<'b, 'c>) -> Option<String> {
|
async fn perform_if_match<'b, 'c>(&self, text: &str, ctx: CommandContext<'b, 'c>) -> Option<String> {
|
||||||
if let Some(cap) = self.regex.captures(text) {
|
if let Some(cap) = self.regex.captures(text) {
|
||||||
Some(self.op.perform_command(text, cap, ctx).await)
|
if self.perms.has_perms(ctx.user) {
|
||||||
|
Some(self.op.perform_command(text, cap, ctx).await)
|
||||||
|
} else {
|
||||||
|
log::warn!("User {} tried to run command {} without sufficient permissions", ctx.user.public_id(), self.regex);
|
||||||
|
None
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@@ -161,12 +168,15 @@ impl BuiltIn {
|
|||||||
}
|
}
|
||||||
Self::Help => {
|
Self::Help => {
|
||||||
use core::fmt::Write;
|
use core::fmt::Write;
|
||||||
|
let force_all = text.trim().split(' ').any(|word| word == "--all");
|
||||||
let mut msg = String::new();
|
let mut msg = String::new();
|
||||||
for command in ctx.chat_system.chat_config().commands.iter() {
|
for command in ctx.chat_system.chat_config().commands.iter() {
|
||||||
let raw_re = command.regex.to_string();
|
if command.perms.has_perms(ctx.user) || force_all {
|
||||||
let pretty_name = Self::prettify_re(&raw_re);
|
let raw_re = command.regex.to_string();
|
||||||
if let Err(e) = write!(msg, "\n{}: {}", pretty_name, command.op.help_str()) {
|
let pretty_name = Self::prettify_re(&raw_re);
|
||||||
log::warn!("Failed to construct help for command `{}`: {}", pretty_name, e);
|
if let Err(e) = write!(msg, "\n{}: {}", pretty_name, command.op.help_str()) {
|
||||||
|
log::warn!("Failed to construct help for command `{}`: {}", pretty_name, e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
msg
|
msg
|
||||||
@@ -187,12 +197,16 @@ impl BuiltIn {
|
|||||||
|
|
||||||
enum Intercom {
|
enum Intercom {
|
||||||
DevMessage,
|
DevMessage,
|
||||||
|
DevBroadcast,
|
||||||
|
Maintenance,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Intercom {
|
impl Intercom {
|
||||||
fn from_persist(intercom: oj_rc_core::persist::IntercomChatOperation) -> Self {
|
fn from_persist(intercom: oj_rc_core::persist::IntercomChatOperation) -> Self {
|
||||||
match intercom {
|
match intercom {
|
||||||
oj_rc_core::persist::IntercomChatOperation::DevMessage => Self::DevMessage,
|
oj_rc_core::persist::IntercomChatOperation::DevMessage => Self::DevMessage,
|
||||||
|
oj_rc_core::persist::IntercomChatOperation::DevBroadcast => Self::DevBroadcast,
|
||||||
|
oj_rc_core::persist::IntercomChatOperation::Maintenance => Self::Maintenance,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,6 +222,32 @@ impl Intercom {
|
|||||||
vec![pub_id.to_owned()],
|
vec![pub_id.to_owned()],
|
||||||
).await;
|
).await;
|
||||||
format!("Sent dev message to {}", pub_id)
|
format!("Sent dev message to {}", pub_id)
|
||||||
|
},
|
||||||
|
Self::DevBroadcast => {
|
||||||
|
if let Some(message) = text.trim().split_once(' ').map(|x| x.1.to_owned()) {
|
||||||
|
ctx.user.show_dev_message(
|
||||||
|
oj_rc_core::persist::user::intercom::IntercomDevMessage {
|
||||||
|
message,
|
||||||
|
duration: 60,
|
||||||
|
},
|
||||||
|
vec![],
|
||||||
|
).await;
|
||||||
|
format!("Sent dev broadcast to everyone")
|
||||||
|
} else {
|
||||||
|
format!("Missing dev message, did not send")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Self::Maintenance => {
|
||||||
|
if let Some(message) = text.trim().split_once(' ').map(|x| x.1.to_owned()) {
|
||||||
|
ctx.user.enter_maintenance(
|
||||||
|
oj_rc_core::persist::user::intercom::IntercomMaintenanceMessage { message },
|
||||||
|
vec![],
|
||||||
|
).await;
|
||||||
|
format!("Sent maintenance message")
|
||||||
|
} else {
|
||||||
|
format!("Missing maintenance message, did not send")
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,6 +256,41 @@ impl Intercom {
|
|||||||
fn do_help(&self) -> String {
|
fn do_help(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
Self::DevMessage => "Show dev message to yourself".to_owned(),
|
Self::DevMessage => "Show dev message to yourself".to_owned(),
|
||||||
|
Self::DevBroadcast => "Show dev message to everyone".to_owned(),
|
||||||
|
Self::Maintenance => "Broadcast maintenance mode to everyone".to_owned(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ExecutePermission {
|
||||||
|
Player,
|
||||||
|
Moderator,
|
||||||
|
Administrator,
|
||||||
|
Developer,
|
||||||
|
Royal,
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExecutePermission {
|
||||||
|
fn from_persist(perm: oj_rc_core::persist::ChatPermission) -> Self {
|
||||||
|
match perm {
|
||||||
|
oj_rc_core::persist::ChatPermission::Player => Self::Player,
|
||||||
|
oj_rc_core::persist::ChatPermission::Moderator => Self::Moderator,
|
||||||
|
oj_rc_core::persist::ChatPermission::Administrator => Self::Administrator,
|
||||||
|
oj_rc_core::persist::ChatPermission::Developer => Self::Developer,
|
||||||
|
oj_rc_core::persist::ChatPermission::Royal => Self::Royal,
|
||||||
|
oj_rc_core::persist::ChatPermission::None => Self::None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_perms(&self, user: &dyn oj_rc_core::persist::user::CommonUser) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::Player => true,
|
||||||
|
Self::Moderator => user.is_mod() || user.is_admin() || user.is_dev() || user.is_royal(),
|
||||||
|
Self::Administrator => user.is_admin() || user.is_dev() || user.is_royal(),
|
||||||
|
Self::Developer => user.is_dev() || user.is_royal(),
|
||||||
|
Self::Royal => user.is_royal(),
|
||||||
|
Self::None => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,38 @@ pub struct ChatConfig {
|
|||||||
|
|
||||||
impl super::config::SelfValidator for ChatConfig {
|
impl super::config::SelfValidator for ChatConfig {
|
||||||
type Context = crate::ConfigImpl;
|
type Context = crate::ConfigImpl;
|
||||||
fn validate(&self, _info: &mut super::config::ValidationInfo, _ctx: &Self::Context) -> bool {
|
fn validate(&self, info: &mut super::config::ValidationInfo, _ctx: &Self::Context) -> bool {
|
||||||
// TODO
|
let mut is_ok = true;
|
||||||
true
|
if !self.public_channels.contains(&self.command_channel) {
|
||||||
|
info.warn(super::config::ValidationMessage {
|
||||||
|
path: vec!["public_channels".to_owned()],
|
||||||
|
message: "Chat command channel is not a public channel".to_owned(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if !self.public_channels.contains(&self.default_channel) {
|
||||||
|
info.warn(super::config::ValidationMessage {
|
||||||
|
path: vec!["public_channels".to_owned()],
|
||||||
|
message: "Chat default channel is not a public channel".to_owned(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if self.command_channel.is_empty() {
|
||||||
|
info.error(super::config::ValidationMessage {
|
||||||
|
path: vec!["command_channel".to_owned()],
|
||||||
|
message: "Chat command channel should not be empty".to_owned(),
|
||||||
|
});
|
||||||
|
is_ok = false;
|
||||||
|
}
|
||||||
|
for (i, cmd) in self.commands.iter().enumerate() {
|
||||||
|
is_ok &= cmd.validate_in(info, self, &format!("commands[{}]", i));
|
||||||
|
}
|
||||||
|
if self.default_channel.is_empty() {
|
||||||
|
info.error(super::config::ValidationMessage {
|
||||||
|
path: vec!["default_channel".to_owned()],
|
||||||
|
message: "Chat default channel should not be empty".to_owned(),
|
||||||
|
});
|
||||||
|
is_ok = false;
|
||||||
|
}
|
||||||
|
is_ok
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,6 +54,52 @@ impl super::config::SelfValidator for ChatConfig {
|
|||||||
pub struct ChatCommand {
|
pub struct ChatCommand {
|
||||||
pub regex: String,
|
pub regex: String,
|
||||||
pub op: ChatOperation,
|
pub op: ChatOperation,
|
||||||
|
pub permission: ChatPermission,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl super::config::SelfValidator for ChatCommand {
|
||||||
|
type Context = ChatConfig;
|
||||||
|
fn validate(&self, info: &mut super::config::ValidationInfo, ctx: &Self::Context) -> bool {
|
||||||
|
let mut is_ok = true;
|
||||||
|
let regex_count = ctx.commands.iter().filter(|other| self.regex == other.regex).count();
|
||||||
|
if regex_count != 1 {
|
||||||
|
info.error(super::config::ValidationMessage {
|
||||||
|
path: vec!["regex".to_owned()],
|
||||||
|
message: format!("Only one chat command can use an identical regex pattern {}; found {}", self.regex, regex_count),
|
||||||
|
});
|
||||||
|
is_ok = false;
|
||||||
|
}
|
||||||
|
// TODO validate regex
|
||||||
|
|
||||||
|
// recommended commands to only allow with elevated permissions
|
||||||
|
if matches!(
|
||||||
|
self.op,
|
||||||
|
ChatOperation::BuiltIn(BuiltInChatOperation::Intercom(IntercomChatOperation::DevBroadcast))
|
||||||
|
| ChatOperation::BuiltIn(BuiltInChatOperation::Intercom(IntercomChatOperation::Maintenance))
|
||||||
|
) {
|
||||||
|
if !matches!(self.permission, ChatPermission::Administrator | ChatPermission::Developer | ChatPermission::Royal) {
|
||||||
|
info.warn(crate::persist::config::ValidationMessage {
|
||||||
|
path: vec!["permission".to_owned()],
|
||||||
|
message: format!("Chat command {:?} is recommended to require Administrator, Developer, or Royal permissions; found {:?}", self.op, self.permission),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is_ok
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
pub enum ChatPermission {
|
||||||
|
Player,
|
||||||
|
#[serde(alias = "Mod")]
|
||||||
|
Moderator,
|
||||||
|
#[serde(alias = "Admin")]
|
||||||
|
Administrator,
|
||||||
|
#[serde(alias = "Dev")]
|
||||||
|
Developer,
|
||||||
|
#[serde(alias = "Special")]
|
||||||
|
Royal,
|
||||||
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
@@ -50,6 +125,8 @@ pub enum BuiltInChatOperation {
|
|||||||
#[serde(tag = "intercom")]
|
#[serde(tag = "intercom")]
|
||||||
pub enum IntercomChatOperation {
|
pub enum IntercomChatOperation {
|
||||||
DevMessage,
|
DevMessage,
|
||||||
|
DevBroadcast,
|
||||||
|
Maintenance,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ mod settings;
|
|||||||
pub use settings::{Settings, QueueMode};
|
pub use settings::{Settings, QueueMode};
|
||||||
|
|
||||||
mod chat;
|
mod chat;
|
||||||
pub use chat::{ChatConfig, ChatCommand, ChatOperation, BuiltInChatOperation, IntercomChatOperation};
|
pub use chat::{ChatConfig, ChatCommand, ChatOperation, BuiltInChatOperation, IntercomChatOperation, ChatPermission};
|
||||||
|
|
||||||
mod vehicle_factory;
|
mod vehicle_factory;
|
||||||
pub use vehicle_factory::{FactoryConfig, AdapterSettings, ArcFactorySettings};
|
pub use vehicle_factory::{FactoryConfig, AdapterSettings, ArcFactorySettings};
|
||||||
|
|||||||
@@ -18,6 +18,10 @@ impl super::CommonUser for UserData {
|
|||||||
self.perms.developer
|
self.perms.developer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_royal(&self) -> bool {
|
||||||
|
self.perms.royalty
|
||||||
|
}
|
||||||
|
|
||||||
fn is_banned(&self) -> bool {
|
fn is_banned(&self) -> bool {
|
||||||
self.perms.banned
|
self.perms.banned
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,23 +65,38 @@ impl super::IntercomUser for super::account_json::UserData {
|
|||||||
let data = IntercomWebServiceMessage {
|
let data = IntercomWebServiceMessage {
|
||||||
public_ids: to,
|
public_ids: to,
|
||||||
data: IntercomWebServiceUserMessage::DevMessage(msg),
|
data: IntercomWebServiceUserMessage::DevMessage(msg),
|
||||||
|
everyone: false,
|
||||||
};
|
};
|
||||||
if let Err(e) = self.post_to_intercom(&data, ".oj_services", "messages").await {
|
if let Err(e) = self.post_to_intercom(&data, ".oj_services", "messages").await {
|
||||||
log::error!("Failed to send intercom dev message: {}", e);
|
log::error!("Failed to send intercom dev message: {}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn enter_maintenance(&self, msg: IntercomMaintenanceMessage, to: Vec<String>) {
|
||||||
|
let send_to_everyone = to.is_empty();
|
||||||
|
let data = IntercomWebServiceMessage {
|
||||||
|
public_ids: to,
|
||||||
|
data: IntercomWebServiceUserMessage::Maintenance(msg),
|
||||||
|
everyone: send_to_everyone,
|
||||||
|
};
|
||||||
|
if let Err(e) = self.post_to_intercom(&data, ".oj_services", "messages").await {
|
||||||
|
log::error!("Failed to send intercom maintenance mode message: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
pub struct IntercomWebServiceMessage {
|
pub struct IntercomWebServiceMessage {
|
||||||
pub public_ids: Vec<String>,
|
pub public_ids: Vec<String>,
|
||||||
pub data: IntercomWebServiceUserMessage,
|
pub data: IntercomWebServiceUserMessage,
|
||||||
|
pub everyone: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
#[serde(tag = "type")]
|
#[serde(tag = "type")]
|
||||||
pub enum IntercomWebServiceUserMessage {
|
pub enum IntercomWebServiceUserMessage {
|
||||||
DevMessage(IntercomDevMessage),
|
DevMessage(IntercomDevMessage),
|
||||||
|
Maintenance(IntercomMaintenanceMessage),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
@@ -90,6 +105,11 @@ pub struct IntercomDevMessage {
|
|||||||
pub duration: u32,
|
pub duration: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
pub struct IntercomMaintenanceMessage {
|
||||||
|
pub message: String,
|
||||||
|
}
|
||||||
|
|
||||||
pub fn generate_token(salt: &[u8], key: &[u8]) -> String {
|
pub fn generate_token(salt: &[u8], key: &[u8]) -> String {
|
||||||
use sha2::{Digest, Sha512};
|
use sha2::{Digest, Sha512};
|
||||||
let mut hasher = Sha512::new();
|
let mut hasher = Sha512::new();
|
||||||
|
|||||||
@@ -338,6 +338,7 @@ pub trait IntercomUser {
|
|||||||
async fn save_custom_avatar(&self, image: Vec<u8>) -> Result<(), polariton_server::operations::SimpleOpError>;
|
async fn save_custom_avatar(&self, image: Vec<u8>) -> Result<(), polariton_server::operations::SimpleOpError>;
|
||||||
async fn webservice_listener(&self) -> Result<IntercomListener<super::intercom::IntercomWebServiceUserMessage>, polariton_server::operations::SimpleOpError>;
|
async fn webservice_listener(&self) -> Result<IntercomListener<super::intercom::IntercomWebServiceUserMessage>, polariton_server::operations::SimpleOpError>;
|
||||||
async fn show_dev_message(&self, msg: super::intercom::IntercomDevMessage, to: Vec<String>);
|
async fn show_dev_message(&self, msg: super::intercom::IntercomDevMessage, to: Vec<String>);
|
||||||
|
async fn enter_maintenance(&self, msg: super::intercom::IntercomMaintenanceMessage, to: Vec<String>);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct IntercomListener<D: serde::de::DeserializeOwned> {
|
pub struct IntercomListener<D: serde::de::DeserializeOwned> {
|
||||||
@@ -373,5 +374,6 @@ pub trait CommonUser: Send + Sync {
|
|||||||
fn is_mod(&self) -> bool;
|
fn is_mod(&self) -> bool;
|
||||||
fn is_admin(&self) -> bool;
|
fn is_admin(&self) -> bool;
|
||||||
fn is_dev(&self) -> bool;
|
fn is_dev(&self) -> bool;
|
||||||
|
fn is_royal(&self) -> bool;
|
||||||
fn is_banned(&self) -> bool;
|
fn is_banned(&self) -> bool;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,12 @@ impl IntercomHandler {
|
|||||||
};
|
};
|
||||||
emitter.emit(event);
|
emitter.emit(event);
|
||||||
},
|
},
|
||||||
|
IntercomWebServiceUserMessage::Maintenance(msg) => {
|
||||||
|
let event = super::MaintenanceMode {
|
||||||
|
message: msg.message,
|
||||||
|
};
|
||||||
|
emitter.emit(event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
|
|||||||
18
rc_services_room/src/events/maintenance_mode.rs
Normal file
18
rc_services_room/src/events/maintenance_mode.rs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
pub struct MaintenanceMode {
|
||||||
|
pub message: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <C: Send + Sync + 'static> polariton_server::events::IntoEvent<C> for MaintenanceMode {
|
||||||
|
const CHANNEL: u8 = 0;
|
||||||
|
const ENCRYPT: bool = true;
|
||||||
|
const RELIABLE: bool = true;
|
||||||
|
|
||||||
|
fn into_event(self) -> polariton::operation::Event<C> {
|
||||||
|
let mut params = polariton::operation::ParameterTable::with_capacity(1);
|
||||||
|
params.insert(19, polariton::operation::Typed::Str(self.message.clone().into()));
|
||||||
|
polariton::operation::Event {
|
||||||
|
code: 3,
|
||||||
|
params,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,3 +3,6 @@ pub use handler::IntercomHandler;
|
|||||||
|
|
||||||
mod dev_message;
|
mod dev_message;
|
||||||
pub use dev_message::DevMessage;
|
pub use dev_message::DevMessage;
|
||||||
|
|
||||||
|
mod maintenance_mode;
|
||||||
|
pub use maintenance_mode::MaintenanceMode;
|
||||||
|
|||||||
Reference in New Issue
Block a user