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
//! What:
//! The shapes the landing board answers with (an early answer, a group admission, a naming, a decision) and the checks and
//! readers of the names it keeps: which identities may name a file, the withdrawal token of a decision, which entries are
//! confirmations.
//! Why:
//! `service_busy.rs` holds the board itself; these need no board, so they are a file it uses.
//!
//! In TS you'd write (pseudocode):
//! ```ts
//! type EarlyAnswer, GroupAdmission, Naming, Decision; function isPlain(id), withdrawalToken(content)
//! ```
use PathBuf;
use SystemTime;
/// What the decision file says when a withdrawal took the request: this word, a colon and the token of the withdrawer that made it.
pub const WITHDRAWN: &str = "withdrawn";
/// The extension of the file that confirms a withdrawal, named `<id>.<token>.cancelled` with the token the decision carries: the
/// withdrawer that won the decision made it after it asked the journal a second time and found no batch naming the request. A
/// decision without its confirmation is provisional: nobody but its creator may rely on it. The token ties the confirmation to
/// that one decision, so a confirmation that outlives its decision (the retention removes the pair in two steps) confirms nothing
/// of the decision that replaces it.
pub const CANCELLED_EXTENSION: &str = "cancelled";
/// The longest request identity the record keeps a decision for; a longer one, or one with a character outside letters, digits and
/// hyphens, gets no early answer, because its name could not be made into a file name that is only a name.
pub const LONGEST_ID: usize = 80;
/// How a withdrawal asked of a connection thread is answered.
/// What the landing thread learns about the requests of a group before it lands them.
/// What the journal says about a request.
pub
/// What a try at the decision came to.
pub
/// Whether `id` can be a file name that is only a name.
pub
/// What:
/// Whether a character may appear in an identity that names a file: an ASCII letter or digit, or a hyphen.
/// Why:
/// `is_plain` checks every character of an identity with it, so no identity can name a path.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// const isPlainCharacter = (character: string) => /^[A-Za-z0-9-]$/.test(character);
/// ```
pub
/// What:
/// Whether a directory entry is the confirmation of a withdrawal: a file with the cancelled extension.
/// Why:
/// The count and the pruning of confirmed withdrawals both filter the directory listing with it.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// const isConfirmation = (entry: Dirent) => path.extname(entry.name) === '.' + CANCELLED_EXTENSION;
/// ```
pub
/// What:
/// The modification time and the path of a directory entry, nothing when either cannot be read.
/// Why:
/// `prune_withdrawals` sorts the confirmations by age, oldest first, and entries that cannot be measured are left alone.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// const modifiedAndPath = (entry: Dirent) => { try { return [statSync(p).mtime, p]; } catch { return undefined; } };
/// ```
pub
/// The token a `withdrawn` decision carries, when `content` is one.
pub