a3s_box_core/traits/
session.rs1use std::sync::Arc;
4
5use async_trait::async_trait;
6
7use crate::exec::{
8 ExecEvent, ExecOutput, ExecRequest, FileRequest, FileResponse, FilesystemRequest,
9 FilesystemResponse,
10};
11use crate::pty::PtyRequest;
12
13use super::execution::{
14 ExecutionGeneration, ExecutionId, ExecutionManagerError, ExecutionManagerResult,
15};
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub enum ExecutionProcessSignal {
23 Terminate,
24 Kill,
25}
26
27impl ExecutionProcessSignal {
28 pub const fn linux_number(self) -> i32 {
29 match self {
30 Self::Terminate => 15,
31 Self::Kill => 9,
32 }
33 }
34}
35
36#[async_trait]
38pub trait ExecutionProcessInput: Send + Sync {
39 async fn write_stdin(&self, data: &[u8]) -> ExecutionManagerResult<()>;
40
41 async fn close_stdin(&self) -> ExecutionManagerResult<()>;
42
43 async fn cancel(&self) -> ExecutionManagerResult<()>;
44
45 async fn send_signal(&self, signal: ExecutionProcessSignal) -> ExecutionManagerResult<()> {
46 match signal {
47 ExecutionProcessSignal::Kill => self.cancel().await,
48 ExecutionProcessSignal::Terminate => Err(ExecutionManagerError::InvalidRequest(
49 "process transport does not support graceful termination".to_string(),
50 )),
51 }
52 }
53
54 async fn resize_pty(&self, cols: u16, rows: u16) -> ExecutionManagerResult<()> {
55 let _ = (cols, rows);
56 Err(ExecutionManagerError::InvalidRequest(
57 "process does not have a PTY".to_string(),
58 ))
59 }
60}
61
62#[async_trait]
64pub trait ExecutionProcessStream: Send {
65 fn input(&self) -> Arc<dyn ExecutionProcessInput>;
66
67 async fn next_event(&mut self) -> ExecutionManagerResult<Option<ExecEvent>>;
68}
69
70pub type ExecutionProcess = Box<dyn ExecutionProcessStream>;
71
72#[async_trait]
79pub trait ExecutionSessionManager: Send + Sync {
80 async fn execute(
81 &self,
82 execution_id: &ExecutionId,
83 generation: ExecutionGeneration,
84 request: ExecRequest,
85 ) -> ExecutionManagerResult<ExecOutput>;
86
87 async fn start_process(
88 &self,
89 execution_id: &ExecutionId,
90 generation: ExecutionGeneration,
91 request: ExecRequest,
92 ) -> ExecutionManagerResult<ExecutionProcess>;
93
94 async fn start_pty(
95 &self,
96 execution_id: &ExecutionId,
97 generation: ExecutionGeneration,
98 request: PtyRequest,
99 ) -> ExecutionManagerResult<ExecutionProcess>;
100
101 async fn transfer_file(
102 &self,
103 execution_id: &ExecutionId,
104 generation: ExecutionGeneration,
105 request: FileRequest,
106 ) -> ExecutionManagerResult<FileResponse>;
107
108 async fn filesystem(
109 &self,
110 _execution_id: &ExecutionId,
111 _generation: ExecutionGeneration,
112 _request: FilesystemRequest,
113 ) -> ExecutionManagerResult<FilesystemResponse> {
114 Err(ExecutionManagerError::Unavailable(
115 "this execution session does not support filesystem metadata operations".to_string(),
116 ))
117 }
118}
119
120#[cfg(test)]
121mod tests {
122 use super::ExecutionProcessSignal;
123
124 #[test]
125 fn managed_process_signals_use_linux_guest_numbers() {
126 assert_eq!(ExecutionProcessSignal::Terminate.linux_number(), 15);
127 assert_eq!(ExecutionProcessSignal::Kill.linux_number(), 9);
128 }
129}