buntrail_protocol/
terminal.rs1use crate::services::invalid;
3use base64::{Engine as _, engine::general_purpose::STANDARD as B64};
4use buntrail_core::contracts as c;
5use serde::{Deserialize, Serialize};
6#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
7#[serde(rename_all = "snake_case")]
8pub enum EndIntent {
9 ExplicitClose,
10 FinalWorkspaceClose,
11 RetentionExpiry,
12}
13impl EndIntent {
14 pub fn core(&self) -> c::TerminalEndIntent {
15 match self {
16 Self::ExplicitClose => c::TerminalEndIntent::ExplicitClose,
17 Self::FinalWorkspaceClose => c::TerminalEndIntent::FinalWorkspaceClose,
18 Self::RetentionExpiry => c::TerminalEndIntent::RetentionExpiry,
19 }
20 }
21 pub fn from_core(v: c::TerminalEndIntent) -> Self {
22 match v {
23 c::TerminalEndIntent::ExplicitClose => Self::ExplicitClose,
24 c::TerminalEndIntent::FinalWorkspaceClose => Self::FinalWorkspaceClose,
25 c::TerminalEndIntent::RetentionExpiry => Self::RetentionExpiry,
26 }
27 }
28}
29#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
30#[serde(tag = "kind", rename_all = "snake_case", deny_unknown_fields)]
31pub enum Event {
32 Output {
33 sequence: u64,
34 bytes_base64: String,
35 },
36 Gap {
37 first: u64,
38 last: u64,
39 },
40 ProcessExit {
41 #[serde(deserialize_with = "crate::types::required_option")]
42 code: Option<i32>,
43 },
44 Ended {
45 intent: EndIntent,
46 },
47 Disconnected {
48 expires_at_unix_seconds: u64,
49 },
50 Reattached,
51 Expired,
52 RuntimeLost,
53}
54impl Event {
55 pub fn from_core(e: c::TerminalEvent) -> Self {
56 match e {
57 c::TerminalEvent::Output { sequence, bytes } => Self::Output {
58 sequence,
59 bytes_base64: B64.encode(bytes),
60 },
61 c::TerminalEvent::Gap { first, last } => Self::Gap { first, last },
62 c::TerminalEvent::ProcessExit { code } => Self::ProcessExit { code },
63 c::TerminalEvent::Ended { intent } => Self::Ended {
64 intent: EndIntent::from_core(intent),
65 },
66 c::TerminalEvent::Disconnected {
67 expires_at_unix_seconds,
68 } => Self::Disconnected {
69 expires_at_unix_seconds,
70 },
71 c::TerminalEvent::Reattached => Self::Reattached,
72 c::TerminalEvent::Expired => Self::Expired,
73 c::TerminalEvent::RuntimeLost => Self::RuntimeLost,
74 }
75 }
76 pub fn core(self) -> Result<c::TerminalEvent, c::CoreError> {
77 Ok(match self {
78 Self::Output {
79 sequence,
80 bytes_base64,
81 } => c::TerminalEvent::Output {
82 sequence,
83 bytes: B64.decode(bytes_base64).map_err(|_| invalid())?,
84 },
85 Self::Gap { first, last } => c::TerminalEvent::Gap { first, last },
86 Self::ProcessExit { code } => c::TerminalEvent::ProcessExit { code },
87 Self::Ended { intent } => c::TerminalEvent::Ended {
88 intent: intent.core(),
89 },
90 Self::Disconnected {
91 expires_at_unix_seconds,
92 } => c::TerminalEvent::Disconnected {
93 expires_at_unix_seconds,
94 },
95 Self::Reattached => c::TerminalEvent::Reattached,
96 Self::Expired => c::TerminalEvent::Expired,
97 Self::RuntimeLost => c::TerminalEvent::RuntimeLost,
98 })
99 }
100}
101pub fn size(columns: u16, rows: u16) -> Result<c::TerminalSize, c::CoreError> {
102 Ok(c::TerminalSize {
103 columns: columns.try_into().map_err(|_| invalid())?,
104 rows: rows.try_into().map_err(|_| invalid())?,
105 })
106}