Some checks failed
CI / Rust Format (push) Has been cancelled
CI / Clippy (push) Has been cancelled
CI / Test Server (push) Has been cancelled
CI / Frontend Check (push) Has been cancelled
CI / Tauri Client Check (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Build Tauri (Linux) (push) Has been cancelled
- Fix 14 Clippy warnings across server and bot-sdk - Add 67 unit tests (32 bot-sdk, 34 server, 1 doctest) - Add Prometheus metrics endpoint (/api/metrics) - Add structured JSON logging (EIFELDC_LOG_FORMAT=json) - Add release workflow (Docker push + GitHub Release + Tauri builds) - Add rate limiting middleware (EIFELDC_RATE_LIMIT) - Add CORS restriction (EIFELDC_CORS_ORIGINS) - Add session token expiry (EIFELDC_SESSION_TTL) - Add input validation (username/password/homeserver length limits) - Add upload size limit (EIFELDC_MAX_UPLOAD_MB) - Upgrade Tauri client from v1 to v2 - Add session store with SQLite persistence - Add proper error types and cleanup across all crates - Format all code with cargo fmt - Update CI pipeline with fmt, clippy, test, frontend, and Tauri checks - Add README with full API reference and setup guide
162 lines
4.0 KiB
Rust
162 lines
4.0 KiB
Rust
use std::collections::HashMap;
|
|
use std::sync::Arc;
|
|
use tokio::sync::Mutex;
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct RoomInfo {
|
|
pub room_id: String,
|
|
pub name: String,
|
|
pub is_encrypted: bool,
|
|
}
|
|
|
|
impl RoomInfo {
|
|
pub fn new(room_id: String, name: String, is_encrypted: bool) -> Self {
|
|
Self {
|
|
room_id,
|
|
name,
|
|
is_encrypted,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Default)]
|
|
pub struct RoomManager {
|
|
pub rooms: HashMap<String, RoomInfo>,
|
|
}
|
|
|
|
impl RoomManager {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
rooms: HashMap::new(),
|
|
}
|
|
}
|
|
|
|
pub fn add_room(&mut self, room: RoomInfo) {
|
|
self.rooms.insert(room.room_id.clone(), room);
|
|
}
|
|
|
|
pub fn remove_room(&mut self, room_id: &str) {
|
|
self.rooms.remove(room_id);
|
|
}
|
|
|
|
pub fn get_room(&self, room_id: &str) -> Option<&RoomInfo> {
|
|
self.rooms.get(room_id)
|
|
}
|
|
|
|
pub fn list_rooms(&self) -> Vec<&RoomInfo> {
|
|
self.rooms.values().collect()
|
|
}
|
|
|
|
pub fn room_count(&self) -> usize {
|
|
self.rooms.len()
|
|
}
|
|
}
|
|
|
|
pub type SharedRoomManager = Arc<Mutex<RoomManager>>;
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn new_creates_empty_manager() {
|
|
let mgr = RoomManager::new();
|
|
assert_eq!(mgr.room_count(), 0);
|
|
}
|
|
|
|
#[test]
|
|
fn default_creates_empty_manager() {
|
|
let mgr = RoomManager::default();
|
|
assert_eq!(mgr.room_count(), 0);
|
|
}
|
|
|
|
#[test]
|
|
fn add_room_inserts_room() {
|
|
let mut mgr = RoomManager::new();
|
|
mgr.add_room(RoomInfo::new(
|
|
"!room1:server".into(),
|
|
"Room One".into(),
|
|
false,
|
|
));
|
|
assert_eq!(mgr.room_count(), 1);
|
|
}
|
|
|
|
#[test]
|
|
fn add_multiple_rooms() {
|
|
let mut mgr = RoomManager::new();
|
|
mgr.add_room(RoomInfo::new("!r1:server".into(), "A".into(), false));
|
|
mgr.add_room(RoomInfo::new("!r2:server".into(), "B".into(), true));
|
|
assert_eq!(mgr.room_count(), 2);
|
|
}
|
|
|
|
#[test]
|
|
fn get_room_returns_correct_room() {
|
|
let mut mgr = RoomManager::new();
|
|
mgr.add_room(RoomInfo::new(
|
|
"!room1:server".into(),
|
|
"Room One".into(),
|
|
false,
|
|
));
|
|
let room = mgr.get_room("!room1:server").unwrap();
|
|
assert_eq!(room.name, "Room One");
|
|
assert!(!room.is_encrypted);
|
|
}
|
|
|
|
#[test]
|
|
fn get_room_returns_none_for_missing() {
|
|
let mgr = RoomManager::new();
|
|
assert!(mgr.get_room("!nonexistent:server").is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn remove_room_deletes_room() {
|
|
let mut mgr = RoomManager::new();
|
|
mgr.add_room(RoomInfo::new(
|
|
"!room1:server".into(),
|
|
"Room One".into(),
|
|
false,
|
|
));
|
|
assert_eq!(mgr.room_count(), 1);
|
|
mgr.remove_room("!room1:server");
|
|
assert_eq!(mgr.room_count(), 0);
|
|
}
|
|
|
|
#[test]
|
|
fn remove_nonexistent_room_is_noop() {
|
|
let mut mgr = RoomManager::new();
|
|
mgr.add_room(RoomInfo::new(
|
|
"!room1:server".into(),
|
|
"Room One".into(),
|
|
false,
|
|
));
|
|
mgr.remove_room("!nonexistent:server");
|
|
assert_eq!(mgr.room_count(), 1);
|
|
}
|
|
|
|
#[test]
|
|
fn add_room_overwrites_existing() {
|
|
let mut mgr = RoomManager::new();
|
|
mgr.add_room(RoomInfo::new(
|
|
"!room1:server".into(),
|
|
"Old Name".into(),
|
|
false,
|
|
));
|
|
mgr.add_room(RoomInfo::new(
|
|
"!room1:server".into(),
|
|
"New Name".into(),
|
|
true,
|
|
));
|
|
assert_eq!(mgr.room_count(), 1);
|
|
assert_eq!(mgr.get_room("!room1:server").unwrap().name, "New Name");
|
|
assert!(mgr.get_room("!room1:server").unwrap().is_encrypted);
|
|
}
|
|
|
|
#[test]
|
|
fn list_rooms_returns_all() {
|
|
let mut mgr = RoomManager::new();
|
|
mgr.add_room(RoomInfo::new("!r1:server".into(), "A".into(), false));
|
|
mgr.add_room(RoomInfo::new("!r2:server".into(), "B".into(), true));
|
|
assert_eq!(mgr.list_rooms().len(), 2);
|
|
}
|
|
}
|