rmux_client/commands/
server.rs1use std::fmt;
2use std::path::Path;
3#[cfg(windows)]
4use std::path::PathBuf;
5
6use rmux_proto::{
7 DaemonStatusRequest, KillServerRequest, LockClientRequest, LockServerRequest,
8 LockSessionRequest, Request, Response, ServerAccessRequest, SessionName, ShutdownIfIdleRequest,
9};
10
11use crate::{
12 auto_start::{ensure_server_running_with_config, AutoStartConfig, AutoStartError},
13 connection::{connect, Connection},
14 ClientError,
15};
16
17#[cfg(windows)]
24pub fn connect_for_server_shutdown(
25 socket_path: &Path,
26) -> Result<(Connection, PathBuf), ClientError> {
27 let primary_error = match connect(socket_path) {
28 Ok(connection) => return Ok((connection, socket_path.to_path_buf())),
29 Err(error) if shutdown_endpoint_is_absent(&error) => error,
30 Err(error) => return Err(error),
31 };
32 let Some(legacy_endpoint) = rmux_ipc::legacy_shutdown_endpoint(socket_path)? else {
33 return Err(primary_error);
34 };
35 let legacy_path = legacy_endpoint.into_path();
36 connect(&legacy_path).map(|connection| (connection, legacy_path))
37}
38
39#[cfg(windows)]
40fn shutdown_endpoint_is_absent(error: &ClientError) -> bool {
41 matches!(
42 error,
43 ClientError::Io(error)
44 if matches!(
45 error.kind(),
46 std::io::ErrorKind::NotFound | std::io::ErrorKind::ConnectionRefused
47 )
48 )
49}
50
51impl Connection {
52 pub fn start_server(
54 socket_path: &Path,
55 no_start_server: bool,
56 config: AutoStartConfig,
57 ) -> Result<Self, StartServerError> {
58 if no_start_server {
59 return connect(socket_path).map_err(StartServerError::Client);
60 }
61
62 ensure_server_running_with_config(socket_path, config).map_err(StartServerError::AutoStart)
63 }
64
65 pub fn kill_server(&mut self) -> Result<Response, ClientError> {
67 self.roundtrip(&Request::KillServer(KillServerRequest))
68 }
69
70 pub fn kill_server_after_write(&mut self) -> Result<(), ClientError> {
76 self.write_request(&Request::KillServer(KillServerRequest))
77 }
78
79 pub fn kill_server_legacy_wire(&mut self, wire_version: u32) -> Result<(), ClientError> {
81 self.write_legacy_wire_request(&Request::KillServer(KillServerRequest), wire_version)
82 }
83
84 pub fn daemon_status(&mut self) -> Result<Response, ClientError> {
86 self.roundtrip(&Request::DaemonStatus(DaemonStatusRequest))
87 }
88
89 pub fn shutdown_if_idle(&mut self) -> Result<Response, ClientError> {
91 self.roundtrip(&Request::ShutdownIfIdle(ShutdownIfIdleRequest))
92 }
93
94 pub fn lock_server(&mut self) -> Result<Response, ClientError> {
96 self.roundtrip(&Request::LockServer(LockServerRequest))
97 }
98
99 pub fn lock_session(&mut self, target: SessionName) -> Result<Response, ClientError> {
101 self.roundtrip(&Request::LockSession(LockSessionRequest { target }))
102 }
103
104 pub fn lock_client(&mut self, target_client: String) -> Result<Response, ClientError> {
106 self.roundtrip(&Request::LockClient(LockClientRequest { target_client }))
107 }
108
109 pub fn server_access(&mut self, request: ServerAccessRequest) -> Result<Response, ClientError> {
111 self.roundtrip(&Request::ServerAccess(request))
112 }
113}
114
115#[derive(Debug)]
117pub enum StartServerError {
118 Client(ClientError),
120 AutoStart(AutoStartError),
122}
123
124impl fmt::Display for StartServerError {
125 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
126 match self {
127 Self::Client(error) => fmt::Display::fmt(error, formatter),
128 Self::AutoStart(error) => fmt::Display::fmt(error, formatter),
129 }
130 }
131}
132
133impl std::error::Error for StartServerError {
134 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
135 match self {
136 Self::Client(error) => Some(error),
137 Self::AutoStart(error) => Some(error),
138 }
139 }
140}