links/
util.rs

1//! Miscellaneous statics, utilities, and macros used throughout links.
2
3use std::{collections::HashMap, panic::Location, sync::LockResult};
4
5use tracing::warn;
6
7/// A string representation of this crate's version.
8///
9/// In debug builds, this is in the form of `[full semver crate version]+debug`.
10/// In release builds this gets shortened to `MAJOR.MINOR`.
11pub const VERSION: &str = if cfg!(debug_assertions) {
12	concat!(env!("CARGO_PKG_VERSION"), "+debug")
13} else {
14	concat!(
15		env!("CARGO_PKG_VERSION_MAJOR"),
16		".",
17		env!("CARGO_PKG_VERSION_MINOR")
18	)
19};
20
21/// The name of the HTTP(S) server implemented by this crate.
22///
23/// Used in e.g. the `Server` HTTP header. Currently this is
24/// `hyperlinks/[version]`, where `hyper` refers to the HTTP library used,
25/// `links` is this crate's name, and the version is `util::VERSION`.
26pub const SERVER_NAME: &str = if cfg!(debug_assertions) {
27	concat!("hyperlinks/", env!("CARGO_PKG_VERSION"), "+debug")
28} else {
29	concat!(
30		"hyperlinks/",
31		env!("CARGO_PKG_VERSION_MAJOR"),
32		".",
33		env!("CARGO_PKG_VERSION_MINOR")
34	)
35};
36
37/// Unpoison a lock guard
38pub trait Unpoison {
39	/// The lock guard type
40	type Guard;
41
42	/// Get the lock guard regardless of poisoning status
43	fn unpoison(self) -> Self::Guard;
44}
45
46impl<G> Unpoison for LockResult<G> {
47	type Guard = G;
48
49	#[track_caller]
50	fn unpoison(self) -> Self::Guard {
51		match self {
52			Ok(g) => g,
53			Err(e) => {
54				warn!("a poisoned lock was encountered at {}", Location::caller());
55				e.into_inner()
56			}
57		}
58	}
59}
60
61/// Make a decent-looking and readable string out of a string -> string map
62pub fn stringify_map<K, V, H>(map: &HashMap<K, V, H>) -> String
63where
64	K: AsRef<str>,
65	V: AsRef<str>,
66{
67	let mut buf = String::with_capacity(map.len() * 16);
68	buf += "{ ";
69
70	for (i, (k, v)) in map.iter().enumerate() {
71		buf += k.as_ref();
72		buf += " = ";
73		buf += v.as_ref();
74		if i < map.len() - 1 {
75			buf += ", ";
76		}
77	}
78
79	buf + " }"
80}
81
82/// One year in seconds
83pub const A_YEAR: u32 = 365 * 24 * 60 * 60;
84
85/// Help string for server CLI
86pub const SERVER_HELP: &str = r#"links server
87
88USAGE:
89    server [FLAGS] [OPTIONS] [CONFIGURATION]
90
91EXAMPLE:
92    server -c ./config.toml --log-level warn
93
94FLAGS:
95 -h --help                   Print this and exit
96    --example-redirect       Set an example redirect on server start ("example" -> "9dDbKpJP" -> "https://example.com/")
97
98OPTIONS:
99 -c --config PATH            Configuration file path. Supported formats: toml (*.toml), yaml/json (*.yaml, *.yml, *.json)
100    --watcher-timeout MS     File watcher timeout in milliseconds, default 10000
101    --watcher-debounce MS    File watcher debounce time in milliseconds, default 1000
102
103CONFIGURATION:
104    --[OPTION] VALUE         Configuration option (in "kebab-case"), see documentation for possible options and values
105
106The FLAGS and OPTIONS above are separate from configuration options, because they influence server behaviour on startup only, and can only be specified on the command-line.
107Configuration options are parsed first from environment variables ("LINKS_[CONFIG_OPTION]"), then from the configuration file, then from command-line arguments ("--[config-option]"), later ones overwriting earlier ones.
108This means that command-line options overwrite everything, config file options overwrite default values and environment variables, environment variable overwrite only defaults, and the default value is used only when an option is not specified anywhere.
109"#;
110
111pub use crate::include_html;
112/// Include a generated minified html file as a `&'static str`.
113///
114/// The file must be generated by the build script and located in the `OUT_DIR`
115/// directory.
116#[macro_export]
117macro_rules! include_html {
118	($name:literal) => {
119		include_str!(concat!(env!("OUT_DIR"), concat!("/", $name, ".html")))
120	};
121}
122
123pub use crate::csp_hashes;
124/// Include a list of allowed style hashes for use in the CSP header as a
125/// `&'static str`.
126///
127/// The hashes are in the CSP header format (`sha256-HASH_ONE sha256-HASH_TWO
128/// ...`), and are generated at compile time by the build script per HTML file.
129#[macro_export]
130macro_rules! csp_hashes {
131	($file_name:literal, $tag_name:literal) => {
132		include_str!(concat!(
133			env!("OUT_DIR"),
134			concat!("/", $file_name, ".", $tag_name, ".hash")
135		))
136	};
137}