1#![allow(non_upper_case_globals)]
2use crate::config::Config;
38use bitflags::bitflags;
39use bytes::{Bytes, BytesMut};
40use num_traits::FromPrimitive;
41use serde::{de::DeserializeOwned, Deserialize, Serialize};
42use serde_cbor::Value;
43use std::collections::{BTreeMap, BTreeSet};
44use std::convert::{TryFrom, TryInto};
45use std::fmt;
46use std::io;
47use std::io::{Seek, SeekFrom};
48
49#[derive(FromPrimitive, Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
59pub enum ResponseCode {
60 Success = 0x00000000,
62 Continuation = 0x00000001,
65
66 NeedsAuthentication = 0x00010000,
70 Forbidden = 0x00010001,
74 Closing = 0x00010002,
76 Errno = 0x00010003,
80 AuthenticationFailed = 0x00010004,
81 Gone = 0x00010005,
83 NotFound = 0x00010006,
84 InternalError = 0x00010007,
85 ChannelDead = 0x00010008,
87 Aborted = 0x00010009,
89 ContinuationNotFound = 0x0001000a,
91 OutOfRange = 0x0001000b,
95 NoSpace = 0x0001000c,
97 Conflict = 0x0001000d,
101 Unlistable = 0x0001000e,
106
107 NotEnabled = 0x00020000,
109 NotSupported = 0x00020001,
111 ParametersNotSupported = 0x00020002,
113 Invalid = 0x00020003,
115 TooLarge = 0x00020004,
117 TooManyMessages = 0x00020005,
119 InvalidParameters = 0x00020006,
123}
124
125impl ResponseCode {
126 fn from_u32(val: u32) -> Self {
127 FromPrimitive::from_u32(val).unwrap_or(Self::Invalid)
128 }
129}
130
131pub struct WrongTypeError(pub Error);
132
133#[derive(Debug, Clone)]
134pub struct Error {
135 pub code: ResponseCode,
136 pub body: Option<ErrorBody>,
137}
138
139impl fmt::Display for Error {
140 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
141 fmt::Debug::fmt(self, f)
142 }
143}
144
145impl std::error::Error for Error {}
146
147impl Error {
148 pub fn from_errno(err: i32) -> Error {
149 io::Error::from_raw_os_error(err).into()
150 }
151}
152
153impl From<io::Error> for Error {
154 fn from(err: io::Error) -> Error {
155 let lerr: lawn_constants::Error = err.into();
156 Error {
157 code: ResponseCode::Errno,
158 body: Some(ErrorBody::Errno(Errno { errno: lerr as u32 })),
159 }
160 }
161}
162
163impl From<ResponseCode> for Error {
164 fn from(code: ResponseCode) -> Error {
165 Error { code, body: None }
166 }
167}
168
169impl TryInto<io::Error> for Error {
170 type Error = WrongTypeError;
171 fn try_into(self) -> Result<io::Error, Self::Error> {
172 if self.code == ResponseCode::Errno {
173 if let Some(ErrorBody::Errno(Errno { errno })) = self.body {
174 if let Some(e) = lawn_constants::Error::from_u32(errno) {
175 return Ok(e.into());
176 }
177 }
178 }
179 Err(WrongTypeError(self))
180 }
181}
182
183#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd)]
184pub struct Empty {}
185
186#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
187pub struct Errno {
188 errno: u32,
189}
190
191#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
192#[serde(untagged)]
193pub enum ErrorBody {
194 Errno(Errno),
195 Exit(i32),
196}
197
198#[derive(FromPrimitive, Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
199pub enum MessageKind {
200 Capability = 0x00000000,
202 Version = 0x00000001,
209 Ping = 0x00000002,
213 Authenticate = 0x00000003,
220 Continue = 0x00000004,
225 Abort = 0x00000005,
230
231 CloseAlert = 0x00001000,
235
236 CreateChannel = 0x00010000,
238 DeleteChannel = 0x00010001,
242 ReadChannel = 0x00010002,
244 WriteChannel = 0x00010003,
246 PollChannel = 0x00010004,
248 PingChannel = 0x00010005,
252 DetachChannelSelector = 0x00010011,
255 ChannelMetadataNotification = 0x00011000,
260
261 CreateExtensionRange = 0x00020000,
263
264 DeleteExtensionRange = 0x00020001,
266
267 ListExtensionRanges = 0x00020002,
269
270 OpenStore = 0x00030000,
272
273 CloseStore = 0x00030001,
275
276 ListStoreElements = 0x00030002,
278
279 AcquireStoreElement = 0x00030003,
281
282 CloseStoreElement = 0x00030004,
284
285 AuthenticateStoreElement = 0x00030005,
287
288 CreateStoreElement = 0x00030006,
290
291 DeleteStoreElement = 0x00030007,
293
294 UpdateStoreElement = 0x00030008,
296
297 ReadStoreElement = 0x00030009,
299
300 RenameStoreElement = 0x0003000a,
302
303 CopyStoreElement = 0x0003000b,
305
306 SearchStoreElements = 0x0003000c,
308
309 ReadServerContext = 0x00040000,
311
312 WriteServerContext = 0x00040001,
314}
315
316#[derive(Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
317pub enum Capability {
318 AuthExternal,
319 AuthKeyboardInteractive,
320 AuthPlain,
321 ChannelCommand,
322 ChannelCommandTTY,
323 Channel9P,
324 ChannelSFTP,
325 ChannelClipboard,
326 ChannelBlockingIO,
327 ExtensionAllocate,
328 StoreCredential,
329 ContextTemplate,
330 Other(Bytes, Option<Bytes>),
331}
332
333impl Capability {
334 #[allow(clippy::mutable_key_type)]
335 pub fn implemented() -> BTreeSet<Capability> {
336 [
337 Self::AuthExternal,
338 Self::AuthKeyboardInteractive,
339 Self::AuthPlain,
340 Self::ChannelCommand,
341 Self::ChannelClipboard,
342 Self::Channel9P,
343 Self::ChannelSFTP,
344 Self::ChannelBlockingIO,
345 Self::ChannelCommandTTY,
346 Self::ExtensionAllocate,
347 Self::StoreCredential,
348 Self::ContextTemplate,
349 ]
350 .iter()
351 .cloned()
352 .collect()
353 }
354
355 pub fn is_implemented(&self) -> bool {
356 matches!(
357 self,
358 Self::AuthExternal
359 | Self::AuthKeyboardInteractive
360 | Self::AuthPlain
361 | Self::ChannelCommand
362 | Self::ChannelClipboard
363 | Self::Channel9P
364 | Self::ChannelSFTP
365 | Self::ChannelBlockingIO
366 | Self::ChannelCommandTTY
367 | Self::ExtensionAllocate
368 | Self::StoreCredential
369 | Self::ContextTemplate
370 )
371 }
372}
373
374impl From<Capability> for (Bytes, Option<Bytes>) {
375 fn from(capa: Capability) -> (Bytes, Option<Bytes>) {
376 match capa {
377 Capability::AuthExternal => (
378 (b"auth" as &[u8]).into(),
379 Some((b"EXTERNAL" as &[u8]).into()),
380 ),
381 Capability::AuthKeyboardInteractive => (
382 (b"auth" as &[u8]).into(),
383 Some((b"keyboard-interactive" as &[u8]).into()),
384 ),
385 Capability::AuthPlain => ((b"auth" as &[u8]).into(), Some((b"PLAIN" as &[u8]).into())),
386 Capability::ChannelCommand => (
387 (b"channel" as &[u8]).into(),
388 Some((b"command" as &[u8]).into()),
389 ),
390 Capability::ChannelCommandTTY => (
391 (b"channel" as &[u8]).into(),
392 Some((b"command/tty" as &[u8]).into()),
393 ),
394 Capability::Channel9P => ((b"channel" as &[u8]).into(), Some((b"9p" as &[u8]).into())),
395 Capability::ChannelSFTP => (
396 (b"channel" as &[u8]).into(),
397 Some((b"sftp" as &[u8]).into()),
398 ),
399 Capability::ChannelClipboard => (
400 (b"channel" as &[u8]).into(),
401 Some((b"clipboard" as &[u8]).into()),
402 ),
403 Capability::ChannelBlockingIO => (
404 (b"channel" as &[u8]).into(),
405 Some((b"blocking-io" as &[u8]).into()),
406 ),
407 Capability::StoreCredential => (
408 (b"store" as &[u8]).into(),
409 Some((b"credential" as &[u8]).into()),
410 ),
411 Capability::ExtensionAllocate => (
412 (b"extension" as &[u8]).into(),
413 Some((b"allocate" as &[u8]).into()),
414 ),
415 Capability::ContextTemplate => (
416 (b"context" as &[u8]).into(),
417 Some((b"template" as &[u8]).into()),
418 ),
419 Capability::Other(name, subtype) => (name, subtype),
420 }
421 }
422}
423
424impl From<(&[u8], Option<&[u8]>)> for Capability {
425 fn from(data: (&[u8], Option<&[u8]>)) -> Capability {
426 match data {
427 (b"auth", Some(b"EXTERNAL")) => Capability::AuthExternal,
428 (b"auth", Some(b"PLAIN")) => Capability::AuthPlain,
429 (b"auth", Some(b"keyboard-interactive")) => Capability::AuthKeyboardInteractive,
430 (b"channel", Some(b"command")) => Capability::ChannelCommand,
431 (b"channel", Some(b"command/tty")) => Capability::ChannelCommandTTY,
432 (b"channel", Some(b"9p")) => Capability::Channel9P,
433 (b"channel", Some(b"sftp")) => Capability::ChannelSFTP,
434 (b"channel", Some(b"clipboard")) => Capability::ChannelClipboard,
435 (b"channel", Some(b"blocking-io")) => Capability::ChannelBlockingIO,
436 (b"store", Some(b"credential")) => Capability::StoreCredential,
437 (b"extension", Some(b"allocate")) => Capability::ExtensionAllocate,
438 (b"context", Some(b"template")) => Capability::ContextTemplate,
439 (name, subtype) => {
440 Capability::Other(name.to_vec().into(), subtype.map(|s| s.to_vec().into()))
441 }
442 }
443 }
444}
445
446impl From<(Bytes, Option<Bytes>)> for Capability {
447 fn from(data: (Bytes, Option<Bytes>)) -> Capability {
448 match data {
449 (a, Some(b)) => (&a as &[u8], Some(&b as &[u8])).into(),
450 (a, None) => (&a as &[u8], None).into(),
451 }
452 }
453}
454
455#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
456#[serde(rename_all = "kebab-case")]
457pub struct CapabilityResponse {
458 pub version: Vec<u32>,
459 pub capabilities: Vec<(Bytes, Option<Bytes>)>,
460 pub user_agent: Option<String>,
461}
462
463#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
464#[serde(rename_all = "kebab-case")]
465pub struct VersionRequest {
466 pub version: u32,
467 pub enable: Vec<(Bytes, Option<Bytes>)>,
468 pub id: Option<Bytes>,
469 pub user_agent: Option<String>,
470}
471
472#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
473#[serde(rename_all = "kebab-case")]
474pub struct AuthenticateRequest {
475 pub last_id: Option<u32>,
476 pub method: Bytes,
479 pub message: Option<Bytes>,
480}
481
482#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
483#[serde(rename_all = "kebab-case")]
484pub struct AuthenticateResponse {
485 pub method: Bytes,
488 pub message: Option<Bytes>,
489}
490
491#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
492#[serde(rename_all = "kebab-case")]
493pub struct PartialContinueRequest {
494 pub id: u32,
495 pub kind: u32,
496}
497
498#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
499#[serde(rename_all = "kebab-case")]
500pub struct ContinueRequest<T> {
501 pub id: u32,
502 pub kind: u32,
503 pub message: Option<T>,
504}
505
506#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
507#[serde(rename_all = "kebab-case")]
508pub struct AbortRequest {
509 pub id: u32,
510 pub kind: u32,
511}
512
513#[derive(Serialize, Deserialize, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
514#[serde(transparent)]
515pub struct ChannelID(pub u32);
516
517impl fmt::Display for ChannelID {
518 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
519 write!(f, "{}", self.0)
520 }
521}
522
523#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
524#[serde(transparent)]
525pub struct ChannelSelectorID(pub u32);
526
527#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
539#[serde(rename_all = "kebab-case")]
540pub struct CreateChannelRequest {
541 pub kind: Bytes,
542 pub kind_args: Option<Vec<Bytes>>,
543 pub args: Option<Vec<Bytes>>,
544 pub env: Option<BTreeMap<Bytes, Bytes>>,
545 pub meta: Option<BTreeMap<Bytes, Value>>,
546 pub selectors: Vec<u32>,
547}
548
549#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
550#[serde(rename_all = "kebab-case")]
551pub struct CreateChannelResponse {
552 pub id: ChannelID,
553}
554
555#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
556#[serde(rename_all = "kebab-case")]
557pub struct ChannelCommandTTYMetadata {
558 pub tty: bool,
559 pub tty_selectors: Vec<u32>,
560 pub term: Bytes,
561 pub modes: BTreeMap<u32, Value>,
562 #[serde(flatten)]
563 pub size: ChannelCommandTTYSizeMetadata,
564}
565
566#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Ord, PartialOrd, Clone)]
567#[serde(rename_all = "kebab-case")]
568pub struct ChannelCommandTTYSizeMetadata {
569 pub height_cells: u32,
570 pub width_cells: u32,
571 pub height_pixels: u32,
572 pub width_pixels: u32,
573}
574
575#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
576#[serde(rename_all = "kebab-case")]
577pub struct DeleteChannelRequest {
578 pub id: ChannelID,
579 pub termination: Option<u32>,
580}
581
582#[derive(Serialize, Deserialize, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
583#[serde(rename_all = "kebab-case")]
584pub struct ReadChannelRequest {
585 pub id: ChannelID,
586 pub selector: u32,
587 pub count: u64,
588 #[serde(default)]
589 pub stream_sync: Option<u64>,
590 #[serde(default)]
591 pub blocking: Option<bool>,
592 #[serde(default)]
593 pub complete: bool,
594}
595
596#[derive(Serialize, Deserialize, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
597#[serde(rename_all = "kebab-case")]
598pub struct ReadChannelResponse {
599 pub bytes: Bytes,
600 #[serde(default)]
601 pub offset: Option<u64>,
602}
603
604#[derive(Serialize, Deserialize, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
605#[serde(rename_all = "kebab-case")]
606pub struct WriteChannelRequest {
607 pub id: ChannelID,
608 pub selector: u32,
609 pub bytes: Bytes,
610 #[serde(default)]
611 pub stream_sync: Option<u64>,
612 #[serde(default)]
613 pub blocking: Option<bool>,
614}
615
616#[derive(Serialize, Deserialize, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
617#[serde(rename_all = "kebab-case")]
618pub struct WriteChannelResponse {
619 pub count: u64,
620 #[serde(default)]
621 pub offset: Option<u64>,
622}
623
624#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
625#[serde(rename_all = "kebab-case")]
626pub struct DetachChannelSelectorRequest {
627 pub id: ChannelID,
628 pub selector: u32,
629}
630
631bitflags! {
632 #[derive(Default)]
633 pub struct PollChannelFlags: u64 {
634 const Input = 0x00000001;
635 const Output = 0x00000002;
636 const Error = 0x00000004;
637 const Hangup = 0x00000008;
638 const Invalid = 0x00000010;
639 const Gone = 0x00000020;
640 }
641}
642
643#[derive(Serialize, Deserialize, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
644#[serde(rename_all = "kebab-case")]
645pub struct CreateExtensionRangeRequest {
646 pub extension: (Bytes, Option<Bytes>),
647 pub count: u32,
648}
649
650#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
651#[serde(rename_all = "kebab-case")]
652pub struct CreateExtensionRangeResponse {
653 pub range: (u32, u32),
654}
655
656#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
657#[serde(rename_all = "kebab-case")]
658pub struct DeleteExtensionRangeRequest {
659 pub extension: (Bytes, Option<Bytes>),
660 pub range: (u32, u32),
661}
662
663#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
664#[serde(rename_all = "kebab-case")]
665pub struct ListExtensionRangesResponse {
666 pub ranges: Vec<ExtensionRange>,
667}
668
669impl IntoIterator for ListExtensionRangesResponse {
670 type Item = ExtensionRange;
671 type IntoIter = std::vec::IntoIter<ExtensionRange>;
672
673 fn into_iter(self) -> Self::IntoIter {
674 self.ranges.into_iter()
675 }
676}
677
678impl<'a> IntoIterator for &'a ListExtensionRangesResponse {
679 type Item = &'a ExtensionRange;
680 type IntoIter = std::slice::Iter<'a, ExtensionRange>;
681
682 fn into_iter(self) -> Self::IntoIter {
683 self.ranges.iter()
684 }
685}
686
687impl<'a> IntoIterator for &'a mut ListExtensionRangesResponse {
688 type Item = &'a mut ExtensionRange;
689 type IntoIter = std::slice::IterMut<'a, ExtensionRange>;
690
691 fn into_iter(self) -> Self::IntoIter {
692 self.ranges.iter_mut()
693 }
694}
695
696#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
697#[serde(rename_all = "kebab-case")]
698pub struct ExtensionRange {
699 pub extension: (Bytes, Option<Bytes>),
700 pub range: (u32, u32),
701}
702
703#[derive(FromPrimitive, Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
704pub enum ChannelMetadataNotificationKind {
705 WaitStatus = 0,
706 TerminalWindowChange = 1,
707}
708
709#[derive(FromPrimitive, Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
710pub enum ChannelMetadataStatusKind {
711 Exited = 0,
712 Signalled = 1,
713 SignalledWithCore = 2,
714 Stopped = 3,
715 Unknown = 0x7fffffff,
716}
717
718#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
719#[serde(rename_all = "kebab-case")]
720pub struct PingChannelRequest {
721 pub id: ChannelID,
722}
723
724#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
725#[serde(rename_all = "kebab-case")]
726pub struct PollChannelRequest {
727 pub id: ChannelID,
728 pub selectors: Vec<u32>,
729 pub milliseconds: Option<u32>,
730 pub wanted: Option<Vec<u64>>,
731}
732
733#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
734#[serde(rename_all = "kebab-case")]
735pub struct PollChannelResponse {
736 pub id: ChannelID,
737 pub selectors: BTreeMap<u32, u64>,
738}
739
740#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
741#[serde(rename_all = "kebab-case")]
742pub struct ChannelMetadataNotification {
743 pub id: ChannelID,
744 pub kind: u32,
745 pub status: Option<u32>,
746 pub status_kind: Option<u32>,
747 pub meta: Option<BTreeMap<Bytes, Value>>,
748}
749
750#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
751#[serde(rename_all = "kebab-case")]
752pub struct ChannelMetadataNotificationTyped<T> {
753 pub id: ChannelID,
754 pub kind: u32,
755 pub status: Option<u32>,
756 pub status_kind: Option<u32>,
757 pub meta: Option<T>,
758}
759
760#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]
761pub enum ClipboardChannelTarget {
762 Primary,
763 Clipboard,
764}
765
766#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]
767pub enum ClipboardChannelOperation {
768 Copy,
769 Paste,
770}
771
772#[derive(Serialize, Deserialize, Hash, Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
773#[serde(transparent)]
774pub struct StoreID(pub u32);
775
776#[derive(Serialize, Deserialize, Hash, Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
777#[serde(transparent)]
778pub struct StoreSelectorID(pub u32);
779
780#[derive(Serialize, Deserialize, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
781#[serde(rename_all = "kebab-case")]
782pub enum StoreSelector {
783 Path(Bytes),
784 #[serde(rename = "id")]
785 ID(StoreSelectorID),
786}
787
788#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
789#[serde(rename_all = "kebab-case")]
790pub struct OpenStoreRequest {
791 pub kind: Bytes,
792 pub path: Option<Bytes>,
793 pub meta: Option<BTreeMap<Bytes, Value>>,
794}
795
796#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
797#[serde(rename_all = "kebab-case")]
798pub struct OpenStoreResponse {
799 pub id: StoreID,
800}
801
802#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
803#[serde(rename_all = "kebab-case")]
804pub struct CloseStoreRequest {
805 pub id: StoreID,
806}
807
808#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
809#[serde(rename_all = "kebab-case")]
810pub struct ListStoreElementsRequest {
811 pub id: StoreID,
812 pub selector: StoreSelector,
813}
814
815#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
816#[serde(rename_all = "kebab-case")]
817pub struct ListStoreElementsResponse {
818 pub elements: Vec<StoreElement>,
819}
820
821impl IntoIterator for ListStoreElementsResponse {
822 type Item = StoreElement;
823 type IntoIter = std::vec::IntoIter<StoreElement>;
824
825 fn into_iter(self) -> Self::IntoIter {
826 self.elements.into_iter()
827 }
828}
829
830impl<'a> IntoIterator for &'a ListStoreElementsResponse {
831 type Item = &'a StoreElement;
832 type IntoIter = std::slice::Iter<'a, StoreElement>;
833
834 fn into_iter(self) -> Self::IntoIter {
835 self.elements.iter()
836 }
837}
838
839impl<'a> IntoIterator for &'a mut ListStoreElementsResponse {
840 type Item = &'a mut StoreElement;
841 type IntoIter = std::slice::IterMut<'a, StoreElement>;
842
843 fn into_iter(self) -> Self::IntoIter {
844 self.elements.iter_mut()
845 }
846}
847
848#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
849#[serde(rename_all = "kebab-case")]
850pub struct AcquireStoreElementRequest {
851 pub id: StoreID,
852 pub selector: Bytes,
853}
854
855#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
856#[serde(rename_all = "kebab-case")]
857pub struct AcquireStoreElementResponse {
858 pub selector: StoreSelectorID,
859}
860
861#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
862#[serde(rename_all = "kebab-case")]
863pub struct CloseStoreElementRequest {
864 pub id: StoreID,
865 pub selector: StoreSelectorID,
866}
867
868#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
869#[serde(rename_all = "kebab-case")]
870pub struct AuthenticateStoreElementRequest {
871 pub id: StoreID,
872 pub selector: StoreSelectorID,
873 pub method: Bytes,
874 pub message: Option<Bytes>,
875}
876
877#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
878#[serde(rename_all = "kebab-case")]
879pub struct AuthenticateStoreElementResponse {
880 pub method: Bytes,
881 pub message: Option<Bytes>,
882}
883
884#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
885#[serde(rename_all = "kebab-case")]
886pub struct StoreElementBareRequest {
887 pub id: StoreID,
888 pub selector: StoreSelector,
889 pub kind: String,
890 pub needs_authentication: Option<bool>,
891 pub authentication_methods: Option<Vec<Bytes>>,
892 pub meta: Option<BTreeMap<Bytes, Value>>,
893}
894
895#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
896#[serde(rename_all = "kebab-case")]
897pub struct CreateStoreElementRequest<T> {
898 pub id: StoreID,
899 pub selector: StoreSelector,
900 pub kind: String,
901 pub needs_authentication: Option<bool>,
902 pub authentication_methods: Option<Vec<Bytes>>,
903 pub meta: Option<BTreeMap<Bytes, Value>>,
904 pub body: T,
905}
906
907#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
908#[serde(rename_all = "kebab-case")]
909pub struct DeleteStoreElementRequest {
910 pub id: StoreID,
911 pub selector: StoreSelector,
912}
913
914#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
915#[serde(rename_all = "kebab-case")]
916pub struct UpdateStoreElementRequest<T> {
917 pub id: StoreID,
918 pub selector: StoreSelector,
919 pub kind: String,
920 pub needs_authentication: Option<bool>,
921 pub authentication_methods: Option<Vec<Bytes>>,
922 pub meta: Option<BTreeMap<Bytes, Value>>,
923 pub body: T,
924}
925
926#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
927#[serde(rename_all = "kebab-case")]
928pub struct ReadStoreElementRequest {
929 pub id: StoreID,
930 pub selector: StoreSelector,
931}
932
933#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
934#[serde(rename_all = "kebab-case")]
935pub struct ReadStoreElementResponse<T> {
936 pub kind: String,
937 pub needs_authentication: Option<bool>,
938 pub authentication_methods: Option<Vec<Bytes>>,
939 pub meta: Option<BTreeMap<Bytes, Value>>,
940 pub body: T,
941}
942
943#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
944#[serde(rename_all = "kebab-case")]
945pub enum StoreSearchRecursionLevel {
946 Boolean(bool),
947 Levels(u32),
948}
949
950#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
951#[serde(rename_all = "kebab-case")]
952pub struct SearchStoreElementsBareRequest {
953 pub id: StoreID,
954 pub selector: StoreSelector,
955 pub recurse: StoreSearchRecursionLevel,
956 pub kind: Option<String>,
957}
958
959#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
960#[serde(rename_all = "kebab-case")]
961pub struct SearchStoreElementsRequest<T> {
962 pub id: StoreID,
963 pub selector: StoreSelector,
964 pub recurse: StoreSearchRecursionLevel,
965 pub kind: Option<String>,
966 pub body: Option<T>,
967}
968
969#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
970#[serde(rename_all = "kebab-case")]
971pub struct SearchStoreElementsResponse<T> {
972 pub elements: Vec<StoreElementWithBody<T>>,
973}
974
975impl<T> IntoIterator for SearchStoreElementsResponse<T> {
976 type Item = StoreElementWithBody<T>;
977 type IntoIter = std::vec::IntoIter<StoreElementWithBody<T>>;
978
979 fn into_iter(self) -> Self::IntoIter {
980 self.elements.into_iter()
981 }
982}
983
984impl<'a, T> IntoIterator for &'a SearchStoreElementsResponse<T> {
985 type Item = &'a StoreElementWithBody<T>;
986 type IntoIter = std::slice::Iter<'a, StoreElementWithBody<T>>;
987
988 fn into_iter(self) -> Self::IntoIter {
989 self.elements.iter()
990 }
991}
992
993impl<'a, T> IntoIterator for &'a mut SearchStoreElementsResponse<T> {
994 type Item = &'a mut StoreElementWithBody<T>;
995 type IntoIter = std::slice::IterMut<'a, StoreElementWithBody<T>>;
996
997 fn into_iter(self) -> Self::IntoIter {
998 self.elements.iter_mut()
999 }
1000}
1001
1002#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Ord, PartialOrd, Clone)]
1003#[serde(rename_all = "kebab-case")]
1004pub struct StoreElement {
1005 pub path: Bytes,
1006 pub id: Option<StoreSelectorID>,
1007 pub kind: String,
1008 pub needs_authentication: Option<bool>,
1009 pub authentication_methods: Option<Vec<Bytes>>,
1010 pub meta: Option<BTreeMap<Bytes, Value>>,
1011}
1012
1013#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
1014#[serde(rename_all = "kebab-case")]
1015pub struct StoreElementWithBody<T> {
1016 pub path: Bytes,
1017 pub id: Option<StoreSelectorID>,
1018 pub kind: String,
1019 pub needs_authentication: Option<bool>,
1020 pub authentication_methods: Option<Vec<Bytes>>,
1021 pub meta: Option<BTreeMap<Bytes, Value>>,
1022 pub body: T,
1023}
1024
1025impl<T> StoreElementWithBody<T> {
1026 pub fn new(elem: StoreElement, body: T) -> Self {
1027 Self {
1028 path: elem.path,
1029 id: elem.id,
1030 kind: elem.kind,
1031 needs_authentication: elem.needs_authentication,
1032 authentication_methods: elem.authentication_methods,
1033 meta: elem.meta,
1034 body,
1035 }
1036 }
1037}
1038
1039#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Ord, PartialOrd, Clone)]
1040#[serde(rename_all = "kebab-case")]
1041pub enum SearchStoreElementType {
1042 Literal(Value),
1043 Set(BTreeSet<SearchStoreElementType>),
1044 Sequence(Vec<SearchStoreElementType>),
1045 Any(()),
1047 None(()),
1048}
1049
1050#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone, Debug)]
1051#[serde(rename_all = "kebab-case")]
1052pub struct CredentialStoreSearchElement {
1053 pub username: SearchStoreElementType,
1054 pub secret: SearchStoreElementType,
1055 pub authtype: SearchStoreElementType,
1056 pub kind: SearchStoreElementType,
1057 pub protocol: SearchStoreElementType,
1058 pub host: SearchStoreElementType,
1059 pub title: SearchStoreElementType,
1060 pub description: SearchStoreElementType,
1061 pub path: SearchStoreElementType,
1062 pub service: SearchStoreElementType,
1063 pub extra: BTreeMap<String, SearchStoreElementType>,
1064 pub id: SearchStoreElementType,
1065}
1066
1067#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Ord, PartialOrd, Clone)]
1068#[serde(rename_all = "kebab-case")]
1069pub struct CredentialStoreLocation {
1070 pub protocol: Option<String>,
1071 pub host: Option<String>,
1072 pub port: Option<u16>,
1073 pub path: Option<String>,
1074}
1075
1076#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Ord, PartialOrd, Clone)]
1077#[serde(rename_all = "kebab-case")]
1078pub struct CredentialStoreElement {
1079 pub username: Option<Bytes>,
1080 pub secret: Option<Bytes>,
1081 pub authtype: Option<String>,
1082 #[serde(rename = "type")]
1083 pub kind: String,
1084 pub title: Option<String>,
1085 pub description: Option<String>,
1086 pub location: Vec<CredentialStoreLocation>,
1087 pub service: Option<String>,
1088 pub extra: BTreeMap<String, Value>,
1089 pub id: Bytes,
1090}
1091
1092#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Ord, PartialOrd, Clone)]
1093pub struct KeyboardInteractiveAuthenticationPrompt {
1094 pub prompt: String,
1095 pub echo: bool,
1096}
1097
1098#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Ord, PartialOrd, Clone)]
1099pub struct KeyboardInteractiveAuthenticationRequest {
1100 pub name: String,
1101 pub instruction: String,
1102 pub prompts: Vec<KeyboardInteractiveAuthenticationPrompt>,
1103}
1104
1105#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Ord, PartialOrd, Clone)]
1106pub struct KeyboardInteractiveAuthenticationResponse {
1107 pub responses: Vec<String>,
1108}
1109
1110#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
1111#[serde(rename_all = "kebab-case")]
1112pub struct ReadServerContextRequest {
1113 pub kind: String,
1114 pub id: Option<Bytes>,
1115 pub meta: Option<BTreeMap<Bytes, Value>>,
1116}
1117
1118#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
1119#[serde(rename_all = "kebab-case")]
1120pub struct ReadServerContextResponse {
1121 pub id: Option<Bytes>,
1122 pub meta: Option<BTreeMap<Bytes, Value>>,
1123}
1124
1125#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
1126#[serde(rename_all = "kebab-case")]
1127pub struct ReadServerContextResponseWithBody<T> {
1128 pub id: Option<Bytes>,
1129 pub meta: Option<BTreeMap<Bytes, Value>>,
1130 pub body: Option<T>,
1131}
1132
1133#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
1134#[serde(rename_all = "kebab-case")]
1135pub struct WriteServerContextRequest {
1136 pub kind: String,
1137 pub id: Option<Bytes>,
1138 pub meta: Option<BTreeMap<Bytes, Value>>,
1139}
1140
1141#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
1142#[serde(rename_all = "kebab-case")]
1143pub struct WriteServerContextRequestWithBody<T> {
1144 pub kind: String,
1145 pub id: Option<Bytes>,
1146 pub meta: Option<BTreeMap<Bytes, Value>>,
1147 pub body: Option<T>,
1148}
1149
1150#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
1151#[serde(rename_all = "kebab-case")]
1152pub struct WriteServerContextResponse {
1153 pub id: Option<Bytes>,
1154 pub meta: Option<BTreeMap<Bytes, Value>>,
1155}
1156
1157#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
1158#[serde(rename_all = "kebab-case")]
1159pub struct TemplateServerContextBody {
1160 pub senv: Option<BTreeMap<Bytes, Bytes>>,
1161 pub cenv: Option<BTreeMap<Bytes, Bytes>>,
1162 pub ctxsenv: Option<BTreeMap<Bytes, Bytes>>,
1163 pub args: Option<Vec<Bytes>>,
1164}
1165
1166#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Clone)]
1167#[serde(rename_all = "kebab-case")]
1168pub struct TemplateServerContextBodyWithBody<T> {
1169 pub senv: Option<BTreeMap<Bytes, Bytes>>,
1170 pub cenv: Option<BTreeMap<Bytes, Bytes>>,
1171 pub ctxsenv: Option<BTreeMap<Bytes, Bytes>>,
1172 pub args: Option<Vec<Bytes>>,
1173 pub body: Option<T>,
1174}
1175
1176#[derive(Hash, Debug, FromPrimitive, Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]
1177#[allow(non_camel_case_types)]
1178pub enum TerminalMode {
1179 VINTR = 1,
1180 VQUIT = 2,
1181 VERASE = 3,
1182 VKILL = 4,
1183 VEOF = 5,
1184 VEOL = 6,
1185 VEOL2 = 7,
1186 VSTART = 8,
1187 VSTOP = 9,
1188 VSUSP = 10,
1189 VDSUSP = 11,
1190 VREPRINT = 12,
1191 VWERASE = 13,
1192 VLNEXT = 14,
1193 VFLUSH = 15,
1194 VSWTCH = 16,
1195 VSTATUS = 17,
1196 VDISCARD = 18,
1197 IGNPAR = 30,
1198 PARMRK = 31,
1199 INPCK = 32,
1200 ISTRIP = 33,
1201 INLCR = 34,
1202 IGNCR = 35,
1203 ICRNL = 36,
1204 IUCLC = 37,
1205 IXON = 38,
1206 IXANY = 39,
1207 IXOFF = 40,
1208 IMAXBEL = 41,
1209 IUTF8 = 42,
1210 ISIG = 50,
1211 ICANON = 51,
1212 XCASE = 52,
1213 ECHO = 53,
1214 ECHOE = 54,
1215 ECHOK = 55,
1216 ECHONL = 56,
1217 NOFLSH = 57,
1218 TOSTOP = 58,
1219 IEXTEN = 59,
1220 ECHOCTL = 60,
1221 ECHOKE = 61,
1222 PENDIN = 62,
1223 OPOST = 70,
1224 OLCUC = 71,
1225 ONLCR = 72,
1226 OCRNL = 73,
1227 ONOCR = 74,
1228 ONLRET = 75,
1229 CS7 = 90,
1230 CS8 = 91,
1231 PARENB = 92,
1232 PARODD = 93,
1233 TTY_OP_ISPEED = 128,
1234 TTY_OP_OSPEED = 129,
1235 VMIN = 0x00010000,
1236 VTIME = 0x00010001,
1237}
1238
1239#[derive(Clone, Debug)]
1241pub struct Message {
1242 pub id: u32,
1243 pub kind: u32,
1244 pub message: Option<Bytes>,
1245}
1246
1247#[derive(Clone, Debug)]
1248pub struct Response {
1249 pub id: u32,
1250 pub code: u32,
1251 pub message: Option<Bytes>,
1252}
1253
1254#[derive(Default)]
1255pub struct ProtocolSerializer {}
1256
1257pub enum Data {
1258 Message(Message),
1259 Response(Response),
1260}
1261
1262#[derive(Clone, Debug, PartialEq, Eq, Ord, PartialOrd)]
1263pub enum ResponseValue<T: DeserializeOwned, U: DeserializeOwned> {
1264 Success(T),
1265 Continuation((u32, U)),
1266}
1267
1268impl ProtocolSerializer {
1269 const MAX_MESSAGE_SIZE: u32 = 0x00ffffff;
1270
1271 pub fn new() -> ProtocolSerializer {
1272 Self {}
1273 }
1274
1275 pub fn is_valid_size(&self, size: u32) -> bool {
1276 (8..=Self::MAX_MESSAGE_SIZE).contains(&size)
1277 }
1278
1279 pub fn serialize_header(&self, id: u32, next: u32, data_len: usize) -> Option<Bytes> {
1280 let size = data_len as u64 + 8;
1281 if size > Self::MAX_MESSAGE_SIZE as u64 {
1282 return None;
1283 }
1284 let mut b = BytesMut::with_capacity(size as usize);
1285 let size = size as u32;
1286 b.extend(&size.to_le_bytes());
1287 b.extend(&id.to_le_bytes());
1288 b.extend(&next.to_le_bytes());
1289 Some(b.into())
1290 }
1291
1292 pub fn serialize_message_simple(&self, msg: &Message) -> Option<Bytes> {
1293 let size = 8 + match &msg.message {
1294 Some(m) => m.len(),
1295 None => 0,
1296 };
1297 if size > Self::MAX_MESSAGE_SIZE as usize {
1298 return None;
1299 }
1300 let mut b = BytesMut::with_capacity(size);
1301 let size = size as u32;
1302 b.extend(&size.to_le_bytes());
1303 b.extend(&msg.id.to_le_bytes());
1304 b.extend(&msg.kind.to_le_bytes());
1305 if let Some(m) = &msg.message {
1306 b.extend(m);
1307 }
1308 Some(b.into())
1309 }
1310
1311 pub fn serialize_message_typed<S: Serialize>(&self, msg: &Message, obj: &S) -> Option<Bytes> {
1312 let mut v: Vec<u8> = Vec::with_capacity(12);
1313 v.extend(&0u32.to_le_bytes());
1315 v.extend(&msg.id.to_le_bytes());
1316 v.extend(&msg.kind.to_le_bytes());
1317 let mut cursor = std::io::Cursor::new(&mut v);
1318 let _ = cursor.seek(SeekFrom::End(0));
1319 if serde_cbor::to_writer(&mut cursor, obj).is_err() {
1320 return None;
1321 }
1322 let size = match u32::try_from(v.len()) {
1323 Ok(sz) if (4..=Self::MAX_MESSAGE_SIZE).contains(&sz) => sz - 4,
1324 _ => return None,
1325 };
1326 v[0..4].copy_from_slice(&size.to_le_bytes());
1327 Some(v.into())
1328 }
1329
1330 pub fn serialize_body<S: Serialize>(&self, obj: &S) -> Option<Bytes> {
1331 match serde_cbor::to_vec(obj) {
1332 Ok(m) => Some(m.into()),
1333 Err(_) => None,
1334 }
1335 }
1336
1337 pub fn serialize_response_simple(&self, resp: &Response) -> Option<Bytes> {
1338 let size = 8 + match &resp.message {
1339 Some(m) => m.len(),
1340 None => 0,
1341 };
1342 if size > Self::MAX_MESSAGE_SIZE as usize {
1343 return None;
1344 }
1345 let mut b = BytesMut::with_capacity(size);
1346 let size = size as u32;
1347 b.extend(&size.to_le_bytes());
1348 b.extend(&resp.id.to_le_bytes());
1349 b.extend(&resp.code.to_le_bytes());
1350 if let Some(m) = &resp.message {
1351 b.extend(m);
1352 }
1353 Some(b.into())
1354 }
1355
1356 pub fn serialize_response_typed<S: Serialize>(&self, msg: &Response, obj: &S) -> Option<Bytes> {
1357 let mut v: Vec<u8> = Vec::with_capacity(12);
1358 v.extend(&0u32.to_le_bytes());
1360 v.extend(&msg.id.to_le_bytes());
1361 v.extend(&msg.code.to_le_bytes());
1362 let mut cursor = std::io::Cursor::new(&mut v);
1363 let _ = cursor.seek(SeekFrom::End(0));
1364 if serde_cbor::to_writer(&mut cursor, obj).is_err() {
1365 return None;
1366 }
1367 let size = match u32::try_from(v.len()) {
1368 Ok(sz) if (4..=Self::MAX_MESSAGE_SIZE).contains(&sz) => sz - 4,
1369 _ => return None,
1370 };
1371 v[0..4].copy_from_slice(&size.to_le_bytes());
1372 Some(v.into())
1373 }
1374
1375 pub fn deserialize_data(
1376 &self,
1377 config: &Config,
1378 header: &[u8],
1379 body: Bytes,
1380 ) -> Result<Data, Error> {
1381 fn is_sender(config: &Config, id: u32) -> bool {
1382 let sender_mask = if config.is_server() { 0x80000000 } else { 0 };
1383 (id & 0x80000000) == sender_mask
1384 }
1385 let _size: u32 = u32::from_le_bytes(header[0..4].try_into().unwrap());
1386 let id: u32 = u32::from_le_bytes(header[4..8].try_into().unwrap());
1387 let arg: u32 = u32::from_le_bytes(header[8..12].try_into().unwrap());
1388 if is_sender(config, id) {
1389 Ok(Data::Response(Response {
1390 id,
1391 code: arg,
1392 message: if body.is_empty() { None } else { Some(body) },
1393 }))
1394 } else {
1395 Ok(Data::Message(Message {
1396 id,
1397 kind: arg,
1398 message: if body.is_empty() { None } else { Some(body) },
1399 }))
1400 }
1401 }
1402
1403 pub fn deserialize_message_typed<'a, D: Deserialize<'a>>(
1404 &self,
1405 msg: &'a Message,
1406 ) -> Result<Option<D>, Error> {
1407 match &msg.message {
1408 Some(body) => match serde_cbor::from_slice(body) {
1409 Ok(decoded) => Ok(Some(decoded)),
1410 Err(_) => Err(Error {
1411 code: ResponseCode::Invalid,
1412 body: None,
1413 }),
1414 },
1415 None => Ok(None),
1416 }
1417 }
1418
1419 pub fn deserialize_response_typed<D1: DeserializeOwned, D2: DeserializeOwned>(
1420 &self,
1421 resp: &Response,
1422 ) -> Result<Option<ResponseValue<D1, D2>>, Error> {
1423 if resp.code == ResponseCode::Success as u32 {
1424 match &resp.message {
1425 Some(body) => match serde_cbor::from_slice(body) {
1426 Ok(decoded) => Ok(Some(ResponseValue::Success(decoded))),
1427 Err(_) => Err(Error {
1428 code: ResponseCode::Invalid,
1429 body: None,
1430 }),
1431 },
1432 None => Ok(None),
1433 }
1434 } else if resp.code == ResponseCode::Continuation as u32 {
1435 match &resp.message {
1436 Some(body) => match serde_cbor::from_slice(body) {
1437 Ok(decoded) => Ok(Some(ResponseValue::Continuation((resp.id, decoded)))),
1438 Err(_) => Err(Error {
1439 code: ResponseCode::Invalid,
1440 body: None,
1441 }),
1442 },
1443 None => Ok(None),
1444 }
1445 } else {
1446 match &resp.message {
1447 Some(body) => match serde_cbor::from_slice(body) {
1448 Ok(decoded) => Err(Error {
1449 code: ResponseCode::from_u32(resp.code),
1450 body: Some(decoded),
1451 }),
1452 Err(_) => Err(Error {
1453 code: ResponseCode::from_u32(resp.code),
1454 body: None,
1455 }),
1456 },
1457 None => Err(Error {
1458 code: ResponseCode::from_u32(resp.code),
1459 body: None,
1460 }),
1461 }
1462 }
1463 }
1464}
1465
1466#[cfg(test)]
1467mod tests {
1468 use super::{
1469 ChannelID, Empty, Message, ProtocolSerializer, Response, ResponseValue,
1470 SearchStoreElementType, StoreID, StoreSelector, StoreSelectorID,
1471 };
1472 use bytes::Bytes;
1473 use serde::{de::DeserializeOwned, Deserialize, Serialize};
1474 use serde_cbor::Value;
1475 use std::convert::TryFrom;
1476 use std::fmt::Debug;
1477
1478 #[test]
1479 fn serialize_header() {
1480 let cases: &[(u32, u32, usize, Option<&[u8]>)] = &[
1481 (
1482 0x01234567,
1483 0xffeeddcc,
1484 0x00000000,
1485 Some(b"\x08\x00\x00\x00\x67\x45\x23\x01\xcc\xdd\xee\xff"),
1486 ),
1487 (
1488 0x87654321,
1489 0x00000000,
1490 0x00000099,
1491 Some(b"\xa1\x00\x00\x00\x21\x43\x65\x87\x00\x00\x00\x00"),
1492 ),
1493 (
1494 0x87654321,
1495 0x00000000,
1496 0x00fffff7,
1497 Some(b"\xff\xff\xff\x00\x21\x43\x65\x87\x00\x00\x00\x00"),
1498 ),
1499 (0x87654321, 0x00000000, 0x00fffff8, None),
1500 ];
1501 let ser = ProtocolSerializer::new();
1502 for (id, next, data_len, response) in cases {
1503 assert_eq!(
1504 ser.serialize_header(*id, *next, *data_len).as_deref(),
1505 *response
1506 );
1507 }
1508 }
1509
1510 fn assert_encode<'a, S: Serialize + Deserialize<'a> + Debug + Clone + PartialEq>(
1511 desc: &str,
1512 s: &S,
1513 seq: &[u8],
1514 ) {
1515 let id = 0x01234567u32;
1516 let next = 0xffeeddccu32;
1517 let mut header = [0u8; 12];
1518
1519 header[0..4].copy_from_slice(&u32::try_from(seq.len() + 8).unwrap().to_le_bytes());
1520 header[4..8].copy_from_slice(&id.to_le_bytes());
1521 header[8..12].copy_from_slice(&next.to_le_bytes());
1522
1523 let ser = ProtocolSerializer::new();
1524 let msg = Message {
1525 id,
1526 kind: next,
1527 message: Some(Bytes::copy_from_slice(seq)),
1528 };
1529
1530 let res = ser.serialize_header(id, next, seq.len()).unwrap();
1531 assert_eq!(&res, &header as &[u8], "header: {}", desc);
1532
1533 let res = ser.serialize_message_simple(&msg).unwrap();
1534 assert_eq!(res[0..12], header, "simple header: {}", desc);
1535 assert_eq!(res[12..], *seq, "simple body: {}", desc);
1536
1537 let res = ser.serialize_body(s).unwrap();
1538 assert_eq!(res, *seq, "body: {}", desc);
1539
1540 let msg = Message {
1541 id,
1542 kind: next,
1543 message: None,
1544 };
1545 let res = ser.serialize_message_typed(&msg, s).unwrap();
1546 assert_eq!(res[0..12], header, "typed header: {}", desc);
1547 assert_eq!(res[12..], *seq, "typed body: {}", desc);
1548 }
1549
1550 fn assert_round_trip<S: Serialize + DeserializeOwned + Debug + Clone + PartialEq>(
1551 desc: &str,
1552 s: &S,
1553 seq: &[u8],
1554 ) {
1555 assert_encode(desc, s, seq);
1556 assert_decode(desc, s, seq);
1557 }
1558
1559 fn assert_decode<S: Serialize + DeserializeOwned + Debug + Clone + PartialEq>(
1560 desc: &str,
1561 s: &S,
1562 seq: &[u8],
1563 ) {
1564 let id = 0x01234567u32;
1565 let next = 0u32;
1566 let mut header = [0u8; 12];
1567
1568 header[0..4].copy_from_slice(&u32::try_from(seq.len() + 8).unwrap().to_le_bytes());
1569 header[4..8].copy_from_slice(&id.to_le_bytes());
1570 header[8..12].copy_from_slice(&next.to_le_bytes());
1571
1572 let body = Bytes::copy_from_slice(seq);
1573
1574 let ser = ProtocolSerializer::new();
1575 let resp = Response {
1576 id,
1577 code: next,
1578 message: Some(body.clone()),
1579 };
1580
1581 let mut full_msg: Vec<u8> = header.into();
1582 full_msg.extend(seq);
1583
1584 let res = ser.deserialize_response_typed::<S, Empty>(&resp);
1585 assert_eq!(
1586 res.unwrap().unwrap(),
1587 ResponseValue::Success(s.clone()),
1588 "deserialize typed response: {}",
1589 desc
1590 );
1591 }
1592
1593 #[test]
1594 fn serialize_basic_types() {
1595 assert_round_trip("0u32", &0u32, b"\x00");
1596 assert_round_trip("all ones u32", &0xfedcba98u32, b"\x1a\xfe\xdc\xba\x98");
1597 assert_round_trip(
1598 "simple Bytes",
1599 &Bytes::from(b"Hello, world!\n" as &'static [u8]),
1600 b"\x4eHello, world!\n",
1601 );
1602 assert_encode("simple &str", &"Hello, world!\n", b"\x6eHello, world!\n");
1603 assert_round_trip(
1604 "simple String",
1605 &String::from("Hello, world!\n"),
1606 b"\x6eHello, world!\n",
1607 );
1608 }
1609
1610 #[test]
1611 fn serialize_encoded_types() {
1612 assert_round_trip("ChannelID 0", &ChannelID(0), b"\x00");
1613 assert_round_trip(
1614 "ChannelID all ones u32",
1615 &ChannelID(0xfedcba98u32),
1616 b"\x1a\xfe\xdc\xba\x98",
1617 );
1618 assert_round_trip("StoreID 0", &StoreID(0), b"\x00");
1619 assert_round_trip(
1620 "StoreID pattern",
1621 &StoreID(0xfedcba98u32),
1622 b"\x1a\xfe\xdc\xba\x98",
1623 );
1624 assert_round_trip("StoreSelectorID 0", &StoreSelectorID(0), b"\x00");
1625 assert_round_trip(
1626 "StoreSelectorID pattern",
1627 &StoreSelectorID(0xfedcba98u32),
1628 b"\x1a\xfe\xdc\xba\x98",
1629 );
1630 assert_round_trip(
1631 "StoreSelector path",
1632 &StoreSelector::Path(Bytes::from(b"/dev/null" as &[u8])),
1633 b"\xa1\x64path\x49/dev/null",
1634 );
1635 assert_round_trip(
1636 "StoreSelector ID",
1637 &StoreSelector::ID(StoreSelectorID(0xfedcba98u32)),
1638 b"\xa1\x62id\x1a\xfe\xdc\xba\x98",
1639 );
1640 assert_round_trip(
1641 "SearchStoreElementType literal text",
1642 &SearchStoreElementType::Literal(Value::Text(String::from("abc123"))),
1643 b"\xa1\x67literal\x66abc123",
1644 );
1645 assert_round_trip(
1646 "SearchStoreElementType literal bytes",
1647 &SearchStoreElementType::Literal(Value::Bytes("abc123".into())),
1648 b"\xa1\x67literal\x46abc123",
1649 );
1650 assert_round_trip(
1651 "SearchStoreElementType literal null",
1652 &SearchStoreElementType::Literal(Value::Null),
1653 b"\xa1\x67literal\xf6",
1654 );
1655 assert_round_trip(
1656 "SearchStoreElementType any",
1657 &SearchStoreElementType::Any(()),
1658 b"\xa1\x63any\xf6",
1659 );
1660 assert_round_trip(
1661 "SearchStoreElementType none",
1662 &SearchStoreElementType::None(()),
1663 b"\xa1\x64none\xf6",
1664 );
1665 }
1666
1667 #[test]
1668 fn serialize_requests() {
1669 assert_round_trip(
1670 "CreateExtensionRangeRequest with no second part",
1671 &super::CreateExtensionRangeRequest {
1672 extension: (
1673 Bytes::from(b"foobar@test.ns.crustytoothpaste.net" as &[u8]),
1674 None,
1675 ),
1676 count: 5,
1677 },
1678 b"\xa2\x69extension\x82\x58\x23foobar@test.ns.crustytoothpaste.net\xf6\x65count\x05",
1679 );
1680 assert_round_trip(
1681 "CreateExtensionRangeRequest with second part",
1682 &super::CreateExtensionRangeRequest {
1683 extension: (
1684 Bytes::from(b"foobar@test.ns.crustytoothpaste.net" as &[u8]),
1685 Some(Bytes::from(b"v1" as &[u8])),
1686 ),
1687 count: 5,
1688 },
1689 b"\xa2\x69extension\x82\x58\x23foobar@test.ns.crustytoothpaste.net\x42v1\x65count\x05",
1690 );
1691 }
1692
1693 #[test]
1694 fn deserialize_requests() {
1695 assert_decode(
1696 "CreateExtensionRangeRequest with extension field",
1697 &super::CreateExtensionRangeRequest {
1698 extension: (
1699 Bytes::from(b"foobar@test.ns.crustytoothpaste.net" as &[u8]),
1700 None,
1701 ),
1702 count: 5,
1703 },
1704 b"\xa3\x69extension\x82\x58\x23foobar@test.ns.crustytoothpaste.net\xf6\x58\x26extension@test.ns.crustytoothpaste.net\xf5\x65count\x05",
1705 );
1706 }
1707
1708 #[test]
1709 fn deserialize_requests_rw_compatible() {
1710 #[derive(Serialize, Deserialize, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
1711 #[serde(rename_all = "kebab-case")]
1712 struct ReadChannelLegacyRequest {
1713 pub id: ChannelID,
1714 pub selector: u32,
1715 pub count: u64,
1716 }
1717
1718 let cases: &[(&[u8], &str)] = &[
1719 (b"\xa3\x62id\x00\x68selector\x02\x65count\x1a\xfe\xdc\xba\x98", "legacy"),
1720 (b"\xa6\x62id\x00\x68selector\x02\x65count\x1a\xfe\xdc\xba\x98\x6bstream-sync\xf6\x68blocking\xf6\x68complete\xf4", "modern"),
1721 ];
1722 for (b, desc) in cases {
1723 assert_decode(
1724 &format!("ReadChannelRequest without blocking I/O: {}", desc),
1725 &super::ReadChannelRequest {
1726 id: ChannelID(0),
1727 selector: 2,
1728 count: 0xfedcba98,
1729 stream_sync: None,
1730 blocking: None,
1731 complete: false,
1732 },
1733 b,
1734 );
1735 assert_decode(
1736 &format!("ReadChannelRequest (legacy): {}", desc),
1737 &ReadChannelLegacyRequest {
1738 id: ChannelID(0),
1739 selector: 2,
1740 count: 0xfedcba98,
1741 },
1742 b,
1743 );
1744 }
1745
1746 #[derive(Serialize, Deserialize, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
1747 #[serde(rename_all = "kebab-case")]
1748 struct WriteChannelLegacyRequest {
1749 pub id: ChannelID,
1750 pub selector: u32,
1751 pub bytes: Bytes,
1752 }
1753
1754 let cases: &[(&[u8], &str)] = &[
1755 (b"\xa3\x62id\x00\x68selector\x02\x65bytes\x44\xff\xfe\xc2\xa9", "legacy"),
1756 (b"\xa5\x62id\x00\x68selector\x02\x65bytes\x44\xff\xfe\xc2\xa9\x6bstream-sync\xf6\x68blocking\xf6", "modern"),
1757 ];
1758 for (b, desc) in cases {
1759 assert_decode(
1760 &format!("WriteChannelRequest without blocking I/O: {}", desc),
1761 &super::WriteChannelRequest {
1762 id: ChannelID(0),
1763 selector: 2,
1764 bytes: vec![0xffu8, 0xfe, 0xc2, 0xa9].into(),
1765 stream_sync: None,
1766 blocking: None,
1767 },
1768 b,
1769 );
1770 assert_decode(
1771 &format!("WriteChannelRequest (legacy): {}", desc),
1772 &WriteChannelLegacyRequest {
1773 id: ChannelID(0),
1774 selector: 2,
1775 bytes: vec![0xffu8, 0xfe, 0xc2, 0xa9].into(),
1776 },
1777 b,
1778 );
1779 }
1780 }
1781}