webterm_agent/models/
activity.rs1use 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
13pub 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}