lawn_protocol/protocol/
mod.rs

1#![allow(non_upper_case_globals)]
2use crate::config::Config;
3use bitflags::bitflags;
4use bytes::{Bytes, BytesMut};
5use num_traits::FromPrimitive;
6use serde::{de::DeserializeOwned, Deserialize, Serialize};
7use serde_cbor::Value;
8use std::collections::{BTreeMap, BTreeSet};
9use std::convert::{TryFrom, TryInto};
10use std::fmt;
11use std::io;
12use std::io::{Seek, SeekFrom};
13
14/// # Overview
15///
16/// The protocol is relatively simple.  Each request consists of a 32-bit size of the resulting
17/// message, a 32-bit request ID, a 32-bit message type, and an optional per-message CBOR blob
18/// representing message data.  For performance and security reasons, the message size is limited
19/// to 2^24 in size.  The size includes all fields other than the size.
20///
21/// Each response consists of a 32-bit size of the message, the 32-bit request ID, a 32-bit
22/// response code, and an optional per-response code CBOR blob.
23///
24/// The bottom 31 bits of the request ID may be any value; the response will use the same ID.  No
25/// check is made for duplicates, so the requestor should prefer not repeating IDs that are in
26/// flight.  The top bit is clear if the request is client-to-server request and it is set if the
27/// request is a server-to-client request.  This helps eliminate confusion as to whether a message
28/// is a request or a response.
29///
30/// All data is serialized in a little-endian format.
31///
32/// ## Extension Messages
33///
34/// Extension values (message types and response codes) are assigned with
35/// values `0xff000000` and larger.  These can be dynamically allocated using
36/// the `CreateExtensionRange` message, and once allocated, will allow the
37/// extension to use the given codes both as message types and response codes.
38///
39/// Note that an implementation is not obligated to allocate or use extension
40/// codes.  For example, an implementation which offers a new sort of channel may
41/// well choose to use the existing channel codes, or it may choose to use new
42/// message types with existing response codes.
43///
44/// Lawn currently allocates these by allocating a 12-bit range internally, so
45/// the first code of the first extension is `0xff000000`, the first code of the next is
46/// `0xfff001000`,  and so on.  This provides 4096 codes per extension while
47/// allowing 4096 extensions.  However, this algorithm is subject to change at any
48/// time.
49
50/// The response codes for the protocol.
51///
52/// The response codes are based around IMAP's response codes, and the top two bytes of the
53/// response indicates the type:
54///
55/// * 00: success
56/// * 01: no (roughly, the request was understood, but not completed)
57/// * 02: bad (roughly, the request was not understood)
58/// * ff: extension message (dynamically allocated)
59#[derive(FromPrimitive, Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
60pub enum ResponseCode {
61    /// The request was successful.  The response contains the requested data.
62    Success = 0x00000000,
63    /// The request is incomplete, but is so far successful.  The request should continue,
64    /// referencing the ID of the last request.
65    Continuation = 0x00000001,
66
67    /// The request requires authentication.
68    ///
69    /// The semantics for this message are equivalent to an HTTP 401 response.
70    NeedsAuthentication = 0x00010000,
71    /// The message was not allowed.
72    ///
73    /// The semantics for this message are equivalent to an HTTP 403 response.
74    Forbidden = 0x00010001,
75    /// The server is shutting down.
76    Closing = 0x00010002,
77    /// The message failed for a system error reason.
78    ///
79    /// This is generally only useful for certain types of channels.
80    Errno = 0x00010003,
81    AuthenticationFailed = 0x00010004,
82    /// The other end of the channel has disappeared.
83    Gone = 0x00010005,
84    NotFound = 0x00010006,
85    InternalError = 0x00010007,
86    /// The channel has ceased to produce new data and this operation cannot complete.
87    ChannelDead = 0x00010008,
88    /// The operation was aborted.
89    Aborted = 0x00010009,
90    /// There is no continuation with the specified parameters.
91    ContinuationNotFound = 0x0001000a,
92    /// The result was out of range.
93    ///
94    /// The semantics for this message are equivalent to `ERANGE`.
95    OutOfRange = 0x0001000b,
96    /// There is no more space for the requested item.
97    NoSpace = 0x0001000c,
98    /// The requested operation would conflict with something already existing.
99    ///
100    /// The semantics for this message are equivalent to an HTTP 409 response.
101    Conflict = 0x0001000d,
102    /// The contents of the object cannot be listed or specified by name.
103    ///
104    /// For example, when using a Git-protocol credential helper, it is not possible to enumerate
105    /// all credentials or pick a credential by ID.
106    Unlistable = 0x0001000e,
107
108    /// The message type was not enabled.
109    NotEnabled = 0x00020000,
110    /// The message type or operation was not supported.
111    NotSupported = 0x00020001,
112    /// The parameters were not supported.
113    ParametersNotSupported = 0x00020002,
114    /// The message type was received, but was not valid.
115    Invalid = 0x00020003,
116    /// The message was too large.
117    TooLarge = 0x00020004,
118    /// There are too many pending messages.
119    TooManyMessages = 0x00020005,
120    /// The parameters are supported, but not correct.
121    ///
122    /// For example, if a selector is not valid for a channel, this message may be sent.
123    InvalidParameters = 0x00020006,
124}
125
126impl ResponseCode {
127    fn from_u32(val: u32) -> Self {
128        FromPrimitive::from_u32(val).unwrap_or(Self::Invalid)
129    }
130}
131
132pub struct WrongTypeError(pub Error);
133
134#[derive(Debug, Clone)]
135pub struct Error {
136    pub code: ResponseCode,
137    pub body: Option<ErrorBody>,
138}
139
140impl fmt::Display for Error {
141    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
142        fmt::Debug::fmt(self, f)
143    }
144}
145
146impl std::error::Error for Error {}
147
148impl Error {
149    pub fn from_errno(err: i32) -> Error {
150        io::Error::from_raw_os_error(err).into()
151    }
152}
153
154impl From<io::Error> for Error {
155    fn from(err: io::Error) -> Error {
156        let lerr: lawn_constants::Error = err.into();
157        Error {
158            code: ResponseCode::Errno,
159            body: Some(ErrorBody::Errno(Errno { errno: lerr as u32 })),
160        }
161    }
162}
163
164impl From<ResponseCode> for Error {
165    fn from(code: ResponseCode) -> Error {
166        Error { code, body: None }
167    }
168}
169
170impl TryInto<io::Error> for Error {
171    type Error = WrongTypeError;
172    fn try_into(self) -> Result<io::Error, Self::Error> {
173        if self.code == ResponseCode::Errno {
174            if let Some(ErrorBody::Errno(Errno { errno })) = self.body {
175                if let Some(e) = lawn_constants::Error::from_u32(errno) {
176                    return Ok(e.into());
177                }
178            }
179        }
180        Err(WrongTypeError(self))
181    }
182}
183
184#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd)]
185pub struct Empty {}
186
187#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
188pub struct Errno {
189    errno: u32,
190}
191
192#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
193#[serde(untagged)]
194pub enum ErrorBody {
195    Errno(Errno),
196    Exit(i32),
197}
198
199#[derive(FromPrimitive, Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
200pub enum MessageKind {
201    /// Requests that the other side provide a list of supported versions and capabilities.
202    Capability = 0x00000000,
203    /// Requests a specific version and capabilities.
204    ///
205    /// This request aborts all other in-flight requests by this sender.  Consequently, it should
206    /// be sent at the beginning of the connection right after a successful `Capability` message.
207    ///
208    /// Authentication is not required for this message.
209    Version = 0x00000001,
210    /// Indicates a no-op request which should always be successful.
211    ///
212    /// Authentication is not required for this message.
213    Ping = 0x00000002,
214    /// Requests authentication.
215    ///
216    /// This request aborts all other in-flight requests by this sender.  Consequently, it should
217    /// be sent at the beginning of the connection right after a successful `Capability` message.
218    ///
219    /// Authentication is not required for this message (obviously).
220    Authenticate = 0x00000003,
221    /// Continue an in-progress request.
222    ///
223    /// This request can be used to continue an operation when the `Continuation` response is
224    /// provided.
225    Continue = 0x00000004,
226    /// Abort an in-progress request.
227    ///
228    /// This request can be used to abort an operation when the `Continuation` response is
229    /// provided.
230    Abort = 0x00000005,
231
232    /// Indicates a graceful shutdown.
233    ///
234    /// Authentication is not required for this message.
235    CloseAlert = 0x00001000,
236
237    /// Requests a channel to be created.
238    CreateChannel = 0x00010000,
239    /// Requests a channel to be deleted.
240    ///
241    /// This request is made from the client to the server to terminate the connection.
242    DeleteChannel = 0x00010001,
243    /// Requests a read on the channel.
244    ReadChannel = 0x00010002,
245    /// Requests a write on the channel.
246    WriteChannel = 0x00010003,
247    /// Requests the status of the selectors on the channel.
248    PollChannel = 0x00010004,
249    /// Requests the status of the object on the other end of the channel.
250    ///
251    /// For command channels, this can be used to check if the child has exited.
252    PingChannel = 0x00010005,
253    // Not implemented:
254    // AttachChannelSelector = 0x00010010,
255    DetachChannelSelector = 0x00010011,
256    /// Provides notification of some sort of metadata condition on the channel.
257    ///
258    /// For command channels, this is used by the server to notify the client that the process has
259    /// terminated.
260    ChannelMetadataNotification = 0x00011000,
261
262    /// Allocates a range of IDs for an extension.
263    CreateExtensionRange = 0x00020000,
264
265    /// Deallocates a range of IDs for an extension.
266    DeleteExtensionRange = 0x00020001,
267
268    /// Lists all allocated ranges of IDs for extensions.
269    ListExtensionRanges = 0x00020002,
270
271    /// Open a store and associate an ID with it.
272    OpenStore = 0x00030000,
273
274    /// Close a store and associate an ID with it.
275    CloseStore = 0x00030001,
276
277    /// Lists all elements of a given type in the given store.
278    ListStoreElements = 0x00030002,
279
280    /// Acquire a handle to an element in the given store.
281    AcquireStoreElement = 0x00030003,
282
283    /// Release the handle of a store element.
284    CloseStoreElement = 0x00030004,
285
286    /// Authenticate to a store element if that's required to open it.
287    AuthenticateStoreElement = 0x00030005,
288
289    /// Create a store element.
290    CreateStoreElement = 0x00030006,
291
292    /// Delete a store element.
293    DeleteStoreElement = 0x00030007,
294
295    /// Update a store element.
296    UpdateStoreElement = 0x00030008,
297
298    /// Read a store element.
299    ReadStoreElement = 0x00030009,
300
301    /// Rename a store element.
302    RenameStoreElement = 0x0003000a,
303
304    /// Copy a store element.
305    CopyStoreElement = 0x0003000b,
306
307    /// Search store elements.
308    SearchStoreElements = 0x0003000c,
309
310    /// Read a server context.
311    ReadServerContext = 0x00040000,
312
313    /// Write a server context.
314    WriteServerContext = 0x00040001,
315}
316
317#[derive(Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
318pub enum Capability {
319    AuthExternal,
320    AuthKeyboardInteractive,
321    AuthPlain,
322    ChannelCommand,
323    Channel9P,
324    ChannelSFTP,
325    ChannelClipboard,
326    ExtensionAllocate,
327    StoreCredential,
328    ContextTemplate,
329    Other(Bytes, Option<Bytes>),
330}
331
332impl Capability {
333    #[allow(clippy::mutable_key_type)]
334    pub fn implemented() -> BTreeSet<Capability> {
335        [
336            Self::AuthExternal,
337            Self::AuthKeyboardInteractive,
338            Self::AuthPlain,
339            Self::ChannelCommand,
340            Self::ChannelClipboard,
341            Self::Channel9P,
342            Self::ChannelSFTP,
343            Self::ExtensionAllocate,
344            Self::StoreCredential,
345            Self::ContextTemplate,
346        ]
347        .iter()
348        .cloned()
349        .collect()
350    }
351
352    pub fn is_implemented(&self) -> bool {
353        matches!(
354            self,
355            Self::AuthExternal
356                | Self::AuthKeyboardInteractive
357                | Self::AuthPlain
358                | Self::ChannelCommand
359                | Self::ChannelClipboard
360                | Self::Channel9P
361                | Self::ChannelSFTP
362                | Self::ExtensionAllocate
363                | Self::StoreCredential
364                | Self::ContextTemplate
365        )
366    }
367}
368
369impl From<Capability> for (Bytes, Option<Bytes>) {
370    fn from(capa: Capability) -> (Bytes, Option<Bytes>) {
371        match capa {
372            Capability::AuthExternal => (
373                (b"auth" as &[u8]).into(),
374                Some((b"EXTERNAL" as &[u8]).into()),
375            ),
376            Capability::AuthKeyboardInteractive => (
377                (b"auth" as &[u8]).into(),
378                Some((b"keyboard-interactive" as &[u8]).into()),
379            ),
380            Capability::AuthPlain => ((b"auth" as &[u8]).into(), Some((b"PLAIN" as &[u8]).into())),
381            Capability::ChannelCommand => (
382                (b"channel" as &[u8]).into(),
383                Some((b"command" as &[u8]).into()),
384            ),
385            Capability::Channel9P => ((b"channel" as &[u8]).into(), Some((b"9p" as &[u8]).into())),
386            Capability::ChannelSFTP => (
387                (b"channel" as &[u8]).into(),
388                Some((b"sftp" as &[u8]).into()),
389            ),
390            Capability::ChannelClipboard => (
391                (b"channel" as &[u8]).into(),
392                Some((b"clipboard" as &[u8]).into()),
393            ),
394            Capability::StoreCredential => (
395                (b"store" as &[u8]).into(),
396                Some((b"credential" as &[u8]).into()),
397            ),
398            Capability::ExtensionAllocate => (
399                (b"extension" as &[u8]).into(),
400                Some((b"allocate" as &[u8]).into()),
401            ),
402            Capability::ContextTemplate => (
403                (b"context" as &[u8]).into(),
404                Some((b"template" as &[u8]).into()),
405            ),
406            Capability::Other(name, subtype) => (name, subtype),
407        }
408    }
409}
410
411impl From<(&[u8], Option<&[u8]>)> for Capability {
412    fn from(data: (&[u8], Option<&[u8]>)) -> Capability {
413        match data {
414            (b"auth", Some(b"EXTERNAL")) => Capability::AuthExternal,
415            (b"auth", Some(b"PLAIN")) => Capability::AuthPlain,
416            (b"auth", Some(b"keyboard-interactive")) => Capability::AuthKeyboardInteractive,
417            (b"channel", Some(b"command")) => Capability::ChannelCommand,
418            (b"channel", Some(b"9p")) => Capability::Channel9P,
419            (b"channel", Some(b"sftp")) => Capability::ChannelSFTP,
420            (b"channel", Some(b"clipboard")) => Capability::ChannelClipboard,
421            (b"store", Some(b"credential")) => Capability::StoreCredential,
422            (b"extension", Some(b"allocate")) => Capability::ExtensionAllocate,
423            (b"context", Some(b"template")) => Capability::ContextTemplate,
424            (name, subtype) => {
425                Capability::Other(name.to_vec().into(), subtype.map(|s| s.to_vec().into()))
426            }
427        }
428    }
429}
430
431impl From<(Bytes, Option<Bytes>)> for Capability {
432    fn from(data: (Bytes, Option<Bytes>)) -> Capability {
433        match data {
434            (a, Some(b)) => (&a as &[u8], Some(&b as &[u8])).into(),
435            (a, None) => (&a as &[u8], None).into(),
436        }
437    }
438}
439
440#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
441#[serde(rename_all = "kebab-case")]
442pub struct CapabilityResponse {
443    pub version: Vec<u32>,
444    pub capabilities: Vec<(Bytes, Option<Bytes>)>,
445    pub user_agent: Option<String>,
446}
447
448#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
449#[serde(rename_all = "kebab-case")]
450pub struct VersionRequest {
451    pub version: u32,
452    pub enable: Vec<(Bytes, Option<Bytes>)>,
453    pub id: Option<Bytes>,
454    pub user_agent: Option<String>,
455}
456
457#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
458#[serde(rename_all = "kebab-case")]
459pub struct AuthenticateRequest {
460    pub last_id: Option<u32>,
461    // All uppercase methods are SASL methods as defined by IANA.  Other methods are defined
462    // internally.
463    pub method: Bytes,
464    pub message: Option<Bytes>,
465}
466
467#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
468#[serde(rename_all = "kebab-case")]
469pub struct AuthenticateResponse {
470    // All uppercase methods are SASL methods as defined by IANA.  Other methods are defined
471    // internally.
472    pub method: Bytes,
473    pub message: Option<Bytes>,
474}
475
476#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
477#[serde(rename_all = "kebab-case")]
478pub struct PartialContinueRequest {
479    pub id: u32,
480    pub kind: u32,
481}
482
483#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
484#[serde(rename_all = "kebab-case")]
485pub struct ContinueRequest<T> {
486    pub id: u32,
487    pub kind: u32,
488    pub message: Option<T>,
489}
490
491#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
492#[serde(rename_all = "kebab-case")]
493pub struct AbortRequest {
494    pub id: u32,
495    pub kind: u32,
496}
497
498#[derive(Serialize, Deserialize, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
499#[serde(transparent)]
500pub struct ChannelID(pub u32);
501
502impl fmt::Display for ChannelID {
503    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
504        write!(f, "{}", self.0)
505    }
506}
507
508#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
509#[serde(transparent)]
510pub struct ChannelSelectorID(pub u32);
511
512/// A message to create a channel.
513///
514/// The following channel types are known:
515///
516/// * `command`: Invoke a command on the remote side.  `args` is the command-line arguments and
517///   `env` is the environment.
518/// * `9p`: Create a channel implementing the 9p2000.L protocol.  `args[0]` is the desired mount
519///   point as specified by the server.
520///
521/// Custom channel types can be created with an at sign and domain name representing the custom
522/// extension.
523#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
524#[serde(rename_all = "kebab-case")]
525pub struct CreateChannelRequest {
526    pub kind: Bytes,
527    pub kind_args: Option<Vec<Bytes>>,
528    pub args: Option<Vec<Bytes>>,
529    pub env: Option<BTreeMap<Bytes, Bytes>>,
530    pub meta: Option<BTreeMap<Bytes, Value>>,
531    pub selectors: Vec<u32>,
532}
533
534#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
535#[serde(rename_all = "kebab-case")]
536pub struct CreateChannelResponse {
537    pub id: ChannelID,
538}
539
540#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
541#[serde(rename_all = "kebab-case")]
542pub struct DeleteChannelRequest {
543    pub id: ChannelID,
544    pub termination: Option<u32>,
545}
546
547#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
548#[serde(rename_all = "kebab-case")]
549pub struct ReadChannelRequest {
550    pub id: ChannelID,
551    pub selector: u32,
552    pub count: u64,
553}
554
555#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
556#[serde(rename_all = "kebab-case")]
557pub struct ReadChannelResponse {
558    pub bytes: Bytes,
559}
560
561#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
562#[serde(rename_all = "kebab-case")]
563pub struct WriteChannelRequest {
564    pub id: ChannelID,
565    pub selector: u32,
566    pub bytes: Bytes,
567}
568
569#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
570#[serde(rename_all = "kebab-case")]
571pub struct WriteChannelResponse {
572    pub count: u64,
573}
574
575#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
576#[serde(rename_all = "kebab-case")]
577pub struct DetachChannelSelectorRequest {
578    pub id: ChannelID,
579    pub selector: u32,
580}
581
582bitflags! {
583    #[derive(Default)]
584    pub struct PollChannelFlags: u64 {
585        const Input   = 0x00000001;
586        const Output  = 0x00000002;
587        const Error   = 0x00000004;
588        const Hangup  = 0x00000008;
589        const Invalid = 0x00000010;
590        const Gone    = 0x00000020;
591    }
592}
593
594#[derive(Serialize, Deserialize, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
595#[serde(rename_all = "kebab-case")]
596pub struct CreateExtensionRangeRequest {
597    pub extension: (Bytes, Option<Bytes>),
598    pub count: u32,
599}
600
601#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
602#[serde(rename_all = "kebab-case")]
603pub struct CreateExtensionRangeResponse {
604    pub range: (u32, u32),
605}
606
607#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
608#[serde(rename_all = "kebab-case")]
609pub struct DeleteExtensionRangeRequest {
610    pub extension: (Bytes, Option<Bytes>),
611    pub range: (u32, u32),
612}
613
614#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
615#[serde(rename_all = "kebab-case")]
616pub struct ListExtensionRangesResponse {
617    pub ranges: Vec<ExtensionRange>,
618}
619
620impl IntoIterator for ListExtensionRangesResponse {
621    type Item = ExtensionRange;
622    type IntoIter = std::vec::IntoIter<ExtensionRange>;
623
624    fn into_iter(self) -> Self::IntoIter {
625        self.ranges.into_iter()
626    }
627}
628
629impl<'a> IntoIterator for &'a ListExtensionRangesResponse {
630    type Item = &'a ExtensionRange;
631    type IntoIter = std::slice::Iter<'a, ExtensionRange>;
632
633    fn into_iter(self) -> Self::IntoIter {
634        self.ranges.iter()
635    }
636}
637
638impl<'a> IntoIterator for &'a mut ListExtensionRangesResponse {
639    type Item = &'a mut ExtensionRange;
640    type IntoIter = std::slice::IterMut<'a, ExtensionRange>;
641
642    fn into_iter(self) -> Self::IntoIter {
643        self.ranges.iter_mut()
644    }
645}
646
647#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
648#[serde(rename_all = "kebab-case")]
649pub struct ExtensionRange {
650    pub extension: (Bytes, Option<Bytes>),
651    pub range: (u32, u32),
652}
653
654#[derive(FromPrimitive, Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
655pub enum ChannelMetadataNotificationKind {
656    WaitStatus = 0,
657}
658
659#[derive(FromPrimitive, Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
660pub enum ChannelMetadataStatusKind {
661    Exited = 0,
662    Signalled = 1,
663    SignalledWithCore = 2,
664    Stopped = 3,
665    Unknown = 0x7fffffff,
666}
667
668#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
669#[serde(rename_all = "kebab-case")]
670pub struct PingChannelRequest {
671    pub id: ChannelID,
672}
673
674#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
675#[serde(rename_all = "kebab-case")]
676pub struct PollChannelRequest {
677    pub id: ChannelID,
678    pub selectors: Vec<u32>,
679    pub milliseconds: Option<u32>,
680    pub wanted: Option<Vec<u64>>,
681}
682
683#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
684#[serde(rename_all = "kebab-case")]
685pub struct PollChannelResponse {
686    pub id: ChannelID,
687    pub selectors: BTreeMap<u32, u64>,
688}
689
690#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
691#[serde(rename_all = "kebab-case")]
692pub struct ChannelMetadataNotification {
693    pub id: ChannelID,
694    pub kind: u32,
695    pub status: Option<u32>,
696    pub status_kind: Option<u32>,
697    pub meta: Option<BTreeMap<Bytes, Value>>,
698}
699
700#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]
701pub enum ClipboardChannelTarget {
702    Primary,
703    Clipboard,
704}
705
706#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]
707pub enum ClipboardChannelOperation {
708    Copy,
709    Paste,
710}
711
712#[derive(Serialize, Deserialize, Hash, Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
713#[serde(transparent)]
714pub struct StoreID(pub u32);
715
716#[derive(Serialize, Deserialize, Hash, Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
717#[serde(transparent)]
718pub struct StoreSelectorID(pub u32);
719
720#[derive(Serialize, Deserialize, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
721#[serde(rename_all = "kebab-case")]
722pub enum StoreSelector {
723    Path(Bytes),
724    #[serde(rename = "id")]
725    ID(StoreSelectorID),
726}
727
728#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
729#[serde(rename_all = "kebab-case")]
730pub struct OpenStoreRequest {
731    pub kind: Bytes,
732    pub path: Option<Bytes>,
733    pub meta: Option<BTreeMap<Bytes, Value>>,
734}
735
736#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
737#[serde(rename_all = "kebab-case")]
738pub struct OpenStoreResponse {
739    pub id: StoreID,
740}
741
742#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
743#[serde(rename_all = "kebab-case")]
744pub struct CloseStoreRequest {
745    pub id: StoreID,
746}
747
748#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
749#[serde(rename_all = "kebab-case")]
750pub struct ListStoreElementsRequest {
751    pub id: StoreID,
752    pub selector: StoreSelector,
753}
754
755#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
756#[serde(rename_all = "kebab-case")]
757pub struct ListStoreElementsResponse {
758    pub elements: Vec<StoreElement>,
759}
760
761impl IntoIterator for ListStoreElementsResponse {
762    type Item = StoreElement;
763    type IntoIter = std::vec::IntoIter<StoreElement>;
764
765    fn into_iter(self) -> Self::IntoIter {
766        self.elements.into_iter()
767    }
768}
769
770impl<'a> IntoIterator for &'a ListStoreElementsResponse {
771    type Item = &'a StoreElement;
772    type IntoIter = std::slice::Iter<'a, StoreElement>;
773
774    fn into_iter(self) -> Self::IntoIter {
775        self.elements.iter()
776    }
777}
778
779impl<'a> IntoIterator for &'a mut ListStoreElementsResponse {
780    type Item = &'a mut StoreElement;
781    type IntoIter = std::slice::IterMut<'a, StoreElement>;
782
783    fn into_iter(self) -> Self::IntoIter {
784        self.elements.iter_mut()
785    }
786}
787
788#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
789#[serde(rename_all = "kebab-case")]
790pub struct AcquireStoreElementRequest {
791    pub id: StoreID,
792    pub selector: Bytes,
793}
794
795#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
796#[serde(rename_all = "kebab-case")]
797pub struct AcquireStoreElementResponse {
798    pub selector: StoreSelectorID,
799}
800
801#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
802#[serde(rename_all = "kebab-case")]
803pub struct CloseStoreElementRequest {
804    pub id: StoreID,
805    pub selector: StoreSelectorID,
806}
807
808#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
809#[serde(rename_all = "kebab-case")]
810pub struct AuthenticateStoreElementRequest {
811    pub id: StoreID,
812    pub selector: StoreSelectorID,
813    pub method: Bytes,
814    pub message: Option<Bytes>,
815}
816
817#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
818#[serde(rename_all = "kebab-case")]
819pub struct AuthenticateStoreElementResponse {
820    pub method: Bytes,
821    pub message: Option<Bytes>,
822}
823
824#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
825#[serde(rename_all = "kebab-case")]
826pub struct StoreElementBareRequest {
827    pub id: StoreID,
828    pub selector: StoreSelector,
829    pub kind: String,
830    pub needs_authentication: Option<bool>,
831    pub authentication_methods: Option<Vec<Bytes>>,
832    pub meta: Option<BTreeMap<Bytes, Value>>,
833}
834
835#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
836#[serde(rename_all = "kebab-case")]
837pub struct CreateStoreElementRequest<T> {
838    pub id: StoreID,
839    pub selector: StoreSelector,
840    pub kind: String,
841    pub needs_authentication: Option<bool>,
842    pub authentication_methods: Option<Vec<Bytes>>,
843    pub meta: Option<BTreeMap<Bytes, Value>>,
844    pub body: T,
845}
846
847#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
848#[serde(rename_all = "kebab-case")]
849pub struct DeleteStoreElementRequest {
850    pub id: StoreID,
851    pub selector: StoreSelector,
852}
853
854#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
855#[serde(rename_all = "kebab-case")]
856pub struct UpdateStoreElementRequest<T> {
857    pub id: StoreID,
858    pub selector: StoreSelector,
859    pub kind: String,
860    pub needs_authentication: Option<bool>,
861    pub authentication_methods: Option<Vec<Bytes>>,
862    pub meta: Option<BTreeMap<Bytes, Value>>,
863    pub body: T,
864}
865
866#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
867#[serde(rename_all = "kebab-case")]
868pub struct ReadStoreElementRequest {
869    pub id: StoreID,
870    pub selector: StoreSelector,
871}
872
873#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
874#[serde(rename_all = "kebab-case")]
875pub struct ReadStoreElementResponse<T> {
876    pub kind: String,
877    pub needs_authentication: Option<bool>,
878    pub authentication_methods: Option<Vec<Bytes>>,
879    pub meta: Option<BTreeMap<Bytes, Value>>,
880    pub body: T,
881}
882
883#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
884#[serde(rename_all = "kebab-case")]
885pub enum StoreSearchRecursionLevel {
886    Boolean(bool),
887    Levels(u32),
888}
889
890#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
891#[serde(rename_all = "kebab-case")]
892pub struct SearchStoreElementsBareRequest {
893    pub id: StoreID,
894    pub selector: StoreSelector,
895    pub recurse: StoreSearchRecursionLevel,
896    pub kind: Option<String>,
897}
898
899#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
900#[serde(rename_all = "kebab-case")]
901pub struct SearchStoreElementsRequest<T> {
902    pub id: StoreID,
903    pub selector: StoreSelector,
904    pub recurse: StoreSearchRecursionLevel,
905    pub kind: Option<String>,
906    pub body: Option<T>,
907}
908
909#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
910#[serde(rename_all = "kebab-case")]
911pub struct SearchStoreElementsResponse<T> {
912    pub elements: Vec<StoreElementWithBody<T>>,
913}
914
915impl<T> IntoIterator for SearchStoreElementsResponse<T> {
916    type Item = StoreElementWithBody<T>;
917    type IntoIter = std::vec::IntoIter<StoreElementWithBody<T>>;
918
919    fn into_iter(self) -> Self::IntoIter {
920        self.elements.into_iter()
921    }
922}
923
924impl<'a, T> IntoIterator for &'a SearchStoreElementsResponse<T> {
925    type Item = &'a StoreElementWithBody<T>;
926    type IntoIter = std::slice::Iter<'a, StoreElementWithBody<T>>;
927
928    fn into_iter(self) -> Self::IntoIter {
929        self.elements.iter()
930    }
931}
932
933impl<'a, T> IntoIterator for &'a mut SearchStoreElementsResponse<T> {
934    type Item = &'a mut StoreElementWithBody<T>;
935    type IntoIter = std::slice::IterMut<'a, StoreElementWithBody<T>>;
936
937    fn into_iter(self) -> Self::IntoIter {
938        self.elements.iter_mut()
939    }
940}
941
942#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Ord, PartialOrd, Clone)]
943#[serde(rename_all = "kebab-case")]
944pub struct StoreElement {
945    pub path: Bytes,
946    pub id: Option<StoreSelectorID>,
947    pub kind: String,
948    pub needs_authentication: Option<bool>,
949    pub authentication_methods: Option<Vec<Bytes>>,
950    pub meta: Option<BTreeMap<Bytes, Value>>,
951}
952
953#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
954#[serde(rename_all = "kebab-case")]
955pub struct StoreElementWithBody<T> {
956    pub path: Bytes,
957    pub id: Option<StoreSelectorID>,
958    pub kind: String,
959    pub needs_authentication: Option<bool>,
960    pub authentication_methods: Option<Vec<Bytes>>,
961    pub meta: Option<BTreeMap<Bytes, Value>>,
962    pub body: T,
963}
964
965impl<T> StoreElementWithBody<T> {
966    pub fn new(elem: StoreElement, body: T) -> Self {
967        Self {
968            path: elem.path,
969            id: elem.id,
970            kind: elem.kind,
971            needs_authentication: elem.needs_authentication,
972            authentication_methods: elem.authentication_methods,
973            meta: elem.meta,
974            body,
975        }
976    }
977}
978
979#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Ord, PartialOrd, Clone)]
980#[serde(rename_all = "kebab-case")]
981pub enum SearchStoreElementType {
982    Literal(Value),
983    Set(BTreeSet<SearchStoreElementType>),
984    Sequence(Vec<SearchStoreElementType>),
985    // The unit value here exists to keep the same form across all serializations.
986    Any(()),
987    None(()),
988}
989
990#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone, Debug)]
991#[serde(rename_all = "kebab-case")]
992pub struct CredentialStoreSearchElement {
993    pub username: SearchStoreElementType,
994    pub secret: SearchStoreElementType,
995    pub authtype: SearchStoreElementType,
996    pub kind: SearchStoreElementType,
997    pub protocol: SearchStoreElementType,
998    pub host: SearchStoreElementType,
999    pub title: SearchStoreElementType,
1000    pub description: SearchStoreElementType,
1001    pub path: SearchStoreElementType,
1002    pub service: SearchStoreElementType,
1003    pub extra: BTreeMap<String, SearchStoreElementType>,
1004    pub id: SearchStoreElementType,
1005}
1006
1007#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Ord, PartialOrd, Clone)]
1008#[serde(rename_all = "kebab-case")]
1009pub struct CredentialStoreLocation {
1010    pub protocol: Option<String>,
1011    pub host: Option<String>,
1012    pub port: Option<u16>,
1013    pub path: Option<String>,
1014}
1015
1016#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Ord, PartialOrd, Clone)]
1017#[serde(rename_all = "kebab-case")]
1018pub struct CredentialStoreElement {
1019    pub username: Option<Bytes>,
1020    pub secret: Option<Bytes>,
1021    pub authtype: Option<String>,
1022    #[serde(rename = "type")]
1023    pub kind: String,
1024    pub title: Option<String>,
1025    pub description: Option<String>,
1026    pub location: Vec<CredentialStoreLocation>,
1027    pub service: Option<String>,
1028    pub extra: BTreeMap<String, Value>,
1029    pub id: Bytes,
1030}
1031
1032#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Ord, PartialOrd, Clone)]
1033pub struct KeyboardInteractiveAuthenticationPrompt {
1034    pub prompt: String,
1035    pub echo: bool,
1036}
1037
1038#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Ord, PartialOrd, Clone)]
1039pub struct KeyboardInteractiveAuthenticationRequest {
1040    pub name: String,
1041    pub instruction: String,
1042    pub prompts: Vec<KeyboardInteractiveAuthenticationPrompt>,
1043}
1044
1045#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Ord, PartialOrd, Clone)]
1046pub struct KeyboardInteractiveAuthenticationResponse {
1047    pub responses: Vec<String>,
1048}
1049
1050#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
1051#[serde(rename_all = "kebab-case")]
1052pub struct ReadServerContextRequest {
1053    pub kind: String,
1054    pub id: Option<Bytes>,
1055    pub meta: Option<BTreeMap<Bytes, Value>>,
1056}
1057
1058#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
1059#[serde(rename_all = "kebab-case")]
1060pub struct ReadServerContextResponse {
1061    pub id: Option<Bytes>,
1062    pub meta: Option<BTreeMap<Bytes, Value>>,
1063}
1064
1065#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
1066#[serde(rename_all = "kebab-case")]
1067pub struct ReadServerContextResponseWithBody<T> {
1068    pub id: Option<Bytes>,
1069    pub meta: Option<BTreeMap<Bytes, Value>>,
1070    pub body: Option<T>,
1071}
1072
1073#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
1074#[serde(rename_all = "kebab-case")]
1075pub struct WriteServerContextRequest {
1076    pub kind: String,
1077    pub id: Option<Bytes>,
1078    pub meta: Option<BTreeMap<Bytes, Value>>,
1079}
1080
1081#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
1082#[serde(rename_all = "kebab-case")]
1083pub struct WriteServerContextRequestWithBody<T> {
1084    pub kind: String,
1085    pub id: Option<Bytes>,
1086    pub meta: Option<BTreeMap<Bytes, Value>>,
1087    pub body: Option<T>,
1088}
1089
1090#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
1091#[serde(rename_all = "kebab-case")]
1092pub struct WriteServerContextResponse {
1093    pub id: Option<Bytes>,
1094    pub meta: Option<BTreeMap<Bytes, Value>>,
1095}
1096
1097#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
1098#[serde(rename_all = "kebab-case")]
1099pub struct TemplateServerContextBody {
1100    pub senv: Option<BTreeMap<Bytes, Bytes>>,
1101    pub cenv: Option<BTreeMap<Bytes, Bytes>>,
1102    pub ctxsenv: Option<BTreeMap<Bytes, Bytes>>,
1103    pub args: Option<Vec<Bytes>>,
1104}
1105
1106#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
1107#[serde(rename_all = "kebab-case")]
1108pub struct TemplateServerContextBodyWithBody<T> {
1109    pub senv: Option<BTreeMap<Bytes, Bytes>>,
1110    pub cenv: Option<BTreeMap<Bytes, Bytes>>,
1111    pub ctxsenv: Option<BTreeMap<Bytes, Bytes>>,
1112    pub args: Option<Vec<Bytes>>,
1113    pub body: Option<T>,
1114}
1115
1116/// A message for the protocol.
1117#[derive(Clone, Debug)]
1118pub struct Message {
1119    pub id: u32,
1120    pub kind: u32,
1121    pub message: Option<Bytes>,
1122}
1123
1124#[derive(Clone, Debug)]
1125pub struct Response {
1126    pub id: u32,
1127    pub code: u32,
1128    pub message: Option<Bytes>,
1129}
1130
1131#[derive(Default)]
1132pub struct ProtocolSerializer {}
1133
1134pub enum Data {
1135    Message(Message),
1136    Response(Response),
1137}
1138
1139#[derive(Clone, Debug, PartialEq, Eq, Ord, PartialOrd)]
1140pub enum ResponseValue<T: DeserializeOwned, U: DeserializeOwned> {
1141    Success(T),
1142    Continuation((u32, U)),
1143}
1144
1145impl ProtocolSerializer {
1146    const MAX_MESSAGE_SIZE: u32 = 0x00ffffff;
1147
1148    pub fn new() -> ProtocolSerializer {
1149        Self {}
1150    }
1151
1152    pub fn is_valid_size(&self, size: u32) -> bool {
1153        (8..=Self::MAX_MESSAGE_SIZE).contains(&size)
1154    }
1155
1156    pub fn serialize_header(&self, id: u32, next: u32, data_len: usize) -> Option<Bytes> {
1157        let size = data_len as u64 + 8;
1158        if size > Self::MAX_MESSAGE_SIZE as u64 {
1159            return None;
1160        }
1161        let mut b = BytesMut::with_capacity(size as usize);
1162        let size = size as u32;
1163        b.extend(&size.to_le_bytes());
1164        b.extend(&id.to_le_bytes());
1165        b.extend(&next.to_le_bytes());
1166        Some(b.into())
1167    }
1168
1169    pub fn serialize_message_simple(&self, msg: &Message) -> Option<Bytes> {
1170        let size = 8 + match &msg.message {
1171            Some(m) => m.len(),
1172            None => 0,
1173        };
1174        if size > Self::MAX_MESSAGE_SIZE as usize {
1175            return None;
1176        }
1177        let mut b = BytesMut::with_capacity(size);
1178        let size = size as u32;
1179        b.extend(&size.to_le_bytes());
1180        b.extend(&msg.id.to_le_bytes());
1181        b.extend(&msg.kind.to_le_bytes());
1182        match &msg.message {
1183            Some(m) => b.extend(m),
1184            None => (),
1185        };
1186        Some(b.into())
1187    }
1188
1189    pub fn serialize_message_typed<S: Serialize>(&self, msg: &Message, obj: &S) -> Option<Bytes> {
1190        let mut v: Vec<u8> = Vec::with_capacity(12);
1191        // Write a dummy size that we'll then fill in later.
1192        v.extend(&0u32.to_le_bytes());
1193        v.extend(&msg.id.to_le_bytes());
1194        v.extend(&msg.kind.to_le_bytes());
1195        let mut cursor = std::io::Cursor::new(&mut v);
1196        let _ = cursor.seek(SeekFrom::End(0));
1197        if serde_cbor::to_writer(&mut cursor, obj).is_err() {
1198            return None;
1199        }
1200        let size = match u32::try_from(v.len()) {
1201            Ok(sz) if (4..=Self::MAX_MESSAGE_SIZE).contains(&sz) => sz - 4,
1202            _ => return None,
1203        };
1204        v[0..4].copy_from_slice(&size.to_le_bytes());
1205        Some(v.into())
1206    }
1207
1208    pub fn serialize_body<S: Serialize>(&self, obj: &S) -> Option<Bytes> {
1209        match serde_cbor::to_vec(obj) {
1210            Ok(m) => Some(m.into()),
1211            Err(_) => None,
1212        }
1213    }
1214
1215    pub fn serialize_response_simple(&self, resp: &Response) -> Option<Bytes> {
1216        let size = 8 + match &resp.message {
1217            Some(m) => m.len(),
1218            None => 0,
1219        };
1220        if size > Self::MAX_MESSAGE_SIZE as usize {
1221            return None;
1222        }
1223        let mut b = BytesMut::with_capacity(size);
1224        let size = size as u32;
1225        b.extend(&size.to_le_bytes());
1226        b.extend(&resp.id.to_le_bytes());
1227        b.extend(&resp.code.to_le_bytes());
1228        match &resp.message {
1229            Some(m) => b.extend(m),
1230            None => (),
1231        };
1232        Some(b.into())
1233    }
1234
1235    pub fn serialize_response_typed<S: Serialize>(&self, msg: &Response, obj: &S) -> Option<Bytes> {
1236        let mut v: Vec<u8> = Vec::with_capacity(12);
1237        // Write a dummy size that we'll then fill in later.
1238        v.extend(&0u32.to_le_bytes());
1239        v.extend(&msg.id.to_le_bytes());
1240        v.extend(&msg.code.to_le_bytes());
1241        let mut cursor = std::io::Cursor::new(&mut v);
1242        let _ = cursor.seek(SeekFrom::End(0));
1243        if serde_cbor::to_writer(&mut cursor, obj).is_err() {
1244            return None;
1245        }
1246        let size = match u32::try_from(v.len()) {
1247            Ok(sz) if (4..=Self::MAX_MESSAGE_SIZE).contains(&sz) => sz - 4,
1248            _ => return None,
1249        };
1250        v[0..4].copy_from_slice(&size.to_le_bytes());
1251        Some(v.into())
1252    }
1253
1254    pub fn deserialize_data(
1255        &self,
1256        config: &Config,
1257        header: &[u8],
1258        body: Bytes,
1259    ) -> Result<Data, Error> {
1260        fn is_sender(config: &Config, id: u32) -> bool {
1261            let sender_mask = if config.is_server() { 0x80000000 } else { 0 };
1262            (id & 0x80000000) == sender_mask
1263        }
1264        let _size: u32 = u32::from_le_bytes(header[0..4].try_into().unwrap());
1265        let id: u32 = u32::from_le_bytes(header[4..8].try_into().unwrap());
1266        let arg: u32 = u32::from_le_bytes(header[8..12].try_into().unwrap());
1267        if is_sender(config, id) {
1268            Ok(Data::Response(Response {
1269                id,
1270                code: arg,
1271                message: if body.is_empty() { None } else { Some(body) },
1272            }))
1273        } else {
1274            Ok(Data::Message(Message {
1275                id,
1276                kind: arg,
1277                message: if body.is_empty() { None } else { Some(body) },
1278            }))
1279        }
1280    }
1281
1282    pub fn deserialize_message_typed<'a, D: Deserialize<'a>>(
1283        &self,
1284        msg: &'a Message,
1285    ) -> Result<Option<D>, Error> {
1286        match &msg.message {
1287            Some(body) => match serde_cbor::from_slice(body) {
1288                Ok(decoded) => Ok(Some(decoded)),
1289                Err(_) => Err(Error {
1290                    code: ResponseCode::Invalid,
1291                    body: None,
1292                }),
1293            },
1294            None => Ok(None),
1295        }
1296    }
1297
1298    pub fn deserialize_response_typed<D1: DeserializeOwned, D2: DeserializeOwned>(
1299        &self,
1300        resp: &Response,
1301    ) -> Result<Option<ResponseValue<D1, D2>>, Error> {
1302        if resp.code == ResponseCode::Success as u32 {
1303            match &resp.message {
1304                Some(body) => match serde_cbor::from_slice(body) {
1305                    Ok(decoded) => Ok(Some(ResponseValue::Success(decoded))),
1306                    Err(_) => Err(Error {
1307                        code: ResponseCode::Invalid,
1308                        body: None,
1309                    }),
1310                },
1311                None => Ok(None),
1312            }
1313        } else if resp.code == ResponseCode::Continuation as u32 {
1314            match &resp.message {
1315                Some(body) => match serde_cbor::from_slice(body) {
1316                    Ok(decoded) => Ok(Some(ResponseValue::Continuation((resp.id, decoded)))),
1317                    Err(_) => Err(Error {
1318                        code: ResponseCode::Invalid,
1319                        body: None,
1320                    }),
1321                },
1322                None => Ok(None),
1323            }
1324        } else {
1325            match &resp.message {
1326                Some(body) => match serde_cbor::from_slice(body) {
1327                    Ok(decoded) => Err(Error {
1328                        code: ResponseCode::from_u32(resp.code),
1329                        body: Some(decoded),
1330                    }),
1331                    Err(_) => Err(Error {
1332                        code: ResponseCode::from_u32(resp.code),
1333                        body: None,
1334                    }),
1335                },
1336                None => Err(Error {
1337                    code: ResponseCode::from_u32(resp.code),
1338                    body: None,
1339                }),
1340            }
1341        }
1342    }
1343}
1344
1345#[cfg(test)]
1346mod tests {
1347    use super::{
1348        ChannelID, Empty, Message, ProtocolSerializer, Response, ResponseValue,
1349        SearchStoreElementType, StoreID, StoreSelector, StoreSelectorID,
1350    };
1351    use bytes::Bytes;
1352    use serde::{de::DeserializeOwned, Deserialize, Serialize};
1353    use serde_cbor::Value;
1354    use std::convert::TryFrom;
1355    use std::fmt::Debug;
1356
1357    #[test]
1358    fn serialize_header() {
1359        let cases: &[(u32, u32, usize, Option<&[u8]>)] = &[
1360            (
1361                0x01234567,
1362                0xffeeddcc,
1363                0x00000000,
1364                Some(b"\x08\x00\x00\x00\x67\x45\x23\x01\xcc\xdd\xee\xff"),
1365            ),
1366            (
1367                0x87654321,
1368                0x00000000,
1369                0x00000099,
1370                Some(b"\xa1\x00\x00\x00\x21\x43\x65\x87\x00\x00\x00\x00"),
1371            ),
1372            (
1373                0x87654321,
1374                0x00000000,
1375                0x00fffff7,
1376                Some(b"\xff\xff\xff\x00\x21\x43\x65\x87\x00\x00\x00\x00"),
1377            ),
1378            (0x87654321, 0x00000000, 0x00fffff8, None),
1379        ];
1380        let ser = ProtocolSerializer::new();
1381        for (id, next, data_len, response) in cases {
1382            assert_eq!(
1383                ser.serialize_header(*id, *next, *data_len).as_deref(),
1384                *response
1385            );
1386        }
1387    }
1388
1389    fn assert_encode<'a, S: Serialize + Deserialize<'a> + Debug + Clone + PartialEq>(
1390        desc: &str,
1391        s: &S,
1392        seq: &[u8],
1393    ) {
1394        let id = 0x01234567u32;
1395        let next = 0xffeeddccu32;
1396        let mut header = [0u8; 12];
1397
1398        header[0..4].copy_from_slice(&u32::try_from(seq.len() + 8).unwrap().to_le_bytes());
1399        header[4..8].copy_from_slice(&id.to_le_bytes());
1400        header[8..12].copy_from_slice(&next.to_le_bytes());
1401
1402        let ser = ProtocolSerializer::new();
1403        let msg = Message {
1404            id,
1405            kind: next,
1406            message: Some(Bytes::copy_from_slice(seq)),
1407        };
1408
1409        let res = ser.serialize_header(id, next, seq.len()).unwrap();
1410        assert_eq!(&res, &header as &[u8], "header: {}", desc);
1411
1412        let res = ser.serialize_message_simple(&msg).unwrap();
1413        assert_eq!(res[0..12], header, "simple header: {}", desc);
1414        assert_eq!(res[12..], *seq, "simple body: {}", desc);
1415
1416        let res = ser.serialize_body(s).unwrap();
1417        assert_eq!(res, *seq, "body: {}", desc);
1418
1419        let msg = Message {
1420            id,
1421            kind: next,
1422            message: None,
1423        };
1424        let res = ser.serialize_message_typed(&msg, s).unwrap();
1425        assert_eq!(res[0..12], header, "typed header: {}", desc);
1426        assert_eq!(res[12..], *seq, "typed body: {}", desc);
1427    }
1428
1429    fn assert_round_trip<S: Serialize + DeserializeOwned + Debug + Clone + PartialEq>(
1430        desc: &str,
1431        s: &S,
1432        seq: &[u8],
1433    ) {
1434        assert_encode(desc, s, seq);
1435        assert_decode(desc, s, seq);
1436    }
1437
1438    fn assert_decode<S: Serialize + DeserializeOwned + Debug + Clone + PartialEq>(
1439        desc: &str,
1440        s: &S,
1441        seq: &[u8],
1442    ) {
1443        let id = 0x01234567u32;
1444        let next = 0u32;
1445        let mut header = [0u8; 12];
1446
1447        header[0..4].copy_from_slice(&u32::try_from(seq.len() + 8).unwrap().to_le_bytes());
1448        header[4..8].copy_from_slice(&id.to_le_bytes());
1449        header[8..12].copy_from_slice(&next.to_le_bytes());
1450
1451        let body = Bytes::copy_from_slice(seq);
1452
1453        let ser = ProtocolSerializer::new();
1454        let resp = Response {
1455            id,
1456            code: next,
1457            message: Some(body.clone()),
1458        };
1459
1460        let mut full_msg: Vec<u8> = header.into();
1461        full_msg.extend(seq);
1462
1463        let res = ser.deserialize_response_typed::<S, Empty>(&resp);
1464        assert_eq!(
1465            res.unwrap().unwrap(),
1466            ResponseValue::Success(s.clone()),
1467            "deserialize typed response: {}",
1468            desc
1469        );
1470    }
1471
1472    #[test]
1473    fn serialize_basic_types() {
1474        assert_round_trip("0u32", &0u32, b"\x00");
1475        assert_round_trip("all ones u32", &0xfedcba98u32, b"\x1a\xfe\xdc\xba\x98");
1476        assert_round_trip(
1477            "simple Bytes",
1478            &Bytes::from(b"Hello, world!\n" as &'static [u8]),
1479            b"\x4eHello, world!\n",
1480        );
1481        assert_encode("simple &str", &"Hello, world!\n", b"\x6eHello, world!\n");
1482        assert_round_trip(
1483            "simple String",
1484            &String::from("Hello, world!\n"),
1485            b"\x6eHello, world!\n",
1486        );
1487    }
1488
1489    #[test]
1490    fn serialize_encoded_types() {
1491        assert_round_trip("ChannelID 0", &ChannelID(0), b"\x00");
1492        assert_round_trip(
1493            "ChannelID all ones u32",
1494            &ChannelID(0xfedcba98u32),
1495            b"\x1a\xfe\xdc\xba\x98",
1496        );
1497        assert_round_trip("StoreID 0", &StoreID(0), b"\x00");
1498        assert_round_trip(
1499            "StoreID pattern",
1500            &StoreID(0xfedcba98u32),
1501            b"\x1a\xfe\xdc\xba\x98",
1502        );
1503        assert_round_trip("StoreSelectorID 0", &StoreSelectorID(0), b"\x00");
1504        assert_round_trip(
1505            "StoreSelectorID pattern",
1506            &StoreSelectorID(0xfedcba98u32),
1507            b"\x1a\xfe\xdc\xba\x98",
1508        );
1509        assert_round_trip(
1510            "StoreSelector path",
1511            &StoreSelector::Path(Bytes::from(b"/dev/null" as &[u8])),
1512            b"\xa1\x64path\x49/dev/null",
1513        );
1514        assert_round_trip(
1515            "StoreSelector ID",
1516            &StoreSelector::ID(StoreSelectorID(0xfedcba98u32)),
1517            b"\xa1\x62id\x1a\xfe\xdc\xba\x98",
1518        );
1519        assert_round_trip(
1520            "SearchStoreElementType literal text",
1521            &SearchStoreElementType::Literal(Value::Text(String::from("abc123"))),
1522            b"\xa1\x67literal\x66abc123",
1523        );
1524        assert_round_trip(
1525            "SearchStoreElementType literal bytes",
1526            &SearchStoreElementType::Literal(Value::Bytes("abc123".into())),
1527            b"\xa1\x67literal\x46abc123",
1528        );
1529        assert_round_trip(
1530            "SearchStoreElementType literal null",
1531            &SearchStoreElementType::Literal(Value::Null),
1532            b"\xa1\x67literal\xf6",
1533        );
1534        assert_round_trip(
1535            "SearchStoreElementType any",
1536            &SearchStoreElementType::Any(()),
1537            b"\xa1\x63any\xf6",
1538        );
1539        assert_round_trip(
1540            "SearchStoreElementType none",
1541            &SearchStoreElementType::None(()),
1542            b"\xa1\x64none\xf6",
1543        );
1544    }
1545
1546    #[test]
1547    fn serialize_requests() {
1548        assert_round_trip(
1549            "CreateExtensionRangeRequest with no second part",
1550            &super::CreateExtensionRangeRequest {
1551                extension: (
1552                    Bytes::from(b"foobar@test.ns.crustytoothpaste.net" as &[u8]),
1553                    None,
1554                ),
1555                count: 5,
1556            },
1557            b"\xa2\x69extension\x82\x58\x23foobar@test.ns.crustytoothpaste.net\xf6\x65count\x05",
1558        );
1559        assert_round_trip(
1560            "CreateExtensionRangeRequest with second part",
1561            &super::CreateExtensionRangeRequest {
1562                extension: (
1563                    Bytes::from(b"foobar@test.ns.crustytoothpaste.net" as &[u8]),
1564                    Some(Bytes::from(b"v1" as &[u8])),
1565                ),
1566                count: 5,
1567            },
1568            b"\xa2\x69extension\x82\x58\x23foobar@test.ns.crustytoothpaste.net\x42v1\x65count\x05",
1569        );
1570    }
1571
1572    #[test]
1573    fn deserialize_requests() {
1574        assert_decode(
1575            "CreateExtensionRangeRequest with extension field",
1576            &super::CreateExtensionRangeRequest {
1577                extension: (
1578                    Bytes::from(b"foobar@test.ns.crustytoothpaste.net" as &[u8]),
1579                    None,
1580                ),
1581                count: 5,
1582            },
1583            b"\xa3\x69extension\x82\x58\x23foobar@test.ns.crustytoothpaste.net\xf6\x58\x26extension@test.ns.crustytoothpaste.net\xf5\x65count\x05",
1584        );
1585    }
1586}