webterm_agent/models/
activity.rs

1use crate::models::activity_registry::ActivityRegistry;
2use crate::models::agent_error::AgentError;
3use crate::models::pty_activity::PtyActivity;
4use crate::models::session::Session;
5use crate::models::session_registry::SessionRegistry;
6use std::sync::Arc;
7use tokio::sync::Mutex;
8use tracing::info;
9use webterm_core::generated::flatbuffers_schema::talk_v1::activity::{PtyInput, PtyInputRoot};
10use webterm_core::serialisers::talk_v1::terminal_output_builder::ActivityInputBlob;
11use webterm_core::types::{ActivityId, SessionId};
12
13// in future, manage more activities like a "file browser"
14pub enum ActivityType {
15    Pty,
16}
17
18pub struct Activity {
19    activity_id: ActivityId,
20    activity_type: ActivityType,
21    terminal: Option<PtyActivity>,
22    parent_session_id: SessionId,
23}
24
25impl PartialEq for Activity {
26    fn eq(&self, other: &Self) -> bool {
27        self.activity_id == other.activity_id
28    }
29}
30
31impl Activity {
32    pub async fn create_pty(session_id: SessionId) -> Result<Arc<Activity>, AgentError> {
33        let activity_id = ActivityRegistry::next_activity_id();
34        let terminal = PtyActivity::new(activity_id, "/bin/bash").await?;
35        let record = Arc::new(Self {
36            activity_id,
37            terminal: Some(terminal),
38            activity_type: ActivityType::Pty,
39            parent_session_id: session_id,
40        });
41
42        ActivityRegistry::register(record.clone()).await?;
43        Ok(record)
44    }
45
46    pub fn activity_id(&self) -> ActivityId {
47        self.activity_id
48    }
49
50    pub async fn parent_session(&self) -> Result<Arc<Mutex<Session>>, AgentError> {
51        SessionRegistry::find(self.parent_session_id).await
52    }
53
54    pub async fn receive_input(&self, payload: ActivityInputBlob) -> Result<(), AgentError> {
55        match self.activity_type {
56            ActivityType::Pty => {
57                let input = flatbuffers::root::<PtyInputRoot>(&payload.0)?;
58                match input.payload_type() {
59                    PtyInput::UserInput => {
60                        self.terminal
61                            .as_ref()
62                            .ok_or(AgentError::RuntimeError(
63                                "Terminal not initialised".to_string(),
64                            ))?
65                            .write(
66                                input
67                                    .payload_as_user_input()
68                                    .ok_or(AgentError::FBParseError(
69                                        "Expected user input vector".to_string(),
70                                    ))?
71                                    .data()
72                                    .ok_or(AgentError::FBParseError(
73                                        "Expected user input data".to_string(),
74                                    ))?
75                                    .bytes(),
76                            )
77                            .await?;
78                        Ok(())
79                    }
80                    PtyInput::Resize => {
81                        info!("Received resize input: {:?}", input.payload_as_resize());
82                        let resize_data = input
83                            .payload_as_resize()
84                            .ok_or(AgentError::FBParseError("Expected resize data".to_string()))?;
85                        self.terminal
86                            .as_ref()
87                            .ok_or(AgentError::RuntimeError(
88                                "Terminal not initialised".to_string(),
89                            ))?
90                            .resize(resize_data.cols(), resize_data.rows())
91                            .await?;
92                        Ok(())
93                    }
94
95                    _ => Err(AgentError::FBParseError(format!(
96                        "Unknown terminal input type: {:?}",
97                        input.payload_type()
98                    ))),
99                }
100            }
101        }
102    }
103}