turboprop 0.1.2

Fast semantic code search and indexing tool
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
//! Lifecycle manager for MCP server - handles server lifecycle management
//!
//! Separates lifecycle concerns from protocol and business logic

use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use tokio::sync::RwLock;
use tracing::{debug, info, warn};

/// Server lifecycle states
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ServerState {
    /// Server is being created
    Creating,
    /// Server is initializing
    Initializing,
    /// Server is ready to handle requests
    Ready,
    /// Server is running and processing requests
    Running,
    /// Server is shutting down
    ShuttingDown,
    /// Server is stopped
    Stopped,
    /// Server encountered a fatal error
    Error,
}

impl ServerState {
    /// Check if the server can accept requests in this state
    pub fn can_accept_requests(&self) -> bool {
        matches!(self, ServerState::Ready | ServerState::Running)
    }

    /// Check if the server is in a terminal state
    pub fn is_terminal(&self) -> bool {
        matches!(self, ServerState::Stopped | ServerState::Error)
    }
}

/// Manages server lifecycle and state transitions
pub struct LifecycleManager {
    /// Current server state
    state: Arc<RwLock<ServerState>>,
    /// Shutdown signal
    shutdown_requested: Arc<AtomicBool>,
    /// Graceful shutdown flag
    graceful_shutdown: Arc<AtomicBool>,
}

impl LifecycleManager {
    /// Create a new lifecycle manager
    pub fn new() -> Self {
        Self {
            state: Arc::new(RwLock::new(ServerState::Creating)),
            shutdown_requested: Arc::new(AtomicBool::new(false)),
            graceful_shutdown: Arc::new(AtomicBool::new(true)),
        }
    }

    /// Get the current server state
    pub async fn get_state(&self) -> ServerState {
        let state_guard = self.state.read().await;
        *state_guard
    }

    /// Check if the server can accept requests
    pub async fn can_accept_requests(&self) -> bool {
        let state = self.get_state().await;
        state.can_accept_requests()
    }

    /// Check if shutdown has been requested
    pub fn is_shutdown_requested(&self) -> bool {
        self.shutdown_requested.load(Ordering::SeqCst)
    }

    /// Check if graceful shutdown is enabled
    pub fn is_graceful_shutdown(&self) -> bool {
        self.graceful_shutdown.load(Ordering::SeqCst)
    }

    /// Transition to initializing state
    pub async fn transition_to_initializing(&self) -> Result<(), LifecycleError> {
        let mut state_guard = self.state.write().await;
        match *state_guard {
            ServerState::Creating => {
                *state_guard = ServerState::Initializing;
                info!("Server state transitioned to Initializing");
                Ok(())
            }
            current_state => {
                warn!(
                    "Invalid state transition from {:?} to Initializing",
                    current_state
                );
                Err(LifecycleError::InvalidStateTransition {
                    from: current_state,
                    to: ServerState::Initializing,
                })
            }
        }
    }

    /// Transition to ready state
    pub async fn transition_to_ready(&self) -> Result<(), LifecycleError> {
        let mut state_guard = self.state.write().await;
        match *state_guard {
            ServerState::Initializing => {
                *state_guard = ServerState::Ready;
                info!("Server state transitioned to Ready");
                Ok(())
            }
            current_state => {
                warn!("Invalid state transition from {:?} to Ready", current_state);
                Err(LifecycleError::InvalidStateTransition {
                    from: current_state,
                    to: ServerState::Ready,
                })
            }
        }
    }

    /// Transition to running state
    pub async fn transition_to_running(&self) -> Result<(), LifecycleError> {
        let mut state_guard = self.state.write().await;
        match *state_guard {
            ServerState::Ready => {
                *state_guard = ServerState::Running;
                info!("Server state transitioned to Running");
                Ok(())
            }
            current_state => {
                warn!("Invalid state transition from {:?} to Running", current_state);
                Err(LifecycleError::InvalidStateTransition {
                    from: current_state,
                    to: ServerState::Running,
                })
            }
        }
    }

