mockforge_collab/
server.rs

1//! Collaboration server implementation
2
3use crate::api::{create_router as create_api_router, ApiState};
4use crate::auth::AuthService;
5use crate::config::CollabConfig;
6use crate::error::Result;
7use crate::events::EventBus;
8use crate::history::{History, VersionControl};
9use crate::sync::SyncEngine;
10use crate::user::UserService;
11use crate::websocket::{ws_handler, WsState};
12use crate::workspace::WorkspaceService;
13use axum::routing::get;
14use axum::Router;
15use sqlx::{Pool, Sqlite};
16use std::sync::Arc;
17
18/// Collaboration server
19pub struct CollabServer {
20    /// Configuration
21    config: CollabConfig,
22    /// Database pool
23    db: Pool<Sqlite>,
24    /// Authentication service
25    auth: Arc<AuthService>,
26    /// User service
27    user: Arc<UserService>,
28    /// Workspace service
29    workspace: Arc<WorkspaceService>,
30    /// Event bus
31    event_bus: Arc<EventBus>,
32    /// Sync engine
33    sync: Arc<SyncEngine>,
34    /// History tracker
35    history: Arc<History>,
36}
37
38impl CollabServer {
39    /// Create a new collaboration server
40    pub async fn new(config: CollabConfig) -> Result<Self> {
41        // Initialize database
42        let db = sqlx::SqlitePool::connect(&config.database_url).await?;
43
44        // Run migrations
45        sqlx::migrate!("./migrations").run(&db).await?;
46
47        // Create services
48        let auth = Arc::new(AuthService::new(config.jwt_secret.clone()));
49        let user = Arc::new(UserService::new(db.clone(), auth.clone()));
50        let workspace = Arc::new(WorkspaceService::new(db.clone()));
51        let event_bus = Arc::new(EventBus::new(config.event_bus_capacity));
52        let sync = Arc::new(SyncEngine::new(event_bus.clone()));
53        let mut history = History::new(db.clone());
54        history.set_auto_commit(config.auto_commit);
55        let history = Arc::new(history);
56
57        Ok(Self {
58            config,
59            db,
60            auth,
61            user,
62            workspace,
63            event_bus,
64            sync,
65            history,
66        })
67    }
68
69    /// Start the collaboration server
70    pub async fn run(self, addr: &str) -> Result<()> {
71        tracing::info!("Starting MockForge Collaboration Server on {}", addr);
72
73        // Create API router
74        let version_control = Arc::new(VersionControl::new(self.db.clone()));
75        let api_state = ApiState {
76            auth: self.auth.clone(),
77            user: self.user.clone(),
78            workspace: self.workspace.clone(),
79            history: version_control,
80        };
81        let api_router = create_api_router(api_state);
82
83        // Create WebSocket state
84        let ws_state = WsState {
85            auth: self.auth.clone(),
86            sync: self.sync.clone(),
87            event_bus: self.event_bus.clone(),
88        };
89
90        // Combine routers
91        let app = Router::new()
92            .route("/ws", get(ws_handler))
93            .with_state(ws_state)
94            .merge(api_router);
95
96        // Parse address
97        let listener = tokio::net::TcpListener::bind(addr)
98            .await
99            .map_err(|e| crate::error::CollabError::Internal(format!("Failed to bind: {}", e)))?;
100
101        tracing::info!("Server listening on {}", addr);
102
103        // Run server
104        axum::serve(listener, app)
105            .await
106            .map_err(|e| crate::error::CollabError::Internal(format!("Server error: {}", e)))?;
107
108        Ok(())
109    }
110
111    /// Get authentication service
112    pub fn auth(&self) -> Arc<AuthService> {
113        self.auth.clone()
114    }
115
116    /// Get workspace service
117    pub fn workspace(&self) -> Arc<WorkspaceService> {
118        self.workspace.clone()
119    }
120
121    /// Get sync engine
122    pub fn sync(&self) -> Arc<SyncEngine> {
123        self.sync.clone()
124    }
125
126    /// Get history tracker
127    pub fn history(&self) -> Arc<History> {
128        self.history.clone()
129    }
130}