group-aware messaging
* reply in group if admin command from group * allow alerts to be sent to a group instead of individual admins
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
alertmanager::AlertPost,
|
alertmanager::AlertPost,
|
||||||
jsonrpc::{Envelope, RpcClient, RpcClientError, SignalMessage, connect_tcp},
|
jsonrpc::{Envelope, MessageTarget, RpcClient, RpcClientError, SignalMessage, connect_tcp},
|
||||||
log_message::{LogMessage, Origin},
|
log_message::{LogMessage, Origin},
|
||||||
message_handler::{AdminMessageResponse, MessageHandler, MessageHandlerResult},
|
message_handler::{AdminMessageResponse, MessageHandler, MessageHandlerResult},
|
||||||
prometheus::{Prometheus, PrometheusConfig},
|
prometheus::{Prometheus, PrometheusConfig},
|
||||||
@@ -52,6 +52,9 @@ pub struct GatewayConfig {
|
|||||||
pub signal_account: String,
|
pub signal_account: String,
|
||||||
#[conf(repeat, long, env)]
|
#[conf(repeat, long, env)]
|
||||||
pub admin_uuid: Vec<String>,
|
pub admin_uuid: Vec<String>,
|
||||||
|
/// If set, alerts are sent to this group instead of individual admins
|
||||||
|
#[conf(long, env)]
|
||||||
|
pub alert_group_id: Option<String>,
|
||||||
#[conf(flatten)]
|
#[conf(flatten)]
|
||||||
pub prometheus: Option<PrometheusConfig>,
|
pub prometheus: Option<PrometheusConfig>,
|
||||||
#[conf(flatten)]
|
#[conf(flatten)]
|
||||||
@@ -256,9 +259,15 @@ impl Gateway {
|
|||||||
msg.text
|
msg.text
|
||||||
};
|
};
|
||||||
let attachments = msg.attachment_paths.into_iter().map(|p| p.to_str().unwrap().to_owned()).collect();
|
let attachments = msg.attachment_paths.into_iter().map(|p| p.to_str().unwrap().to_owned()).collect();
|
||||||
|
// Send to group if configured, otherwise to individual admins
|
||||||
|
let target = if let Some(group_id) = &self.config.alert_group_id {
|
||||||
|
MessageTarget::Group(group_id.clone())
|
||||||
|
} else {
|
||||||
|
MessageTarget::Recipients(self.config.admin_uuid.clone())
|
||||||
|
};
|
||||||
SignalMessage {
|
SignalMessage {
|
||||||
sender: self.config.signal_account.clone(),
|
sender: self.config.signal_account.clone(),
|
||||||
recipient: self.config.admin_uuid.clone(),
|
target,
|
||||||
message,
|
message,
|
||||||
attachments,
|
attachments,
|
||||||
}.send(signal_cli).await?;
|
}.send(signal_cli).await?;
|
||||||
@@ -280,11 +289,16 @@ impl Gateway {
|
|||||||
}
|
}
|
||||||
Some(Ok(msg)) => {
|
Some(Ok(msg)) => {
|
||||||
//info!("Signal Rx: {msg:?}");
|
//info!("Signal Rx: {msg:?}");
|
||||||
if msg.envelope.data_message.is_none() {
|
let Some(data_message) = &msg.envelope.data_message else {
|
||||||
debug!("Ignoring message which was not a data message: {msg:?}");
|
debug!("Ignoring message which was not a data message: {msg:?}");
|
||||||
continue;
|
continue;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
// Determine if this message came from a group
|
||||||
|
let from_group = data_message.group_info.as_ref().map(|g| g.group_id.clone());
|
||||||
|
|
||||||
|
// For group messages, check if sender is an admin
|
||||||
|
// For direct messages, check if sender is an admin
|
||||||
if !self.config.admin_uuid.contains(&msg.envelope.source_uuid) {
|
if !self.config.admin_uuid.contains(&msg.envelope.source_uuid) {
|
||||||
warn!("Ignoring message from non-admin: {msg:?}");
|
warn!("Ignoring message from non-admin: {msg:?}");
|
||||||
continue;
|
continue;
|
||||||
@@ -307,9 +321,16 @@ impl Gateway {
|
|||||||
|
|
||||||
let attachments = resp.attachments.into_iter().map(|p| p.to_str().expect("attachments must have utf8 paths").to_owned()).collect();
|
let attachments = resp.attachments.into_iter().map(|p| p.to_str().expect("attachments must have utf8 paths").to_owned()).collect();
|
||||||
|
|
||||||
|
// Reply to group if message came from a group, otherwise reply to sender
|
||||||
|
let target = if let Some(group_id) = from_group {
|
||||||
|
MessageTarget::Group(group_id)
|
||||||
|
} else {
|
||||||
|
MessageTarget::Recipients(vec![msg.envelope.source_uuid.clone()])
|
||||||
|
};
|
||||||
|
|
||||||
SignalMessage {
|
SignalMessage {
|
||||||
sender: self.config.signal_account.clone(),
|
sender: self.config.signal_account.clone(),
|
||||||
recipient: vec![msg.envelope.source_uuid.clone()],
|
target,
|
||||||
message: resp.text,
|
message: resp.text,
|
||||||
attachments,
|
attachments,
|
||||||
}.send(signal_cli).await?;
|
}.send(signal_cli).await?;
|
||||||
|
|||||||
@@ -430,6 +430,14 @@ pub struct Envelope {
|
|||||||
pub struct DataMessage {
|
pub struct DataMessage {
|
||||||
pub timestamp: u64,
|
pub timestamp: u64,
|
||||||
pub message: String,
|
pub message: String,
|
||||||
|
#[serde(default)]
|
||||||
|
pub group_info: Option<GroupInfo>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct GroupInfo {
|
||||||
|
pub group_id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Connect to signal-cli over tcp socket
|
/// Connect to signal-cli over tcp socket
|
||||||
@@ -472,10 +480,19 @@ impl Envelope {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Target for a SignalMessage - either individual recipients or a group
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum MessageTarget {
|
||||||
|
/// Send to individual recipients
|
||||||
|
Recipients(Vec<String>),
|
||||||
|
/// Send to a group
|
||||||
|
Group(String),
|
||||||
|
}
|
||||||
|
|
||||||
/// Helper for invoking send, which has way too many parameters
|
/// Helper for invoking send, which has way too many parameters
|
||||||
pub struct SignalMessage {
|
pub struct SignalMessage {
|
||||||
pub sender: String,
|
pub sender: String,
|
||||||
pub recipient: Vec<String>,
|
pub target: MessageTarget,
|
||||||
pub message: String,
|
pub message: String,
|
||||||
pub attachments: Vec<String>,
|
pub attachments: Vec<String>,
|
||||||
}
|
}
|
||||||
@@ -512,8 +529,10 @@ impl SignalMessage {
|
|||||||
editTimestamp: Option<u64>,
|
editTimestamp: Option<u64>,
|
||||||
*/
|
*/
|
||||||
let account = Some(self.sender);
|
let account = Some(self.sender);
|
||||||
let recipients = self.recipient;
|
let (recipients, groupIds) = match self.target {
|
||||||
let groupIds = vec![];
|
MessageTarget::Recipients(r) => (r, vec![]),
|
||||||
|
MessageTarget::Group(g) => (vec![], vec![g]),
|
||||||
|
};
|
||||||
let noteToSelf = false;
|
let noteToSelf = false;
|
||||||
let endSession = false;
|
let endSession = false;
|
||||||
let message = self.message;
|
let message = self.message;
|
||||||
|
|||||||
Reference in New Issue
Block a user