use rmux_proto::request::{AttachSessionExt2Request, AttachSessionExtRequest};
use rmux_proto::{AttachSessionResponse, ErrorResponse, Response, RmuxError};
use tokio::sync::mpsc;
use super::super::{
attach_support::attach_target_for_session, client_environment_snapshot,
control_support::ManagedClient, effective_client_terminal_context, parse_client_flags,
update_environment_from_client, RequestHandler,
};
use crate::outer_terminal::OuterTerminalContext;
use crate::pane_io::HandleOutcome;
impl RequestHandler {
pub(in crate::handler) async fn handle_attach_session(
&self,
requester_pid: u32,
request: rmux_proto::AttachSessionRequest,
) -> HandleOutcome {
self.handle_attach_session_ext(
requester_pid,
AttachSessionExtRequest {
target: Some(request.target),
detach_other_clients: false,
kill_other_clients: false,
read_only: false,
skip_environment_update: false,
flags: None,
},
)
.await
}
pub(in crate::handler) async fn handle_attach_session_ext(
&self,
requester_pid: u32,
request: AttachSessionExtRequest,
) -> HandleOutcome {
let target_spec = request.target.as_ref().map(ToString::to_string);
self.handle_attach_session_ext2(
requester_pid,
AttachSessionExt2Request {
target: request.target,
target_spec,
detach_other_clients: request.detach_other_clients,
kill_other_clients: request.kill_other_clients,
read_only: request.read_only,
skip_environment_update: request.skip_environment_update,
flags: request.flags,
working_directory: None,
client_terminal: rmux_proto::ClientTerminalContext::default(),
client_size: None,
},
)
.await
}
pub(in crate::handler) async fn handle_attach_session_ext2(
&self,
requester_pid: u32,
request: AttachSessionExt2Request,
) -> HandleOutcome {
let mut session_name = match request.target {
Some(session_name) => session_name,
None => match self.preferred_session_name().await {
Ok(session_name) => session_name,
Err(error) => {
return HandleOutcome::response(Response::Error(ErrorResponse { error }));
}
},
};
if let Some(target_spec) = request.target_spec.as_deref() {
match self.apply_switch_target(target_spec, false).await {
Ok(next_session_name) => session_name = next_session_name,
Err(error) => {
return HandleOutcome::response(Response::Error(ErrorResponse { error }));
}
}
}
let flags = match parse_client_flags(request.flags.as_ref(), request.read_only) {
Ok(flags) => flags,
Err(error) => return HandleOutcome::response(Response::Error(ErrorResponse { error })),
};
if let Some(template) = request.working_directory.as_deref() {
if let Err(error) = self
.update_session_cwd_from_template(&session_name, template)
.await
{
return HandleOutcome::response(Response::Error(ErrorResponse { error }));
}
}
let client_environment = client_environment_snapshot(requester_pid);
let client_terminal = effective_client_terminal_context(
client_environment.as_ref(),
&request.client_terminal,
);
let terminal_context = OuterTerminalContext::from_environment(client_environment.as_ref())
.with_client_terminal(&client_terminal);
if let Some(client_environment) = client_environment.as_ref() {
if !request.skip_environment_update {
let mut state = self.state.lock().await;
update_environment_from_client(&mut state, &session_name, client_environment);
}
}
if request.detach_other_clients || request.kill_other_clients {
self.detach_other_attach_clients_for_session(
&session_name,
requester_pid,
request.kill_other_clients,
)
.await;
}
if let Err(error) = self
.resize_session_for_attach_client(&session_name, request.client_size)
.await
{
return HandleOutcome::response(Response::Error(ErrorResponse { error }));
}
if let Some(client) = self.managed_client_for_pid(requester_pid).await {
if let ManagedClient::Attach(attach_pid) = client {
if let Err(error) = self.set_attached_client_flags(attach_pid, flags).await {
return HandleOutcome::response(Response::Error(ErrorResponse { error }));
}
} else if request.read_only || request.flags.is_some() {
return HandleOutcome::response(Response::Error(ErrorResponse {
error: RmuxError::Server(
"attach-session client flags are not available for control clients"
.to_owned(),
),
}));
}
return HandleOutcome::response(
self.switch_managed_client_to_session(
requester_pid,
client,
session_name,
request.skip_environment_update,
)
.await,
);
}
let attached_count = self.attached_count(&session_name).await.saturating_add(1);
let target = {
let state = self.state.lock().await;
match attach_target_for_session(
&state,
&session_name,
attached_count,
&terminal_context,
) {
Ok(target) => target,
Err(error) => {
return HandleOutcome::response(Response::Error(ErrorResponse { error }));
}
}
};
let (control_tx, control_rx) = mpsc::unbounded_channel();
HandleOutcome::attach(
Response::AttachSession(AttachSessionResponse { session_name }),
target,
control_tx,
control_rx,
flags,
request.client_size,
)
}
}