1pub mod benchmark;
21mod client;
22pub mod error;
23mod server;
24pub mod tcp;
25
26pub use client::*;
27use serde_json::json;
28pub use server::*;
29
30use error::WorterbuchResult;
31use serde::{Deserialize, Serialize, de::DeserializeOwned};
32use serde_repr::*;
33use sha2::{Digest, Sha256};
34use std::{fmt, ops::Deref};
35
36pub const SYSTEM_TOPIC_ROOT: &str = "$SYS";
37pub const SYSTEM_TOPIC_ROOT_PREFIX: &str = "$SYS/";
38pub const SYSTEM_TOPIC_CLIENTS: &str = "clients";
39pub const SYSTEM_TOPIC_VERSION: &str = "version";
40pub const SYSTEM_TOPIC_LICENSE: &str = "license";
41pub const SYSTEM_TOPIC_SOURCES: &str = "source-code";
42pub const SYSTEM_TOPIC_SUBSCRIPTIONS: &str = "subscriptions";
43pub const SYSTEM_TOPIC_CLIENTS_PROTOCOL: &str = "protocol";
44pub const SYSTEM_TOPIC_CLIENTS_ADDRESS: &str = "address";
45pub const SYSTEM_TOPIC_LAST_WILL: &str = "lastWill";
46pub const SYSTEM_TOPIC_GRAVE_GOODS: &str = "graveGoods";
47pub const SYSTEM_TOPIC_CLIENT_NAME: &str = "clientName";
48pub const SYSTEM_TOPIC_SUPPORTED_PROTOCOL_VERSION: &str = "protocolVersion";
49pub const SYSTEM_TOPIC_MODE: &str = "mode";
50
51pub type TransactionId = u64;
52pub type RequestPattern = String;
53pub type RequestPatterns = Vec<RequestPattern>;
54pub type Key = String;
55pub type Value = serde_json::Value;
56pub type KeyValuePairs = Vec<KeyValuePair>;
57pub type TypedKeyValuePairs<T> = Vec<TypedKeyValuePair<T>>;
58pub type MetaData = String;
59pub type Path = String;
60pub type ProtocolVersionSegment = u32;
61pub type ProtocolVersions = Vec<ProtocolVersion>;
62pub type LastWill = KeyValuePairs;
63pub type GraveGoods = RequestPatterns;
64pub type UniqueFlag = bool;
65pub type LiveOnlyFlag = bool;
66pub type AuthToken = String;
67pub type CasVersion = u64;
68
69#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
70#[serde(rename_all = "camelCase")]
71pub enum Privilege {
72 Read,
73 Write,
74 Delete,
75}
76
77impl fmt::Display for Privilege {
78 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79 match self {
80 Privilege::Read => "read".fmt(f),
81 Privilege::Write => "write".fmt(f),
82 Privilege::Delete => "delete".fmt(f),
83 }
84 }
85}
86
87#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize_repr, Deserialize_repr)]
88#[repr(u8)]
89pub enum ErrorCode {
90 IllegalWildcard = 0b00000000,
91 IllegalMultiWildcard = 0b00000001,
92 MultiWildcardAtIllegalPosition = 0b00000010,
93 IoError = 0b00000011,
94 SerdeError = 0b00000100,
95 NoSuchValue = 0b00000101,
96 NotSubscribed = 0b00000110,
97 ProtocolNegotiationFailed = 0b00000111,
98 InvalidServerResponse = 0b00001000,
99 ReadOnlyKey = 0b00001001,
100 AuthorizationFailed = 0b00001010,
101 AuthorizationRequired = 0b00001011,
102 AlreadyAuthorized = 0b00001100,
103 MissingValue = 0b00001101,
104 Unauthorized = 0b00001110,
105 NoPubStream = 0b00001111,
106 NotLeader = 0b00010000,
107 Cas = 0b00010001,
108 CasVersionMismatch = 0b00010010,
109 NotImplemented = 0b00010011,
110 Other = 0b11111111,
111}
112
113impl fmt::Display for ErrorCode {
114 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115 (self.to_owned() as u8).fmt(f)
116 }
117}
118
119#[macro_export]
120macro_rules! topic {
121 ($( $x:expr ),+ ) => {
122 {
123 let mut segments = Vec::new();
124 $(
125 segments.push($x.to_string());
126 )+
127 segments.join("/")
128 }
129 };
130}
131
132pub type Version = String;
133
134#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
135pub struct ProtocolVersion(ProtocolVersionSegment, ProtocolVersionSegment);
136
137impl ProtocolVersion {
138 pub const fn new(major: ProtocolVersionSegment, minor: ProtocolVersionSegment) -> Self {
139 Self(major, minor)
140 }
141
142 pub const fn major(&self) -> ProtocolVersionSegment {
143 self.0
144 }
145
146 pub const fn minor(&self) -> ProtocolVersionSegment {
147 self.1
148 }
149
150 pub fn is_compatible_with_server(&self, server_version: &ProtocolVersion) -> bool {
151 self.major() == server_version.major() && self.minor() <= server_version.minor()
152 }
153
154 pub fn is_compatible_with_client_version(&self, client_version: &ProtocolVersion) -> bool {
155 self.major() == client_version.major() && self.minor() >= client_version.minor()
156 }
157}
158
159impl fmt::Display for ProtocolVersion {
160 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
161 write!(f, "{}.{}", self.0, self.1)
162 }
163}
164
165#[derive(Debug, Clone, PartialEq, Eq, Serialize, Hash, Deserialize)]
166pub enum Protocol {
167 TCP,
168 WS,
169 HTTP,
170 UNIX,
171}
172
173#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
174#[serde(rename_all = "camelCase")]
175pub struct KeyValuePair {
176 pub key: Key,
177 pub value: Value,
178}
179
180impl fmt::Display for KeyValuePair {
181 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
182 write!(f, "{}={}", self.key, self.value)
183 }
184}
185
186impl From<KeyValuePair> for Option<Value> {
187 fn from(kvp: KeyValuePair) -> Self {
188 Some(kvp.value)
189 }
190}
191
192impl From<KeyValuePair> for Value {
193 fn from(kvp: KeyValuePair) -> Self {
194 kvp.value
195 }
196}
197
198impl KeyValuePair {
199 pub fn new<S: Serialize>(key: String, value: S) -> Self {
200 (key, value).into()
201 }
202
203 pub fn of<S: Serialize>(key: String, value: S) -> Self {
204 KeyValuePair::new(key, value)
205 }
206}
207
208#[derive(Debug, Clone, PartialEq, Eq)]
209pub struct TypedKeyValuePair<T: DeserializeOwned> {
210 pub key: Key,
211 pub value: T,
212}
213
214impl<T: DeserializeOwned> TryFrom<KeyValuePair> for TypedKeyValuePair<T> {
215 type Error = serde_json::Error;
216
217 fn try_from(kvp: KeyValuePair) -> Result<Self, Self::Error> {
218 let deserialized = serde_json::from_value(kvp.value)?;
219 Ok(TypedKeyValuePair {
220 key: kvp.key,
221 value: deserialized,
222 })
223 }
224}
225
226impl<S: Serialize> From<(String, S)> for KeyValuePair {
227 fn from((key, value): (String, S)) -> Self {
228 let value = json!(value);
229 KeyValuePair { key, value }
230 }
231}
232
233impl<S: Serialize> From<(&str, S)> for KeyValuePair {
234 fn from((key, value): (&str, S)) -> Self {
235 let value = json!(value);
236 KeyValuePair {
237 key: key.to_owned(),
238 value,
239 }
240 }
241}
242
243pub type RegularKeySegment = String;
245
246pub fn parse_segments(pattern: &str) -> WorterbuchResult<Vec<RegularKeySegment>> {
247 let mut segments = Vec::new();
248 for segment in pattern.split('/') {
249 let ks: KeySegment = segment.into();
250 match ks {
251 KeySegment::Regular(reg) => segments.push(reg),
252 KeySegment::Wildcard => {
253 return Err(error::WorterbuchError::IllegalWildcard(pattern.to_owned()));
254 }
255 KeySegment::MultiWildcard => {
256 return Err(error::WorterbuchError::IllegalMultiWildcard(
257 pattern.to_owned(),
258 ));
259 }
260 }
261 }
262 Ok(segments)
263}
264
265#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
266pub enum KeySegment {
267 Regular(RegularKeySegment),
268 Wildcard,
269 MultiWildcard,
270 }
272
273pub fn format_path(path: &[KeySegment]) -> String {
274 path.iter()
275 .map(|seg| format!("{seg}"))
276 .collect::<Vec<String>>()
277 .join("/")
278}
279
280impl From<RegularKeySegment> for KeySegment {
281 fn from(reg: RegularKeySegment) -> Self {
282 Self::Regular(reg)
283 }
284}
285
286impl Deref for KeySegment {
287 type Target = str;
288
289 fn deref(&self) -> &Self::Target {
290 match self {
291 KeySegment::Regular(reg) => reg,
292 KeySegment::Wildcard => "?",
293 KeySegment::MultiWildcard => "#",
294 }
295 }
296}
297
298impl fmt::Display for KeySegment {
299 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
300 match self {
301 KeySegment::Regular(segment) => segment.fmt(f),
302 KeySegment::Wildcard => write!(f, "?"),
303 KeySegment::MultiWildcard => write!(f, "#"),
304 }
306 }
307}
308
309impl From<&str> for KeySegment {
310 fn from(str: &str) -> Self {
311 match str {
312 "?" => KeySegment::Wildcard,
313 "#" => KeySegment::MultiWildcard,
314 other => KeySegment::Regular(other.to_owned()),
315 }
316 }
317}
318
319impl KeySegment {
320 pub fn parse(pattern: impl AsRef<str>) -> Vec<KeySegment> {
321 let segments = pattern.as_ref().split('/');
322 segments.map(KeySegment::from).collect()
323 }
324}
325
326pub fn quote(str: impl AsRef<str>) -> String {
327 let str_ref = str.as_ref();
328 if str_ref.starts_with('\"') && str_ref.ends_with('\"') {
329 str_ref.to_owned()
330 } else {
331 format!("\"{str_ref}\"")
332 }
333}
334
335pub fn digest_token(auth_token: &Option<String>, client_id: String) -> Option<String> {
336 auth_token.as_deref().map(|token| {
337 let salted = client_id + token;
338 let mut hasher = Sha256::new();
339 hasher.update(salted.as_bytes());
340 format!("{:x}", hasher.finalize())
341 })
342}
343
344#[cfg(test)]
345mod test {
346 use crate::{ErrorCode, ProtocolVersion};
347 use serde_json::json;
348
349 #[test]
350 fn protocol_versions_are_sorted_correctly() {
351 assert!(ProtocolVersion::new(1, 2) < ProtocolVersion::new(3, 2));
352 assert!(ProtocolVersion::new(1, 2) == ProtocolVersion::new(1, 2));
353 assert!(ProtocolVersion::new(2, 1) > ProtocolVersion::new(1, 9));
354
355 let mut versions = vec![
356 ProtocolVersion::new(1, 2),
357 ProtocolVersion::new(0, 456),
358 ProtocolVersion::new(9, 0),
359 ProtocolVersion::new(3, 15),
360 ];
361 versions.sort();
362 assert_eq!(
363 vec![
364 ProtocolVersion::new(0, 456),
365 ProtocolVersion::new(1, 2),
366 ProtocolVersion::new(3, 15),
367 ProtocolVersion::new(9, 0)
368 ],
369 versions
370 );
371 }
372
373 #[test]
374 fn topic_macro_generates_topic_correctly() {
375 assert_eq!(
376 "hello/world/foo/bar",
377 topic!("hello", "world", "foo", "bar")
378 );
379 }
380
381 #[test]
382 fn error_codes_are_serialized_as_numbers() {
383 assert_eq!(
384 "1",
385 serde_json::to_string(&ErrorCode::IllegalMultiWildcard).unwrap()
386 )
387 }
388
389 #[test]
390 fn error_codes_are_deserialized_from_numbers() {
391 assert_eq!(
392 ErrorCode::ProtocolNegotiationFailed,
393 serde_json::from_str("7").unwrap()
394 )
395 }
396
397 #[test]
398 fn protocol_version_get_serialized_correctly() {
399 assert_eq!(&json!(ProtocolVersion::new(2, 1)).to_string(), "[2,1]")
400 }
401
402 #[test]
403 fn protocol_version_get_formatted_correctly() {
404 assert_eq!(&ProtocolVersion::new(2, 1).to_string(), "2.1")
405 }
406
407 #[test]
408 fn compatible_version_is_selected_correctly() {
409 let client_version = ProtocolVersion::new(1, 2);
410 let server_versions = [
411 ProtocolVersion::new(0, 11),
412 ProtocolVersion::new(1, 6),
413 ProtocolVersion::new(2, 0),
414 ];
415 let compatible_version = server_versions
416 .iter()
417 .find(|v| client_version.is_compatible_with_server(v));
418 assert_eq!(compatible_version, Some(&server_versions[1]))
419 }
420}