use crate::legion::{LegionError, LegionResult, LegionManager};
use legion_protocol::utils::{is_legion_encrypted_channel, ChannelType, get_channel_type};
use std::collections::HashMap;
use serde::{Serialize, Deserialize};
use std::time::SystemTime;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ChannelOperation {
Create,
Join,
Leave,
SendMessage,
EditMessage,
DeleteMessage,
KeyRotation,
MemberAdd,
MemberRemove,
RoleChange,
SettingsChange,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChannelEvent {
pub channel: String,
pub operation: ChannelOperation,
pub actor: String,
pub target: Option<String>,
pub timestamp: u64,
pub metadata: HashMap<String, String>,
}
impl LegionManager {
pub fn validate_channel_name(channel_name: &str) -> LegionResult<ChannelType> {
let channel_type = get_channel_type(channel_name);
match channel_type {
ChannelType::LegionEncrypted => Ok(channel_type),
ChannelType::IrcGlobal | ChannelType::IrcLocal => {
Err(LegionError::Channel(format!(
"Channel {} is not a Legion encrypted channel", channel_name
)))
},
ChannelType::Invalid => {
Err(LegionError::Channel(format!(
"Invalid channel name: {}", channel_name
)))
},
}
}
pub async fn handle_create_channel(&self, channel_name: String, creator_id: String) -> LegionResult<()> {
self::LegionManager::validate_channel_name(&channel_name)?;
if !self.supports_legion(&creator_id).await {
return Err(LegionError::Member(format!(
"Client {} does not support Legion Protocol", creator_id
)));
}
self.create_channel(channel_name.clone(), creator_id.clone()).await?;
self.log_channel_event(ChannelEvent {
channel: channel_name.clone(),
operation: ChannelOperation::Create,
actor: creator_id,
target: None,
timestamp: SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs(),
metadata: HashMap::new(),
}).await?;
Ok(())
}
pub async fn handle_join_channel(&self, channel_name: String, client_id: String) -> LegionResult<()> {
self::LegionManager::validate_channel_name(&channel_name)?;
if !self.channels.contains_key(&channel_name) {
return Err(LegionError::Channel(format!("Channel does not exist: {}", channel_name)));
}
self.join_channel(channel_name.clone(), client_id.clone()).await?;
self.log_channel_event(ChannelEvent {
channel: channel_name.clone(),
operation: ChannelOperation::Join,
actor: client_id,
target: None,
timestamp: SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs(),
metadata: HashMap::new(),
}).await?;
Ok(())
}
pub async fn handle_leave_channel(&self, channel_name: String, client_id: String) -> LegionResult<()> {
self::LegionManager::validate_channel_name(&channel_name)?;
self.leave_channel(channel_name.clone(), client_id.clone()).await?;
self.log_channel_event(ChannelEvent {
channel: channel_name.clone(),
operation: ChannelOperation::Leave,
actor: client_id,
target: None,
timestamp: SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs(),
metadata: HashMap::new(),
}).await?;
Ok(())
}
pub async fn handle_send_message(&self, channel_name: String, sender_id: String, message: String) -> LegionResult<Vec<u8>> {
self::LegionManager::validate_channel_name(&channel_name)?;
if !self.member_manager.has_permission(&channel_name, &sender_id, crate::legion::members::Permission::SendMessages).await? {
return Err(LegionError::Member("Insufficient permissions to send messages".to_string()));
}
let encrypted_data = self.send_message(channel_name.clone(), sender_id.clone(), message.clone()).await?;
let mut metadata = HashMap::new();
metadata.insert("message_size".to_string(), encrypted_data.len().to_string());
self.log_channel_event(ChannelEvent {
channel: channel_name,
operation: ChannelOperation::SendMessage,
actor: sender_id,
target: None,
timestamp: SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs(),
metadata,
}).await?;
Ok(encrypted_data)
}
pub async fn handle_receive_message(&self, channel_name: String, recipient_id: String, encrypted_data: Vec<u8>) -> LegionResult<String> {
self::LegionManager::validate_channel_name(&channel_name)?;
let message = self.receive_message(channel_name, recipient_id, encrypted_data).await?;
Ok(message)
}
pub async fn handle_key_rotation(&self, channel_name: String, admin_id: String) -> LegionResult<()> {
self::LegionManager::validate_channel_name(&channel_name)?;
if !self.member_manager.has_permission(&channel_name, &admin_id, crate::legion::members::Permission::ManageKeys).await? {
return Err(LegionError::Member("Insufficient permissions to rotate keys".to_string()));
}
self.rotate_channel_keys(channel_name.clone(), admin_id.clone()).await?;
self.log_channel_event(ChannelEvent {
channel: channel_name,
operation: ChannelOperation::KeyRotation,
actor: admin_id,
target: None,
timestamp: SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs(),
metadata: HashMap::new(),
}).await?;
Ok(())
}
pub async fn get_channel_info(&self, channel_name: &str, requester_id: &str) -> LegionResult<ChannelInfo> {
self::LegionManager::validate_channel_name(channel_name)?;
if !self.member_manager.is_channel_member(channel_name, requester_id).await? {
return Err(LegionError::Member("Not a member of this channel".to_string()));
}
let phalanx_stats = self.channel_stats(channel_name).await?;
let member_stats = self.member_manager.channel_stats(channel_name).await?;
let key_stats = self.key_manager.channel_stats(channel_name).await?;
let created_at = member_stats.created_at;
Ok(ChannelInfo {
name: channel_name.to_string(),
phalanx_stats,
member_stats,
key_stats,
created_at,
})
}
pub async fn list_user_channels(&self, user_id: &str) -> LegionResult<Vec<ChannelSummary>> {
let mut summaries = Vec::new();
let user_channels = self.member_manager.get_user_channels(user_id).await?;
for channel_name in user_channels {
if let Ok(info) = self.get_channel_info(&channel_name, user_id).await {
summaries.push(ChannelSummary {
name: info.name,
member_count: info.member_stats.total_members,
active_members: info.member_stats.active_members,
last_activity: info.key_stats.last_rotation,
user_role: None, });
}
}
Ok(summaries)
}
async fn log_channel_event(&self, event: ChannelEvent) -> LegionResult<()> {
tracing::info!("Channel event: {:?}", event);
Ok(())
}
}
#[derive(Debug, Clone, Serialize)]
pub struct ChannelInfo {
pub name: String,
pub phalanx_stats: phalanx_crypto::group::GroupStats,
pub member_stats: crate::legion::members::ChannelStats,
pub key_stats: crate::legion::keys::ChannelKeyStats,
pub created_at: SystemTime,
}
#[derive(Debug, Clone, Serialize)]
pub struct ChannelSummary {
pub name: String,
pub member_count: usize,
pub active_members: usize,
pub last_activity: SystemTime,
pub user_role: Option<crate::legion::members::MemberRole>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_channel_name_validation() {
assert!(LegionManager::validate_channel_name("!encrypted").is_ok());
assert!(LegionManager::validate_channel_name("#regular").is_err());
assert!(LegionManager::validate_channel_name("invalid").is_err());
}
}