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}