diff --git a/Cargo.lock b/Cargo.lock index bcde1bb..d9b7545 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,853 +1,1236 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "abnf" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47feb9fbcef700639ef28e04ca2a87eab8161a01a075ee227b15c90143805462" +dependencies = [ + "nom", +] + +[[package]] +name = "abnf_to_pest" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "372baaa5d3a422d8816b513bcdb2c120078c8614f7ecbcc3baf34a1634bbbe2e" +dependencies = [ + "abnf", + "indexmap", + "itertools", + "pretty", +] + [[package]] name = "aho-corasick" version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b476ce7103678b0c6d3d395dbbae31d48ff910bd28be979ba5d48c6351131d0d" dependencies = [ - "memchr 2.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr", +] + +[[package]] +name = "annotate-snippets" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c96c3d1062ea7101741480185a6a1275eab01cbe8b20e378d1311bc056d2e08" +dependencies = [ + "unicode-width", ] [[package]] name = "ansi_term" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" dependencies = [ - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi", ] [[package]] name = "arrayref" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" [[package]] name = "arrayvec" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] name = "async-channel" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59740d83946db6a5af71ae25ddf9562c2b176b2ca42cf99a455f09f4a220d6b9" dependencies = [ - "concurrent-queue 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "event-listener 2.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "concurrent-queue", + "event-listener", + "futures-core", ] [[package]] name = "async-executor" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d373d78ded7d0b3fa8039375718cde0aace493f2e34fb60f51cbf567562ca801" dependencies = [ - "async-task 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "concurrent-queue 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "fastrand 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-lite 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", - "once_cell 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "vec-arena 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "once_cell", + "vec-arena", ] [[package]] name = "async-fs" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b3ca4f8ff117c37c278a2f7415ce9be55560b846b5bc4412aaa5d29c1c3dae2" dependencies = [ - "async-lock 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "blocking 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-lite 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", + "async-lock", + "blocking", + "futures-lite", ] [[package]] name = "async-io" version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54bc4c1c7292475efb2253227dbcfad8fe1ca4c02bc62c510cc2f3da5c4704e" dependencies = [ - "concurrent-queue 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "fastrand 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-lite 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "nb-connect 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "once_cell 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "polling 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "vec-arena 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "waker-fn 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "concurrent-queue", + "fastrand", + "futures-lite", + "libc", + "log", + "nb-connect", + "once_cell", + "parking", + "polling", + "vec-arena", + "waker-fn", + "winapi", ] [[package]] name = "async-lock" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1996609732bde4a9988bc42125f55f2af5f3c36370e27c778d5191a4a1b63bfb" dependencies = [ - "event-listener 2.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "event-listener", ] [[package]] name = "async-net" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06de475c85affe184648202401d7622afb32f0f74e02192857d0201a16defbe5" dependencies = [ - "async-io 1.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "blocking 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "fastrand 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-lite 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", + "async-io", + "blocking", + "fastrand", + "futures-lite", ] [[package]] name = "async-process" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8cea09c1fb10a317d1b5af8024eeba256d6554763e85ecd90ff8df31c7bbda" dependencies = [ - "async-io 1.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "blocking 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "event-listener 2.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-lite 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", - "once_cell 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "signal-hook 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "async-io", + "blocking", + "cfg-if 0.1.10", + "event-listener", + "futures-lite", + "once_cell", + "signal-hook", + "winapi", ] [[package]] name = "async-task" version = "4.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91831deabf0d6d7ec49552e489aed63b7456a7a3c46cff62adad428110b0af0" [[package]] name = "async-trait" version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b246867b8b3b6ae56035f1eb1ed557c1d8eae97f0d53696138a50fa0e3a3b8c0" dependencies = [ - "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "atomic-waker" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" [[package]] name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi", + "libc", + "winapi", ] [[package]] name = "autocfg" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "base64" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" [[package]] name = "bindgen" version = "0.55.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b13ce559e6433d360c26305643803cb52cfbabbc2b9c47ce04a58493dfb443" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cexpr 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "clang-sys 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazycell 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hash 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "which 3.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", + "cexpr", + "cfg-if 0.1.10", + "clang-sys", + "clap", + "env_logger", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "which", ] [[package]] name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "blake2b_simd" version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" dependencies = [ - "arrayref 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "arrayvec 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayref", + "arrayvec", + "constant_time_eq", +] + +[[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +dependencies = [ + "block-padding", + "byte-tools", + "byteorder", + "generic-array 0.12.3", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array 0.14.4", +] + +[[package]] +name = "block-padding" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +dependencies = [ + "byte-tools", ] [[package]] name = "blocking" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e170dbede1f740736619b776d7251cb1b9095c435c34d8ca9f57fcd2f335e9" dependencies = [ - "async-channel 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "async-task 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "atomic-waker 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "fastrand 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-lite 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", - "once_cell 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "async-channel", + "async-task", + "atomic-waker", + "fastrand", + "futures-lite", + "once_cell", ] +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" + [[package]] name = "byteorder" version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" [[package]] name = "cache-padded" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba" [[package]] name = "capnp" version = "0.13.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e76a319e55a4ef27c8c383215fa3160167bd8a883e8d27c0ecd57ed81bca2af" [[package]] name = "capnp-futures" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9f9ff1dae086de0d7ecbc147fee21aed8b3ad64468f0f991c98da06fb8c8459" dependencies = [ - "capnp 0.13.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "capnp", + "futures 0.3.7", ] [[package]] name = "capnp-rpc" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37998522d42bbe4a1d266f418b1a053b679a338e904e55afd5ff22333df0e09e" dependencies = [ - "capnp 0.13.6 (registry+https://github.com/rust-lang/crates.io-index)", - "capnp-futures 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "capnp", + "capnp-futures", + "futures 0.3.7", ] [[package]] name = "capnpc" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81855cee80548f7a2ee549d3bc2e55ed5f7cabe469e85614046e5475712f75c1" dependencies = [ - "capnp 0.13.6 (registry+https://github.com/rust-lang/crates.io-index)", + "capnp", ] [[package]] name = "cc" version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed67cbde08356238e75fc4656be4749481eeffb09e19f320a25237d5221c985d" [[package]] name = "cexpr" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27" dependencies = [ - "nom 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "nom", ] [[package]] name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" dependencies = [ - "libc 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "num-integer", + "num-traits", + "time", + "winapi", ] [[package]] name = "clang-sys" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa785e9017cb8e8c8045e3f096b7d1ebc4d7337cceccdca8d678a27f788ac133" dependencies = [ - "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)", - "libloading 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "glob", + "libc", + "libloading", ] [[package]] name = "clap" version = "2.33.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" dependencies = [ - "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ansi_term", + "atty", + "bitflags", + "strsim", + "textwrap", + "unicode-width", + "vec_map", ] [[package]] name = "cmake" version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e56268c17a6248366d66d4a47a3381369d068cce8409bb1716ed77ea32163bb" dependencies = [ - "cc 1.0.61 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", ] [[package]] name = "concurrent-queue" version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" dependencies = [ - "cache-padded 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "config" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "nom 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.117 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cache-padded", ] [[package]] name = "constant_time_eq" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "cpuid-bool" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" [[package]] name = "crossbeam-channel" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87" dependencies = [ - "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils", + "maybe-uninit", ] [[package]] name = "crossbeam-utils" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" dependencies = [ - "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg", + "cfg-if 0.1.10", + "lazy_static", ] [[package]] name = "derivative" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb582b60359da160a9477ee80f15c8d784c477e69c217ef2cdd4169c24ea380f" dependencies = [ - "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "dhall" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7930c7ac2b3989a07a2a3400bf9f4bc1c65074f330e3ff22b372a4d386fabd0" +dependencies = [ + "abnf_to_pest", + "annotate-snippets", + "hex", + "itertools", + "lazy_static", + "once_cell", + "percent-encoding", + "pest", + "pest_consume", + "pest_generator", + "quote", + "serde", + "serde_cbor", + "sha2", + "url", +] + +[[package]] +name = "dhall_proc_macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf6cff1e2ddd03851652e0cde982b01dc877c9fc9da9ba25ad4241a151945f09" +dependencies = [ + "itertools", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "diflouroborane" version = "0.1.0" dependencies = [ - "async-trait 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "capnp 0.13.6 (registry+https://github.com/rust-lang/crates.io-index)", - "capnp-futures 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", - "capnp-rpc 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", - "capnpc 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)", - "config 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "flexbuffers 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-signals 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)", - "lmdb-rkv 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", - "paho-mqtt 0.8.0 (git+https://github.com/dequbed/paho.mqtt.rust.git)", - "rsasl 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.117 (registry+https://github.com/rust-lang/crates.io-index)", - "signal-hook 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-async 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-term 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smol 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", - "uuid 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "async-channel", + "async-trait", + "capnp", + "capnp-futures", + "capnp-rpc", + "capnpc", + "clap", + "easy-parallel", + "flexbuffers", + "futures 0.3.7", + "futures-signals", + "futures-test", + "futures-util", + "genawaiter", + "lazy_static", + "libc", + "lmdb-rkv", + "paho-mqtt", + "rand", + "rsasl", + "rust-argon2", + "serde", + "serde_dhall", + "signal-hook", + "slog", + "slog-async", + "slog-term", + "smol", + "toml", + "uuid", +] + +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +dependencies = [ + "generic-array 0.12.3", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array 0.14.4", ] [[package]] name = "dirs" version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "dirs-sys 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10", + "dirs-sys", ] [[package]] name = "dirs-sys" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a" dependencies = [ - "libc 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_users 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "redox_users", + "winapi", ] [[package]] name = "discard" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" + +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + +[[package]] +name = "easy-parallel" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd4afd79212583ff429b913ad6605242ed7eec277e950b1438f300748f948f4" + +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" [[package]] name = "env_logger" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" dependencies = [ - "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atty", + "humantime", + "log", + "regex", + "termcolor", ] [[package]] name = "event-listener" version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59" + +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" [[package]] name = "fastrand" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca5faf057445ce5c9d4329e382b2ce7ca38550ef3b73a5348362d5f24e0c7fe3" dependencies = [ - "instant 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "instant", ] [[package]] name = "flexbuffers" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf2255651c8e4ba123ff7027b70b4d0aaffeb84b38c99771a70d5cc6a75821b3" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "num_enum 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.117 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.117 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", + "byteorder", + "num_enum", + "serde", + "serde_derive", +] + +[[package]] +name = "form_urlencoded" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ece68d15c92e84fa4f19d3780f1294e5ca82a78a6d515f1efaabcc144688be00" +dependencies = [ + "matches", + "percent-encoding", ] [[package]] name = "futures" version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7e4c2612746b0df8fed4ce0c69156021b704c9aefa360311c04e6e9e002eed" [[package]] name = "futures" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95314d38584ffbfda215621d723e0a3906f032e03ae5551e650058dac83d4797" dependencies = [ - "futures-channel 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-executor 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-io 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-sink 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-task 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", ] [[package]] name = "futures-channel" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0448174b01148032eed37ac4aed28963aaaa8cfa93569a08e5b479bbc6c2c151" dependencies = [ - "futures-core 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-sink 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core", + "futures-sink", ] [[package]] name = "futures-channel-preview" version = "0.3.0-alpha.19" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5e5f4df964fa9c1c2f8bddeb5c3611631cacd93baf810fc8bb2fb4b495c263a" dependencies = [ - "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core-preview", + "futures-sink-preview", ] [[package]] name = "futures-core" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18eaa56102984bed2c88ea39026cff3ce3b4c7f508ca970cedf2450ea10d4e46" [[package]] name = "futures-core-preview" version = "0.3.0-alpha.19" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b35b6263fb1ef523c3056565fa67b1d16f0a8604ff12b11b08c25f28a734c60a" [[package]] name = "futures-executor" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5f8e0c9258abaea85e78ebdda17ef9666d390e987f006be6080dfe354b708cb" dependencies = [ - "futures-core 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-task 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core", + "futures-task", + "futures-util", + "num_cpus", ] [[package]] name = "futures-executor-preview" version = "0.3.0-alpha.19" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75236e88bd9fe88e5e8bfcd175b665d0528fe03ca4c5207fabc028c8f9d93e98" dependencies = [ - "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core-preview", + "futures-util-preview", + "num_cpus", ] [[package]] name = "futures-io" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1798854a4727ff944a7b12aa999f58ce7aa81db80d2dfaaf2ba06f065ddd2b" [[package]] name = "futures-io-preview" version = "0.3.0-alpha.19" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4914ae450db1921a56c91bde97a27846287d062087d4a652efc09bb3a01ebda" [[package]] name = "futures-lite" version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6c079abfac3ab269e2927ec048dabc89d009ebfdda6b8ee86624f30c689658" dependencies = [ - "fastrand 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-io 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "parking 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "pin-project-lite 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "waker-fn 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "fastrand", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", ] [[package]] name = "futures-macro" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e36fccf3fc58563b4a14d265027c627c3b665d7fed489427e88e7cc929559efe" dependencies = [ - "proc-macro-hack 0.5.19 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "futures-preview" version = "0.3.0-alpha.19" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b1dce2a0267ada5c6ff75a8ba864b4e679a9e2aa44262af7a3b5516d530d76e" dependencies = [ - "futures-channel-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-executor-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-io-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-channel-preview", + "futures-core-preview", + "futures-executor-preview", + "futures-io-preview", + "futures-sink-preview", + "futures-util-preview", ] [[package]] name = "futures-signals" version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc25a8a9a6d6ff91068ca03a3d0526dbee38708faaf850825a1647969dc1dead" dependencies = [ - "discard 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-channel 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.117 (registry+https://github.com/rust-lang/crates.io-index)", + "discard", + "futures-channel", + "futures-core", + "futures-util", + "serde", ] [[package]] name = "futures-sink" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e3ca3f17d6e8804ae5d3df7a7d35b2b3a6fe89dac84b31872720fc3060a0b11" [[package]] name = "futures-sink-preview" version = "0.3.0-alpha.19" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f148ef6b69f75bb610d4f9a2336d4fc88c4b5b67129d1a340dd0fd362efeec" [[package]] name = "futures-task" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d502af37186c4fef99453df03e374683f8a1eec9dcc1e66b3b82dc8278ce3c" dependencies = [ - "once_cell 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "once_cell", +] + +[[package]] +name = "futures-test" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a493f2b7cb378c703e494b8c7e1f4505236ca54e9db6d7f1f769d4f1441d6771" +dependencies = [ + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", + "once_cell", + "pin-project", + "pin-utils", ] [[package]] name = "futures-timer" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f9eb554aa23143abc64ec4d0016f038caf53bb7cbc3d91490835c54edc96550" dependencies = [ - "futures-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-preview", + "pin-utils", ] [[package]] name = "futures-util" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abcb44342f62e6f3e8ac427b8aa815f724fd705dfad060b18ac7866c15bb8e34" dependencies = [ - "futures 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-channel 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-io 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-macro 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-sink 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-task 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "pin-project 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-hack 0.5.19 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-nested 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.30", + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project", + "pin-utils", + "proc-macro-hack", + "proc-macro-nested", + "slab", ] [[package]] name = "futures-util-preview" version = "0.3.0-alpha.19" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ce968633c17e5f97936bd2797b6e38fb56cf16a7422319f7ec2e30d3c470e8d" dependencies = [ - "futures-channel-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-io-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-channel-preview", + "futures-core-preview", + "futures-io-preview", + "futures-sink-preview", + "memchr", + "pin-utils", + "slab", +] + +[[package]] +name = "genawaiter" +version = "0.99.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c86bd0361bcbde39b13475e6e36cb24c329964aa2611be285289d1e4b751c1a0" +dependencies = [ + "genawaiter-macro", + "genawaiter-proc-macro", + "proc-macro-hack", +] + +[[package]] +name = "genawaiter-macro" +version = "0.99.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b32dfe1fdfc0bbde1f22a5da25355514b5e450c33a6af6770884c8750aedfbc" + +[[package]] +name = "genawaiter-proc-macro" +version = "0.99.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784f84eebc366e15251c4a8c3acee82a6a6f427949776ecb88377362a9621738" +dependencies = [ + "proc-macro-error", + "proc-macro-hack", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "generic-array" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" +dependencies = [ + "typenum", +] + +[[package]] +name = "generic-array" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +dependencies = [ + "typenum", + "version_check", ] [[package]] name = "getrandom" version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)", - "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", ] [[package]] name = "glob" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" [[package]] name = "gsasl-sys" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89192b27c2356690cddc81ef17438cede69f0e6794a645debe579de3a6bb835" dependencies = [ - "bindgen 0.55.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bindgen", ] +[[package]] +name = "half" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d36fab90f82edc3c747f9d438e06cf0a491055896f2a279638bb5beed6c40177" + +[[package]] +name = "hashbrown" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" + [[package]] name = "hermit-abi" version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" dependencies = [ - "libc 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] +[[package]] +name = "hex" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" + [[package]] name = "humantime" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" dependencies = [ - "quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "quick-error", +] + +[[package]] +name = "idna" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55e2e4c765aa53a0424761bf9f41aa7a6ac1efa87238f59560640e27fca028f2" +dependencies = [ + "autocfg", + "hashbrown", ] [[package]] name = "instant" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb1fc4429a33e1f80d41dc9fea4d108a88bec1de8053878898ae448a0b52f613" dependencies = [ - "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", +] + +[[package]] +name = "itertools" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" +dependencies = [ + "either", ] [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "lazycell" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "lexical-core" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db65c6da02e61f55dae90a0ae427b2a5f6b3e8db09f58d10efab23af92592616" dependencies = [ - "arrayvec 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "static_assertions 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec", + "bitflags", + "cfg-if 0.1.10", + "ryu", + "static_assertions", ] [[package]] name = "libc" version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614" [[package]] name = "libloading" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1090080fe06ec2648d0da3881d9453d97e71a45f00eb179af7fdd7e3f686fdb0" dependencies = [ - "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "winapi", ] [[package]] name = "lmdb-rkv" version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "447a296f7aca299cfbb50f4e4f3d49451549af655fb7215d7f8c0c3d64bad42b" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)", - "lmdb-rkv-sys 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", + "byteorder", + "libc", + "lmdb-rkv-sys", ] [[package]] name = "lmdb-rkv-sys" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b27470ac25167b3afdfb6af8fcd3bc1be67de50ffbdaf4073378cfded6ae24a5" dependencies = [ - "cc 1.0.61 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", + "libc", + "pkg-config", ] [[package]] name = "log" version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10", ] +[[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" + +[[package]] +name = "matches" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" + [[package]] name = "maybe-uninit" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" [[package]] name = "memchr" version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" [[package]] name = "nb-connect" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8123a81538e457d44b933a02faf885d3fe8408806b23fa700e8f01c6c3a98998" dependencies = [ - "libc 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "winapi", ] [[package]] name = "nom" version = "5.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" dependencies = [ - "lexical-core 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lexical-core", + "memchr", + "version_check", ] [[package]] name = "num-integer" version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" dependencies = [ - "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg", + "num-traits", ] [[package]] name = "num-traits" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" dependencies = [ - "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg", ] [[package]] name = "num_cpus" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" dependencies = [ - "hermit-abi 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi", + "libc", ] [[package]] name = "num_enum" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "226b45a5c2ac4dd696ed30fa6b94b057ad909c7b7fc2e0d0808192bced894066" dependencies = [ - "derivative 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num_enum_derive 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "derivative", + "num_enum_derive", ] [[package]] name = "num_enum_derive" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c0fd9eba1d5db0994a239e09c1be402d35622277e35468ba891aa5e3188ce7e" dependencies = [ - "proc-macro-crate 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "once_cell" version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "260e51e7efe62b592207e9e13a68e43692a7a279171d6ba57abd208bf23645ad" + +[[package]] +name = "opaque-debug" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "paho-mqtt" version = "0.8.0" source = "git+https://github.com/dequbed/paho.mqtt.rust.git#14ec804ecf284564ee71b04345d1fdf1f75571df" dependencies = [ - "futures 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-timer 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "paho-mqtt-sys 0.4.1 (git+https://github.com/dequbed/paho.mqtt.rust.git)", - "thiserror 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.3.7", + "futures-timer", + "libc", + "log", + "paho-mqtt-sys", + "thiserror", ] [[package]] @@ -855,639 +1238,773 @@ name = "paho-mqtt-sys" version = "0.4.1" source = "git+https://github.com/dequbed/paho.mqtt.rust.git#14ec804ecf284564ee71b04345d1fdf1f75571df" dependencies = [ - "bindgen 0.55.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cmake 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", + "bindgen", + "cmake", ] [[package]] name = "parking" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" [[package]] name = "peeking_take_while" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pest" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +dependencies = [ + "ucd-trie", +] + +[[package]] +name = "pest_consume" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f06d200abe3be440ee3be3dcd2a65518250c0181364a332fa334b35152cb82e" +dependencies = [ + "pest", + "pest_consume_macros", + "pest_derive", + "proc-macro-hack", +] + +[[package]] +name = "pest_consume_macros" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "466dea9184791ec0b5304cc103dcbd3f267b0157aa60b2efc74ea1b1c886ea51" +dependencies = [ + "proc-macro-hack", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pest_derive" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pest_meta" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d" +dependencies = [ + "maplit", + "pest", + "sha-1", +] [[package]] name = "pin-project" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee41d838744f60d959d7074e3afb6b35c7456d0f61cad38a24e35e6553f73841" dependencies = [ - "pin-project-internal 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-project-internal", ] [[package]] name = "pin-project-internal" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81a4ffa594b66bff340084d4081df649a7dc049ac8d7fc458d8e628bfbbb2f86" dependencies = [ - "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "pin-project-lite" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c917123afa01924fc84bb20c4c03f004d9c38e5127e3c039bbf7f4b9c76a2f6b" [[package]] name = "pin-utils" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" [[package]] name = "polling" version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2a7bc6b2a29e632e45451c941832803a18cce6781db04de8a04696cdca8bde4" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "wepoll-sys 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10", + "libc", + "log", + "wepoll-sys", + "winapi", ] [[package]] name = "ppv-lite86" version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20" + +[[package]] +name = "pretty" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60c0d9f6fc88ecdd245d90c1920ff76a430ab34303fc778d33b1d0a4c3bf6d3" +dependencies = [ + "typed-arena", +] [[package]] name = "proc-macro-crate" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" dependencies = [ - "toml 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", + "toml", +] + +[[package]] +name = "proc-macro-error" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18f33027081eba0a6d8aba6d1b1c3a3be58cbb12106341c2d5759fcd9b5277e7" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a5b4b77fdb63c1eca72173d68d24501c54ab1269409f6b672c85deb18af69de" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "syn-mid", + "version_check", ] [[package]] name = "proc-macro-hack" version = "0.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro-nested" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a" [[package]] name = "proc-macro2" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" dependencies = [ - "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid", ] [[package]] name = "quick-error" version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" dependencies = [ - "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", ] [[package]] name = "rand" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom", + "libc", + "rand_chacha", + "rand_core", + "rand_hc", ] [[package]] name = "rand_chacha" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" dependencies = [ - "ppv-lite86 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86", + "rand_core", ] [[package]] name = "rand_core" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom", ] [[package]] name = "rand_hc" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" dependencies = [ - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core", ] [[package]] name = "redox_syscall" version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" [[package]] name = "redox_users" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" dependencies = [ - "getrandom 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-argon2 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom", + "redox_syscall", + "rust-argon2", ] [[package]] name = "regex" version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c" dependencies = [ - "aho-corasick 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick", + "memchr", + "regex-syntax", + "thread_local", ] [[package]] name = "regex-syntax" version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189" [[package]] name = "rsasl" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa53c56546f3cce59ac6c58bb4f6f1f11f3a162f2ab2b8cf03eaf7b43a932a53" dependencies = [ - "gsasl-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)", + "gsasl-sys", + "libc", ] [[package]] name = "rust-argon2" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dab61250775933275e84053ac235621dfb739556d5c54a2f2e9313b7cf43a19" dependencies = [ - "base64 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", - "blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", - "constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "base64", + "blake2b_simd", + "constant_time_eq", + "crossbeam-utils", ] [[package]] name = "rustc-hash" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "ryu" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] name = "serde" version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b88fa983de7720629c9387e9f517353ed404164b1e482c970a90c1a4aaf7dc1a" dependencies = [ - "serde_derive 1.0.117 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive", +] + +[[package]] +name = "serde_cbor" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e18acfa2f90e8b735b2836ab8d538de304cbb6729a7360729ea5a895d15a622" +dependencies = [ + "half", + "serde", ] [[package]] name = "serde_derive" version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbd1ae72adb44aab48f325a02444a5fc079349a8d804c1fc922aed3f7454c74e" dependencies = [ - "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_dhall" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f80d945a711c648e559c4d39832379f36a303d393fca4719080de51701266f38" +dependencies = [ + "dhall", + "dhall_proc_macros", + "doc-comment", + "serde", + "url", +] + +[[package]] +name = "sha-1" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" +dependencies = [ + "block-buffer 0.7.3", + "digest 0.8.1", + "fake-simd", + "opaque-debug 0.2.3", +] + +[[package]] +name = "sha2" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e7aab86fe2149bad8c507606bdb3f4ef5e7b2380eb92350f56122cca72a42a8" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if 1.0.0", + "cpuid-bool", + "digest 0.9.0", + "opaque-debug 0.3.0", ] [[package]] name = "shlex" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" [[package]] name = "signal-hook" version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "604508c1418b99dfe1925ca9224829bb2a8a9a04dda655cc01fcad46f4ab05ed" dependencies = [ - "libc 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)", - "signal-hook-registry 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "signal-hook-registry", ] [[package]] name = "signal-hook-registry" version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce32ea0c6c56d5eacaeb814fbed9960547021d3edd010ded1425f180536b20ab" dependencies = [ - "libc 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] name = "slab" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" [[package]] name = "slog" version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cc9c640a4adbfbcc11ffb95efe5aa7af7309e002adab54b185507dbf2377b99" [[package]] name = "slog-async" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b3336ce47ce2f96673499fc07eb85e3472727b9a7a2959964b002c2ce8fbbb" dependencies = [ - "crossbeam-channel 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel", + "slog", + "take_mut", + "thread_local", ] [[package]] name = "slog-term" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab1d807cf71129b05ce36914e1dbb6fbfbdecaf686301cb457f4fa967f9f5b6" dependencies = [ - "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "chrono 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "atty", + "chrono", + "slog", + "term", + "thread_local", ] [[package]] name = "smol" version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aaf8ded16994c0ae59596c6e4733c76faeb0533c26fd5ca1b1bc89271a049a66" dependencies = [ - "async-channel 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "async-executor 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "async-fs 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "async-io 1.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "async-lock 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "async-net 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "async-process 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "blocking 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-lite 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", - "once_cell 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "async-channel", + "async-executor", + "async-fs", + "async-io", + "async-lock", + "async-net", + "async-process", + "blocking", + "futures-lite", + "once_cell", ] [[package]] name = "static_assertions" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "strsim" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" [[package]] name = "syn" version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc371affeffc477f42a221a1e4297aedcea33d47d19b61455588bd9d8f6b19ac" dependencies = [ - "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "syn-mid" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c42823f0ff906a3eb8109610e825221b07fb1456d45c7d01cf18cb581b23ecfb" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] name = "take_mut" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" [[package]] name = "term" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0863a3345e70f61d613eab32ee046ccd1bcc5f9105fe402c61fcd0c13eeb8b5" dependencies = [ - "dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "dirs", + "winapi", ] [[package]] name = "termcolor" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" dependencies = [ - "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util", ] [[package]] name = "textwrap" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" dependencies = [ - "unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width", ] [[package]] name = "thiserror" version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "318234ffa22e0920fe9a40d7b8369b5f649d490980cf7aadcf1eb91594869b42" dependencies = [ - "thiserror-impl 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror-impl", ] [[package]] name = "thiserror-impl" version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cae2447b6282786c3493999f40a9be2a6ad20cb8bd268b0a0dbf5a065535c0ab" dependencies = [ - "proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "thread_local" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static", ] [[package]] name = "time" version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" dependencies = [ - "libc 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)", - "wasi 0.10.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi", ] +[[package]] +name = "tinyvec" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf8dbc19eb42fba10e8feaaec282fb50e2c14b2726d6301dbfeed0f73306a6f" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + [[package]] name = "toml" version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75cf45bb0bef80604d001caaec0d09da99611b3c0fd39d3080468875cdb65645" dependencies = [ - "serde 1.0.117 (registry+https://github.com/rust-lang/crates.io-index)", + "serde", +] + +[[package]] +name = "typed-arena" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9b2228007eba4120145f785df0f6c92ea538f5a3635a612ecf4e334c8c1446d" + +[[package]] +name = "typenum" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" + +[[package]] +name = "ucd-trie" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" + +[[package]] +name = "unicode-bidi" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" +dependencies = [ + "matches", +] + +[[package]] +name = "unicode-normalization" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a13e63ab62dbe32aeee58d1c5408d35c36c392bba5d9d3142287219721afe606" +dependencies = [ + "tinyvec", ] [[package]] name = "unicode-width" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" [[package]] name = "unicode-xid" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" + +[[package]] +name = "url" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5909f2b0817350449ed73e8bcd81c8c3c8d9a7a5d8acba4b27db277f1868976e" +dependencies = [ + "form_urlencoded", + "idna", + "matches", + "percent-encoding", +] [[package]] name = "uuid" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fde2f6a4bea1d6e007c4ad38c6839fa71cbb63b6dbf5b595aa38dc9b1093c11" dependencies = [ - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.117 (registry+https://github.com/rust-lang/crates.io-index)", + "rand", + "serde", ] [[package]] name = "vec-arena" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eafc1b9b2dfc6f5529177b62cf806484db55b32dc7c9658a118e11bbeb33061d" [[package]] name = "vec_map" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" [[package]] name = "version_check" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" [[package]] name = "waker-fn" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "wasi" version = "0.10.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" [[package]] name = "wepoll-sys" version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcb14dea929042224824779fbc82d9fab8d2e6d3cbc0ac404de8edf489e77ff" dependencies = [ - "cc 1.0.61 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", ] [[package]] name = "which" version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724" dependencies = [ - "libc 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ - "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum aho-corasick 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b476ce7103678b0c6d3d395dbbae31d48ff910bd28be979ba5d48c6351131d0d" -"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" -"checksum arrayref 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" -"checksum arrayvec 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" -"checksum async-channel 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "59740d83946db6a5af71ae25ddf9562c2b176b2ca42cf99a455f09f4a220d6b9" -"checksum async-executor 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d373d78ded7d0b3fa8039375718cde0aace493f2e34fb60f51cbf567562ca801" -"checksum async-fs 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8b3ca4f8ff117c37c278a2f7415ce9be55560b846b5bc4412aaa5d29c1c3dae2" -"checksum async-io 1.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d54bc4c1c7292475efb2253227dbcfad8fe1ca4c02bc62c510cc2f3da5c4704e" -"checksum async-lock 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1996609732bde4a9988bc42125f55f2af5f3c36370e27c778d5191a4a1b63bfb" -"checksum async-net 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "06de475c85affe184648202401d7622afb32f0f74e02192857d0201a16defbe5" -"checksum async-process 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c8cea09c1fb10a317d1b5af8024eeba256d6554763e85ecd90ff8df31c7bbda" -"checksum async-task 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e91831deabf0d6d7ec49552e489aed63b7456a7a3c46cff62adad428110b0af0" -"checksum async-trait 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b246867b8b3b6ae56035f1eb1ed557c1d8eae97f0d53696138a50fa0e3a3b8c0" -"checksum atomic-waker 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" -"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -"checksum autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" -"checksum base64 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" -"checksum bindgen 0.55.1 (registry+https://github.com/rust-lang/crates.io-index)" = "75b13ce559e6433d360c26305643803cb52cfbabbc2b9c47ce04a58493dfb443" -"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -"checksum blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" -"checksum blocking 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c5e170dbede1f740736619b776d7251cb1b9095c435c34d8ca9f57fcd2f335e9" -"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" -"checksum cache-padded 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba" -"checksum capnp 0.13.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4e76a319e55a4ef27c8c383215fa3160167bd8a883e8d27c0ecd57ed81bca2af" -"checksum capnp-futures 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e9f9ff1dae086de0d7ecbc147fee21aed8b3ad64468f0f991c98da06fb8c8459" -"checksum capnp-rpc 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37998522d42bbe4a1d266f418b1a053b679a338e904e55afd5ff22333df0e09e" -"checksum capnpc 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "81855cee80548f7a2ee549d3bc2e55ed5f7cabe469e85614046e5475712f75c1" -"checksum cc 1.0.61 (registry+https://github.com/rust-lang/crates.io-index)" = "ed67cbde08356238e75fc4656be4749481eeffb09e19f320a25237d5221c985d" -"checksum cexpr 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27" -"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -"checksum chrono 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)" = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" -"checksum clang-sys 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fa785e9017cb8e8c8045e3f096b7d1ebc4d7337cceccdca8d678a27f788ac133" -"checksum clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)" = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" -"checksum cmake 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)" = "0e56268c17a6248366d66d4a47a3381369d068cce8409bb1716ed77ea32163bb" -"checksum concurrent-queue 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" -"checksum config 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "19b076e143e1d9538dde65da30f8481c2a6c44040edb8e02b9bf1351edb92ce3" -"checksum constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" -"checksum crossbeam-channel 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87" -"checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" -"checksum derivative 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cb582b60359da160a9477ee80f15c8d784c477e69c217ef2cdd4169c24ea380f" -"checksum dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" -"checksum dirs-sys 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a" -"checksum discard 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" -"checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" -"checksum event-listener 2.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59" -"checksum fastrand 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca5faf057445ce5c9d4329e382b2ce7ca38550ef3b73a5348362d5f24e0c7fe3" -"checksum flexbuffers 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bf2255651c8e4ba123ff7027b70b4d0aaffeb84b38c99771a70d5cc6a75821b3" -"checksum futures 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "4c7e4c2612746b0df8fed4ce0c69156021b704c9aefa360311c04e6e9e002eed" -"checksum futures 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "95314d38584ffbfda215621d723e0a3906f032e03ae5551e650058dac83d4797" -"checksum futures-channel 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0448174b01148032eed37ac4aed28963aaaa8cfa93569a08e5b479bbc6c2c151" -"checksum futures-channel-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "d5e5f4df964fa9c1c2f8bddeb5c3611631cacd93baf810fc8bb2fb4b495c263a" -"checksum futures-core 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "18eaa56102984bed2c88ea39026cff3ce3b4c7f508ca970cedf2450ea10d4e46" -"checksum futures-core-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "b35b6263fb1ef523c3056565fa67b1d16f0a8604ff12b11b08c25f28a734c60a" -"checksum futures-executor 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f5f8e0c9258abaea85e78ebdda17ef9666d390e987f006be6080dfe354b708cb" -"checksum futures-executor-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "75236e88bd9fe88e5e8bfcd175b665d0528fe03ca4c5207fabc028c8f9d93e98" -"checksum futures-io 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6e1798854a4727ff944a7b12aa999f58ce7aa81db80d2dfaaf2ba06f065ddd2b" -"checksum futures-io-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "f4914ae450db1921a56c91bde97a27846287d062087d4a652efc09bb3a01ebda" -"checksum futures-lite 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5e6c079abfac3ab269e2927ec048dabc89d009ebfdda6b8ee86624f30c689658" -"checksum futures-macro 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "e36fccf3fc58563b4a14d265027c627c3b665d7fed489427e88e7cc929559efe" -"checksum futures-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "3b1dce2a0267ada5c6ff75a8ba864b4e679a9e2aa44262af7a3b5516d530d76e" -"checksum futures-signals 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "cc25a8a9a6d6ff91068ca03a3d0526dbee38708faaf850825a1647969dc1dead" -"checksum futures-sink 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0e3ca3f17d6e8804ae5d3df7a7d35b2b3a6fe89dac84b31872720fc3060a0b11" -"checksum futures-sink-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "86f148ef6b69f75bb610d4f9a2336d4fc88c4b5b67129d1a340dd0fd362efeec" -"checksum futures-task 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "96d502af37186c4fef99453df03e374683f8a1eec9dcc1e66b3b82dc8278ce3c" -"checksum futures-timer 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8f9eb554aa23143abc64ec4d0016f038caf53bb7cbc3d91490835c54edc96550" -"checksum futures-util 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "abcb44342f62e6f3e8ac427b8aa815f724fd705dfad060b18ac7866c15bb8e34" -"checksum futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "5ce968633c17e5f97936bd2797b6e38fb56cf16a7422319f7ec2e30d3c470e8d" -"checksum getrandom 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" -"checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" -"checksum gsasl-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d89192b27c2356690cddc81ef17438cede69f0e6794a645debe579de3a6bb835" -"checksum hermit-abi 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" -"checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" -"checksum instant 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "cb1fc4429a33e1f80d41dc9fea4d108a88bec1de8053878898ae448a0b52f613" -"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum lazycell 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" -"checksum lexical-core 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "db65c6da02e61f55dae90a0ae427b2a5f6b3e8db09f58d10efab23af92592616" -"checksum libc 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614" -"checksum libloading 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1090080fe06ec2648d0da3881d9453d97e71a45f00eb179af7fdd7e3f686fdb0" -"checksum lmdb-rkv 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "447a296f7aca299cfbb50f4e4f3d49451549af655fb7215d7f8c0c3d64bad42b" -"checksum lmdb-rkv-sys 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b27470ac25167b3afdfb6af8fcd3bc1be67de50ffbdaf4073378cfded6ae24a5" -"checksum log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" -"checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" -"checksum memchr 2.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" -"checksum nb-connect 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8123a81538e457d44b933a02faf885d3fe8408806b23fa700e8f01c6c3a98998" -"checksum nom 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" -"checksum num-integer 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)" = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" -"checksum num-traits 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" -"checksum num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" -"checksum num_enum 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "226b45a5c2ac4dd696ed30fa6b94b057ad909c7b7fc2e0d0808192bced894066" -"checksum num_enum_derive 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1c0fd9eba1d5db0994a239e09c1be402d35622277e35468ba891aa5e3188ce7e" -"checksum once_cell 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "260e51e7efe62b592207e9e13a68e43692a7a279171d6ba57abd208bf23645ad" -"checksum paho-mqtt 0.8.0 (git+https://github.com/dequbed/paho.mqtt.rust.git)" = "" -"checksum paho-mqtt-sys 0.4.1 (git+https://github.com/dequbed/paho.mqtt.rust.git)" = "" -"checksum parking 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" -"checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" -"checksum pin-project 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ee41d838744f60d959d7074e3afb6b35c7456d0f61cad38a24e35e6553f73841" -"checksum pin-project-internal 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "81a4ffa594b66bff340084d4081df649a7dc049ac8d7fc458d8e628bfbbb2f86" -"checksum pin-project-lite 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c917123afa01924fc84bb20c4c03f004d9c38e5127e3c039bbf7f4b9c76a2f6b" -"checksum pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -"checksum pkg-config 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" -"checksum polling 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a2a7bc6b2a29e632e45451c941832803a18cce6781db04de8a04696cdca8bde4" -"checksum ppv-lite86 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20" -"checksum proc-macro-crate 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" -"checksum proc-macro-hack 0.5.19 (registry+https://github.com/rust-lang/crates.io-index)" = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" -"checksum proc-macro-nested 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a" -"checksum proc-macro2 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" -"checksum quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" -"checksum quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" -"checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -"checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -"checksum redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)" = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" -"checksum redox_users 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" -"checksum regex 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c" -"checksum regex-syntax 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)" = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189" -"checksum rsasl 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fa53c56546f3cce59ac6c58bb4f6f1f11f3a162f2ab2b8cf03eaf7b43a932a53" -"checksum rust-argon2 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9dab61250775933275e84053ac235621dfb739556d5c54a2f2e9313b7cf43a19" -"checksum rustc-hash 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" -"checksum ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" -"checksum serde 1.0.117 (registry+https://github.com/rust-lang/crates.io-index)" = "b88fa983de7720629c9387e9f517353ed404164b1e482c970a90c1a4aaf7dc1a" -"checksum serde_derive 1.0.117 (registry+https://github.com/rust-lang/crates.io-index)" = "cbd1ae72adb44aab48f325a02444a5fc079349a8d804c1fc922aed3f7454c74e" -"checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" -"checksum signal-hook 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "604508c1418b99dfe1925ca9224829bb2a8a9a04dda655cc01fcad46f4ab05ed" -"checksum signal-hook-registry 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ce32ea0c6c56d5eacaeb814fbed9960547021d3edd010ded1425f180536b20ab" -"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" -"checksum slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1cc9c640a4adbfbcc11ffb95efe5aa7af7309e002adab54b185507dbf2377b99" -"checksum slog-async 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b3336ce47ce2f96673499fc07eb85e3472727b9a7a2959964b002c2ce8fbbb" -"checksum slog-term 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bab1d807cf71129b05ce36914e1dbb6fbfbdecaf686301cb457f4fa967f9f5b6" -"checksum smol 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "aaf8ded16994c0ae59596c6e4733c76faeb0533c26fd5ca1b1bc89271a049a66" -"checksum static_assertions 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -"checksum syn 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)" = "cc371affeffc477f42a221a1e4297aedcea33d47d19b61455588bd9d8f6b19ac" -"checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" -"checksum term 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c0863a3345e70f61d613eab32ee046ccd1bcc5f9105fe402c61fcd0c13eeb8b5" -"checksum termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" -"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -"checksum thiserror 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)" = "318234ffa22e0920fe9a40d7b8369b5f649d490980cf7aadcf1eb91594869b42" -"checksum thiserror-impl 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)" = "cae2447b6282786c3493999f40a9be2a6ad20cb8bd268b0a0dbf5a065535c0ab" -"checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" -"checksum time 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)" = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" -"checksum toml 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)" = "75cf45bb0bef80604d001caaec0d09da99611b3c0fd39d3080468875cdb65645" -"checksum unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" -"checksum unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" -"checksum uuid 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fde2f6a4bea1d6e007c4ad38c6839fa71cbb63b6dbf5b595aa38dc9b1093c11" -"checksum vec-arena 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eafc1b9b2dfc6f5529177b62cf806484db55b32dc7c9658a118e11bbeb33061d" -"checksum vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" -"checksum version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" -"checksum waker-fn 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" -"checksum wasi 0.10.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" -"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" -"checksum wepoll-sys 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0fcb14dea929042224824779fbc82d9fab8d2e6d3cbc0ac404de8edf489e77ff" -"checksum which 3.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724" -"checksum winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index 7c13c58..47274d6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,11 +31,10 @@ capnp-rpc = "0.13" capnp-futures = "0.13" serde = { version = "1.0", features = ["derive"] } +toml = "0.5" flexbuffers = "0.1" -glob = "0.3" -toml = "0.5" -config = { version = "0.10", default-features = false, features = ["toml"] } +serde_dhall = { version = "0.9", default-features = false } uuid = { version = "0.8", features = ["serde", "v4"] } @@ -55,5 +54,17 @@ lmdb-rkv = "0.14" async-trait = "0.1" +lazy_static = "1.4.0" + +rust-argon2 = "0.8" +rand = "0.7" + +async-channel = "1.5" +easy-parallel = "3.1" +genawaiter = "0.99" + [build-dependencies] capnpc = "0.13" + +[dev-dependencies] +futures-test = "0.3" diff --git a/Dockerfile b/Dockerfile index 43caff1..c492217 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,7 +15,8 @@ FROM debian:buster-slim RUN apt-get update && apt-get upgrade -yqq RUN apt-get install -yqq libgsasl7 && rm -rf /var/lib/apt/lists/* COPY --from=builder /usr/local/cargo/bin/diflouroborane /usr/local/bin/diflouroborane +COPY --from=builder /usr/src/bffh/examples/bffh.dhall /etc/diflouroborane.dhall # RUN diflouroborane --print-default > /etc/diflouroborane.toml -VOLUME /etc/diflouroborane.toml +VOLUME /etc/diflouroborane.dhall EXPOSE 59661 -ENTRYPOINT ["diflouroborane"] \ No newline at end of file +ENTRYPOINT ["diflouroborane"] diff --git a/examples/README.md b/examples/README.md index f3b2795..edfc946 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,12 +1,9 @@ # API-Testsetup -wirklich nur um das API zu testen. ATM implementiert: machine::read +wirklich nur um das API zu testen. ATM implementiert: machines::* & machine::read, authenticate -1. `cargo run -- --print-default > /tmp/bffh.toml` um eine default config zu generieren -1. in /tmp/bffh.toml den parameter `machines` auf ./examples/machines.toml umbiegen - * Bei mir z.b. `~/Development/FabInfra/Diflouroborane/examples/machines.toml` 1. Ein mosquitto o.ä MQTT Server starten - * Bringt aber leider gerade nicht viel ^^' -1. `cargo run -- -c /tmp/bffh.toml` +1. Datenbanken füllen: `cargo run -- -c examples/bffh.dhall --load=examples` +1. Daemon starten: `cargo run -- -c examples/bffh.dhall` 1. ??? 1. PROFIT! diff --git a/examples/bffh.dhall b/examples/bffh.dhall new file mode 100644 index 0000000..1c483b0 --- /dev/null +++ b/examples/bffh.dhall @@ -0,0 +1,20 @@ +{ actor_connections = [{ _1 = "Testmachine", _2 = "Actor" }] +, actors = + { Actor = { module = "Shelly", params = {=} } + } +, init_connections = [{ _1 = "Initiator", _2 = "Testmachine" }] +, initiators = + { Initiator = { module = "Dummy", params = {=} } + } +, listens = [{ address = "localhost", port = Some 59661 }] +, machines = + { Testmachine = + { description = Some "A test machine" + , disclose = "lab.test.read" + , manage = "lab.test.admin" + , name = "Testmachine" + , read = "lab.test.read" + , write = "lab.test.write" + } } +, mqtt_url = "tcp://localhost:1883" +} diff --git a/examples/machines.toml b/examples/machines.toml deleted file mode 100644 index 866aef1..0000000 --- a/examples/machines.toml +++ /dev/null @@ -1,14 +0,0 @@ -[e5408099-d3e5-440b-a92b-3aabf7683d6b] -name = "Somemachine" -disclose = "lab.some.disclose" -read = "lab.some.read" -write = "lab.some.write" -manage = "lab.some.admin" - -[eaabebae-34d1-4a3a-912a-967b495d3d6e] -name = "Testmachine" -description = "An optional description" -disclose = "lab.test.read" -read = "lab.test.read" -write = "lab.test.write" -manage = "lab.test.admin" diff --git a/examples/pass.toml b/examples/pass.toml new file mode 100644 index 0000000..6d4855d --- /dev/null +++ b/examples/pass.toml @@ -0,0 +1 @@ +Testuser = "secret" diff --git a/examples/users.toml b/examples/users.toml new file mode 100644 index 0000000..46c4a67 --- /dev/null +++ b/examples/users.toml @@ -0,0 +1,11 @@ +[Testuser] +# Define them in roles.toml as well +roles = [] + +# If two or more users want to use the same machine at once the higher prio +# wins +priority = 0 + +# You can add whatever random data you want. +# It will get stored in the `kv` field in UserData. +noot = "noot!" diff --git a/schema b/schema index a4667b9..83cd61e 160000 --- a/schema +++ b/schema @@ -1 +1 @@ -Subproject commit a4667b94f331f9f624416bbbb951fe78d5304d26 +Subproject commit 83cd61e299230f33474e2efa950667d1acfbe085 diff --git a/src/actor.rs b/src/actor.rs new file mode 100644 index 0000000..fdbff1c --- /dev/null +++ b/src/actor.rs @@ -0,0 +1,178 @@ +use std::pin::Pin; +use std::task::{Poll, Context}; +use std::sync::{Arc, Mutex}; +use std::collections::HashMap; +use std::future::Future; + +use smol::Executor; + +use futures::{future::BoxFuture, Stream, StreamExt}; +use futures::channel::mpsc; +use futures_signals::signal::{Signal, MutableSignalCloned, MutableSignal, Mutable}; + +use crate::db::machine::MachineState; +use crate::config::Config; +use crate::error::Result; +use crate::network::ActorMap; + +use paho_mqtt::AsyncClient; +use slog::Logger; + +pub trait Actuator { + fn apply(&mut self, state: MachineState) -> BoxFuture<'static, ()>; +} + +pub type ActorSignal = Box + Unpin + Send>; + +pub struct Actor { + // FIXME: This should really be a Signal. + // But, alas, MutableSignalCloned is itself not `Clone`. For good reason as keeping track of + // the changes itself happens in a way that Clone won't work (well). + // So, you can't clone it, you can't copy it and you can't get at the variable inside outside + // of a task context. In short, using Mutable isn't possible and we would have to write our own + // implementation of MutableSignal*'s . Preferably with the correct optimizations for our case + // where there is only one consumer. So a mpsc channel that drops all but the last input. + rx: mpsc::Receiver>, + inner: Option, + + actuator: Box, + future: Option>, +} + +impl Actor { + pub fn new(rx: mpsc::Receiver>, actuator: Box) -> Self { + Self { + rx: rx, + inner: None, + actuator: actuator, + future: None, + } + } + + pub fn wrap(actuator: Box) -> (mpsc::Sender>, Self) { + let (tx, rx) = mpsc::channel(1); + (tx, Self::new(rx, actuator)) + } +} + +impl Future for Actor { + type Output = (); + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll { + let mut this = &mut *self; + let mut done = false; // Is the channel with new state-signals exhausted? + + // FIXME: This is potentially invalid, and may lead to the situation that the signal is + // replaced *twice* but the second change will not be honoured since this implementation of + // events is *EDGE*-triggered! + // Update the signal we're polling from, if there is an update that is. + match Stream::poll_next(Pin::new(&mut this.rx), cx) { + Poll::Ready(None) => done = true, + Poll::Ready(Some(new_signal)) => this.inner = new_signal, + Poll::Pending => { }, + } + + // Work until there is no more work to do. + loop { + + // Poll the `apply` future. And ensure it's completed before the next one is started + match this.future.as_mut().map(|future| Future::poll(Pin::new(future), cx)) { + // Skip and poll for a new future to do + None => { } + + // This apply future is done, get a new one + Some(Poll::Ready(_)) => this.future = None, + + // This future would block so we return to continue work another time + Some(Poll::Pending) => return Poll::Pending, + } + + // Poll the signal and apply any change that happen to the inner Actuator + match this.inner.as_mut().map(|inner| Signal::poll_change(Pin::new(inner), cx)) { + // No signal to poll + None => return Poll::Pending, + Some(Poll::Pending) => return Poll::Pending, + Some(Poll::Ready(None)) => { + this.inner = None; + + if done { + return Poll::Ready(()); + } else { + return Poll::Pending; + } + }, + Some(Poll::Ready(Some(state))) => { + // This future MUST be polled before we exit from the Actor::poll because if we + // do not do that it will not register the dependency and thus NOT BE POLLED. + this.future.replace(this.actuator.apply(state)); + } + } + } + } +} + +pub struct Dummy { + log: Logger, +} + +impl Dummy { + pub fn new(log: &Logger) -> Self { + Self { log: log.new(o!("module" => "Dummy Actor")) } + } +} + +impl Actuator for Dummy { + fn apply(&mut self, state: MachineState) -> BoxFuture<'static, ()> { + info!(self.log, "New state for dummy actuator: {:?}", state); + Box::pin(smol::future::ready(())) + } +} + +pub fn load(log: &Logger, client: &AsyncClient, config: &Config) -> Result<(ActorMap, Vec)> { + let mut map = HashMap::new(); + + let actuators = config.actors.iter() + .map(|(k,v)| (k, load_single(log, client, k, &v.module, &v.params))) + .filter_map(|(k, n)| match n { + None => None, + Some(a) => Some((k, a)) + }); + + let mut v = Vec::new(); + for (name, actuator) in actuators { + let (tx, a) = Actor::wrap(actuator); + map.insert(name.clone(), Mutex::new(tx)); + v.push(a); + } + + + Ok(( map, v )) +} + +fn load_single( + log: &Logger, + client: &AsyncClient, + name: &String, + module_name: &String, + params: &HashMap + ) -> Option> +{ + use crate::modules::*; + + match module_name.as_ref() { + "Shelly" => { + if !params.is_empty() { + warn!(log, "\"{}\" module expects no parameters. Configured as \"{}\".", + module_name, name); + } + Some(Box::new(Shelly::new(log, name.clone(), client.clone()))) + }, + "Dummy" => { + Some(Box::new(Dummy::new(log))) + } + _ => { + error!(log, "No actor found with name \"{}\", configured as \"{}\".", module_name, name); + None + }, + } +} diff --git a/src/api.rs b/src/api.rs index 54a2a97..70604b7 100644 --- a/src/api.rs +++ b/src/api.rs @@ -9,21 +9,27 @@ use crate::connection::Session; use crate::db::Databases; +use crate::builtin; + +use crate::network::Network; + pub mod auth; mod machine; mod machines; use machines::Machines; +// TODO Session restoration by making the Bootstrap cap a SturdyRef pub struct Bootstrap { session: Arc, db: Databases, + nw: Arc, } impl Bootstrap { - pub fn new(session: Arc, db: Databases) -> Self { + pub fn new(session: Arc, db: Databases, nw: Arc) -> Self { info!(session.log, "Created Bootstrap"); - Self { session, db } + Self { session, db, nw } } } @@ -33,12 +39,11 @@ impl connection_capnp::bootstrap::Server for Bootstrap { _: Params, mut res: Results ) -> Promise<(), capnp::Error> { - // Forbid mutltiple authentication for now + // TODO: Forbid mutltiple authentication for now // TODO: When should we allow multiple auth and how do me make sure that does not leak // priviledges (e.g. due to previously issues caps)? - if self.session.user.is_none() { - res.get().set_auth(capnp_rpc::new_client(auth::Auth::new(self.session.clone()))) - } + + res.get().set_auth(capnp_rpc::new_client(auth::Auth::new(self.db.passdb.clone(), self.session.clone()))); Promise::ok(()) } @@ -55,7 +60,7 @@ impl connection_capnp::bootstrap::Server for Bootstrap { mut res: Results ) -> Promise<(), capnp::Error> { // TODO actual permission check and stuff - let c = capnp_rpc::new_client(Machines::new(self.session.clone(), self.db.clone())); + let c = capnp_rpc::new_client(Machines::new(self.session.clone(), self.db.clone(), self.nw.clone())); res.get().set_machines(c); Promise::ok(()) diff --git a/src/api/auth.rs b/src/api/auth.rs index 9f39651..6c3bbc2 100644 --- a/src/api/auth.rs +++ b/src/api/auth.rs @@ -27,20 +27,46 @@ use crate::config::Settings; use crate::api::Session; pub use crate::schema::auth_capnp; +use crate::db::pass::PassDB; -pub struct AppData; +pub struct AppData { + passdb: Arc, +} pub struct SessionData; + struct CB; impl Callback for CB { - fn callback(sasl: SaslCtx, session: SaslSession, prop: Property) -> libc::c_int { + fn callback(mut sasl: SaslCtx, session: SaslSession, prop: Property) -> libc::c_int { let ret = match prop { Property::GSASL_VALIDATE_SIMPLE => { - let authid = session.get_property(Property::GSASL_AUTHID).unwrap().to_string_lossy(); - let pass = session.get_property(Property::GSASL_PASSWORD).unwrap().to_string_lossy(); + let authid = match session.get_property(Property::GSASL_AUTHID) { + None => return ReturnCode::GSASL_NO_AUTHID as libc::c_int, + Some(a) => { + match a.to_str() { + Ok(s) => s, + Err(e) => return ReturnCode::GSASL_SASLPREP_ERROR as libc::c_int, + } + }, + }; - if authid == "test" && pass == "secret" { - ReturnCode::GSASL_OK + let pass = session.get_property(Property::GSASL_PASSWORD); + if pass.is_none() { + return ReturnCode::GSASL_NO_PASSWORD as libc::c_int; + } + let pass = pass.unwrap(); + + + if let Some(sessiondata) = sasl.retrieve_mut() { + if let Ok(Some(b)) = sessiondata.passdb.check(authid, pass.to_bytes()) { + if b { + ReturnCode::GSASL_OK + } else { + ReturnCode::GSASL_AUTHENTICATION_ERROR + } + } else { + ReturnCode::GSASL_AUTHENTICATION_ERROR + } } else { ReturnCode::GSASL_AUTHENTICATION_ERROR } @@ -60,10 +86,10 @@ pub struct Auth { } impl Auth { - pub fn new(session: Arc) -> Self { + pub fn new(passdb: Arc, session: Arc) -> Self { let mut ctx = SASL::new().unwrap(); - let mut appdata = Box::new(AppData); + let mut appdata = Box::new(AppData { passdb }); ctx.store(appdata); @@ -172,58 +198,34 @@ impl auth_capnp::authentication::Server for Auth { // somewhere and pass it somewhere else and in between don't check if it's the right type and // accidentally pass the authzid where the authcid should have gone. -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] -/// Authentication Identity -/// -/// Under the hood a string because the form depends heavily on the method -struct AuthCId(String); - -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] -/// Authorization Identity -/// -/// This identity is internal to FabAccess and completely independent from the authentication -/// method or source -struct AuthZId { - /// Main User ID. Generally an user name or similar - uid: String, - /// Sub user ID. - /// - /// Can change scopes for permissions, e.g. having a +admin account with more permissions than - /// the default account and +dashboard et.al. accounts that have restricted permissions for - /// their applications - subuid: String, - /// Realm this account originates. - /// - /// The Realm is usually described by a domain name but local policy may dictate an unrelated - /// mapping - realm: String, -} - // What is a man?! A miserable little pile of secrets! #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] /// Authentication/Authorization user object. /// -/// This struct contains the user as is passed to the actual authentication/authorization -/// subsystems +/// This struct describes the user as can be gathered from API authentication exchanges. +/// Specifically this is the value bffh gets after a successful authentication. /// -pub struct User { +pub struct AuthenticationData { /// Contains the Authentication ID used /// - /// The authentication ID is an identifier for the authentication exchange. This is different - /// than the ID of the user to be authenticated; for example when using x509 the authcid is - /// the dn of the certificate, when using GSSAPI the authcid is of form `@` - authcid: AuthCId, + /// The authentication ID is an identifier for the authentication exchange. This is + /// conceptually different than the ID of the user to be authenticated; for example when using + /// x509 the authcid is the dn of the certificate, when using GSSAPI the authcid is of form + /// `@` + authcid: String, - /// Contains the Authorization ID + /// Authorization ID /// - /// This is the identifier of the user to *authenticate as*. This in several cases is different - /// to the `authcid`: + /// The authzid represents the identity that a client wants to act as. In our case this is + /// always an user id. If unset no preference is indicated and the server will authenticate the + /// client as whatever user — if any — they associate with the authcid. Setting the authzid is + /// useful in a number if situations: /// If somebody wants to authenticate as somebody else, su-style. /// If a person wants to authenticate as a higher-permissions account, e.g. foo may set authzid foo+admin /// to split normal user and "admin" accounts. /// If a method requires a specific authcid that is different from the identifier of the user /// to authenticate as, e.g. GSSAPI, x509 client certificates, API TOKEN authentication. - authzid: AuthZId, + authzid: String, /// Contains the authentication method used /// diff --git a/src/api/machine.rs b/src/api/machine.rs index da6485d..90b2ed5 100644 --- a/src/api/machine.rs +++ b/src/api/machine.rs @@ -1,25 +1,26 @@ use std::sync::Arc; +use std::ops::Deref; use capnp::capability::Promise; use capnp::Error; use crate::schema::api_capnp::State; use crate::schema::api_capnp::machine::*; -use crate::db::machine::MachineIdentifier; use crate::connection::Session; use crate::db::Databases; use crate::db::machine::Status; +use crate::machine::Machine as NwMachine; #[derive(Clone)] pub struct Machine { session: Arc, - id: MachineIdentifier, + machine: NwMachine, db: Databases, } impl Machine { - pub fn new(session: Arc, id: MachineIdentifier, db: Databases) -> Self { - Machine { session, id, db } + pub fn new(session: Arc, machine: NwMachine, db: Databases) -> Self { + Machine { session, machine, db } } pub fn fill(self: Arc, builder: &mut Builder) { @@ -28,32 +29,33 @@ impl Machine { // TODO set all the others } - pub fn fill_info(&self, builder: &mut m_info::Builder) { - if let Some(desc) = self.db.machine.get_desc(&self.id) { - builder.set_name(&desc.name); - if let Some(d) = desc.description.as_ref() { - builder.set_description(d); - } + pub async fn fill_info(&self, builder: &mut m_info::Builder<'_>) { + let guard = self.machine.lock().await; - // TODO: Set `responsible` - // TODO: Error Handling - if let Some(state) = self.db.machine.get_state(&self.id) { - match state.state { - Status::Free => builder.set_state(State::Free), - Status::InUse(_u) => { - builder.set_state(State::InUse); - } - Status::ToCheck(_u) => { - builder.set_state(State::ToCheck); - } - Status::Blocked(_u) => { - builder.set_state(State::Blocked); - } - Status::Disabled => builder.set_state(State::Disabled), - Status::Reserved(_u) => { - builder.set_state(State::Reserved); - } - } + builder.set_name(guard.desc.name.as_ref()); + + if let Some(desc) = guard.desc.description.as_ref() { + builder.set_description(desc); + } + + match guard.read_state().lock_ref().deref().state { + Status::Free => { + builder.set_state(State::Free); + } + Status::Disabled => { + builder.set_state(State::Disabled); + } + Status::Blocked(_,_) => { + builder.set_state(State::Blocked); + } + Status::InUse(_,_) => { + builder.set_state(State::InUse); + } + Status::ToCheck(_,_) => { + builder.set_state(State::ToCheck); + } + Status::Reserved(_,_) => { + builder.set_state(State::Reserved); } } } diff --git a/src/api/machines.rs b/src/api/machines.rs index 42f4171..15ddf28 100644 --- a/src/api/machines.rs +++ b/src/api/machines.rs @@ -8,7 +8,8 @@ use crate::connection::Session; use crate::db::Databases; use crate::db::machine::uuid_from_api; -use crate::db::machine::MachineDB; + +use crate::network::Network; use super::machine::Machine; @@ -19,12 +20,13 @@ pub struct Machines { session: Arc, db: Databases, + network: Arc, } impl Machines { - pub fn new(session: Arc, db: Databases) -> Self { + pub fn new(session: Arc, db: Databases, network: Arc) -> Self { info!(session.log, "Machines created"); - Self { session, db } + Self { session, db, network } } } @@ -34,6 +36,19 @@ impl machines::Server for Machines { mut results: machines::ListMachinesResults) -> Promise<(), Error> { + let v: Vec<(String, crate::machine::Machine)> = self.network.machines.iter() + .map(|(n, m)| (n.clone(), m.clone())) + .collect(); + + let mut res = results.get(); + let mut machines = res.init_machines(v.len() as u32); + + for (i, (name, machine)) in v.into_iter().enumerate() { + let machine = Arc::new(Machine::new(self.session.clone(), machine, self.db.clone())); + let mut builder = machines.reborrow().get(i as u32); + Machine::fill(machine, &mut builder); + } + Promise::ok(()) } @@ -42,26 +57,14 @@ impl machines::Server for Machines { mut results: machines::GetMachineResults) -> Promise<(), Error> { - match params.get() { - Ok(reader) => { - if let Ok(api_id) = reader.get_uuid() { - let id = uuid_from_api(api_id); - if self.db.machine.exists(id) { - debug!(self.session.log, "Accessing machine {}", id); - // TODO check disclose permission - - let mut builder = results.get().init_machine(); - - let m = Machine::new(self.session.clone(), id, self.db.clone()); - - Machine::fill(Arc::new(m), &mut builder); - } else { - debug!(self.session.log, "Client requested nonexisting machine {}", id); - } - } - Promise::ok(()) + if let Ok(uid) = params.get().and_then(|x| x.get_uid()) { + if let Some(machine_inner) = self.network.machines.get(uid) { + let machine = Arc::new(Machine::new(self.session.clone(), machine_inner.clone(), self.db.clone())); + let mut builder = results.get().init_machine(); + Machine::fill(machine, &mut builder); } - Err(e) => Promise::err(e), } + + Promise::ok(()) } } diff --git a/src/builtin.rs b/src/builtin.rs new file mode 100644 index 0000000..dc32f11 --- /dev/null +++ b/src/builtin.rs @@ -0,0 +1,42 @@ +use std::collections::HashMap; +use lazy_static::lazy_static; +use crate::db::access::{ + Permission, + PermissionBuf, + PermRule, + RoleIdentifier, + Role, +}; + +lazy_static! { + static ref AUTH_PERM: &'static Permission = Permission::new("bffh.auth"); +} + +// +// lazy_static! { +// pub static ref AUTH_ROLE: RoleIdentifier = { +// RoleIdentifier::Local { +// name: "mayauth".to_string(), +// source: "builtin".to_string(), +// } +// }; +// } +// +// lazy_static! { +// pub static ref DEFAULT_ROLEIDS: [RoleIdentifier; 1] = { +// [ AUTH_ROLE.clone(), ] +// }; +// +// pub static ref DEFAULT_ROLES: HashMap = { +// let mut m = HashMap::new(); +// m.insert(AUTH_ROLE.clone(), +// Role { +// parents: vec![], +// permissions: vec![ +// PermRule::Base(PermissionBuf::from_perm(AUTH_PERM)), +// ] +// } +// ); +// m +// }; +// } diff --git a/src/config.rs b/src/config.rs index d1e5b07..a18b7d6 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,37 +1,47 @@ +use std::default::Default; use std::str::FromStr; use std::path::{Path, PathBuf}; -use serde::{Serialize, Deserialize}; use std::io::Read; -use std::fs::File; - -use crate::error::Result; - -use std::default::Default; - +use std::fs; use std::collections::HashMap; -use config::Config; -pub use config::ConfigError; -use glob::glob; +use serde::{Serialize, Deserialize}; -pub fn read(path: &Path) -> Result { - let mut settings = Config::default(); - settings - .merge(config::File::from(path)).unwrap(); +use crate::error::Result; +use crate::machine::MachineDescription; +use crate::db::machine::MachineIdentifier; +use crate::db::access::*; - Ok(settings.try_into()?) +pub fn read(path: &Path) -> Result { + serde_dhall::from_file(path) + .parse() + .map_err(Into::into) } +#[deprecated] +pub type Settings = Config; + #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Settings { - pub machines: PathBuf, +pub struct Config { + /// A list of address/port pairs to listen on. + // TODO: This should really be a variant type; that is something that can figure out itself if + // it contains enough information to open a socket (i.e. it checks if it's a valid path (=> + // Unix socket) or IPv4/v6 address) pub listens: Box<[Listen]>, - pub shelly: Option, -} -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct ShellyCfg { - pub mqtt_url: String + /// Machine descriptions to load + pub machines: HashMap, + + /// Actors to load and their configuration options + pub actors: HashMap, + + /// Initiators to load and their configuration options + pub initiators: HashMap, + + pub mqtt_url: String, + + pub actor_connections: Box<[(String, String)]>, + pub init_connections: Box<[(String, String)]>, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -40,21 +50,55 @@ pub struct Listen { pub port: Option, } -impl Default for Settings { +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ModuleConfig { + pub module: String, + pub params: HashMap +} + +impl Default for Config { fn default() -> Self { - Settings { - listens: Box::new([Listen { - address: "127.0.0.1".to_string(), - port: Some(DEFAULT_PORT) - }, + let mut actors: HashMap:: = HashMap::new(); + let mut initiators: HashMap:: = HashMap::new(); + let mut machines = HashMap::new(); + + actors.insert("Actor".to_string(), ModuleConfig { + module: "Shelly".to_string(), + params: HashMap::new(), + }); + initiators.insert("Initiator".to_string(), ModuleConfig { + module: "TCP-Listen".to_string(), + params: HashMap::new(), + }); + + machines.insert("Testmachine".to_string(), MachineDescription { + name: "Testmachine".to_string(), + description: Some("A test machine".to_string()), + privs: PrivilegesBuf { + disclose: PermissionBuf::from_string("lab.test.read".to_string()), + read: PermissionBuf::from_string("lab.test.read".to_string()), + write: PermissionBuf::from_string("lab.test.write".to_string()), + manage: PermissionBuf::from_string("lab.test.admin".to_string()), + }, + }); + + Config { + listens: Box::new([ Listen { - address: "::1".to_string(), - port: Some(DEFAULT_PORT) - }]), - shelly: Some(ShellyCfg { - mqtt_url: "127.0.0.1:1883".to_string() - }), - machines: PathBuf::from("/etc/bffh/machines/") + address: "localhost".to_string(), + port: Some(DEFAULT_PORT), + } + ]), + machines: machines, + actors: actors, + initiators: initiators, + mqtt_url: "tcp://localhost:1883".to_string(), + actor_connections: Box::new([ + ("Testmachine".to_string(), "Actor".to_string()), + ]), + init_connections: Box::new([ + ("Initiator".to_string(), "Testmachine".to_string()), + ]), } } } diff --git a/src/connection.rs b/src/connection.rs index 1974e1b..7022c7d 100644 --- a/src/connection.rs +++ b/src/connection.rs @@ -1,4 +1,6 @@ use std::sync::Arc; +use std::future::Future; +use futures::FutureExt; use slog::Logger; @@ -13,63 +15,60 @@ use capnp_rpc::{twoparty, rpc_twoparty_capnp}; use crate::schema::connection_capnp; use crate::db::Databases; +use crate::db::access::{AccessControl, Permission}; +use crate::db::user::User; +use crate::builtin; +use crate::network::Network; #[derive(Debug, Clone)] /// Connection context // TODO this should track over several connections pub struct Session { + // Session-spezific log pub log: Logger, - pub user: Option, + user: Option, + accessdb: Arc, } impl Session { - pub fn new(log: Logger) -> Self { + pub fn new(log: Logger, accessdb: Arc) -> Self { let user = None; - Session { log, user } + Session { log, user, accessdb } } -} -async fn handshake(log: &Logger, stream: &mut TcpStream) -> Result<()> { - if let Some(m) = capnp_futures::serialize::read_message(stream.clone(), Default::default()).await? { - let greeting = m.get_root::()?; - let major = greeting.get_major(); - let minor = greeting.get_minor(); - - if major != 0 { - Err(Error::BadVersion((major, minor))) + /// Check if the current session has a certain permission + pub async fn check_permission>(&self, perm: &P) -> Result { + if let Some(user) = self.user.as_ref() { + self.accessdb.check(&user.data, perm).await } else { - let program = format!("{}-{}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")); - - let mut answer = ::capnp::message::Builder::new_default(); - let mut b = answer.init_root::(); - b.set_program(&program); - b.set_host("localhost"); - b.set_major(0); - b.set_minor(1); - capnp_futures::serialize::write_message(stream, answer).await?; - info!(log, "Handshake successful with peer {} running {}, API {}.{}", - greeting.get_host()?, greeting.get_program()?, major, minor); - Ok(()) + Ok(false) } - } else { - unimplemented!() } } -pub async fn handle_connection(log: Logger, mut stream: TcpStream, db: Databases) -> Result<()> { - handshake(&log, &mut stream).await?; - - info!(log, "New connection from on {:?}", stream); - let session = Arc::new(Session::new(log)); - let boots = Bootstrap::new(session, db); - let rpc: connection_capnp::bootstrap::Client = capnp_rpc::new_client(boots); - - let network = twoparty::VatNetwork::new(stream.clone(), stream, - rpc_twoparty_capnp::Side::Server, Default::default()); - let rpc_system = capnp_rpc::RpcSystem::new(Box::new(network), - Some(rpc.client)); - - rpc_system.await.unwrap(); - Ok(()) +pub struct ConnectionHandler { + log: Logger, + db: Databases, + network: Arc, +} + +impl ConnectionHandler { + pub fn new(log: Logger, db: Databases, network: Arc) -> Self { + Self { log, db, network } + } + + pub fn handle(&mut self, mut stream: TcpStream) -> impl Future> { + info!(self.log, "New connection from on {:?}", stream); + let session = Arc::new(Session::new(self.log.new(o!()), self.db.access.clone())); + let boots = Bootstrap::new(session, self.db.clone(), self.network.clone()); + let rpc: connection_capnp::bootstrap::Client = capnp_rpc::new_client(boots); + + let network = twoparty::VatNetwork::new(stream.clone(), stream, + rpc_twoparty_capnp::Side::Server, Default::default()); + let rpc_system = capnp_rpc::RpcSystem::new(Box::new(network), Some(rpc.client)); + + // Convert the error type to one of our errors + rpc_system.map(|r| r.map_err(Into::into)) + } } diff --git a/src/db.rs b/src/db.rs index 6a67f44..e3c044c 100644 --- a/src/db.rs +++ b/src/db.rs @@ -1,14 +1,22 @@ use std::sync::Arc; +use std::path::PathBuf; +use std::str::FromStr; +use slog::Logger; + +use crate::error::Result; +use crate::config::Settings; + +/// (Hashed) password database +pub mod pass; + +/// User storage +pub mod user; /// Access control storage /// /// Stores&Retrieves Permissions and Roles pub mod access; -/// User storage -/// -/// Stores&Retrieves Users -pub mod user; /// Machine storage /// @@ -18,5 +26,41 @@ pub mod machine; #[derive(Clone)] pub struct Databases { pub access: Arc, - pub machine: Arc, + pub machine: Arc, + pub passdb: Arc, + pub userdb: Arc, +} + +const LMDB_MAX_DB: u32 = 16; + +impl Databases { + pub fn new(log: &Logger, config: &Settings) -> Result { + + // Initialize the LMDB environment. This blocks until the mmap() finishes + info!(log, "LMDB env"); + let env = lmdb::Environment::new() + .set_flags(lmdb::EnvironmentFlags::MAP_ASYNC | lmdb::EnvironmentFlags::NO_SUB_DIR) + .set_max_dbs(LMDB_MAX_DB as libc::c_uint) + .open(&PathBuf::from_str("/tmp/a.db").unwrap())?; + + // Start loading the machine database, authentication system and permission system + // All of those get a custom logger so the source of a log message can be better traced and + // filtered + let env = Arc::new(env); + let mdb = machine::init(log.new(o!("system" => "machines")), &config, env.clone())?; + + let permdb = access::init(log.new(o!("system" => "permissions")), &config, env.clone())?; + let mut ac = access::AccessControl::new(permdb); + + let passdb = pass::PassDB::init(log.new(o!("system" => "passwords")), env.clone()).unwrap(); + + let userdb = user::init(log.new(o!("system" => "users")), &config, env.clone())?; + + Ok(Self { + access: Arc::new(ac), + passdb: Arc::new(passdb), + machine: Arc::new(mdb), + userdb: Arc::new(userdb), + }) + } } diff --git a/src/db/access.rs b/src/db/access.rs index dc77cf3..1c3a1a7 100644 --- a/src/db/access.rs +++ b/src/db/access.rs @@ -29,16 +29,18 @@ use crate::error::Result; pub mod internal; -use crate::db::user::User; -pub use internal::init; +use crate::db::user::UserData; +pub use internal::{init, Internal}; pub struct AccessControl { + pub internal: Internal, sources: HashMap>, } impl AccessControl { - pub fn new() -> Self { + pub fn new(internal: Internal) -> Self { Self { + internal: internal, sources: HashMap::new() } } @@ -49,25 +51,52 @@ impl AccessControl { self.sources.insert(name, source); } - pub async fn check>(&self, user: &User, perm: &P) -> Result { + pub async fn check>(&self, user: &UserData, perm: &P) -> Result { for v in self.sources.values() { if v.check(user, perm.as_ref())? { return Ok(true); } } + if self.internal.check(user, perm.as_ref())? { + return Ok(true); + } + + return Ok(false); + } + + pub async fn check_roles>(&self, roles: &[RoleIdentifier], perm: &P) + -> Result + { + for v in self.sources.values() { + if v.check_roles(roles, perm.as_ref())? { + return Ok(true); + } + } return Ok(false); } } +impl fmt::Debug for AccessControl { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut b = f.debug_struct("AccessControl"); + for (name, roledb) in self.sources.iter() { + b.field(name, &roledb.get_type_name().to_string()); + } + b.finish() + } +} + pub trait RoleDB { + fn get_type_name(&self) -> &'static str; + fn get_role(&self, roleID: &RoleIdentifier) -> Result>; /// Check if a given user has the given permission /// /// Default implementation which adapter may overwrite with more efficient specialized /// implementations. - fn check(&self, user: &User, perm: &Permission) -> Result { + fn check(&self, user: &UserData, perm: &Permission) -> Result { self.check_roles(&user.roles, perm) } @@ -130,8 +159,6 @@ pub trait RoleDB { /// assign to all users. #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Role { - name: String, - // If a role doesn't define parents, default to an empty Vec. #[serde(default, skip_serializing_if = "Vec::is_empty")] /// A Role can have parents, inheriting all permissions @@ -328,6 +355,10 @@ impl PermissionBuf { Self { inner } } + pub fn from_perm(perm: &Permission) -> Self { + Self { inner: perm.inner.to_string() } + } + pub fn into_string(self) -> String { self.inner } @@ -501,7 +532,7 @@ impl TryFrom for PermRule { } } -#[cfg(test)] +#[cfg(test_DISABLED)] mod tests { use super::*; diff --git a/src/db/access/internal.rs b/src/db/access/internal.rs index 05d73e6..b4bd94e 100644 --- a/src/db/access/internal.rs +++ b/src/db/access/internal.rs @@ -17,24 +17,23 @@ use crate::config::Settings; use crate::error::Result; use crate::db::access::{Permission, Role, RoleIdentifier, RoleDB}; -use crate::db::user::{UserIdentifier, User}; +use crate::db::user::{User, UserData}; #[derive(Clone, Debug)] pub struct Internal { log: Logger, env: Arc, roledb: lmdb::Database, - userdb: lmdb::Database, } impl Internal { - pub fn new(log: Logger, env: Arc, roledb: lmdb::Database, userdb: lmdb::Database) -> Self { - Self { log, env, roledb, userdb } + pub fn new(log: Logger, env: Arc, roledb: lmdb::Database) -> Self { + Self { log, env, roledb, } } /// Check if a given user has the given permission #[allow(unused)] - pub fn _check>(&self, txn: &T, user: &User, perm: &P) + pub fn _check>(&self, txn: &T, user: &UserData, perm: &P) -> Result { // Tally all roles. Makes dependent roles easier @@ -117,40 +116,29 @@ impl Internal { unimplemented!() } - pub fn load_db(&mut self, txn: &mut RwTransaction, mut path: PathBuf) -> Result<()> { - path.push("roles"); - if !path.is_dir() { - error!(self.log, "Given load directory is malformed, no 'roles' subdir, not loading roles!"); - } else { - self.load_roles(txn, path.as_path())?; - } - - Ok(()) + pub fn load_roles>(&self, path: P) -> Result<()> { + let mut txn = self.env.begin_rw_txn()?; + self.load_roles_txn(&mut txn, path.as_ref()) } + fn load_roles_txn(&self, txn: &mut RwTransaction, path: &Path) -> Result<()> { + let roles = Role::load_file(path)?; - fn load_roles(&mut self, txn: &mut RwTransaction, path: &Path) -> Result<()> { - if path.is_file() { - let roles = Role::load_file(path)?; - - for (k,v) in roles.iter() { - self.put_role(txn, k, v.clone())?; - } - } else { - for entry in std::fs::read_dir(path)? { - let roles = Role::load_file(entry?.path())?; - - for (k,v) in roles.iter() { - self.put_role(txn, k, v.clone())?; - } - } + for (k,v) in roles.iter() { + self.put_role(txn, k, v.clone())?; } + debug!(self.log, "Loaded roles: {:?}", roles); + Ok(()) } } impl RoleDB for Internal { - fn check(&self, user: &User, perm: &Permission) -> Result { + fn get_type_name(&self) -> &'static str { + "Internal" + } + + fn check(&self, user: &UserData, perm: &Permission) -> Result { let txn = self.env.begin_ro_txn()?; self._check(&txn, user, &perm) } @@ -178,9 +166,6 @@ pub fn init(log: Logger, config: &Settings, env: Arc) debug!(&log, "Opened access database '{}' successfully.", "role"); //let permdb = env.create_db(Some("perm"), flags)?; //debug!(&log, "Opened access database '{}' successfully.", "perm"); - let userdb = env.create_db(Some("user"), flags)?; - debug!(&log, "Opened access database '{}' successfully.", "user"); - info!(&log, "Opened all access databases"); - Ok(Internal::new(log, env, roledb, userdb)) + Ok(Internal::new(log, env, roledb)) } diff --git a/src/db/machine.rs b/src/db/machine.rs index e508643..a243408 100644 --- a/src/db/machine.rs +++ b/src/db/machine.rs @@ -16,8 +16,6 @@ use crate::error::Result; use crate::config::Settings; use crate::db::access; -use crate::db::user::UserIdentifier; - use capnp::Error; use uuid::Uuid; @@ -29,15 +27,15 @@ use smol::channel::{Receiver, Sender}; use futures::{Future, Stream, StreamExt}; use futures_signals::signal::*; -use crate::registries::StatusSignal; -use crate::db::user::User; - use crate::machine::MachineDescription; +use crate::db::user::UserId; + pub mod internal; use internal::Internal; -pub type MachineIdentifier = Uuid; +pub type MachineIdentifier = String; +pub type Priority = u64; /// Status of a Machine #[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] @@ -45,15 +43,15 @@ pub enum Status { /// Not currently used by anybody Free, /// Used by somebody - InUse(UserIdentifier), + InUse(UserId, Priority), /// Was used by somebody and now needs to be checked for cleanliness - ToCheck(UserIdentifier), + ToCheck(UserId, Priority), /// Not used by anybody but also can not be used. E.g. down for maintenance - Blocked(UserIdentifier), + Blocked(UserId, Priority), /// Disabled for some other reason Disabled, /// Reserved - Reserved(UserIdentifier), + Reserved(UserId, Priority), } pub fn uuid_from_api(uuid: crate::schema::api_capnp::u_u_i_d::Reader) -> Uuid { @@ -76,8 +74,37 @@ pub struct MachineState { pub state: Status, } +impl MachineState { + pub fn new() -> Self { + Self { state: Status::Free } + } + + pub fn free() -> Self { + Self { state: Status::Free } + } + + pub fn used(uid: UserId, priority: Priority) -> Self { + Self { state: Status::InUse(uid, priority) } + } + + /// Check if the given priority is higher than one's own. + /// + /// If `self` does not have a priority then this function always returns `true` + pub fn is_higher_priority(&self, priority: u64) -> bool { + match self.state { + Status::Disabled | Status::Free => { true }, + Status::Blocked(_, self_prio) | + Status::InUse(_, self_prio) | + Status::ToCheck(_, self_prio) | + Status::Reserved(_, self_prio) => + { + priority > self_prio + } + } + } +} + pub fn init(log: Logger, config: &Settings, env: Arc) -> Result { - let mut machine_descriptions = MachineDescription::load_file(&config.machines)?; let mut flags = lmdb::DatabaseFlags::empty(); flags.set(lmdb::DatabaseFlags::INTEGER_KEY, true); let machdb = env.create_db(Some("machines"), flags)?; @@ -85,30 +112,3 @@ pub fn init(log: Logger, config: &Settings, env: Arc) -> Resu Ok(Internal::new(log, env, machdb)) } - -type MachMap = HashMap; - -#[derive(Debug)] -pub struct MachineDB { - state_db: Internal, - def_db: MachMap, -} - -impl MachineDB { - pub fn new(state_db: Internal, def_db: MachMap) -> Self { - Self { state_db, def_db } - } - - pub fn exists(&self, id: MachineIdentifier) -> bool { - self.def_db.get(&id).is_some() - } - - pub fn get_desc(&self, id: &MachineIdentifier) -> Option<&MachineDescription> { - self.def_db.get(&id) - } - - pub fn get_state(&self, id: &MachineIdentifier) -> Option { - // TODO: Error Handling - self.state_db.get(id).unwrap_or(None) - } -} diff --git a/src/db/machine/internal.rs b/src/db/machine/internal.rs index 8b6f90b..74cbadd 100644 --- a/src/db/machine/internal.rs +++ b/src/db/machine/internal.rs @@ -30,10 +30,10 @@ impl Internal { Self { log, env, db } } - pub fn get_with_txn(&self, txn: &T, uuid: &Uuid) + pub fn get_with_txn(&self, txn: &T, id: &String) -> Result> { - match txn.get(self.db, uuid.as_bytes()) { + match txn.get(self.db, &id.as_bytes()) { Ok(bytes) => { let mut machine: MachineState = flexbuffers::from_slice(bytes)?; Ok(Some(machine)) @@ -48,20 +48,25 @@ impl Internal { self.get_with_txn(&txn, id) } - pub fn put_with_txn(&self, txn: &mut RwTransaction, uuid: &Uuid, status: MachineState) + pub fn put_with_txn(&self, txn: &mut RwTransaction, uuid: &String, status: &MachineState) -> Result<()> { let bytes = flexbuffers::to_vec(status)?; - txn.put(self.db, uuid.as_bytes(), &bytes, lmdb::WriteFlags::empty())?; + txn.put(self.db, &uuid.as_bytes(), &bytes, lmdb::WriteFlags::empty())?; Ok(()) } + pub fn put(&self, id: &MachineIdentifier, status: &MachineState) -> Result<()> { + let mut txn = self.env.begin_rw_txn()?; + self.put_with_txn(&mut txn, id, status)?; + txn.commit().map_err(Into::into) + } + pub fn iter(&self, txn: &T) -> Result> { let mut cursor = txn.open_ro_cursor(self.db)?; Ok(cursor.iter_start().map(|buf| { let (kbuf, vbuf) = buf.unwrap(); - let machID = uuid::Uuid::from_slice(kbuf).unwrap(); flexbuffers::from_slice(vbuf).unwrap() })) } diff --git a/src/db/pass.rs b/src/db/pass.rs new file mode 100644 index 0000000..4ee9321 --- /dev/null +++ b/src/db/pass.rs @@ -0,0 +1,79 @@ +use std::sync::Arc; +use std::path::Path; +use std::fs; +use std::collections::HashMap; + +use argon2; +use lmdb::{Environment, Transaction, RwTransaction, Cursor}; +use rand::prelude::*; +use slog::Logger; + +use crate::error::Result; + +pub struct PassDB { + log: Logger, + env: Arc, + db: lmdb::Database, +} + +impl PassDB { + pub fn new(log: Logger, env: Arc, db: lmdb::Database) -> Self { + Self { log, env, db } + } + + pub fn init(log: Logger, env: Arc) -> Result { + let mut flags = lmdb::DatabaseFlags::empty(); + flags.set(lmdb::DatabaseFlags::INTEGER_KEY, true); + let db = env.create_db(Some("pass"), flags)?; + + Ok(Self::new(log, env, db)) + } + + /// Check a password for a given authcid. + /// + /// `Ok(None)` means the given authcid is not stored in the database + pub fn check_with_txn(&self, txn: &T, authcid: &str, password: &[u8]) -> Result> { + match txn.get(self.db, &authcid.as_bytes()) { + Ok(bytes) => { + let encoded = unsafe { std::str::from_utf8_unchecked(bytes) }; + let res = argon2::verify_encoded(encoded, password)?; + Ok(Some(res)) + }, + Err(lmdb::Error::NotFound) => { Ok(None) }, + Err(e) => { Err(e.into()) }, + } + } + pub fn check(&self, authcid: &str, password: &[u8]) -> Result> { + let txn = self.env.begin_ro_txn()?; + self.check_with_txn(&txn, authcid, password) + } + + /// Store a password for a given authcid, potentially overwriting an existing password + pub fn store_with_txn(&self, txn: &mut RwTransaction, authcid: &str, password: &[u8]) -> Result<()> { + let config = argon2::Config::default(); + let salt: [u8; 16] = rand::random(); + let hash = argon2::hash_encoded(password, &salt, &config)?; + txn.put(self.db, &authcid.as_bytes(), &hash.as_bytes(), lmdb::WriteFlags::empty()) + .map_err(Into::into) + } + + pub fn insert_multiple(&self, vec: Vec<(String, String)>) -> Result<()> { + let mut txn = self.env.begin_rw_txn()?; + for (authcid, password) in vec.iter() { + self.store_with_txn(&mut txn, authcid.as_ref(), password.as_bytes())?; + } + txn.commit()?; + + let v: Vec<&String> = vec.iter().map(|(a,_)| a).collect(); + debug!(self.log, "Loaded passwords for: {:?}", v); + + Ok(()) + } + + pub fn load_file>(&self, path: P) -> Result<()> { + let f = fs::read(path)?; + let mut map: HashMap = toml::from_slice(&f)?; + + self.insert_multiple(map.drain().collect()) + } +} diff --git a/src/db/user.rs b/src/db/user.rs index c5a3f23..e26bdaa 100644 --- a/src/db/user.rs +++ b/src/db/user.rs @@ -1,63 +1,137 @@ +//! UserDB does two kinds of lookups: +//! 1. "I have this here username, what user is that" +//! 2. "I have this here user, what are their roles (and other associated data)" use serde::{Serialize, Deserialize}; use std::fmt; +use std::fs; +use std::sync::Arc; +use std::iter::FromIterator; +use std::path::Path; use crate::db::access::RoleIdentifier; use std::collections::HashMap; -/// A Person, from the Authorization perspective -#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)] +use slog::Logger; + +use crate::error::Result; +use crate::config::Config; + +mod internal; +pub use internal::Internal; + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +/// An user pub struct User { - /// The identification of this user. - pub id: UserIdentifier, - - /// A Person has N ≥ 0 roles. - /// Persons are only ever given roles, not permissions directly - pub roles: Vec, - - /// Additional data storage - #[serde(flatten)] - kv: HashMap, Box<[u8]>>, + /// The precise (and unique) identifier of this user + pub id: UserId, + /// Data BFFH stores on this user to base decisions on + pub data: UserData, } - -/// Locally unique identifier for an user -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] -pub struct UserIdentifier { - /// Main UID. Must be unique in this instance so that the tuple (uid, location) is globally - /// unique. - uid: String, - /// Subordinate ID. Must be unique for this user, i.e. the tuple (uid, subuid) must be unique - /// but two different uids can have the same subuid. `None` means no subuid is set and the ID - /// refers to the main users - subuid: Option, - /// Location of the instance the user comes from. `None` means the local instance. - location: Option, -} - -impl UserIdentifier { - pub fn new(uid: String, subuid: Option, location: Option) -> Self { - Self { uid, subuid, location } +impl User { + pub fn new(id: UserId, data: UserData) -> Self { + Self { id, data } } } -impl fmt::Display for UserIdentifier { +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] +/// Authorization Identity +/// +/// This identity is internal to FabAccess and completely independent from the authentication +/// method or source +pub struct UserId { + /// Main User ID. Generally an user name or similar. Locally unique + uid: String, + /// Sub user ID. + /// + /// Can change scopes for permissions, e.g. having a +admin account with more permissions than + /// the default account and +dashboard et.al. accounts that have restricted permissions for + /// their applications + subuid: Option, + /// Realm this account originates. + /// + /// The Realm is usually described by a domain name but local policy may dictate an unrelated + /// mapping + realm: Option, +} + +impl UserId { + pub fn new(uid: String, subuid: Option, realm: Option) -> Self { + Self { uid, subuid, realm } + } +} + +impl fmt::Display for UserId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let r = write!(f, "{}", self.uid); if let Some(ref s) = self.subuid { write!(f, "+{}", s)?; } - if let Some(ref l) = self.location { + if let Some(ref l) = self.realm { write!(f, "@{}", l)?; } r } } -/// User Database Trait -pub trait UserDB { - fn get_user(&self, uid: UserIdentifier) -> Option; +#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)] +/// Data on an user to base decisions on +/// +/// This of course includes authorization data, i.e. that users set roles +pub struct UserData { + /// A Person has N ≥ 0 roles. + /// Persons are only ever given roles, not permissions directly + pub roles: Vec, + + #[serde(skip_serializing_if = "is_zero")] + #[serde(default = "default_priority")] + /// A priority number, defaulting to 0. + /// + /// The higher, the higher the priority. Higher priority users overwrite lower priority ones. + pub priority: u64, + + /// Additional data storage + #[serde(flatten, skip_serializing_if = "HashMap::is_empty")] + kv: HashMap, } -#[cfg(test)] +impl UserData { + pub fn new(roles: Vec, priority: u64) -> Self { + Self { + roles: roles, + priority: priority, + kv: HashMap::new(), + } + } +} + +fn is_zero(i: &u64) -> bool { + *i == 0 +} +const fn default_priority() -> u64 { + 0 +} + +pub fn load_file>(path: P) -> Result> { + let f = fs::read(path)?; + let mut map: HashMap = toml::from_slice(&f)?; + + Ok(HashMap::from_iter(map.drain().map(|(uid, user_data)| + ( uid.clone() + , User::new(UserId::new(uid, None, None), user_data) + ) + ))) +} + +pub fn init(log: Logger, config: &Config, env: Arc) -> Result { + let mut flags = lmdb::DatabaseFlags::empty(); + flags.set(lmdb::DatabaseFlags::INTEGER_KEY, true); + let db = env.create_db(Some("users"), flags)?; + debug!(&log, "Opened user db successfully."); + + Ok(Internal::new(log, env, db)) +} + +#[cfg(test_DISABLED)] mod tests { use super::*; @@ -65,7 +139,7 @@ mod tests { fn format_uid_test() { let uid = "testuser".to_string(); let suid = "testsuid".to_string(); - let location = "testloc".to_string(); + let realm = "testloc".to_string(); assert_eq!("testuser", format!("{}", UserIdentifier::new(uid.clone(), None, None))); @@ -74,6 +148,6 @@ mod tests { assert_eq!("testuser+testsuid", format!("{}", UserIdentifier::new(uid.clone(), Some(suid.clone()), None))); assert_eq!("testuser+testsuid@testloc", - format!("{}", UserIdentifier::new(uid, Some(suid), Some(location)))); + format!("{}", UserIdentifier::new(uid, Some(suid), Some(realm)))); } } diff --git a/src/db/user/internal.rs b/src/db/user/internal.rs new file mode 100644 index 0000000..49c5580 --- /dev/null +++ b/src/db/user/internal.rs @@ -0,0 +1,49 @@ +use std::sync::Arc; + +use slog::Logger; +use lmdb::{Environment, Transaction, RwTransaction, Cursor}; + +use crate::error::Result; + +use super::*; + +#[derive(Clone, Debug)] +pub struct Internal { + log: Logger, + env: Arc, + db: lmdb::Database, +} + +impl Internal { + pub fn new(log: Logger, env: Arc, db: lmdb::Database) -> Self { + Self { log, env, db } + } + + pub fn get_user_txn(&self, txn: &T, uid: &str) -> Result> { + match txn.get(self.db, &uid.as_bytes()) { + Ok(bytes) => { + Ok(Some(flexbuffers::from_slice(bytes)?)) + }, + Err(lmdb::Error::NotFound) => Ok(None), + Err(e) => Err(e.into()), + } + } + pub fn get_user(&self, uid: &str) -> Result> { + let txn = self.env.begin_ro_txn()?; + self.get_user_txn(&txn, uid) + } + + pub fn put_user_txn(&self, txn: &mut RwTransaction, uid: &str, user: &User) -> Result<()> { + let bytes = flexbuffers::to_vec(user)?; + txn.put(self.db, &uid.as_bytes(), &bytes, lmdb::WriteFlags::empty())?; + + Ok(()) + } + pub fn put_user(&self, uid: &str, user: &User) -> Result<()> { + let mut txn = self.env.begin_rw_txn()?; + self.put_user_txn(&mut txn, uid, user)?; + txn.commit()?; + + Ok(()) + } +} diff --git a/src/error.rs b/src/error.rs index 758260d..801b435 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,18 +1,22 @@ use std::io; use std::fmt; use toml; +use serde_dhall; use rsasl::SaslError; // SpawnError is a somewhat ambigous name, `use as` to make it futures::SpawnError instead. -use futures::task as futures; +use futures::task as futures_task; use paho_mqtt::errors as mqtt; +use crate::network; + #[derive(Debug)] pub enum Error { TomlDe(toml::de::Error), TomlSer(toml::ser::Error), + Dhall(serde_dhall::Error), SASL(SaslError), IO(io::Error), Boxed(Box), @@ -20,10 +24,12 @@ pub enum Error { LMDB(lmdb::Error), FlexbuffersDe(flexbuffers::DeserializationError), FlexbuffersSer(flexbuffers::SerializationError), - FuturesSpawn(futures::SpawnError), + FuturesSpawn(futures_task::SpawnError), MQTT(mqtt::Error), - Config(config::ConfigError), BadVersion((u32,u32)), + Argon2(argon2::Error), + EventNetwork(network::Error), + Denied, } impl fmt::Display for Error { @@ -35,6 +41,9 @@ impl fmt::Display for Error { Error::TomlSer(e) => { write!(f, "TOML Serialization error: {}", e) }, + Error::Dhall(e) => { + write!(f, "Dhall coding error: {}", e) + }, Error::SASL(e) => { write!(f, "SASL Error: {}", e) }, @@ -62,12 +71,18 @@ impl fmt::Display for Error { Error::MQTT(e) => { write!(f, "Paho MQTT encountered an error: {}", e) }, - Error::Config(e) => { - write!(f, "Failed to parse config: {}", e) + Error::Argon2(e) => { + write!(f, "Argon2 en/decoding failure: {}", e) } Error::BadVersion((major,minor)) => { write!(f, "Peer uses API version {}.{} which is incompatible!", major, minor) } + Error::Denied => { + write!(f, "You do not have the permission required to do that.") + } + Error::EventNetwork(e) => { + e.fmt(f) + } } } } @@ -96,6 +111,12 @@ impl From for Error { } } +impl From for Error { + fn from(e: serde_dhall::Error) -> Error { + Error::Dhall(e) + } +} + impl From> for Error { fn from(e: Box) -> Error { Error::Boxed(e) @@ -126,8 +147,8 @@ impl From for Error { } } -impl From for Error { - fn from(e: futures::SpawnError) -> Error { +impl From for Error { + fn from(e: futures_task::SpawnError) -> Error { Error::FuturesSpawn(e) } } @@ -138,9 +159,15 @@ impl From for Error { } } -impl From for Error { - fn from(e: config::ConfigError) -> Error { - Error::Config(e) +impl From for Error { + fn from(e: network::Error) -> Error { + Error::EventNetwork(e) + } +} + +impl From for Error { + fn from(e: argon2::Error) -> Error { + Error::Argon2(e) } } diff --git a/src/initiator.rs b/src/initiator.rs new file mode 100644 index 0000000..94765f8 --- /dev/null +++ b/src/initiator.rs @@ -0,0 +1,169 @@ +use std::pin::Pin; +use std::task::{Poll, Context}; +use std::future::Future; +use std::collections::HashMap; + +use smol::{Task, Timer}; + +use slog::Logger; + +use paho_mqtt::AsyncClient; + +use futures::FutureExt; +use futures::future::BoxFuture; + +use genawaiter::{sync::{Gen, GenBoxed, Co}, GeneratorState}; + +use futures_signals::signal::{Signal, Mutable, MutableSignalCloned}; +use crate::machine::{Machine, ReturnToken}; +use crate::db::machine::MachineState; +use crate::db::user::{User, UserId, UserData}; + +use crate::network::InitMap; + +use crate::error::Result; +use crate::config::Config; + +pub trait Sensor { + fn run_sensor(&mut self) -> BoxFuture<'static, (Option, MachineState)>; +} + +type BoxSensor = Box; + +pub struct Initiator { + signal: MutableSignalCloned>, + machine: Option, + future: Option, MachineState)>>, + token: Option, + sensor: BoxSensor, +} + +impl Initiator { + pub fn new(sensor: BoxSensor, signal: MutableSignalCloned>) -> Self { + Self { + signal: signal, + machine: None, + future: None, + token: None, + sensor: sensor, + } + } + + pub fn wrap(sensor: BoxSensor) -> (Mutable>, Self) { + let m = Mutable::new(None); + let s = m.signal_cloned(); + + (m, Self::new(sensor, s)) + } +} + +impl Future for Initiator { + type Output = (); + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll { + let mut this = &mut *self; + + // First of course, see what machine we should work with. + match Signal::poll_change(Pin::new(&mut this.signal), cx) { + Poll::Pending => { } + Poll::Ready(None) => return Poll::Ready(()), + // Keep in mind this is actually an Option + Poll::Ready(Some(machine)) => this.machine = machine, + } + + // Do as much work as we can: + loop { + // If there is a future, poll it + match this.future.as_mut().map(|future| Future::poll(Pin::new(future), cx)) { + None => { + this.future = Some(this.sensor.run_sensor()); + }, + Some(Poll::Ready((user, state))) => { + this.future.take(); + this.machine.as_mut().map(|machine| machine.request_state_change(user.as_ref(), state).unwrap()); + } + Some(Poll::Pending) => return Poll::Pending, + } + } + } +} + +pub fn load(log: &Logger, client: &AsyncClient, config: &Config) -> Result<(InitMap, Vec)> { + let mut map = HashMap::new(); + + let initiators = config.initiators.iter() + .map(|(k,v)| (k, load_single(log, client, k, &v.module, &v.params))) + .filter_map(|(k,n)| match n { + None => None, + Some(i) => Some((k, i)), + }); + + let mut v = Vec::new(); + for (name, initiator) in initiators { + let (m, i) = Initiator::wrap(initiator); + map.insert(name.clone(), m); + v.push(i); + } + + Ok((map, v)) +} + +fn load_single( + log: &Logger, + client: &AsyncClient, + name: &String, + module_name: &String, + params: &HashMap + ) -> Option +{ + match module_name.as_ref() { + "Dummy" => { + Some(Box::new(Dummy::new(log))) + }, + _ => { + error!(log, "No initiator found with name \"{}\", configured as \"{}\"", + module_name, name); + None + } + } +} + +pub struct Dummy { + log: Logger, + step: bool, +} + +impl Dummy { + pub fn new(log: &Logger) -> Self { + Self { log: log.new(o!("module" => "Dummy Initiator")), step: false } + } +} + +impl Sensor for Dummy { + fn run_sensor(&mut self) + -> BoxFuture<'static, (Option, MachineState)> + { + let step = self.step; + self.step = !step; + + info!(self.log, "Kicking off new dummy initiator state change: {}", step); + + let f = async move { + Timer::after(std::time::Duration::from_secs(1)).await; + if step { + return (None, MachineState::free()); + } else { + let user = User::new( + UserId::new("test".to_string(), None, None), + UserData::new(vec![], 0), + ); + let p = user.data.priority; + let id = user.id.clone(); + return (Some(user), MachineState::used(id, p)); + } + }; + + Box::pin(f) + } +} + diff --git a/src/log.rs b/src/log.rs index 0e1643a..9f052e1 100644 --- a/src/log.rs +++ b/src/log.rs @@ -3,7 +3,7 @@ use slog_async; use slog_term::{TermDecorator, FullFormat}; use crate::config::Settings; -pub fn init(_config: &Settings) -> Logger { +pub fn init() -> Logger { let decorator = TermDecorator::new().build(); let drain = FullFormat::new(decorator).build().fuse(); let drain = slog_async::Async::new(drain).build().fuse(); diff --git a/src/machine.rs b/src/machine.rs index cec9211..f96943e 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -1,4 +1,12 @@ +use std::ops::{Deref, DerefMut}; +use std::iter::FromIterator; +use std::sync::Arc; +use futures_util::lock::Mutex; use std::path::Path; +use std::task::{Poll, Context}; +use std::pin::Pin; +use std::future::Future; + use std::collections::HashMap; use std::fs; @@ -6,15 +14,85 @@ use serde::{Serialize, Deserialize}; use futures_signals::signal::Signal; use futures_signals::signal::SignalExt; -use futures_signals::signal::Mutable; +use futures_signals::signal::{Mutable, ReadOnlyMutable}; use uuid::Uuid; -use crate::error::Result; +use crate::error::{Result, Error}; -use crate::db::user::User; use crate::db::access; use crate::db::machine::{MachineIdentifier, Status, MachineState}; +use crate::db::user::User; + +use crate::network::MachineMap; + +#[derive(Debug, Clone)] +pub struct Index { + inner: HashMap, +} + +impl Index { + pub fn new() -> Self { + Self { + inner: HashMap::new(), + } + } + + pub fn insert(&mut self, key: String, value: Machine) -> Option { + self.inner.insert(key, value) + } + + pub fn get(&mut self, key: &String) -> Option { + self.inner.get(key).map(|m| m.clone()) + } +} + +#[derive(Debug, Clone)] +pub struct Machine { + inner: Arc> +} + +impl Machine { + pub fn new(inner: Inner) -> Self { + Self { inner: Arc::new(Mutex::new(inner)) } + } + + pub fn construct + ( id: MachineIdentifier + , desc: MachineDescription + , state: MachineState + ) -> Machine + { + Self::new(Inner::new(id, desc, state)) + } + + pub fn from_file>(path: P) -> Result> { + let mut map: HashMap = MachineDescription::load_file(path)?; + Ok(map.drain().map(|(id, desc)| { + Self::construct(id, desc, MachineState::new()) + }).collect()) + } + + pub fn request_state_change(&self, who: Option<&User>, new_state: MachineState) + -> Result + { + let mut guard = self.inner.try_lock().unwrap(); + guard.request_state_change(who, new_state) + } + + pub fn signal(&self) -> impl Signal { + let mut guard = self.inner.try_lock().unwrap(); + guard.signal() + } +} + +impl Deref for Machine { + type Target = Mutex; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} #[derive(Debug)] /// Internal machine representation @@ -22,7 +100,7 @@ use crate::db::machine::{MachineIdentifier, Status, MachineState}; /// A machine connects an event from a sensor to an actor activating/deactivating a real-world /// machine, checking that the user who wants the machine (de)activated has the required /// permissions. -pub struct Machine { +pub struct Inner { /// Globally unique machine readable identifier pub id: MachineIdentifier, @@ -34,14 +112,18 @@ pub struct Machine { /// This is a Signal generator. Subscribers to this signal will be notified of changes. In the /// case of an actor it should then make sure that the real world matches up with the set state state: Mutable, + reset: Option, + rx: Option>, } -impl Machine { - pub fn new(id: MachineIdentifier, desc: MachineDescription, perm: access::PermIdentifier) -> Machine { - Machine { +impl Inner { + pub fn new(id: MachineIdentifier, desc: MachineDescription, state: MachineState) -> Inner { + Inner { id: id, desc: desc, - state: Mutable::new(MachineState { state: Status::Free}), + state: Mutable::new(state), + reset: None, + rx: None, } } @@ -57,26 +139,76 @@ impl Machine { Box::pin(self.state.signal_cloned().dedupe_cloned()) } - /// Requests to use a machine. Returns `true` if successful. + /// Requests to use a machine. Returns a return token if successful. /// /// This will update the internal state of the machine, notifying connected actors, if any. - pub async fn request_use - ( &mut self - , access: access::AccessControl - , who: &User - ) -> Result + /// The return token is a channel that considers the machine 'returned' if anything is sent + /// along it or if the sending end gets dropped. Anybody who holds this token needs to check if + /// the receiving end was canceled which indicates that the machine has been taken off their + /// hands. + pub fn request_state_change(&mut self, who: Option<&User>, new_state: MachineState) + -> Result { - // TODO: Check different levels - if access.check(who, &self.desc.privs.write).await? { - self.state.set(MachineState { state: Status::InUse(who.id.clone()) }); - return Ok(true); + if who.is_none() { + if new_state.state == Status::Free { + return self.do_state_change(new_state); + } } else { - return Ok(false); + if self.state.lock_ref().is_higher_priority(who.unwrap().data.priority) { + return self.do_state_change(new_state); + } } + + return Err(Error::Denied); } - pub fn set_state(&mut self, state: Status) { - self.state.set(MachineState { state }) + fn do_state_change(&mut self, new_state: MachineState) -> Result { + let (tx, rx) = futures::channel::oneshot::channel(); + let old_state = self.state.replace(new_state); + self.reset.replace(old_state); + // Also this drops the old receiver, which will signal to the initiator that the + // machine has been taken off their hands. + self.rx.replace(rx); + return Ok(tx); + } + + pub fn read_state(&self) -> ReadOnlyMutable { + self.state.read_only() + } + + pub fn get_signal(&self) -> impl Signal { + self.state.signal_cloned() + } + + pub fn reset_state(&mut self) { + if let Some(state) = self.reset.take() { + self.state.replace(state); + } + } +} + +pub type ReturnToken = futures::channel::oneshot::Sender<()>; + +impl Future for Inner { + type Output = MachineState; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll { + let mut this = &mut *self; + // TODO Return this on exit + if false { + return Poll::Ready(self.state.get_cloned()); + } + + // Check if the return token was sent/dropped + if let Some(mut rx) = this.rx.take() { + match Future::poll(Pin::new(&mut rx), cx) { + // Regardless if we were canceled or properly returned, reset. + Poll::Ready(_) => self.reset_state(), + Poll::Pending => { this.rx.replace(rx); }, + } + } + + Poll::Pending } } @@ -93,7 +225,7 @@ pub struct MachineDescription { /// The permission required #[serde(flatten)] - privs: access::PrivilegesBuf, + pub privs: access::PrivilegesBuf, } impl MachineDescription { @@ -103,7 +235,18 @@ impl MachineDescription { } } -#[cfg(test)] +pub fn load(config: &crate::config::Settings) -> Result { + let mut map = config.machines.clone(); + + let it = map.drain() + .map(|(k,v)| { + // TODO: Read state from the state db + (v.name.clone(), Machine::construct(k, v, MachineState::new())) + }); + Ok(HashMap::from_iter(it)) +} + +#[cfg(test_DISABLED)] mod tests { use super::*; use std::iter::FromIterator; diff --git a/src/main.rs b/src/main.rs index 547750e..3e9e58b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,10 +13,14 @@ mod api; mod config; mod error; mod connection; -mod registries; mod schema; mod db; mod machine; +mod builtin; +mod server; +mod network; +mod actor; +mod initiator; use clap::{App, Arg}; @@ -26,9 +30,6 @@ use futures::compat::Stream01CompatExt; use futures::join; use futures::task::LocalSpawn; -use smol::net::TcpListener; -use smol::net::unix::UnixStream; - use std::io; use std::io::Write; use std::path::PathBuf; @@ -37,32 +38,17 @@ use std::str::FromStr; use std::sync::Arc; use lmdb::Transaction; +use smol::net::TcpListener; + +use smol::Executor; use error::Error; -use registries::Registries; +use slog::Logger; -const LMDB_MAX_DB: u32 = 16; - -// Returning a `Result` from `main` allows us to use the `?` shorthand. -// In the case of an Err it will be printed using `fmt::Debug` -fn main() -> Result<(), Error> { - let signal = Box::pin(async { - let (tx, mut rx) = UnixStream::pair()?; - // Initialize signal handler. - // We currently only care about Ctrl-C so SIGINT it is. - // TODO: Make this do SIGHUP and a few others too. (By cloning the tx end of the pipe) - signal_hook::pipe::register(signal_hook::SIGINT, tx)?; - // When a signal is received this future can complete and read a byte from the underlying - // socket — the actual data is discarded but the act of being able to receive data tells us - // that we received a SIGINT. - - // FIXME: What errors are possible and how to handle them properly? - rx.read_exact(&mut [0u8]).await?; - - io::Result::Ok(LoopResult::Stop) - }); +use paho_mqtt::AsyncClient; +fn main() { use clap::{crate_version, crate_description, crate_name}; // Argument parsing @@ -97,255 +83,123 @@ fn main() -> Result<(), Error> { // Check for the --print-default option first because we don't need to do anything else in that // case. if matches.is_present("print default") { - let config = config::Settings::default(); - let encoded = toml::to_vec(&config)?; + let config = config::Config::default(); + let encoded = serde_dhall::serialize(&config).to_string().unwrap(); // Direct writing to fd 1 is faster but also prevents any print-formatting that could // invalidate the generated TOML let stdout = io::stdout(); let mut handle = stdout.lock(); - handle.write_all(&encoded)?; + handle.write_all(&encoded.as_bytes()).unwrap(); // Early return to exit. - return Ok(()) + return; } + let retval; + // Scope to drop everything before exiting. + { + // Initialize the logging subsystem first to be able to better document the progress from now + // on. + // TODO: Now would be a really good time to close stdin/out and move logging to syslog + // Log is in an Arc so we can do very cheap clones in closures. + let log = Arc::new(log::init()); + info!(log, "Starting"); + + match maybe(matches, log.clone()) { + Ok(_) => retval = 0, + Err(e) => { + error!(log, "{}", e); + retval = -1; + } + } + } + + std::process::exit(retval); +} + +// Returning a `Result` from `main` allows us to use the `?` shorthand. +// In the case of an Err it will be printed using `fmt::Debug` +fn maybe(matches: clap::ArgMatches, log: Arc) -> Result<(), Error> { // If no `config` option is given use a preset default. let configpath = matches.value_of("config").unwrap_or("/etc/bffh/config.toml"); let config = config::read(&PathBuf::from_str(configpath).unwrap())?; + debug!(log, "Loaded Config: {:?}", config); - // Initialize the logging subsystem first to be able to better document the progress from now - // on. - // TODO: Now would be a really good time to close stdin/out and move logging to syslog - // Log is in an Arc so we can do very cheap clones in closures. - let log = Arc::new(log::init(&config)); - info!(log, "Starting"); + if matches.is_present("dump") { + error!(log, "Dumping is currently not implemented"); + Ok(()) + } else if matches.is_present("load") { + let db = db::Databases::new(&log, &config)?; + let mut dir = PathBuf::from(matches.value_of_os("load").unwrap()); - // Initialize the LMDB environment. Since this would usually block untill the mmap() finishes - // we wrap it in smol::unblock which runs this as future in a different thread. - let e_config = config.clone(); - info!(log, "LMDB env"); - let env = lmdb::Environment::new() - .set_flags(lmdb::EnvironmentFlags::MAP_ASYNC | lmdb::EnvironmentFlags::NO_SUB_DIR) - .set_max_dbs(LMDB_MAX_DB as libc::c_uint) - .open(&PathBuf::from_str("/tmp/a.db").unwrap())?; - - // Kick up an executor - // Most initializations from now on do some amount of IO and are much better done in an - // asyncronous fashion. - let mut exec = LocalPool::new(); - - - // Start loading the machine database, authentication system and permission system - // All of those get a custom logger so the source of a log message can be better traced and - // filtered - let env = Arc::new(env); - let mdb = db::machine::init(log.new(o!("system" => "machines")), &config, env.clone()); - let pdb = db::access::init(log.new(o!("system" => "permissions")), &config, env.clone()); - - // If --load or --dump is given we can stop at this point and load/dump the database and then - // exit. - if matches.is_present("load") { - if let Some(pathstr) = matches.value_of("load") { - let path = std::path::Path::new(pathstr); - - let mut txn = env.begin_rw_txn()?; - let path = path.to_path_buf(); - pdb?.load_db(&mut txn, path.clone())?; - //mdb?.load_db(&mut txn, path)?; - txn.commit()?; - } else { - error!(log, "You must provide a directory path to load from"); + dir.push("users.toml"); + let map = db::user::load_file(&dir)?; + for (uid,user) in map.iter() { + db.userdb.put_user(uid, user)?; } + debug!(log, "Loaded users: {:?}", map); + dir.pop(); - return Ok(()) - } else if matches.is_present("dump") { - if let Some(pathstr) = matches.value_of("dump") { - let path = std::path::Path::new(pathstr); - if let Err(e) = std::fs::create_dir_all(path) { - error!(log, "The provided path could not be created: {}", e); - return Ok(()) + dir.push("roles.toml"); + db.access.internal.load_roles(&dir)?; + dir.pop(); + + dir.push("pass.toml"); + db.passdb.load_file(&dir); + dir.pop(); + + Ok(()) + } else { + let ex = Executor::new(); + + let mqtt = AsyncClient::new(config.mqtt_url.clone())?; + let tok = mqtt.connect(paho_mqtt::ConnectOptions::new()); + + smol::block_on(tok)?; + + let machines = machine::load(&config)?; + let (mut actor_map, actors) = actor::load(&log, &mqtt, &config)?; + let (mut init_map, initiators) = initiator::load(&log, &mqtt, &config)?; + + // TODO: restore connections between initiators, machines, actors + let mut network = network::Network::new(machines, actor_map, init_map); + + for (a,b) in config.actor_connections.iter() { + if let Err(e) = network.connect_actor(a,b) { + error!(log, "{}", e); } - - let txn = env.begin_ro_txn()?; - let path = path.to_path_buf(); - pdb?.dump_db(&txn, path.clone())?; - //mdb?.dump_db(&txn, path)?; - } else { - error!(log, "You must provide a directory path to dump into"); } - return Ok(()) + for (a,b) in config.init_connections.iter() { + if let Err(e) = network.connect_init(a,b) { + error!(log, "{}", e); + } + } + + for actor in actors.into_iter() { + ex.spawn(actor).detach(); + } + for init in initiators.into_iter() { + ex.spawn(init).detach(); + } + + let (signal, shutdown) = async_channel::bounded::<()>(1); + let (_, r) = easy_parallel::Parallel::new() + .each(0..4, |_| smol::block_on(ex.run(shutdown.recv()))) + .finish(|| { + let db = db::Databases::new(&log, &config)?; + // TODO: Spawn api connections on their own (non-main) thread, use the main thread to + // handle signals (a cli if stdin is not closed?) and make it stop and clean up all threads + // when bffh should exit + let r = server::serve_api_connections(log.clone(), config, db, network); + + signal.try_send(()); + std::mem::drop(signal); + return r; + }); + + return r; } - - - // Bind to each address in config.listen. - // This is a Stream over Futures so it will do absolutely nothing unless polled to completion - let listeners_s: futures::stream::Collect<_, Vec> - = stream::iter((&config).listens.iter()) - .map(|l| { - let addr = l.address.clone(); - let port = l.port.unwrap_or(config::DEFAULT_PORT); - TcpListener::bind((l.address.as_str(), port)) - // If the bind errors, include the address so we can log it - // Since this closure is lazy we need to have a cloned addr - .map_err(move |e| { (addr, port, e) }) - }) - .filter_map(|f| async { - match f.await { - Ok(l) => Some(l), - Err((addr, port, e)) => { - error!(&log, "Could not setup socket on {} port {}: {}", addr, port, e); - None - } - } - }).collect(); - - //let (mach, auth) = exec.run_until(async { - // // Rull all futures to completion in parallel. - // // This will block until all three are done starting up. - // join!(machinedb_f, authentication_f) - //}); - - // Error out if any of the subsystems failed to start. - let mdb = mdb?; - let defs = machine::MachineDescription::load_file(&config.machines)?; - let machdb = db::machine::MachineDB::new(mdb, defs); - info!(log, "{:?}", machdb); - let pdb = pdb?; - let mut ac = db::access::AccessControl::new(); - ac.add_source_unchecked("Internal".to_string(), Box::new(pdb)); - let db = db::Databases { - access: Arc::new(db::access::AccessControl::new()), - machine: Arc::new(machdb), - }; - - // Since the below closures will happen at a much later time we need to make sure all pointers - // are still valid. Thus, Arc. - let start_log = log.clone(); - let stop_log = log.clone(); - - // Create a thread pool to run tasks on - let pool = ThreadPool::builder() - .after_start(move |i| { - info!(start_log.new(o!("system" => "threadpool")), "Starting Thread <{}>", i) - }) - .before_stop(move |i| { - info!(stop_log.new(o!("system" => "threadpool")), "Stopping Thread <{}>", i) - }) - .create()?; - let local_spawn = exec.spawner(); - - // Start all modules on the threadpool. The pool will run the modules until it is dropped. - // FIXME: implement notification so the modules can shut down cleanly instead of being killed - // without warning. - let modlog = log.clone(); - let mut regs = Registries::new(); - match exec.run_until(modules::init(modlog.new(o!("system" => "modules")), config.clone(), pool.clone(), regs.clone())) { - Ok(()) => {} - Err(e) => { - error!(modlog, "Module startup failed: {}", e); - return Err(e); - } - } - - // Closure inefficiencies. Lucky cloning an Arc is pretty cheap. - let inner_log = log.clone(); - let loop_log = log.clone(); - - exec.run_until(async move { - // Generate a stream of TcpStreams appearing on any of the interfaces we listen to - let listeners = listeners_s.await; - let incoming = stream::select_all(listeners.iter().map(|l| l.incoming())); - - // For each incoming connection start a new task to handle it - let handle_sockets = incoming.map(|socket| { - // incoming.next() returns an error when the underlying `accept` call yielded an error - // In POSIX those are protocol errors we can't really handle, so we just log the error - // and the move on - match socket { - Ok(socket) => { - // If we have it available add the peer's address to all log messages - let log = - if let Ok(addr) = socket.peer_addr() { - inner_log.new(o!("address" => addr)) - } else { - inner_log.new(o!()) - }; - - // Clone a log for potential error handling - let elog = log.clone(); - - // We handle the error using map_err - let f = connection::handle_connection(log.clone(), socket, db.clone()) - .map_err(move |e| { - error!(log, "Error occured during protocol handling: {}", e); - }) - // Void any and all results since pool.spawn allows no return value. - .map(|_| ()); - - // In this case only the error is relevant since the Value is always () - // The future is Boxed to make it the `LocalFutureObj` that LocalSpawn expects - if let Err(e) = local_spawn.spawn_local_obj(Box::new(f).into()) { - error!(elog, "Failed to spawn connection handler: {}", e); - // Failing to spawn a handler means we are most likely overloaded - return LoopResult::Overloaded; - } - }, - Err(e) => { - error!(inner_log, "Socket `accept` error: {}", e); - } - } - - // Unless we are overloaded we just want to keep going. - return LoopResult::Continue; - }); - - // Check each signal as it arrives - let handle_signals = signal.map(|r| { r.unwrap() }).into_stream(); - - let mut combined = stream::select(handle_signals, handle_sockets); - - // This is the basic main loop that drives execution - loop { - match combined.next().await { - // When the result says to continue, do exactly that - Some(LoopResult::Continue) => {} - Some(LoopResult::Overloaded) => { - // In case over server overload we should install a replacement handler that - // would instead just return `overloaded` for all connections until the - // situation is remedied. - // - // For now, just log the overload and keep going. - error!(loop_log, "Server overloaded"); - } - // When the result says to stop the server, do exactly that. - // Also catches a `None` from the stream; None should never be returned because it - // would mean all sockets were closed and we can not receive any further signals. - // Still, in that case shut down cleanly anyway, the only reason this could happen - // are some heavy bugs in the runtime - Some(LoopResult::Stop) | None => { - warn!(loop_log, "Stopping server"); - break; - } - } - } - }); - - // TODO: Run actual shut down code here - info!(log, "Shutting down..."); - - // Returning () is an implicit success so this will properly set the exit code as well - Ok(()) -} - -/// The result of one iteration of the core loop -enum LoopResult { - /// Everything was fine, keep going - Continue, - /// Something happened that means we should shut down - Stop, - /// The Server is currently overloaded - Overloaded, } diff --git a/src/modules.rs b/src/modules.rs index 9f8a21e..51e218c 100644 --- a/src/modules.rs +++ b/src/modules.rs @@ -8,17 +8,10 @@ use slog::Logger; mod shelly; +pub use shelly::Shelly; use futures::prelude::*; use futures::task::Spawn; use crate::config::Settings; use crate::error::Result; -use crate::registries::Registries; - -// spawner is a type that allows 'tasks' to be spawned on it, running them to completion. -pub async fn init(log: Logger, config: Settings, spawner: S, registries: Registries) -> Result<()> { - shelly::run(log.clone(), config.clone(), registries.clone(), spawner.clone()).await; - - Ok(()) -} diff --git a/src/modules/shelly.rs b/src/modules/shelly.rs index b8037c0..c4c6cdc 100644 --- a/src/modules/shelly.rs +++ b/src/modules/shelly.rs @@ -1,120 +1,61 @@ use slog::Logger; use crate::config::Settings; -use crate::registries::{Registries, Actuator, ActBox, StatusSignal}; use crate::error::Result; use crate::db::machine::Status; use std::pin::Pin; use futures::prelude::*; use futures::channel::mpsc; +use futures::future::BoxFuture; use futures::ready; use futures::task::{Poll, Context, Waker, Spawn, FutureObj}; use futures::StreamExt; use futures_signals::signal::Signal; +use crate::actor::Actuator; +use crate::db::machine::MachineState; + use paho_mqtt as mqtt; -// TODO: Late config parsing. Right now the config is validated at the very startup in its -// entirety. This works reasonably enough for this static modules here but if we do dynamic loading -// via dlopen(), lua API, python API etc it will not. -pub async fn run(log: Logger, config: Settings, registries: Registries, spawner: S) { - let (tx, rx) = mpsc::channel(1); - let mut shelly = Shelly::new(log, config, rx).await; - - let r = registries.actuators.register("shelly".to_string(), tx).await; - - let f = shelly.for_each(|f| f); - spawner.spawn_obj(FutureObj::from(Box::pin(f))); - -} - -/// An actuator for all Shellies connected listening on one MQTT broker +/// An actuator for a Shellie connected listening on one MQTT broker /// -/// This actuator can power toggle an arbitrariy named shelly on the broker it is connected to. If -/// you need to toggle shellies on multiple brokers you need multiple instanced of this actuator. -struct Shelly { +/// This actuator will toggle the shellie with the given `name`. +/// If you need to toggle shellies on multiple brokers you need multiple instanced of this +/// actuator with different clients. +pub struct Shelly { log: Logger, - sigchan: mpsc::Receiver, - signal: Option, - waker: Option, name: String, client: mqtt::AsyncClient, } impl Shelly { - // Can't use Error, it's not Send. fabinfra/fabaccess/bffh#7 - pub async fn new(log: Logger, config: Settings, sigchan: mpsc::Receiver) -> Self { - let client = mqtt::AsyncClient::new(config.shelly.unwrap().mqtt_url).unwrap(); + pub fn new(log_view: &Logger, name: String, client: mqtt::AsyncClient) -> Self { + let log = log_view.new(o!("shelly_name" => name.clone())); + debug!(log, "Starting shelly module for {}", &name); + Shelly { log, name, client, } + } - let o = client.connect(mqtt::ConnectOptions::new()).await.unwrap(); - println!("{:?}", o); - - let name = "test".to_string(); - let signal: Option = None; - let waker = None; - - Shelly { log, sigchan, signal, waker, name, client } + /// Set the name to a new one. This changes the shelly that will be activated + pub fn set_name(&mut self, new_name: String) { + let log = self.log.new(o!("shelly_name" => new_name.clone())); + self.name = new_name; + self.log = log; } } impl Actuator for Shelly { - fn subscribe(&mut self, signal: StatusSignal) { - self.signal.replace(signal); - if let Some(waker) = self.waker.take() { - waker.wake(); - } - } -} - -impl Stream for Shelly { - type Item = future::BoxFuture<'static, ()>; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { - let unpin = Pin::into_inner(self); - - info!(unpin.log, "tick {}", unpin.signal.is_some()); - - if let Poll::Ready(v) = Stream::poll_next(Pin::new(&mut unpin.sigchan), cx) { - if let Some(s) = v { - // We have received a new signal to use - unpin.signal.replace(s); - // We use `if let` instead of .and_then because we want the waker to be dropped - // afterwards. It's only there to ensure the future is called when a signal is - // installed the first time - // TODO probably don't need that here because we're polling it either way directly - // afterwards, eh? - if let Some(waker) = unpin.waker.take() { - waker.wake(); - } - } else { - info!(unpin.log, "bye"); - // This means that the sending end was dropped, so we shut down - unpin.signal.take(); - unpin.waker.take(); - return Poll::Ready(None); - } - } - - if let Some(ref mut s) = unpin.signal { - if let Some(status) = ready!(Signal::poll_change(Pin::new(s), cx)) { - info!(unpin.log, "Machine Status changed: {:?}", status); - let topic = format!("shellies/{}/relay/0/command", unpin.name); - let pl = match status { - Status::InUse(_) => "on", - _ => "off", - }; - let msg = mqtt::Message::new(topic, pl, 0); - let f = unpin.client.publish(msg).map(|_| ()); - - return Poll::Ready(Some(Box::pin(f))); - } - } else { - info!(unpin.log, "I ain't got no signal son"); - unpin.waker.replace(cx.waker().clone()); - } - - Poll::Pending + fn apply(&mut self, state: MachineState) -> BoxFuture<'static, ()> { + info!(self.log, "Machine Status changed: {:?}", state); + let topic = format!("shellies/{}/relay/0/command", self.name); + let pl = match state.state { + Status::InUse(_, _) => "on", + _ => "off", + }; + let msg = mqtt::Message::new(topic, pl, 0); + let f = self.client.publish(msg).map(|_| ()); + + return Box::pin(f); } } diff --git a/src/network.rs b/src/network.rs new file mode 100644 index 0000000..a962e20 --- /dev/null +++ b/src/network.rs @@ -0,0 +1,85 @@ +use std::fmt; + +use std::sync::{Arc, Mutex, MutexGuard, TryLockResult}; +use std::collections::HashMap; + +use smol::Executor; + +use futures::channel::mpsc; +use futures_signals::signal::{Signal, MutableSignalCloned, Mutable}; + +use crate::machine::Machine; +use crate::actor::{Actor, ActorSignal}; +use crate::initiator::Initiator; +use crate::db::machine::MachineState; + +use crate::error::Result; + +pub type MachineMap = HashMap; +pub type ActorMap = HashMap>>>; +pub type InitMap = HashMap>>; + +#[derive(Debug, PartialEq, Eq)] +pub enum Error { + NoSuchInitiator, + NoSuchMachine, + NoSuchActor, +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Error::NoSuchInitiator => write!(f, "No initiator found with that name"), + Error::NoSuchActor => write!(f, "No actor found with that name"), + Error::NoSuchMachine => write!(f, "No machine found with that name"), + } + } +} + +/// Main signal network +/// +/// Network as per FRP, not the one with packages and frames +// TODO De/Serialize established connection on startup/shutdown. +pub struct Network { + inits: InitMap, + + // Store connections + //miconn: Vec<(String, String)>, + + pub machines: MachineMap, + + // Store connections + //maconn: Vec<(String, String)>, + + actors: ActorMap, +} + +impl Network { + pub fn new(machines: MachineMap, actors: ActorMap, inits: InitMap) -> Self { + Self { machines, actors, inits } + } + + pub fn connect_init(&self, init_key: &String, machine_key: &String) -> Result<()> { + let init = self.inits.get(init_key) + .ok_or(Error::NoSuchInitiator)?; + let machine = self.machines.get(machine_key) + .ok_or(Error::NoSuchMachine)?; + + init.set(Some(machine.clone())); + Ok(()) + } + + pub fn connect_actor(&mut self, machine_key: &String, actor_key: &String) + -> Result<()> + { + let machine = self.machines.get(machine_key) + .ok_or(Error::NoSuchMachine)?; + let actor = self.actors.get(actor_key) + .ok_or(Error::NoSuchActor)?; + + // FIXME Yeah this should not unwrap. Really, really shoudln't. + let mut guard = actor.try_lock().unwrap(); + + guard.try_send(Some(Box::new(machine.signal()))).map_err(|_| Error::NoSuchActor.into()) + } +} diff --git a/src/registries.rs b/src/registries.rs deleted file mode 100644 index 0975bab..0000000 --- a/src/registries.rs +++ /dev/null @@ -1,24 +0,0 @@ -mod actuators; -mod sensors; - -pub use actuators::{Actuator, ActBox, StatusSignal}; -pub use sensors::{Sensor, SensBox}; - -#[derive(Clone)] -/// BFFH registries -/// -/// This struct is only a reference to the underlying registries - cloning it will generate a new -/// reference, not clone the registries -pub struct Registries { - pub actuators: actuators::Actuators, - pub sensors: sensors::Sensors, -} - -impl Registries { - pub fn new() -> Self { - Registries { - actuators: actuators::Actuators::new(), - sensors: sensors::Sensors::new(), - } - } -} diff --git a/src/registries/actuators.rs b/src/registries/actuators.rs deleted file mode 100644 index 5094f3c..0000000 --- a/src/registries/actuators.rs +++ /dev/null @@ -1,82 +0,0 @@ -use slog::Logger; - -use std::sync::Arc; -use smol::lock::RwLock; - -use std::pin::Pin; -use futures::ready; -use futures::prelude::*; -use futures::channel::mpsc; -use futures::task::{Context, Poll, Spawn}; -use futures_signals::signal::Signal; - -use crate::db::machine::Status; - -use std::collections::HashMap; - -#[derive(Clone)] -pub struct Actuators { - inner: Arc>, -} - -pub type ActBox = Box; - -type Inner = HashMap>; - -impl Actuators { - pub fn new() -> Self { - Actuators { - inner: Arc::new(RwLock::new(Inner::new())) - } - } - - pub async fn register(&self, name: String, tx: mpsc::Sender) { - let mut wlock = self.inner.write().await; - // TODO: Log an error or something if that name was already taken - wlock.insert(name, tx); - } - - pub async fn subscribe(&mut self, name: String, signal: StatusSignal) { - let mut wlock = self.inner.write().await; - if let Some(tx) = wlock.get_mut(&name) { - tx.send(signal).await; - } - } -} - -pub type StatusSignal = Pin + Send + Sync>>; - -pub trait Actuator: Stream> { - fn subscribe(&mut self, signal: StatusSignal); -} - -// This is merely a proof that Actuator *can* be implemented on a finite, known type. Yay for type -// systems with halting problems. -struct Dummy { - log: Logger, - sigchan: mpsc::Receiver, - signal: Option, -} - -impl Actuator for Dummy { - fn subscribe(&mut self, signal: StatusSignal) { - self.signal.replace(signal); - } -} - -impl Stream for Dummy { - type Item = future::BoxFuture<'static, ()>; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { - let unpin = Pin::into_inner(self); - if let Some(ref mut s) = unpin.signal { - let status = ready!(Signal::poll_change(Pin::new(s), cx)); - - info!(unpin.log, "Dummy actuator would set status to {:?}, but is a Dummy", status); - - Poll::Ready(Some(Box::pin(futures::future::ready(())))) - } else { - Poll::Pending - } - } -} diff --git a/src/registries/sensors.rs b/src/registries/sensors.rs deleted file mode 100644 index 2b7819e..0000000 --- a/src/registries/sensors.rs +++ /dev/null @@ -1,73 +0,0 @@ -use std::pin::Pin; -use futures::task::{Context, Poll}; -use futures::{Future, Stream}; -use futures::future::BoxFuture; - -use std::sync::Arc; -use smol::lock::RwLock; -use std::collections::HashMap; - -#[derive(Clone)] -pub struct Sensors { - inner: Arc>, -} - -impl Sensors { - pub fn new() -> Self { - Sensors { - inner: Arc::new(RwLock::new(Inner::new())), - } - } -} - -pub type SensBox = Box; -type Inner = HashMap; - - -// Implementing Sensors. -// -// Given the coroutine/task split stays as it is - Sensor input to machine update being one, -// machine update signal to actor doing thing being another, a Sensor implementation would send a -// Stream of futures - each future being an atomic Machine update. -#[async_trait] -/// BFFH Sensor -/// -/// A sensor is anything that can forward an intent of an user to do something to bffh. -/// This may be a card reader connected to a machine, a website allowing users to select a machine -/// they want to use or something like QRHello -pub trait Sensor: Stream> { - /// Setup the Sensor. - /// - /// After this async function completes the Stream implementation should be able to generate - /// futures when polled. - /// Implementations can rely on this function being polled to completeion before the stream - /// is polled. - // TODO Is this sensible vs just having module-specific setup fns? - async fn setup(&mut self); - - /// Shutdown the sensor gracefully - /// - /// Implementations can rely on that the stream will not be polled after this function has been - /// called. - async fn shutdown(&mut self); -} - -struct Dummy; -#[async_trait] -impl Sensor for Dummy { - async fn setup(&mut self) { - return; - } - - async fn shutdown(&mut self) { - return; - } -} - -impl Stream for Dummy { - type Item = BoxFuture<'static, ()>; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { - Poll::Ready(Some(Box::pin(futures::future::ready(())))) - } -} diff --git a/src/server.rs b/src/server.rs new file mode 100644 index 0000000..8e14ad9 --- /dev/null +++ b/src/server.rs @@ -0,0 +1,176 @@ +use slog::Logger; + +use crate::config; +use crate::config::Settings; +use crate::error::Error; +use crate::connection; + +use smol::net::TcpListener; +use smol::net::unix::UnixStream; +use smol::LocalExecutor; + +use clap::{App, Arg}; + +use futures::prelude::*; +use futures::executor::{LocalPool, ThreadPool}; +use futures::compat::Stream01CompatExt; +use futures::join; +use futures::task::LocalSpawn; + +use std::io; +use std::io::Write; +use std::path::PathBuf; +use std::str::FromStr; + +use std::sync::Arc; + +use crate::db::Databases; +use crate::network::Network; + +/// Handle all API connections and run the RPC tasks spawned from that on the local thread. +pub fn serve_api_connections(log: Arc, config: Settings, db: Databases, nw: Network) + -> Result<(), Error> +{ + let signal = Box::pin(async { + let (tx, mut rx) = UnixStream::pair()?; + // Initialize signal handler. + // We currently only care about Ctrl-C so SIGINT it is. + // TODO: Make this do SIGHUP and a few others too. (By cloning the tx end of the pipe) + signal_hook::pipe::register(signal_hook::SIGINT, tx)?; + // When a signal is received this future can complete and read a byte from the underlying + // socket — the actual data is discarded but the act of being able to receive data tells us + // that we received a SIGINT. + + // FIXME: What errors are possible and how to handle them properly? + rx.read_exact(&mut [0u8]).await?; + + io::Result::Ok(LoopResult::Stop) + }); + + // Bind to each address in config.listens. + // This is a Stream over Futures so it will do absolutely nothing unless polled to completion + let listeners_s: futures::stream::Collect<_, Vec> + = stream::iter((&config).listens.iter()) + .map(|l| { + let addr = l.address.clone(); + let port = l.port.unwrap_or(config::DEFAULT_PORT); + info!(&log, "Binding to {} port {}.", l.address.as_str(), &port); + TcpListener::bind((l.address.as_str(), port)) + // If the bind errors, include the address so we can log it + // Since this closure is lazy we need to have a cloned addr + .map_err(move |e| { (addr, port, e) }) + }) + // Filter out the sockets we couldn't open and log those + .filter_map(|f| async { + match f.await { + Ok(l) => Some(l), + Err((addr, port, e)) => { + error!(&log, "Could not setup socket on {} port {}: {}", addr, port, e); + None + } + } + }).collect(); + + let local_ex = LocalExecutor::new(); + + let network = Arc::new(nw); + + let inner_log = log.clone(); + let loop_log = log.clone(); + + smol::block_on(local_ex.run(async { + // Generate a stream of TcpStreams appearing on any of the interfaces we listen to + let listeners = listeners_s.await; + let incoming = stream::select_all(listeners.iter().map(|l| l.incoming())); + + let mut handler = connection::ConnectionHandler::new(inner_log.new(o!()), db, network.clone()); + + // For each incoming connection start a new task to handle it + let handle_sockets = incoming.map(|socket| { + // incoming.next() returns an error when the underlying `accept` call yielded an error + // In POSIX those are protocol errors we can't really handle, so we just log the error + // and the move on + match socket { + Ok(socket) => { + // If we have it available add the peer's address to all log messages + let log = + if let Ok(addr) = socket.peer_addr() { + inner_log.new(o!("address" => addr)) + } else { + inner_log.new(o!()) + }; + + // Clone a log for potential error handling + let elog = log.clone(); + + // We handle the error using map_err + let f = handler.handle(socket) + .map_err(move |e| { + error!(log, "Error occured during protocol handling: {}", e); + }) + // Void any and all results since pool.spawn allows no return value. + .map(|_| ()); + + // Spawn the connection context onto the local executor since it isn't Send + // Also `detach` it so the task isn't canceled as soon as it's dropped. + // TODO: Store all those tasks to have a easier way of managing them? + local_ex.spawn(f).detach(); + }, + Err(e) => { + error!(inner_log, "Socket `accept` error: {}", e); + } + } + + // Unless we are overloaded we just want to keep going. + return LoopResult::Continue; + }); + + info!(&log, "Started"); + + // Check each signal as it arrives + let handle_signals = signal.map(|r| { r.unwrap() }).into_stream(); + + let mut combined = stream::select(handle_signals, handle_sockets); + + // This is the basic main loop that drives execution + loop { + match combined.next().await { + // When the result says to continue, do exactly that + Some(LoopResult::Continue) => {} + Some(LoopResult::Overloaded) => { + // In case over server overload we should install a replacement handler that + // would instead just return `overloaded` for all connections until the + // situation is remedied. + // + // For now, just log the overload and keep going. + error!(loop_log, "Server overloaded"); + } + // When the result says to stop the server, do exactly that. + // Also catches a `None` from the stream; None should never be returned because it + // would mean all sockets were closed and we can not receive any further signals. + // Still, in that case shut down cleanly anyway, the only reason this could happen + // are some heavy bugs in the runtime + Some(LoopResult::Stop) | None => { + warn!(loop_log, "Stopping server"); + break; + } + } + } + })); + + // TODO: Run actual shut down code here + info!(log, "Shutting down..."); + + // Returning () is an implicit success so this will properly set the exit code as well + Ok(()) +} + +/// The result of one iteration of the core loop +pub enum LoopResult { + /// Everything was fine, keep going + Continue, + /// Something happened that means we should shut down + Stop, + /// The Server is currently overloaded + Overloaded, +}