Skip to main content

rmux_client/commands/
server.rs

1use std::fmt;
2use std::path::Path;
3
4use rmux_proto::{
5    DaemonStatusRequest, KillServerRequest, LockClientRequest, LockServerRequest,
6    LockSessionRequest, Request, Response, ServerAccessRequest, SessionName, ShutdownIfIdleRequest,
7};
8
9use crate::{
10    auto_start::{ensure_server_running_with_config, AutoStartConfig, AutoStartError},
11    connection::{connect, Connection},
12    ClientError,
13};
14
15impl Connection {
16    /// Ensures the server is available, honouring top-level no-start-server behavior.
17    pub fn start_server(
18        socket_path: &Path,
19        no_start_server: bool,
20        config: AutoStartConfig,
21    ) -> Result<Self, StartServerError> {
22        if no_start_server {
23            return connect(socket_path).map_err(StartServerError::Client);
24        }
25
26        ensure_server_running_with_config(socket_path, config).map_err(StartServerError::AutoStart)
27    }
28
29    /// Sends a `kill-server` request over the detached RPC channel.
30    pub fn kill_server(&mut self) -> Result<Response, ClientError> {
31        self.roundtrip(&Request::KillServer(KillServerRequest))
32    }
33
34    /// Sends a `kill-server` request and returns after the frame is written.
35    ///
36    /// Windows package clients use this for the tmux-style fire-and-forget
37    /// shutdown path, where waiting for the daemon's final cleanup dominates
38    /// the command latency and the named pipe does not need client-side socket
39    /// removal.
40    pub fn kill_server_after_write(&mut self) -> Result<(), ClientError> {
41        self.write_request(&Request::KillServer(KillServerRequest))
42    }
43
44    /// Sends a legacy-wire `kill-server` request for stale daemon cleanup.
45    pub fn kill_server_legacy_wire(&mut self, wire_version: u32) -> Result<(), ClientError> {
46        self.write_legacy_wire_request(&Request::KillServer(KillServerRequest), wire_version)
47    }
48
49    /// Sends an internal daemon status request over the detached RPC channel.
50    pub fn daemon_status(&mut self) -> Result<Response, ClientError> {
51        self.roundtrip(&Request::DaemonStatus(DaemonStatusRequest))
52    }
53
54    /// Sends an internal idle-only daemon shutdown request.
55    pub fn shutdown_if_idle(&mut self) -> Result<Response, ClientError> {
56        self.roundtrip(&Request::ShutdownIfIdle(ShutdownIfIdleRequest))
57    }
58
59    /// Sends a `lock-server` request over the detached RPC channel.
60    pub fn lock_server(&mut self) -> Result<Response, ClientError> {
61        self.roundtrip(&Request::LockServer(LockServerRequest))
62    }
63
64    /// Sends a `lock-session` request over the detached RPC channel.
65    pub fn lock_session(&mut self, target: SessionName) -> Result<Response, ClientError> {
66        self.roundtrip(&Request::LockSession(LockSessionRequest { target }))
67    }
68
69    /// Sends a `lock-client` request over the detached RPC channel.
70    pub fn lock_client(&mut self, target_client: String) -> Result<Response, ClientError> {
71        self.roundtrip(&Request::LockClient(LockClientRequest { target_client }))
72    }
73
74    /// Sends a `server-access` request over the detached RPC channel.
75    pub fn server_access(&mut self, request: ServerAccessRequest) -> Result<Response, ClientError> {
76        self.roundtrip(&Request::ServerAccess(request))
77    }
78}
79
80/// Client-side `start-server` failure surface.
81#[derive(Debug)]
82pub enum StartServerError {
83    /// Connecting to an already-running server failed.
84    Client(ClientError),
85    /// Auto-starting the server failed.
86    AutoStart(AutoStartError),
87}
88
89impl fmt::Display for StartServerError {
90    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
91        match self {
92            Self::Client(error) => fmt::Display::fmt(error, formatter),
93            Self::AutoStart(error) => fmt::Display::fmt(error, formatter),
94        }
95    }
96}
97
98impl std::error::Error for StartServerError {
99    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
100        match self {
101            Self::Client(error) => Some(error),
102            Self::AutoStart(error) => Some(error),
103        }
104    }
105}