Skip to main content

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    ///
48    /// # Errors
49    ///
50    /// Returns an error if the database connection or migrations fail.
51    pub async fn new(config: CollabConfig) -> Result<Self> {
52        // Initialize database
53        let db = sqlx::SqlitePool::connect(&config.database_url).await?;
54
55        // Run migrations automatically
56        Self::run_migrations(&db).await?;
57
58        // Create CoreBridge for workspace integration
59        let workspace_dir = config.workspace_dir.as_deref().unwrap_or("./workspaces");
60        let core_bridge = Arc::new(CoreBridge::new(workspace_dir));
61
62        // Create services
63        let auth = Arc::new(AuthService::new(config.jwt_secret.clone()));
64        let user = Arc::new(UserService::new(db.clone(), auth.clone()));
65        let workspace =
66            Arc::new(WorkspaceService::with_core_bridge(db.clone(), core_bridge.clone()));
67        let event_bus = Arc::new(EventBus::new(config.event_bus_capacity));
68        let sync = Arc::new(SyncEngine::with_integration(
69            event_bus.clone(),
70            db.clone(),
71            core_bridge.clone(),
72            workspace.clone(),
73        ));
74        let mut history = History::new(db.clone());
75        history.set_auto_commit(config.auto_commit);
76        let history = Arc::new(history);
77
78        // Create merge service
79        let merge = Arc::new(MergeService::new(db.clone()));
80
81        // Create backup service
82        let backup = Arc::new(BackupService::new(
83            db.clone(),
84            config.backup_dir.clone(),
85            core_bridge,
86            workspace.clone(),
87        ));
88
89        Ok(Self {
90            _config: config,
91            db,
92            auth,
93            user,
94            workspace,
95            event_bus,
96            sync,
97            history,
98            merge,
99            backup,
100        })
101    }
102
103    /// Run database migrations
104    ///
105    /// This method can be called independently to ensure migrations are up to date.
106    /// It's automatically called during server initialization.
107    ///
108    /// # Errors
109    ///
110    /// Returns an error if the migrations fail to run.
111    pub async fn run_migrations(db: &sqlx::SqlitePool) -> Result<()> {
112        tracing::info!("Running database migrations");
113        sqlx::migrate!("./migrations").run(db).await.map_err(|e| {
114            tracing::error!("Migration failed: {}", e);
115            crate::error::CollabError::DatabaseError(format!("Migration failed: {e}"))
116        })?;
117        tracing::info!("Database migrations completed successfully");
118        Ok(())
119    }
120
121    /// Start the collaboration server
122    ///
123    /// # Errors
124    ///
125    /// Returns an error if the server cannot bind to the address or encounters a runtime error.
126    pub async fn run(self, addr: &str) -> Result<()> {
127        tracing::info!("Starting MockForge Collaboration Server on {}", addr);
128
129        // Create API router
130        let version_control = Arc::new(VersionControl::new(self.db.clone()));
131
132        // Get merge and backup services from config or create them
133        // For now, we'll need to store them in the server struct
134        // Let me check what we have available...
135
136        // Actually, we need to restructure this - let me add merge and backup to the server struct
137        let api_state = ApiState {
138            auth: self.auth.clone(),
139            user: self.user.clone(),
140            workspace: self.workspace.clone(),
141            history: version_control,
142            merge: self.merge.clone(),
143            backup: self.backup.clone(),
144            sync: self.sync.clone(),
145        };
146        let api_router = create_api_router(api_state);
147
148        // Create WebSocket state
149        let ws_state = WsState {
150            auth: self.auth.clone(),
151            sync: self.sync.clone(),
152            event_bus: self.event_bus.clone(),
153            workspace: self.workspace.clone(),
154        };
155
156        // Combine routers
157        let app = Router::new()
158            .route("/ws", get(ws_handler))
159            .with_state(ws_state)
160            .merge(api_router);
161
162        // Parse address
163        let listener = tokio::net::TcpListener::bind(addr)
164            .await
165            .map_err(|e| crate::error::CollabError::Internal(format!("Failed to bind: {e}")))?;
166
167        tracing::info!("Server listening on {}", addr);
168
169        // Run server
170        axum::serve(listener, app)
171            .await
172            .map_err(|e| crate::error::CollabError::Internal(format!("Server error: {e}")))?;
173
174        Ok(())
175    }
176
177    /// Get authentication service
178    #[must_use]
179    pub fn auth(&self) -> Arc<AuthService> {
180        self.auth.clone()
181    }
182
183    /// Get workspace service
184    #[must_use]
185    pub fn workspace(&self) -> Arc<WorkspaceService> {
186        self.workspace.clone()
187    }
188
189    /// Get sync engine
190    #[must_use]
191    pub fn sync(&self) -> Arc<SyncEngine> {
192        self.sync.clone()
193    }
194
195    /// Get history tracker
196    #[must_use]
197    pub fn history(&self) -> Arc<History> {
198        self.history.clone()
199    }
200}