    /// Transition to shutting down state
    pub async fn transition_to_shutting_down(&self) -> Result<(), LifecycleError> {
        let mut state_guard = self.state.write().await;
        match *state_guard {
            ServerState::Ready | ServerState::Running => {
                *state_guard = ServerState::ShuttingDown;
                info!("Server state transitioned to ShuttingDown");
                Ok(())
            }
            current_state => {
                debug!(
                    "State transition from {:?} to ShuttingDown allowed in emergency",
                    current_state
                );
                *state_guard = ServerState::ShuttingDown;
                Ok(())
            }
        }
    }

    /// Transition to stopped state
    pub async fn transition_to_stopped(&self) -> Result<(), LifecycleError> {
        let mut state_guard = self.state.write().await;
        match *state_guard {
            ServerState::ShuttingDown => {
                *state_guard = ServerState::Stopped;
                info!("Server state transitioned to Stopped");
                Ok(())
            }
            current_state => {
                warn!("Invalid state transition from {:?} to Stopped", current_state);
                Err(LifecycleError::InvalidStateTransition {
                    from: current_state,
                    to: ServerState::Stopped,
                })
            }
        }
    }

    /// Transition to error state
    pub async fn transition_to_error(&self, error_reason: String) -> Result<(), LifecycleError> {
        let mut state_guard = self.state.write().await;
        let current_state = *state_guard;
        *state_guard = ServerState::Error;
        warn!(
            "Server state transitioned to Error from {:?}: {}",
            current_state, error_reason
        );
        Ok(())
    }

    /// Request server shutdown
    pub fn request_shutdown(&self, graceful: bool) {
        self.shutdown_requested.store(true, Ordering::SeqCst);
        self.graceful_shutdown.store(graceful, Ordering::SeqCst);
        
        if graceful {
            info!("Graceful shutdown requested");
        } else {
            warn!("Immediate shutdown requested");
        }
    }

    /// Reset the lifecycle manager (for tests)
    pub async fn reset(&self) {
        let mut state_guard = self.state.write().await;
        *state_guard = ServerState::Creating;
        self.shutdown_requested.store(false, Ordering::SeqCst);
        self.graceful_shutdown.store(true, Ordering::SeqCst);
        debug!("Lifecycle manager reset");
    }

    /// Get a summary of the current lifecycle state
    pub async fn get_summary(&self) -> LifecycleSummary {
        let state = self.get_state().await;
        LifecycleSummary {
            state,
            shutdown_requested: self.is_shutdown_requested(),
            graceful_shutdown: self.is_graceful_shutdown(),
            can_accept_requests: state.can_accept_requests(),
            is_terminal: state.is_terminal(),
        }
    }

    /// Handle STDIN closure (triggers shutdown)
    pub async fn handle_stdin_closed(&self) {
        info!("STDIN closed, initiating graceful shutdown");
        self.request_shutdown(true);
        let _ = self.transition_to_shutting_down().await;
    }

    /// Handle fatal error (transitions to error state)
    pub async fn handle_fatal_error(&self, error: String) {
        warn!("Fatal error occurred: {}", error);
        let _ = self.transition_to_error(error).await;
    }
}

impl Default for LifecycleManager {
    fn default() -> Self {
        Self::new()
    }
}

/// Lifecycle manager summary
#[derive(Debug, Clone)]
pub struct LifecycleSummary {
    pub state: ServerState,
    pub shutdown_requested: bool,
    pub graceful_shutdown: bool,
    pub can_accept_requests: bool,
    pub is_terminal: bool,
}

/// Lifecycle manager errors
#[derive(Debug, thiserror::Error)]
pub enum LifecycleError {
    #[error("Invalid state transition from {from:?} to {to:?}")]
    InvalidStateTransition { from: ServerState, to: ServerState },

    #[error("Server is in terminal state: {state:?}")]
    TerminalState { state: ServerState },

    #[error("Operation not allowed in current state: {state:?}")]
    OperationNotAllowed { state: ServerState },
}

#[cfg(test)]
mod tests {
    use super::*;

    #[tokio::test]
    async fn test_lifecycle_manager_creation() {
        let manager = LifecycleManager::new();
        let state = manager.get_state().await;
        assert_eq!(state, ServerState::Creating);
        assert!(!manager.is_shutdown_requested());
        assert!(manager.is_graceful_shutdown());
    }

