zbus/connection/handshake/
command.rs1use std::{borrow::Cow, fmt, str::FromStr};
2
3use crate::{conn::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(Cow<'static, str>),
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) => write!(f, "REJECTED {mechs}"),
46 Command::Ok(guid) => write!(f, "OK {guid}"),
47 Command::AgreeUnixFD => write!(f, "AGREE_UNIX_FD"),
48 }
49 }
50}
51
52impl FromStr for Command {
53 type Err = Error;
54
55 fn from_str(s: &str) -> Result<Self> {
56 let mut words = s.split_ascii_whitespace();
57 let cmd = match words.next() {
58 Some("AUTH") => {
59 let mech = if let Some(m) = words.next() {
60 Some(m.parse()?)
61 } else {
62 None
63 };
64 let resp = match words.next() {
65 Some(resp) => Some(hex::decode(resp)?),
66 None => None,
67 };
68 Command::Auth(mech, resp)
69 }
70 Some("CANCEL") => Command::Cancel,
71 Some("BEGIN") => Command::Begin,
72 Some("DATA") => {
73 let data = match words.next() {
74 Some(data) => Some(hex::decode(data)?),
75 None => None,
76 };
77
78 Command::Data(data)
79 }
80 Some("ERROR") => Command::Error(s.into()),
81 Some("NEGOTIATE_UNIX_FD") => Command::NegotiateUnixFD,
82 Some("REJECTED") => {
83 let mechs = words.collect::<Vec<_>>().join(" ").into();
84 Command::Rejected(mechs)
85 }
86 Some("OK") => {
87 let guid = words
88 .next()
89 .ok_or_else(|| Error::Handshake("Missing OK server GUID!".into()))?;
90 Command::Ok(Guid::from_str(guid)?.into())
91 }
92 Some("AGREE_UNIX_FD") => Command::AgreeUnixFD,
93 _ => return Err(Error::Handshake(format!("Unknown command: {s}"))),
94 };
95 Ok(cmd)
96 }
97}
98
99impl From<hex::FromHexError> for Error {
100 fn from(e: hex::FromHexError) -> Self {
101 Error::Handshake(format!("Invalid hexcode: {e}"))
102 }
103}