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::backup::BackupService;
6use crate::config::CollabConfig;
7use crate::core_bridge::CoreBridge;
8use crate::error::Result;
9use crate::events::EventBus;
10use crate::history::{History, VersionControl};
11use crate::merge::MergeService;
12use crate::sync::SyncEngine;
13use crate::user::UserService;
14use crate::websocket::{ws_handler, WsState};
15use crate::workspace::WorkspaceService;
16use axum::routing::get;
17use axum::Router;
18use sqlx::{Pool, Sqlite};
19use std::sync::Arc;
20
21/// Collaboration server
22pub struct CollabServer {
23    /// Configuration
24    config: CollabConfig,
25    /// Database pool
26    db: Pool<Sqlite>,
27    /// Authentication service
28    auth: Arc<AuthService>,
29    /// User service
30    user: Arc<UserService>,
31    /// Workspace service
32    workspace: Arc<WorkspaceService>,
33    /// Event bus
34    event_bus: Arc<EventBus>,
35    /// Sync engine
36    sync: Arc<SyncEngine>,
37    /// History tracker
38    history: Arc<History>,
39    /// Merge service
40    merge: Arc<MergeService>,
41    /// Backup service
42    backup: Arc<BackupService>,
43}
44
45impl CollabServer {
46    /// Create a new collaboration server
47    pub async fn new(config: CollabConfig) -> Result<Self> {
48        // Initialize database
49        let db = sqlx::SqlitePool::connect(&config.database_url).await?;
50
51        // Run migrations
52        sqlx::migrate!("./migrations").run(&db).await?;
53
54        // Create CoreBridge for workspace integration
55        let workspace_dir =
56            config.workspace_dir.as_ref().map(|s| s.as_str()).unwrap_or("./workspaces");
57        let core_bridge = Arc::new(CoreBridge::new(workspace_dir));
58
59        // Create services
60        let auth = Arc::new(AuthService::new(config.jwt_secret.clone()));
61        let user = Arc::new(UserService::new(db.clone(), auth.clone()));
62        let workspace =
63            Arc::new(WorkspaceService::with_core_bridge(db.clone(), core_bridge.clone()));
64        let event_bus = Arc::new(EventBus::new(config.event_bus_capacity));
65        let sync = Arc::new(SyncEngine::with_integration(
66            event_bus.clone(),
67            db.clone(),
68            core_bridge.clone(),
69            workspace.clone(),
70        ));
71        let mut history = History::new(db.clone());
72        history.set_auto_commit(config.auto_commit);
73        let history = Arc::new(history);
74
75        // Create merge service
76        let merge = Arc::new(MergeService::new(db.clone()));
77
78        // Create backup service
79        let backup = Arc::new(BackupService::new(
80            db.clone(),
81            config.backup_dir.clone(),
82            core_bridge.clone(),
83            workspace.clone(),
84        ));
85
86        Ok(Self {
87            config,
88            db,
89            auth,
90            user,
91            workspace,
92            event_bus,
93            sync,
94            history,
95            merge,
96            backup,
97        })
98    }
99
100    /// Start the collaboration server
101    pub async fn run(self, addr: &str) -> Result<()> {
102        tracing::info!("Starting MockForge Collaboration Server on {}", addr);
103
104        // Create API router
105        let version_control = Arc::new(VersionControl::new(self.db.clone()));
106
107        // Get merge and backup services from config or create them
108        // For now, we'll need to store them in the server struct
109        // Let me check what we have available...
110
111        // Actually, we need to restructure this - let me add merge and backup to the server struct
112        let api_state = ApiState {
113            auth: self.auth.clone(),
114            user: self.user.clone(),
115            workspace: self.workspace.clone(),
116            history: version_control,
117            merge: self.merge.clone(),
118            backup: self.backup.clone(),
119            sync: self.sync.clone(),
120        };
121        let api_router = create_api_router(api_state);
122
123        // Create WebSocket state
124        let ws_state = WsState {
125            auth: self.auth.clone(),
126            sync: self.sync.clone(),
127            event_bus: self.event_bus.clone(),
128        };
129
130        // Combine routers
131        let app = Router::new()
132            .route("/ws", get(ws_handler))
133            .with_state(ws_state)
134            .merge(api_router);
135
136        // Parse address
137        let listener = tokio::net::TcpListener::bind(addr)
138            .await
139            .map_err(|e| crate::error::CollabError::Internal(format!("Failed to bind: {}", e)))?;
140
141        tracing::info!("Server listening on {}", addr);
142
143        // Run server
144        axum::serve(listener, app)
145            .await
146            .map_err(|e| crate::error::CollabError::Internal(format!("Server error: {}", e)))?;
147
148        Ok(())
149    }
150
151    /// Get authentication service
152    pub fn auth(&self) -> Arc<AuthService> {
153        self.auth.clone()
154    }
155
156    /// Get workspace service
157    pub fn workspace(&self) -> Arc<WorkspaceService> {
158        self.workspace.clone()
159    }
160
161    /// Get sync engine
162    pub fn sync(&self) -> Arc<SyncEngine> {
163        self.sync.clone()
164    }
165
166    /// Get history tracker
167    pub fn history(&self) -> Arc<History> {
168        self.history.clone()
169    }
170}