    #[tokio::test]
    async fn test_state_transitions() {
        let manager = LifecycleManager::new();
        
        // Creating -> Initializing
        assert!(manager.transition_to_initializing().await.is_ok());
        assert_eq!(manager.get_state().await, ServerState::Initializing);
        
        // Initializing -> Ready
        assert!(manager.transition_to_ready().await.is_ok());
        assert_eq!(manager.get_state().await, ServerState::Ready);
        
        // Ready -> Running
        assert!(manager.transition_to_running().await.is_ok());
        assert_eq!(manager.get_state().await, ServerState::Running);
        
        // Running -> ShuttingDown
        assert!(manager.transition_to_shutting_down().await.is_ok());
        assert_eq!(manager.get_state().await, ServerState::ShuttingDown);
        
        // ShuttingDown -> Stopped
        assert!(manager.transition_to_stopped().await.is_ok());
        assert_eq!(manager.get_state().await, ServerState::Stopped);
    }

    #[tokio::test]
    async fn test_invalid_state_transition() {
        let manager = LifecycleManager::new();
        
        // Try to go directly from Creating to Running (should fail)
        let result = manager.transition_to_running().await;
        assert!(result.is_err());
        matches!(result.unwrap_err(), LifecycleError::InvalidStateTransition { .. });
    }

    #[tokio::test]
    async fn test_can_accept_requests() {
        let manager = LifecycleManager::new();
        
        // Creating state - cannot accept requests
        assert!(!manager.can_accept_requests().await);
        
        // Transition to Ready - can accept requests
        assert!(manager.transition_to_initializing().await.is_ok());
        assert!(manager.transition_to_ready().await.is_ok());
        assert!(manager.can_accept_requests().await);
        
        // Transition to Running - can accept requests
        assert!(manager.transition_to_running().await.is_ok());
        assert!(manager.can_accept_requests().await);
        
        // Transition to ShuttingDown - cannot accept requests
        assert!(manager.transition_to_shutting_down().await.is_ok());
        assert!(!manager.can_accept_requests().await);
    }

    #[tokio::test]
    async fn test_shutdown_request() {
        let manager = LifecycleManager::new();
        
        assert!(!manager.is_shutdown_requested());
        
        manager.request_shutdown(true);
        assert!(manager.is_shutdown_requested());
        assert!(manager.is_graceful_shutdown());
        
        manager.request_shutdown(false);
        assert!(manager.is_shutdown_requested());
        assert!(!manager.is_graceful_shutdown());
    }

    #[tokio::test]
    async fn test_error_state_transition() {
        let manager = LifecycleManager::new();
        
        let result = manager.transition_to_error("Test error".to_string()).await;
        assert!(result.is_ok());
        assert_eq!(manager.get_state().await, ServerState::Error);
    }

    #[tokio::test]
    async fn test_lifecycle_summary() {
        let manager = LifecycleManager::new();
        
        let summary = manager.get_summary().await;
        assert_eq!(summary.state, ServerState::Creating);
        assert!(!summary.shutdown_requested);
        assert!(summary.graceful_shutdown);
        assert!(!summary.can_accept_requests);
        assert!(!summary.is_terminal);
    }

    #[tokio::test]
    async fn test_stdin_closed_handling() {
        let manager = LifecycleManager::new();
        
        // Set up server in running state
        assert!(manager.transition_to_initializing().await.is_ok());
        assert!(manager.transition_to_ready().await.is_ok());
        assert!(manager.transition_to_running().await.is_ok());
        
        // Handle STDIN closed
        manager.handle_stdin_closed().await;
        
        assert!(manager.is_shutdown_requested());
        assert_eq!(manager.get_state().await, ServerState::ShuttingDown);
    }

    #[tokio::test]
    async fn test_reset() {
        let manager = LifecycleManager::new();
        
        // Change state and request shutdown
        assert!(manager.transition_to_initializing().await.is_ok());
        manager.request_shutdown(false);
        
        // Reset
        manager.reset().await;
        
        // Verify reset state
        assert_eq!(manager.get_state().await, ServerState::Creating);
        assert!(!manager.is_shutdown_requested());
        assert!(manager.is_graceful_shutdown());
    }
}