openvpn_mgmt_codec/client_event.rs
1use std::fmt;
2
3/// The sub-type of a `>CLIENT:` notification.
4#[derive(Debug, Clone, PartialEq, Eq)]
5pub enum ClientEvent {
6 /// A new client is connecting (`>CLIENT:CONNECT`).
7 Connect,
8
9 /// An existing client is re-authenticating (`>CLIENT:REAUTH`).
10 Reauth,
11
12 /// A client connection has been fully established (`>CLIENT:ESTABLISHED`).
13 Established,
14
15 /// A client has disconnected (`>CLIENT:DISCONNECT`).
16 Disconnect,
17
18 /// A client challenge-response (`>CLIENT:CR_RESPONSE,{CID},{KID},{base64}`).
19 ///
20 /// The base64-encoded response is carried inline because it appears as
21 /// the third comma-separated field on the header line (after CID and KID),
22 /// not in the ENV block. Both cedws/openvpn-mgmt-go and
23 /// jkroepke/openvpn-auth-oauth2 handle this as a distinct event type.
24 CrResponse(String),
25
26 /// An unrecognized event type (forward compatibility).
27 Custom(String),
28}
29
30impl ClientEvent {
31 /// Parse a wire event string into a typed variant.
32 ///
33 /// Note: `CR_RESPONSE` is handled separately in the codec's CLIENT
34 /// parser because it carries an extra trailing field (the base64
35 /// response). This method maps it to [`Custom`](Self::Custom) as a
36 /// fallback; the codec never calls `parse("CR_RESPONSE")`.
37 pub(crate) fn parse(s: &str) -> Self {
38 match s {
39 "CONNECT" => Self::Connect,
40 "REAUTH" => Self::Reauth,
41 "ESTABLISHED" => Self::Established,
42 "DISCONNECT" => Self::Disconnect,
43 other => Self::Custom(other.to_string()),
44 }
45 }
46}
47
48impl fmt::Display for ClientEvent {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 match self {
51 Self::Connect => f.write_str("CONNECT"),
52 Self::Reauth => f.write_str("REAUTH"),
53 Self::Established => f.write_str("ESTABLISHED"),
54 Self::Disconnect => f.write_str("DISCONNECT"),
55 Self::CrResponse(_) => f.write_str("CR_RESPONSE"),
56 Self::Custom(s) => f.write_str(s),
57 }
58 }
59}