rmux-server 0.9.0

Tokio daemon and request dispatcher for the RMUX terminal multiplexer.
Documentation
use rmux_core::LifecycleEvent;
use rmux_proto::{HookName, SessionId, SessionName};

use crate::hook_runtime::PendingInlineHookFormat;

use super::super::RequestHandler;

#[cfg(test)]
#[derive(Debug, Default)]
pub(crate) struct CreatedSessionControlAttachPause {
    pub(crate) reached: tokio::sync::Notify,
    pub(crate) release: tokio::sync::Notify,
}

#[cfg(test)]
static CREATED_SESSION_CONTROL_ATTACH_PAUSES: std::sync::Mutex<
    Vec<(
        SessionName,
        std::sync::Arc<CreatedSessionControlAttachPause>,
    )>,
> = std::sync::Mutex::new(Vec::new());

impl RequestHandler {
    #[cfg(test)]
    pub(crate) fn install_created_session_control_attach_pause(
        &self,
        session_name: SessionName,
    ) -> std::sync::Arc<CreatedSessionControlAttachPause> {
        let pause = std::sync::Arc::new(CreatedSessionControlAttachPause::default());
        let mut pauses = CREATED_SESSION_CONTROL_ATTACH_PAUSES
            .lock()
            .expect("created-session control attach pause lock");
        pauses.retain(|(paused_session, _)| paused_session != &session_name);
        pauses.push((session_name, pause.clone()));
        pause
    }

    #[cfg(test)]
    pub(in crate::handler) async fn pause_before_created_session_control_attach(
        &self,
        session_name: &SessionName,
    ) {
        let pause = CREATED_SESSION_CONTROL_ATTACH_PAUSES
            .lock()
            .expect("created-session control attach pause lock")
            .iter()
            .find(|(paused_session, _)| paused_session == session_name)
            .map(|(_, pause)| pause.clone());
        let Some(pause) = pause else {
            return;
        };
        pause.reached.notify_one();
        pause.release.notified().await;
        let mut pauses = CREATED_SESSION_CONTROL_ATTACH_PAUSES
            .lock()
            .expect("created-session control attach pause lock");
        pauses.retain(|(paused_session, current)| {
            paused_session != session_name || !std::sync::Arc::ptr_eq(current, &pause)
        });
    }

    #[cfg(not(test))]
    pub(in crate::handler) async fn pause_before_created_session_control_attach(
        &self,
        _session_name: &SessionName,
    ) {
    }

    pub(in crate::handler) async fn finish_new_session_lifecycle(
        &self,
        requester_pid: u32,
        session_name: &SessionName,
        session_id: SessionId,
        template_session: Option<&SessionName>,
        detached: bool,
    ) {
        self.sync_new_session_silence_timers(session_name, session_id, template_session)
            .await;
        self.queue_exact_session_inline_hook(
            HookName::AfterNewSession,
            session_name.clone(),
            session_id,
            None,
            PendingInlineHookFormat::AfterCommand,
        );
        let control_attached = !detached
            && self
                .prepare_created_session_control_attach(requester_pid, session_name, session_id)
                .await;
        self.emit_for_session_identity(
            LifecycleEvent::SessionCreated {
                session_name: session_name.clone(),
            },
            session_name,
            session_id,
        )
        .await;
        if control_attached {
            self.emit_for_session_identity(
                LifecycleEvent::ClientSessionChanged {
                    session_name: session_name.clone(),
                    client_name: Some(requester_pid.to_string()),
                },
                session_name,
                session_id,
            )
            .await;
        }
    }
}