1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// License: see LICENSE file at root directory of `master` branch
//! # Namaste
//!
//! ## Project
//!
//! - Repository: <https://bitbucket.org/haibison/namaste-rs>
//! - License: Nice License 1.0.0 _(see LICENSE file at root directory of `master` branch)_
//! - _This project follows [Semantic Versioning 2.0.0]_
//!
//! ## Features
//!
//! - Handling locks amongst processes via TCP.
//!
//! ## Design
//!
//! ### Unique identifier
//!
//! A unique identifier (UID) is a 64-byte array, which matches an [SHA3-512][wiki:SHA3] hash.
//!
//! ### Server and client
//!
//! - Server starts on a fixed TCP port, and listens for clients.
//!
//! - "Book" command:
//!
//! + When a new client connects to, they are expected to send 4 pieces of information:
//!
//! + A one-byte "book" command.
//! + Global UID. This UID is used within a lifetime of the server, as an identification of the client.
//! + Handshake UID. This UID is used for the server to communicate with client.
//! + Client's local TCP server port, consisting of 2 bytes, in big-endian order.
//!
//! + Server then connects to the client's local server, sends the handshake UID, reads a UID and compares it with the first one above.
//!
//! + If the verification passes, server stores client UID in memory, and sends back _one non-zero byte_ to client.
//!
//! + If the verification does _not_ passes, server sends back _one zero byte_ to client.
//!
//! - "Check out" command sends along one-byte command, UID, handshake UID, and nothing more.
//!
//! ## Usage
//!
//! - You should only rely on this library for _limited small amount_ of locks between your program's processes. For instance, this library can
//! help with single-instance designed programs.
//! - Client side will ask system to grant it a random TCP server port. On most systems, TCP ports are _limited_. So it's highly recommended
//! that you should _not_ rely too much on this library (client side).
//!
//! ## FAQ
//!
//! ### Why not Unix Domain Socket?
//!
//! UDS has a good design, but its implementation has some **serious** flaws:
//!
//! - Already-bound file path _can be deleted_. Any new binding to that path will _silently take control_ of current one.
//! - Linux has an extension to UDS, which is called abstract sockets. Its design is very good, and can totally replace this library. However
//! its documentation clearly states that it is _not_ portable.
//!
//! ### Why not file locks?
//!
//! - On Unix, locked files can still be deleted.
//!
//! ## Examples
//!
//! It is expected that the system _already_ has Namaste server running!
//!
//! ```ignore
//! use namaste::client::Client;
//!
//! const NAMASTE_UID: namaste::Uid = [...];
//!
//! fn main() {
//! // UID must be a constant.
//! // However, you should generate new handshake UID per each session of your program.
//! // That means handshake UID should only be valid within lifetime of the process.
//! let handshake_uid = ...;
//!
//! match Client::book(NAMASTE_UID, handshake_uid, None, namaste::DEFAULT_RW_TIMEOUT) {
//! Ok(Some(client)) => {
//! run_main_job();
//! match client.check_out() {
//! Ok(true) => println!("Successfully checked out of Namaste server"),
//! Ok(false) => eprintln!("Couldn't check out of Namaste server"),
//! Err(err) => eprintln!("Failed checking out of Namaste server: {}", err),
//! };
//! },
//! Ok(None) => eprintln!("Another instance is running"),
//! Err(err) => eprintln!("Failed connecting to Namaste server: {}", err),
//! };
//! }
//! ```
//!
//! [Semantic Versioning 2.0.0]: https://semver.org/spec/v2.0.0.html
//! [wiki:SHA3]: https://en.wikipedia.org/wiki/SHA-3
pub use *;
// ╔═════════════════╗
// ║ IDENTIFIERS ║
// ╚═════════════════╝
/// # Crate name
pub const NAME: &'static str = "Namaste";
/// # Crate code name
pub const CODE_NAME: &'static str = code_name!;
/// # Crate version
pub const VERSION: &'static str = version!;
/// # Crate release date (year/month/day)
pub const RELEASE_DATE: = ;
/// # Unique universally identifier of this crate
pub const UUID: &'static str = "3099ee70-1e54-4f54-9587-5905b04ecd1a";
/// # Tag, which can be used for logging...
pub const TAG: &'static str = concat!;
// ╔════════════════════╗
// ║ IMPLEMENTATION ║
// ╚════════════════════╝