use serde::{Deserialize, Serialize};
pub type MessageId = String;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Message {
pub id: MessageId,
pub from: String,
pub to: MessageTarget,
pub content: String,
pub timestamp: i64,
pub reply_to: Option<String>,
pub mentions: Vec<String>,
}
impl Message {
pub fn private(
from: impl Into<String>,
to: impl Into<String>,
content: impl Into<String>,
) -> Self {
Self {
id: uuid::Uuid::new_v4().to_string(),
from: from.into(),
to: MessageTarget::Direct(to.into()),
content: content.into(),
timestamp: chrono::Utc::now().timestamp(),
reply_to: None,
mentions: Vec::new(),
}
}
pub fn group(
from: impl Into<String>,
group_id: impl Into<String>,
content: impl Into<String>,
) -> Self {
Self {
id: uuid::Uuid::new_v4().to_string(),
from: from.into(),
to: MessageTarget::Group(group_id.into()),
content: content.into(),
timestamp: chrono::Utc::now().timestamp(),
reply_to: None,
mentions: Vec::new(),
}
}
pub fn with_reply_to(mut self, message_id: impl Into<String>) -> Self {
self.reply_to = Some(message_id.into());
self
}
pub fn with_mention(mut self, agent_id: impl Into<String>) -> Self {
let id = agent_id.into();
if !self.mentions.contains(&id) {
self.mentions.push(id);
}
self
}
pub fn with_mentions(mut self, agent_ids: Vec<impl Into<String>>) -> Self {
for id in agent_ids {
let id = id.into();
if !self.mentions.contains(&id) {
self.mentions.push(id);
}
}
self
}
pub fn target_agent(&self) -> Option<&str> {
match &self.to {
MessageTarget::Direct(agent_id) => Some(agent_id),
_ => None,
}
}
pub fn target_group(&self) -> Option<&str> {
match &self.to {
MessageTarget::Group(group_id) => Some(group_id),
_ => None,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum MessageTarget {
Direct(String),
Group(String),
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum GroupVisibility {
#[serde(rename = "public")]
Public,
#[serde(rename = "hidden")]
Hidden,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Group {
pub id: String,
pub name: String,
pub creator_id: String,
pub members: Vec<String>,
pub created_at: i64,
pub visibility: GroupVisibility,
}
impl Group {
pub fn new(
id: impl Into<String>,
name: impl Into<String>,
creator_id: impl Into<String>,
members: Vec<String>,
) -> Self {
Self {
id: id.into(),
name: name.into(),
creator_id: creator_id.into(),
members,
created_at: chrono::Utc::now().timestamp(),
visibility: GroupVisibility::Public,
}
}
pub fn new_hidden(
id: impl Into<String>,
name: impl Into<String>,
creator_id: impl Into<String>,
members: Vec<String>,
) -> Self {
Self {
id: id.into(),
name: name.into(),
creator_id: creator_id.into(),
members,
created_at: chrono::Utc::now().timestamp(),
visibility: GroupVisibility::Hidden,
}
}
pub fn add_member(&mut self, agent_id: impl Into<String>) {
let id = agent_id.into();
if !self.members.contains(&id) {
self.members.push(id);
}
}
pub fn remove_member(&mut self, agent_id: &str) {
self.members.retain(|m| m != agent_id);
}
pub fn has_member(&self, agent_id: &str) -> bool {
self.members.contains(&agent_id.to_string())
}
}