Skip to main content

perl_dap/server/
lifecycle.rs

1use crate::bridge_adapter::BridgeAdapter;
2use crate::debug_adapter::DebugAdapter;
3use crate::server::config::DapConfig;
4use crate::server::mode::DapMode;
5
6/// DAP server
7///
8/// Supports two operating modes:
9/// - **Native** (default): Uses the built-in [`DebugAdapter`] with `perl -d`
10/// - **Bridge**: Proxies DAP messages to Perl::LanguageServer via [`BridgeAdapter`]
11pub struct DapServer {
12    /// Server configuration
13    pub config: DapConfig,
14    /// The underlying debug adapter (used in Native mode)
15    adapter: DebugAdapter,
16}
17
18impl DapServer {
19    /// Create a new DAP server instance
20    ///
21    /// # Arguments
22    ///
23    /// * `config` - Server configuration including operating mode
24    ///
25    /// # Errors
26    ///
27    /// Currently always succeeds. Phase 2 will add validation and initialization errors.
28    pub fn new(config: DapConfig) -> anyhow::Result<Self> {
29        Ok(Self { config, adapter: DebugAdapter::new() })
30    }
31
32    /// Run the DAP server
33    ///
34    /// Dispatches to the appropriate transport based on the configured [`DapMode`]:
35    /// - [`DapMode::Native`]: Starts the stdio transport loop via `DebugAdapter::run`
36    /// - [`DapMode::Bridge`]: Spawns Perl::LanguageServer and proxies DAP messages
37    ///   via [`BridgeAdapter`] using a tokio async runtime
38    pub fn run(&mut self) -> anyhow::Result<()> {
39        match self.config.mode {
40            DapMode::Native => self.adapter.run().map_err(Into::into),
41            DapMode::Bridge => {
42                tracing::info!("Starting DAP server in bridge mode");
43                let rt = tokio::runtime::Runtime::new()?;
44                rt.block_on(async {
45                    let mut bridge = BridgeAdapter::new();
46                    bridge.spawn_pls_dap().await?;
47                    bridge.proxy_messages().await?;
48                    bridge.shutdown().await?;
49                    Ok(())
50                })
51            }
52        }
53    }
54
55    /// Run the DAP server over TCP socket transport.
56    ///
57    /// This binds to `127.0.0.1:<port>` and serves one DAP client session.
58    ///
59    /// # Errors
60    ///
61    /// Returns an error if bridge mode is selected, since socket transport
62    /// is only supported for native mode.
63    pub fn run_socket(&mut self, port: u16) -> anyhow::Result<()> {
64        if self.config.mode == DapMode::Bridge {
65            anyhow::bail!("Socket transport is not supported in bridge mode");
66        }
67        self.adapter.run_socket(port).map_err(Into::into)
68    }
69}