zbus/connection/handshake/
command.rs
1use std::{fmt, str::FromStr};
2
3use crate::{AuthMechanism, Error, Guid, OwnedGuid, Result};
4
5#[derive(Debug)]
10#[allow(clippy::upper_case_acronyms)]
11pub(super) enum Command {
12 Auth(Option<AuthMechanism>, Option<Vec<u8>>),
13 Cancel,
14 Begin,
15 Data(Option<Vec<u8>>),
16 Error(String),
17 NegotiateUnixFD,
18 Rejected(Vec<AuthMechanism>),
19 Ok(OwnedGuid),
20 AgreeUnixFD,
21}
22
23impl From<&Command> for Vec<u8> {
24 fn from(c: &Command) -> Self {
25 c.to_string().into()
26 }
27}
28
29impl fmt::Display for Command {
30 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31 match self {
32 Command::Auth(mech, resp) => match (mech, resp) {
33 (Some(mech), Some(resp)) => write!(f, "AUTH {mech} {}", hex::encode(resp)),
34 (Some(mech), None) => write!(f, "AUTH {mech}"),
35 _ => write!(f, "AUTH"),
36 },
37 Command::Cancel => write!(f, "CANCEL"),
38 Command::Begin => write!(f, "BEGIN"),
39 Command::Data(data) => match data {
40 None => write!(f, "DATA"),
41 Some(data) => write!(f, "DATA {}", hex::encode(data)),
42 },
43 Command::Error(expl) => write!(f, "ERROR {expl}"),
44 Command::NegotiateUnixFD => write!(f, "NEGOTIATE_UNIX_FD"),
45 Command::Rejected(mechs) => {
46 write!(
47 f,
48 "REJECTED {}",
49 mechs
50 .iter()
51 .map(|m| m.to_string())
52 .collect::<Vec<_>>()
53 .join(" ")
54 )
55 }
56 Command::Ok(guid) => write!(f, "OK {guid}"),
57 Command::AgreeUnixFD => write!(f, "AGREE_UNIX_FD"),
58 }
59 }
60}
61
62impl FromStr for Command {
63 type Err = Error;
64
65 fn from_str(s: &str) -> Result<Self> {
66 let mut words = s.split_ascii_whitespace();
67 let cmd = match words.next() {
68 Some("AUTH") => {
69 let mech = if let Some(m) = words.next() {
70 Some(m.parse()?)
71 } else {
72 None
73 };
74 let resp = match words.next() {
75 Some(resp) => Some(hex::decode(resp)?),
76 None => None,
77 };
78 Command::Auth(mech, resp)
79 }
80 Some("CANCEL") => Command::Cancel,
81 Some("BEGIN") => Command::Begin,
82 Some("DATA") => {
83 let data = match words.next() {
84 Some(data) => Some(hex::decode(data)?),
85 None => None,
86 };
87
88 Command::Data(data)
89 }
90 Some("ERROR") => Command::Error(s.into()),
91 Some("NEGOTIATE_UNIX_FD") => Command::NegotiateUnixFD,
92 Some("REJECTED") => {
93 let mechs = words.map(|m| m.parse()).collect::<Result<_>>()?;
94 Command::Rejected(mechs)
95 }
96 Some("OK") => {
97 let guid = words
98 .next()
99 .ok_or_else(|| Error::Handshake("Missing OK server GUID!".into()))?;
100 Command::Ok(Guid::from_str(guid)?.into())
101 }
102 Some("AGREE_UNIX_FD") => Command::AgreeUnixFD,
103 _ => return Err(Error::Handshake(format!("Unknown command: {s}"))),
104 };
105 Ok(cmd)
106 }
107}