nwep/role.rs
1use crate::ffi;
2use std::ffi::{CStr, CString};
3use std::fmt;
4
5/// `ServerRole` describes the functional role of an NWEP server node.
6///
7/// The role affects how the C library routes incoming requests internally:
8/// certain path prefixes are intercepted and handled by built-in subsystems
9/// rather than dispatched to application-level handlers. A server built with
10/// the Rust bindings must choose a role at construction time via
11/// `ServerBuilder::role`.
12///
13/// The `Default` implementation returns [`ServerRole::Regular`], which is the
14/// appropriate choice for application-level servers.
15#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
16pub enum ServerRole {
17 /// `Regular` identifies a standard application server.
18 ///
19 /// All incoming requests are dispatched to the application's registered
20 /// handlers. No paths are intercepted by the library. This is the default
21 /// role and should be used for all nodes that do not serve trust-log or
22 /// anchor functions.
23 #[default]
24 Regular,
25
26 /// `LogServer` identifies a node that hosts the distributed Merkle
27 /// identity log.
28 ///
29 /// In addition to application handlers, a `LogServer` intercepts all
30 /// requests whose path begins with `/log/` and routes them to the C
31 /// library's built-in log management subsystem. These paths handle log
32 /// entry submission, Merkle proof retrieval, and checkpoint synchronization.
33 ///
34 /// Only designate a node as `LogServer` if it has been provisioned with
35 /// persistent log storage and configured as a trust authority in the
36 /// network's root anchoring document.
37 LogServer,
38
39 /// `Anchor` identifies a BLS threshold signing authority node.
40 ///
41 /// An `Anchor` intercepts all requests whose path begins with
42 /// `/checkpoint/` and routes them to the C library's built-in BLS
43 /// checkpoint subsystem. Anchor nodes hold a BLS private key share and
44 /// participate in threshold signing rounds to produce periodic checkpoints
45 /// over the Merkle log root.
46 ///
47 /// The network requires at least [`crate::types::DEFAULT_ANCHOR_THRESHOLD`]
48 /// functioning anchor nodes to ratify a checkpoint. Anchor nodes are
49 /// registered in the trust root and their BLS public keys are well-known.
50 Anchor,
51}
52
53impl ServerRole {
54 /// `from_str` parses a role string (as advertised in the `roles` header)
55 /// and returns the corresponding [`ServerRole`] variant.
56 ///
57 /// The parsing is delegated to the C library. Unrecognized strings map to
58 /// [`ServerRole::Regular`], which is the safe default.
59 ///
60 /// # Example
61 ///
62 /// ```rust
63 /// use nwep::role::ServerRole;
64 ///
65 /// assert_eq!(ServerRole::from_str("regular"), ServerRole::Regular);
66 /// assert_eq!(ServerRole::from_str("log_server"), ServerRole::LogServer);
67 /// assert_eq!(ServerRole::from_str("anchor"), ServerRole::Anchor);
68 /// assert_eq!(ServerRole::from_str("unknown"), ServerRole::Regular);
69 /// ```
70 pub fn from_str(s: &str) -> Self {
71 let c = CString::new(s).unwrap_or_default();
72 let r = unsafe { ffi::nwep_role_from_str(c.as_ptr()) };
73 match r {
74 ffi::nwep_server_role_NWEP_ROLE_LOG_SERVER => ServerRole::LogServer,
75 ffi::nwep_server_role_NWEP_ROLE_ANCHOR => ServerRole::Anchor,
76 _ => ServerRole::Regular,
77 }
78 }
79
80 /// `as_str` returns the canonical lowercase wire-format string for this
81 /// role.
82 ///
83 /// The string is retrieved from the C library's string table and is valid
84 /// for the lifetime of the process. It is the same value that appears in
85 /// the `roles` header of a `connect` response.
86 ///
87 /// # Example
88 ///
89 /// ```rust
90 /// use nwep::role::ServerRole;
91 ///
92 /// assert_eq!(ServerRole::Regular.as_str(), "regular");
93 /// assert_eq!(ServerRole::LogServer.as_str(), "log_server");
94 /// assert_eq!(ServerRole::Anchor.as_str(), "anchor");
95 /// ```
96 pub fn as_str(&self) -> &'static str {
97 let r = match self {
98 ServerRole::Regular => ffi::nwep_server_role_NWEP_ROLE_REGULAR,
99 ServerRole::LogServer => ffi::nwep_server_role_NWEP_ROLE_LOG_SERVER,
100 ServerRole::Anchor => ffi::nwep_server_role_NWEP_ROLE_ANCHOR,
101 };
102 unsafe {
103 let ptr = ffi::nwep_role_to_str(r);
104 if ptr.is_null() {
105 "regular"
106 } else {
107 CStr::from_ptr(ptr).to_str().unwrap_or("regular")
108 }
109 }
110 }
111
112 /// `to_ffi` converts this [`ServerRole`] to the raw `nwep_server_role`
113 /// integer discriminant expected by C library functions.
114 #[allow(dead_code)]
115 pub(crate) fn to_ffi(&self) -> ffi::nwep_server_role {
116 match self {
117 ServerRole::Regular => ffi::nwep_server_role_NWEP_ROLE_REGULAR,
118 ServerRole::LogServer => ffi::nwep_server_role_NWEP_ROLE_LOG_SERVER,
119 ServerRole::Anchor => ffi::nwep_server_role_NWEP_ROLE_ANCHOR,
120 }
121 }
122}
123
124impl fmt::Display for ServerRole {
125 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126 f.write_str(self.as_str())
127 }
128}
129
130impl From<ffi::nwep_server_role> for ServerRole {
131 fn from(r: ffi::nwep_server_role) -> Self {
132 match r {
133 ffi::nwep_server_role_NWEP_ROLE_LOG_SERVER => ServerRole::LogServer,
134 ffi::nwep_server_role_NWEP_ROLE_ANCHOR => ServerRole::Anchor,
135 _ => ServerRole::Regular,
136 }
137 }
138}