Skip to main content

cbf_chrome/data/
ipc.rs

1//! Chrome transport IPC data models and conversions.
2
3/// Chromium-facing IPC config.
4#[derive(Debug, Clone, PartialEq, Eq, Default)]
5pub struct TabIpcConfig {
6    /// Allowed top-level origins for page -> host invoke.
7    ///
8    /// The match is exact string equality on origin. If empty, invoke is denied.
9    pub allowed_origins: Vec<String>,
10}
11
12impl From<cbf::data::ipc::IpcConfig> for TabIpcConfig {
13    fn from(value: cbf::data::ipc::IpcConfig) -> Self {
14        Self {
15            allowed_origins: value.allowed_origins,
16        }
17    }
18}
19
20impl From<TabIpcConfig> for cbf::data::ipc::IpcConfig {
21    fn from(value: TabIpcConfig) -> Self {
22        Self {
23            allowed_origins: value.allowed_origins,
24        }
25    }
26}
27
28/// Chromium-facing IPC payload.
29#[derive(Debug, Clone, PartialEq, Eq)]
30pub enum TabIpcPayload {
31    Text(String),
32    Binary(Vec<u8>),
33}
34
35impl From<cbf::data::ipc::IpcPayload> for TabIpcPayload {
36    fn from(value: cbf::data::ipc::IpcPayload) -> Self {
37        match value {
38            cbf::data::ipc::IpcPayload::Text(text) => Self::Text(text),
39            cbf::data::ipc::IpcPayload::Binary(binary) => Self::Binary(binary),
40        }
41    }
42}
43
44impl From<TabIpcPayload> for cbf::data::ipc::IpcPayload {
45    fn from(value: TabIpcPayload) -> Self {
46        match value {
47            TabIpcPayload::Text(text) => Self::Text(text),
48            TabIpcPayload::Binary(binary) => Self::Binary(binary),
49        }
50    }
51}
52
53/// Chromium-facing IPC message type.
54#[derive(Debug, Clone, Copy, PartialEq, Eq)]
55pub enum TabIpcMessageType {
56    Request,
57    Response,
58    Event,
59}
60
61impl From<cbf::data::ipc::IpcMessageType> for TabIpcMessageType {
62    fn from(value: cbf::data::ipc::IpcMessageType) -> Self {
63        match value {
64            cbf::data::ipc::IpcMessageType::Request => Self::Request,
65            cbf::data::ipc::IpcMessageType::Response => Self::Response,
66            cbf::data::ipc::IpcMessageType::Event => Self::Event,
67        }
68    }
69}
70
71impl From<TabIpcMessageType> for cbf::data::ipc::IpcMessageType {
72    fn from(value: TabIpcMessageType) -> Self {
73        match value {
74            TabIpcMessageType::Request => Self::Request,
75            TabIpcMessageType::Response => Self::Response,
76            TabIpcMessageType::Event => Self::Event,
77        }
78    }
79}
80
81/// Chromium-facing IPC error code.
82#[derive(Debug, Clone, Copy, PartialEq, Eq)]
83pub enum TabIpcErrorCode {
84    Timeout,
85    Aborted,
86    Disconnected,
87    IpcDisabled,
88    ContextClosed,
89    RemoteError,
90    ProtocolError,
91}
92
93impl From<cbf::data::ipc::IpcErrorCode> for TabIpcErrorCode {
94    fn from(value: cbf::data::ipc::IpcErrorCode) -> Self {
95        match value {
96            cbf::data::ipc::IpcErrorCode::Timeout => Self::Timeout,
97            cbf::data::ipc::IpcErrorCode::Aborted => Self::Aborted,
98            cbf::data::ipc::IpcErrorCode::Disconnected => Self::Disconnected,
99            cbf::data::ipc::IpcErrorCode::IpcDisabled => Self::IpcDisabled,
100            cbf::data::ipc::IpcErrorCode::ContextClosed => Self::ContextClosed,
101            cbf::data::ipc::IpcErrorCode::RemoteError => Self::RemoteError,
102            cbf::data::ipc::IpcErrorCode::ProtocolError => Self::ProtocolError,
103        }
104    }
105}
106
107impl From<TabIpcErrorCode> for cbf::data::ipc::IpcErrorCode {
108    fn from(value: TabIpcErrorCode) -> Self {
109        match value {
110            TabIpcErrorCode::Timeout => Self::Timeout,
111            TabIpcErrorCode::Aborted => Self::Aborted,
112            TabIpcErrorCode::Disconnected => Self::Disconnected,
113            TabIpcErrorCode::IpcDisabled => Self::IpcDisabled,
114            TabIpcErrorCode::ContextClosed => Self::ContextClosed,
115            TabIpcErrorCode::RemoteError => Self::RemoteError,
116            TabIpcErrorCode::ProtocolError => Self::ProtocolError,
117        }
118    }
119}
120
121/// Chromium-facing tab IPC message envelope.
122#[derive(Debug, Clone, PartialEq, Eq)]
123pub struct TabIpcMessage {
124    pub channel: String,
125    pub message_type: TabIpcMessageType,
126    pub request_id: u64,
127    pub payload: TabIpcPayload,
128    pub content_type: Option<String>,
129    pub error_code: Option<TabIpcErrorCode>,
130}
131
132impl From<cbf::data::ipc::BrowsingContextIpcMessage> for TabIpcMessage {
133    fn from(value: cbf::data::ipc::BrowsingContextIpcMessage) -> Self {
134        Self {
135            channel: value.channel,
136            message_type: value.message_type.into(),
137            request_id: value.request_id,
138            payload: value.payload.into(),
139            content_type: value.content_type,
140            error_code: value.error_code.map(Into::into),
141        }
142    }
143}
144
145impl From<TabIpcMessage> for cbf::data::ipc::BrowsingContextIpcMessage {
146    fn from(value: TabIpcMessage) -> Self {
147        Self {
148            channel: value.channel,
149            message_type: value.message_type.into(),
150            request_id: value.request_id,
151            payload: value.payload.into(),
152            content_type: value.content_type,
153            error_code: value.error_code.map(Into::into),
154        }
155    }
156}
157
158#[cfg(test)]
159mod tests {
160    use super::{TabIpcConfig, TabIpcErrorCode, TabIpcMessage, TabIpcMessageType, TabIpcPayload};
161
162    #[test]
163    fn tab_ipc_config_round_trip_with_generic() {
164        let config = TabIpcConfig {
165            allowed_origins: vec!["https://example.com".to_string()],
166        };
167
168        let generic: cbf::data::ipc::IpcConfig = config.clone().into();
169        let round_trip = TabIpcConfig::from(generic);
170
171        assert_eq!(round_trip, config);
172    }
173
174    #[test]
175    fn tab_ipc_message_round_trip_with_generic() {
176        let message = TabIpcMessage {
177            channel: "app.rpc".to_string(),
178            message_type: TabIpcMessageType::Response,
179            request_id: 77,
180            payload: TabIpcPayload::Binary(vec![1, 2, 3]),
181            content_type: Some("application/octet-stream".to_string()),
182            error_code: Some(TabIpcErrorCode::RemoteError),
183        };
184
185        let generic: cbf::data::ipc::BrowsingContextIpcMessage = message.clone().into();
186        let round_trip = TabIpcMessage::from(generic);
187
188        assert_eq!(round_trip, message);
189    }
190}