From f669e414f9ca2faf0026c31cc0bf1aab7772669a Mon Sep 17 00:00:00 2001 From: Kirguir Date: Thu, 31 Jan 2019 15:10:43 +0200 Subject: [PATCH 01/20] Add dependencies --- Cargo.lock | 170 +++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 2 + 2 files changed, 172 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index a83447acf..44bc06b3f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,13 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "aho-corasick" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "arrayvec" version = "0.4.10" @@ -46,6 +54,21 @@ dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "config" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "nom 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rust-ini 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", + "serde-hjson 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "yaml-rust 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam" version = "0.6.0" @@ -130,6 +153,11 @@ name = "itoa" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "lazy_static" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "lazy_static" version = "1.2.0" @@ -140,6 +168,20 @@ name = "libc" version = "0.2.47" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "linked-hash-map" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_test 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "linked-hash-map" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "lock_api" version = "0.1.5" @@ -154,11 +196,22 @@ name = "medea" version = "0.1.0" dependencies = [ "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "config 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "slog-async 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "slog-json 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "slog-scope 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "memchr" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -171,6 +224,15 @@ name = "nodrop" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "nom" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "num-integer" version = "0.1.39" @@ -179,6 +241,14 @@ dependencies = [ "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "num-traits" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "num-traits" version = "0.2.6" @@ -311,6 +381,31 @@ name = "redox_syscall" version = "0.1.50" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "regex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-syntax" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rust-ini" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "rustc_version" version = "0.2.3" @@ -342,11 +437,28 @@ name = "semver-parser" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "serde" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "serde" version = "1.0.84" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "serde-hjson" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "serde_json" version = "1.0.36" @@ -357,6 +469,14 @@ dependencies = [ "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "serde_test" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "slog" version = "2.4.1" @@ -429,6 +549,19 @@ dependencies = [ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "toml" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ucd-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "unreachable" version = "1.0.0" @@ -437,6 +570,16 @@ dependencies = [ "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "utf8-ranges" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "version_check" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "void" version = "1.0.2" @@ -461,7 +604,16 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "yaml-rust" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [metadata] +"checksum aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9a933f4e58658d7b12defcf96dc5c720f20832deebe3e0a19efd3b6aaeeb9e" "checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" "checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" @@ -469,6 +621,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" "checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +"checksum config 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3e82d07fac0a5eeaa9d959b5194d01bb66e414665f547416958d2b430f8f4852" "checksum crossbeam 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad4c7ea749d9fb09e23c5cb17e3b70650860553a0e2744e38446b1803bf7db94" "checksum crossbeam-channel 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "137bc235f622ffaa0428e3854e24acb53291fc0b3ff6fb2cb75a8be6fb02f06b" "checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13" @@ -478,12 +631,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3bae29b6653b3412c2e71e9d486db9f9df5d701941d86683005efb9f2d28e3da" "checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b" +"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" "checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" "checksum libc 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)" = "48450664a984b25d5b479554c29cc04e3150c97aa4c01da5604a2d4ed9151476" +"checksum linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d262045c5b87c0861b3f004610afd0e2c851e2908d08b6c870cbb9d5f494ecd" +"checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e" "checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" +"checksum memchr 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e1dd4eaac298c32ce07eb6ed9242eda7d82955b9170b7d6db59b2e02cc63fcb8" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" +"checksum nom 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b30adc557058ce00c9d0d7cb3c6e0b5bc6f36e2e2eabe74b0ba726d194abd588" "checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" +"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" "checksum num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5a69d464bdc213aaaff628444e99578ede64e9c854025aa43b9796530afa9238" "checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" @@ -499,13 +658,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum redox_syscall 0.1.50 (registry+https://github.com/rust-lang/crates.io-index)" = "52ee9a534dc1301776eff45b4fa92d2c39b1d8c3d3357e6eb593e0d795506fc2" +"checksum regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37e7cbbd370869ce2e8dff25c7018702d10b21a20ef7135316f8daecd6c25b7f" +"checksum regex-syntax 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8c2f35eedad5295fdf00a63d7d4b238135723f92b434ec06774dad15c7ab0861" +"checksum rust-ini 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e52c148ef37f8c375d49d5a73aa70713125b7f19095948a923f80afdeb22ec2" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +"checksum serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8" "checksum serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)" = "0e732ed5a5592c17d961555e3b552985baf98d50ce418b7b655f31f6ba7eb1b7" +"checksum serde-hjson 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0b833c5ad67d52ced5f5938b2980f32a9c1c5ef047f0b4fb3127e7a423c76153" "checksum serde_json 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)" = "574378d957d6dcdf1bbb5d562a15cbd5e644159432f84634b94e485267abbcc7" +"checksum serde_test 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "110b3dbdf8607ec493c22d5d947753282f3bae73c0f56d322af1e8c78e4c23d5" "checksum slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1e1a2eec401952cd7b12a84ea120e2d57281329940c3f93c2bf04f462539508e" "checksum slog-async 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e544d16c6b230d84c866662fe55e31aacfca6ae71e6fc49ae9a311cb379bfc2f" "checksum slog-json 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ddc0d2aff1f8f325ef660d9a0eb6e6dcd20b30b3f581a5897f58bf42d061c37a" @@ -515,8 +680,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" +"checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" +"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" +"checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737" +"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +"checksum yaml-rust 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "95acf0db5515d07da9965ec0e0ba6cc2d825e2caeb7303b66ca441729801254e" diff --git a/Cargo.toml b/Cargo.toml index 7281bb4ae..586d3c153 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,9 +10,11 @@ readme = "README.md" repository = "https://github.com/instrumentisto/medea" [dependencies] +config = "0.9" chrono = "0.4" hashbrown = "0.1" slog = { version = "2.4", features = ["max_level_debug", "release_max_level_warn"] } slog-async = "2.3" slog-json = "2.3" slog-scope = "4.1" +toml = "0.4" From 330128465e6a76c5d0fa712969074bd939ccee11 Mon Sep 17 00:00:00 2001 From: Kirguir Date: Wed, 6 Feb 2019 15:37:29 +0200 Subject: [PATCH 02/20] Impl settings --- Cargo.lock | 133 +++++++++++++++++++++++++++++++++++++++ Cargo.toml | 6 ++ config.toml | 0 src/main.rs | 10 +++ src/settings/duration.rs | 53 ++++++++++++++++ src/settings/mod.rs | 25 ++++++++ src/settings/server.rs | 20 ++++++ 7 files changed, 247 insertions(+) create mode 100644 config.toml create mode 100644 src/settings/duration.rs create mode 100644 src/settings/mod.rs create mode 100644 src/settings/server.rs diff --git a/Cargo.lock b/Cargo.lock index 44bc06b3f..4b5b609c6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,6 +21,28 @@ name = "autocfg" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "backtrace" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "backtrace-sys" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bitflags" version = "1.0.4" @@ -31,6 +53,11 @@ name = "byteorder" version = "1.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "cc" +version = "1.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "cfg-if" version = "0.1.6" @@ -125,6 +152,36 @@ dependencies = [ "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "dotenv" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "failure" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "failure_derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "fuchsia-zircon" version = "0.3.3" @@ -197,7 +254,13 @@ version = "0.1.0" dependencies = [ "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "config 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", + "dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "slog-async 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "slog-json 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -291,6 +354,22 @@ dependencies = [ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "proc-macro2" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quote" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand" version = "0.6.4" @@ -406,6 +485,11 @@ name = "rust-ini" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "rustc-demangle" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "rustc_version" version = "0.2.3" @@ -459,6 +543,16 @@ dependencies = [ "serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "serde_derive" +version = "1.0.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "serde_json" version = "1.0.36" @@ -526,6 +620,27 @@ name = "stable_deref_trait" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "syn" +version = "0.15.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "synstructure" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "take_mut" version = "0.2.2" @@ -562,6 +677,11 @@ name = "ucd-util" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "unreachable" version = "1.0.0" @@ -616,8 +736,11 @@ dependencies = [ "checksum aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9a933f4e58658d7b12defcf96dc5c720f20832deebe3e0a19efd3b6aaeeb9e" "checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" "checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" +"checksum backtrace 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "b5b493b66e03090ebc4343eb02f94ff944e0cbc9ac6571491d170ba026741eb5" +"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" "checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d" +"checksum cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)" = "4390a3b5f4f6bce9c1d0c00128379df433e53777fdd30e92f16a529332baec4e" "checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" "checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" @@ -627,6 +750,9 @@ dependencies = [ "checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13" "checksum crossbeam-epoch 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f10a4f8f409aaac4b16a5474fb233624238fcdeefb9ba50d5ea059aab63ba31c" "checksum crossbeam-utils 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "41ee4864f4797060e52044376f7d107429ce1fb43460021b126424b7180ee21a" +"checksum dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0d0a1279c96732bc6800ce6337b6a614697b0e74ae058dc03c62ebeb78b4d86" +"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" +"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3bae29b6653b3412c2e71e9d486db9f9df5d701941d86683005efb9f2d28e3da" @@ -648,6 +774,8 @@ dependencies = [ "checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" "checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" "checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" +"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915" +"checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1" "checksum rand 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3906503e80ac6cbcacb2c2973fa8e473f24d7e2747c8c92bb230c2441cad96b5" "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" "checksum rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0905b6b7079ec73b314d4c748701f6931eb79fd97c668caa3f1899b22b32c6db" @@ -661,6 +789,7 @@ dependencies = [ "checksum regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37e7cbbd370869ce2e8dff25c7018702d10b21a20ef7135316f8daecd6c25b7f" "checksum regex-syntax 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8c2f35eedad5295fdf00a63d7d4b238135723f92b434ec06774dad15c7ab0861" "checksum rust-ini 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e52c148ef37f8c375d49d5a73aa70713125b7f19095948a923f80afdeb22ec2" +"checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" @@ -669,6 +798,7 @@ dependencies = [ "checksum serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8" "checksum serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)" = "0e732ed5a5592c17d961555e3b552985baf98d50ce418b7b655f31f6ba7eb1b7" "checksum serde-hjson 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0b833c5ad67d52ced5f5938b2980f32a9c1c5ef047f0b4fb3127e7a423c76153" +"checksum serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)" = "633e97856567e518b59ffb2ad7c7a4fd4c5d91d9c7f32dd38a27b2bf7e8114ea" "checksum serde_json 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)" = "574378d957d6dcdf1bbb5d562a15cbd5e644159432f84634b94e485267abbcc7" "checksum serde_test 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "110b3dbdf8607ec493c22d5d947753282f3bae73c0f56d322af1e8c78e4c23d5" "checksum slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1e1a2eec401952cd7b12a84ea120e2d57281329940c3f93c2bf04f462539508e" @@ -677,11 +807,14 @@ dependencies = [ "checksum slog-scope 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "60c04b4726fa04595ccf2c2dad7bcd15474242c4c5e109a8a376e8a2c9b1539a" "checksum smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b73ea3738b47563803ef814925e69be00799a8c07420be8b996f8e98fb2336db" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" +"checksum syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9" +"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" "checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" "checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" +"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" "checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737" "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" diff --git a/Cargo.toml b/Cargo.toml index 586d3c153..159bfe39a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,13 @@ repository = "https://github.com/instrumentisto/medea" [dependencies] config = "0.9" chrono = "0.4" +dotenv = "0.13" +failure = "0.1" hashbrown = "0.1" +lazy_static = "1.2" +regex = "1" +serde = "1" +serde_derive = "1" slog = { version = "2.4", features = ["max_level_debug", "release_max_level_warn"] } slog-async = "2.3" slog-json = "2.3" diff --git a/config.toml b/config.toml new file mode 100644 index 000000000..e69de29bb diff --git a/src/main.rs b/src/main.rs index 2a30589d0..5532e126b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,11 @@ //! Medea media server application. +use dotenv::dotenv; + use crate::{ api::control::{Member, MemberRepository}, log::prelude::*, + settings::Settings, }; #[macro_use] @@ -10,8 +13,10 @@ mod utils; mod api; mod log; +mod settings; fn main() { + dotenv().ok(); let logger = log::new_dual_logger(std::io::stdout(), std::io::stderr()); let _scope_guard = slog_scope::set_global_logger(logger); @@ -24,4 +29,9 @@ fn main() { info!("Hooray!"); warn!("It works"); } + + match Settings::new() { + Ok(settings) => info!("{:?}", settings), + Err(e) => error!("settings error: {}", e), + } } diff --git a/src/settings/duration.rs b/src/settings/duration.rs new file mode 100644 index 000000000..c0a23862d --- /dev/null +++ b/src/settings/duration.rs @@ -0,0 +1,53 @@ +use std::fmt; +use std::time::Duration; + +use lazy_static::*; +use regex::Regex; +use serde::de::{self, Unexpected}; +use serde::Serializer; + +lazy_static! { + static ref REGEX_DURATION: Regex = + Regex::new(r"^(?P\d+)m|(?P\d+)s$").unwrap(); +} + +struct DurationFromStringVisitor; + +pub fn deserialize<'de, D>(d: D) -> Result +where + D: de::Deserializer<'de>, +{ + Ok(d.deserialize_str(DurationFromStringVisitor)?) +} + +impl<'de> de::Visitor<'de> for DurationFromStringVisitor { + type Value = Duration; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "a string representation of duration") + } + + fn visit_str(self, value: &str) -> Result + where + E: de::Error, + { + let caps = REGEX_DURATION + .captures(value) + .ok_or(de::Error::invalid_value(Unexpected::Str(value), &self))?; + let m = caps + .name("minutes") + .map_or(0, |s| s.as_str().parse::().unwrap()); + let s = caps + .name("seconds") + .map_or(0, |s| s.as_str().parse::().unwrap()); + + Ok(Duration::from_secs(m * 60 + s)) + } +} + +pub fn serialize(d: &Duration, s: S) -> Result +where + S: Serializer, +{ + s.serialize_str(format!("{}s", d.as_secs()).as_str()) +} diff --git a/src/settings/mod.rs b/src/settings/mod.rs new file mode 100644 index 000000000..5810a1cdb --- /dev/null +++ b/src/settings/mod.rs @@ -0,0 +1,25 @@ +use config::{Config, Environment, File, FileFormat}; +use failure::Error; +use serde_derive::{Deserialize, Serialize}; +use toml::to_string; + +mod duration; +mod server; + +#[derive(Debug, Default, Deserialize, Serialize)] +pub struct Settings { + server: server::Server, +} + +impl Settings { + pub fn new() -> Result { + let mut cfg = Config::new(); + let defaults = to_string(&Settings::default())?; + cfg.merge(File::from_str(defaults.as_str(), FileFormat::Toml))?; + cfg.merge(File::with_name("config"))?; + cfg.merge(Environment::with_prefix("conf").separator("__"))?; + + let s: Settings = cfg.try_into()?; + Ok(s) + } +} diff --git a/src/settings/server.rs b/src/settings/server.rs new file mode 100644 index 000000000..0826c64fd --- /dev/null +++ b/src/settings/server.rs @@ -0,0 +1,20 @@ +use std::time::Duration; + +use serde_derive::{Deserialize, Serialize}; + +use crate::settings::duration; + +#[derive(Debug, Deserialize, Serialize)] +pub struct Server { + #[serde(serialize_with = "duration::serialize")] + #[serde(deserialize_with = "duration::deserialize")] + client_idle_timeout: Duration, +} + +impl Default for Server { + fn default() -> Server { + Server { + client_idle_timeout: Duration::from_secs(10), + } + } +} From 4b0a60b8c9d119355321a36c108345ce9f2fe4e3 Mon Sep 17 00:00:00 2001 From: Kirguir Date: Thu, 7 Feb 2019 12:48:00 +0200 Subject: [PATCH 03/20] Add docs --- config.default.toml | 5 +++++ src/settings/duration.rs | 1 + src/settings/mod.rs | 3 +++ src/settings/server.rs | 3 +++ 4 files changed, 12 insertions(+) create mode 100644 config.default.toml diff --git a/config.default.toml b/config.default.toml new file mode 100644 index 000000000..ebf1a99ce --- /dev/null +++ b/config.default.toml @@ -0,0 +1,5 @@ +[server] +# Timeout for websocket session to wait message from [`Web Client`]. +# +# Default: +# idle_timeout = "10s" diff --git a/src/settings/duration.rs b/src/settings/duration.rs index c0a23862d..695666f6c 100644 --- a/src/settings/duration.rs +++ b/src/settings/duration.rs @@ -1,3 +1,4 @@ +/// Provides deserialize [`time::Duration`] from string. use std::fmt; use std::time::Duration; diff --git a/src/settings/mod.rs b/src/settings/mod.rs index 5810a1cdb..b8f77d051 100644 --- a/src/settings/mod.rs +++ b/src/settings/mod.rs @@ -1,3 +1,6 @@ +/// Provides application configuration options. +/// +/// Configuration options can be parsed from config files in TOML format. use config::{Config, Environment, File, FileFormat}; use failure::Error; use serde_derive::{Deserialize, Serialize}; diff --git a/src/settings/server.rs b/src/settings/server.rs index 0826c64fd..87dfbafac 100644 --- a/src/settings/server.rs +++ b/src/settings/server.rs @@ -4,13 +4,16 @@ use serde_derive::{Deserialize, Serialize}; use crate::settings::duration; +/// Server represents [server] configuration section. #[derive(Debug, Deserialize, Serialize)] pub struct Server { + /// Timeout for websocket session to wait message from [`Web Client`]. #[serde(serialize_with = "duration::serialize")] #[serde(deserialize_with = "duration::deserialize")] client_idle_timeout: Duration, } +/// Default returns default configuration parameters of [server] section. impl Default for Server { fn default() -> Server { Server { From 0b454ca1fb31c848d0238335bc0bf50611dad289 Mon Sep 17 00:00:00 2001 From: Kirguir Date: Fri, 22 Mar 2019 16:41:55 +0200 Subject: [PATCH 04/20] Add docs --- Cargo.lock | 98 +++++++++++++++++++++++++++++++++++++++ Cargo.toml | 2 + src/api/client/server.rs | 33 +++++++++---- src/api/client/session.rs | 27 ++++++----- src/main.rs | 15 +++--- src/settings/mod.rs | 6 ++- src/settings/server.rs | 10 ++-- 7 files changed, 155 insertions(+), 36 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a41f54a68..a2901580a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -263,6 +263,21 @@ dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "config" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "nom 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rust-ini 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", + "serde-hjson 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cookie" version = "0.11.0" @@ -611,6 +626,11 @@ name = "language-tags" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "lazy_static" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "lazy_static" version = "1.2.0" @@ -626,6 +646,15 @@ name = "libc" version = "0.2.47" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "linked-hash-map" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_test 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "linked-hash-map" version = "0.4.2" @@ -676,11 +705,15 @@ dependencies = [ "actix 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", "actix-web 0.7.18 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "config 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "slog-async 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -688,6 +721,7 @@ dependencies = [ "slog-json 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "slog-scope 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "slog-stdlog 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -829,6 +863,14 @@ dependencies = [ "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "num-traits" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "num-traits" version = "0.2.6" @@ -1099,6 +1141,11 @@ dependencies = [ "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rust-ini" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "rustc-demangle" version = "0.1.13" @@ -1140,6 +1187,11 @@ name = "semver-parser" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "serde" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "serde" version = "1.0.84" @@ -1148,6 +1200,18 @@ dependencies = [ "serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "serde-hjson" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "serde_derive" version = "1.0.87" @@ -1168,6 +1232,14 @@ dependencies = [ "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "serde_test" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "serde_urlencoded" version = "0.5.4" @@ -1548,6 +1620,14 @@ dependencies = [ "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "toml" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "tower-service" version = "0.1.0" @@ -1800,6 +1880,14 @@ dependencies = [ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "yaml-rust" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "linked-hash-map 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [metadata] "checksum actix 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6c616db5fa4b0c40702fb75201c2af7f8aa8f3a2e2c1dda3b0655772aa949666" "checksum actix-net 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8bebfbe6629e0131730746718c9e032b58f02c6ce06ed7c982b9fef6c8545acd" @@ -1825,6 +1913,7 @@ dependencies = [ "checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" "checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +"checksum config 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3e82d07fac0a5eeaa9d959b5194d01bb66e414665f547416958d2b430f8f4852" "checksum cookie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1465f8134efa296b4c19db34d909637cb2bf0f7aaf21299e23e18fa29ac557cf" "checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" "checksum crc32fast 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e91d5240c6975ef33aeb5f148f35275c25eda8e8a5f95abe421978b05b8bf192" @@ -1865,9 +1954,11 @@ dependencies = [ "checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" +"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" "checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" "checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" "checksum libc 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)" = "48450664a984b25d5b479554c29cc04e3150c97aa4c01da5604a2d4ed9151476" +"checksum linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d262045c5b87c0861b3f004610afd0e2c851e2908d08b6c870cbb9d5f494ecd" "checksum linked-hash-map 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7860ec297f7008ff7a1e3382d7f7e1dcd69efc94751a2284bafc3d013c2aa939" "checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" @@ -1889,6 +1980,7 @@ dependencies = [ "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" "checksum nom 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9c349f68f25f596b9f44cf0e7c69752a5c633b0550c3ff849518bfba0233774a" "checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" +"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" "checksum num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5a69d464bdc213aaaff628444e99578ede64e9c854025aa43b9796530afa9238" "checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" @@ -1920,6 +2012,7 @@ dependencies = [ "checksum regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4e47a2ed29da7a9e1960e1639e7a982e6edc6d49be308a3b02daf511504a16d1" "checksum resolv-conf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b263b4aa1b5de9ffc0054a2386f96992058bb6870aab516f8cdeb8a667d56dcb" "checksum ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2c4db68a2e35f3497146b7e4563df7d4773a2433230c5e4b448328e31740458a" +"checksum rust-ini 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e52c148ef37f8c375d49d5a73aa70713125b7f19095948a923f80afdeb22ec2" "checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7" @@ -1927,9 +2020,12 @@ dependencies = [ "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +"checksum serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8" "checksum serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)" = "0e732ed5a5592c17d961555e3b552985baf98d50ce418b7b655f31f6ba7eb1b7" +"checksum serde-hjson 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0b833c5ad67d52ced5f5938b2980f32a9c1c5ef047f0b4fb3127e7a423c76153" "checksum serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)" = "633e97856567e518b59ffb2ad7c7a4fd4c5d91d9c7f32dd38a27b2bf7e8114ea" "checksum serde_json 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)" = "574378d957d6dcdf1bbb5d562a15cbd5e644159432f84634b94e485267abbcc7" +"checksum serde_test 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "110b3dbdf8607ec493c22d5d947753282f3bae73c0f56d322af1e8c78e4c23d5" "checksum serde_urlencoded 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d48f9f99cd749a2de71d29da5f948de7f2764cc5a9d7f3c97e3514d4ee6eabf2" "checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" "checksum signal-hook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1f272d1b7586bec132ed427f532dd418d8beca1ca7f2caf7df35569b1415a4b4" @@ -1967,6 +2063,7 @@ dependencies = [ "checksum tokio-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "4f37f0111d76cc5da132fe9bc0590b9b9cfd079bc7e75ac3846278430a299ff8" "checksum tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "66268575b80f4a4a710ef83d087fdfeeabdce9b74c797535fbac18a2cb906e92" "checksum tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "037ffc3ba0e12a0ab4aca92e5234e0dedeb48fddf6ccd260f1f150a36a9f2445" +"checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" "checksum tower-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b32f72af77f1bfe3d3d4da8516a238ebe7039b51dd8637a09841ac7f16d2c987" "checksum trust-dns-proto 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0838272e89f1c693b4df38dc353412e389cf548ceed6f9fd1af5a8d6e0e7cf74" "checksum trust-dns-proto 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30dde452f5d142d5e316a3b32386da95280c98b7e266639f8f3bc6fdf507d279" @@ -1997,3 +2094,4 @@ dependencies = [ "checksum winreg 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a27a759395c1195c4cc5cda607ef6f8f6498f64e78f7900f5de0a127a424704a" "checksum winutil 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7daf138b6b14196e3830a588acf1e86966c694d3e8fb026fb105b8b5dca07e6e" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +"checksum yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "65923dd1784f44da1d2c3dbbc5e822045628c590ba72123e1c73d3c230c4434d" diff --git a/Cargo.toml b/Cargo.toml index 71721c67b..10e6c6e94 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,9 @@ failure = "0.1" futures = "0.1" hashbrown = "0.1" lazy_static = "1.2" +regex = "1.1" serde = { version = "1.0", features = ["derive"] } +serde_derive = "1.0" serde_json = "1.0" slog = "2.4" slog-envlogger = "2.1" diff --git a/src/api/client/server.rs b/src/api/client/server.rs index d3a96d334..1de4aad95 100644 --- a/src/api/client/server.rs +++ b/src/api/client/server.rs @@ -16,6 +16,7 @@ use crate::{ control::Id as MemberId, }, log::prelude::*, + settings::server::Server, }; /// Parameters of new WebSocket connection creation HTTP request. @@ -52,7 +53,11 @@ fn ws_index( .and_then(move |res| match res { Ok(_) => ws::start( &r.drop_state(), - WsSession::new(info.member_id, room), + WsSession::new( + info.member_id, + room, + state.config.client_idle_timeout, + ), ), Err(MemberNotExists) => Ok(HttpResponse::NotFound().into()), Err(InvalidCredentials) => Ok(HttpResponse::Forbidden().into()), @@ -66,13 +71,17 @@ fn ws_index( pub struct Context { /// Repository of all currently existing [`Room`]s in application. pub rooms: RoomsRepository, + + /// Settings of application. + pub config: Server, } /// Starts HTTP server for handling WebSocket connections of Client API. -pub fn run(rooms: RoomsRepository) { +pub fn run(rooms: RoomsRepository, config: Server) { server::new(move || { App::with_state(Context { rooms: rooms.clone(), + config: config.clone(), }) .middleware(middleware::Logger::default()) .resource("/ws/{room_id}/{member_id}/{credentials}", |r| { @@ -95,9 +104,12 @@ mod test { use futures::Stream; use hashbrown::HashMap; - use crate::api::{ - client::{session, Room}, - control::Member, + use crate::{ + api::{ + client::{session, Room}, + control::Member, + }, + settings::Settings, }; use super::*; @@ -120,10 +132,13 @@ mod test { /// Creates test WebSocket server of Client API which can handle requests. fn ws_server() -> test::TestServer { test::TestServer::with_factory(move || { - App::with_state(Context { rooms: room() }) - .resource("/ws/{room_id}/{member_id}/{credentials}", |r| { - r.method(http::Method::GET).with(ws_index) - }) + App::with_state(Context { + rooms: room(), + config: Settings::new().unwrap().server, + }) + .resource("/ws/{room_id}/{member_id}/{credentials}", |r| { + r.method(http::Method::GET).with(ws_index) + }) }) } diff --git a/src/api/client/session.rs b/src/api/client/session.rs index 3e0c5cd7a..a25a4aa0a 100644 --- a/src/api/client/session.rs +++ b/src/api/client/session.rs @@ -19,10 +19,6 @@ use crate::{ log::prelude::*, }; -// TODO: via conf -/// Timeout of receiving any WebSocket messages from client. -pub const CLIENT_IDLE_TIMEOUT: Duration = Duration::from_secs(10); - /// Long-running WebSocket connection of Client API. #[derive(Debug)] #[allow(clippy::module_name_repetitions)] @@ -33,12 +29,15 @@ pub struct WsSession { room: Addr, /// Handle for watchdog which checks whether WebSocket client became - /// idle (no `ping` messages received during [`CLIENT_IDLE_TIMEOUT`]). + /// idle (no `ping` messages received during [`idle_timeout`]). /// - /// This one should be renewed on any received WebSocket message + /// This one should be renewed on received ping WebSocket message /// from client. idle_handler: Option, + /// Timeout of receiving ping messages from client. + idle_timeout: Duration, + /// Indicates whether WebSocket connection is closed by server ot by /// client. closed_by_server: bool, @@ -46,11 +45,16 @@ pub struct WsSession { impl WsSession { /// Creates new [`WsSession`] for specified [`Member`]. - pub fn new(member_id: MemberId, room: Addr) -> Self { + pub fn new( + member_id: MemberId, + room: Addr, + idle_timeout: Duration, + ) -> Self { Self { member_id, room, idle_handler: None, + idle_timeout, closed_by_server: false, } } @@ -62,7 +66,7 @@ impl WsSession { } self.idle_handler = - Some(ctx.run_later(CLIENT_IDLE_TIMEOUT, |sess, ctx| { + Some(ctx.run_later(self.idle_timeout, |sess, ctx| { info!("WsConnection with member {} is idle", sess.member_id); let member_id = sess.member_id; @@ -110,8 +114,8 @@ impl Actor for WsSession { .map(|_| ()) .map_err(move |err| { error!( - "WsSession of member {} failed to join Room, \ - because: {:?}", + "WsSession of member {} failed to join Room, because: \ + {:?}", member_id, err, ) }), @@ -188,8 +192,8 @@ impl StreamHandler for WsSession { ); match msg { ws::Message::Text(text) => { - self.reset_idle_timeout(ctx); if let Ok(msg) = serde_json::from_str::(&text) { + self.reset_idle_timeout(ctx); ctx.notify(msg); } } @@ -215,7 +219,6 @@ impl StreamHandler for WsSession { }), )); ctx.close(reason); - ctx.stop(); } } _ => error!( diff --git a/src/main.rs b/src/main.rs index ca7a459dd..ce0d9c907 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,9 +4,11 @@ use actix::prelude::*; use dotenv::dotenv; use hashbrown::HashMap; -use crate::api::{ - client::{server, Room, RoomsRepository}, - control::Member, +use crate::{ + api::{ + client::{server, Room, RoomsRepository}, + control::Member, + }, settings::Settings, }; @@ -37,11 +39,8 @@ fn main() { let rooms = hashmap! {1 => room}; let rooms_repo = RoomsRepository::new(rooms); - match Settings::new() { - Ok(settings) => info!("{:?}", settings), - Err(e) => error!("settings error: {}", e), - } + let config = Settings::new().unwrap(); - server::run(rooms_repo); + server::run(rooms_repo, config.server); let _ = sys.run(); } diff --git a/src/settings/mod.rs b/src/settings/mod.rs index b8f77d051..3da49b14d 100644 --- a/src/settings/mod.rs +++ b/src/settings/mod.rs @@ -7,11 +7,13 @@ use serde_derive::{Deserialize, Serialize}; use toml::to_string; mod duration; -mod server; +pub mod server; +/// Settings represents all configuration setting of application. #[derive(Debug, Default, Deserialize, Serialize)] pub struct Settings { - server: server::Server, + /// Represents [`Server`] configuration section. + pub server: server::Server, } impl Settings { diff --git a/src/settings/server.rs b/src/settings/server.rs index 87dfbafac..919ddd7be 100644 --- a/src/settings/server.rs +++ b/src/settings/server.rs @@ -4,16 +4,16 @@ use serde_derive::{Deserialize, Serialize}; use crate::settings::duration; -/// Server represents [server] configuration section. -#[derive(Debug, Deserialize, Serialize)] +/// Server represents [`Server`] configuration section. +#[derive(Clone, Debug, Deserialize, Serialize)] pub struct Server { - /// Timeout for websocket session to wait message from [`Web Client`]. + /// Timeout for [`WsSession`] to wait ping message from [`Web Client`]. #[serde(serialize_with = "duration::serialize")] #[serde(deserialize_with = "duration::deserialize")] - client_idle_timeout: Duration, + pub client_idle_timeout: Duration, } -/// Default returns default configuration parameters of [server] section. +/// Default returns default configuration parameters of [`Server`] section. impl Default for Server { fn default() -> Server { Server { From 754ab2538feb0220749fad130b9a98ddfee2dfff Mon Sep 17 00:00:00 2001 From: alexlapa Date: Mon, 25 Mar 2019 22:50:05 +0200 Subject: [PATCH 05/20] refactor, pass conf file path in args/env, serde duration via humantime, add basic makefile, add config tests, add duration serde tests --- Cargo.lock | 20 +++++ Cargo.toml | 6 +- Makefile | 99 +++++++++++++++++++++ src/api/client/server.rs | 22 ++--- src/conf/duration.rs | 126 ++++++++++++++++++++++++++ src/conf/mod.rs | 146 +++++++++++++++++++++++++++++++ src/{settings => conf}/server.rs | 6 +- src/main.rs | 9 +- src/settings/duration.rs | 54 ------------ src/settings/mod.rs | 30 ------- 10 files changed, 416 insertions(+), 102 deletions(-) create mode 100644 Makefile create mode 100644 src/conf/duration.rs create mode 100644 src/conf/mod.rs rename src/{settings => conf}/server.rs (88%) delete mode 100644 src/settings/duration.rs delete mode 100644 src/settings/mod.rs diff --git a/Cargo.lock b/Cargo.lock index a2901580a..d78b8f597 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -560,6 +560,14 @@ name = "httparse" version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "humantime" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "idna" version = "0.1.5" @@ -710,11 +718,13 @@ dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_test 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "slog-async 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "slog-envlogger 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1240,6 +1250,14 @@ dependencies = [ "serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "serde_test" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "serde_urlencoded" version = "0.5.4" @@ -1946,6 +1964,7 @@ dependencies = [ "checksum hostname 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "21ceb46a83a85e824ef93669c8b390009623863b5c195d1ba747292c0c72f94e" "checksum http 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "02096a6d2c55e63f7fcb800690e4f889a25f6ec342e3adb4594e293b625215ab" "checksum httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83" +"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" "checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" @@ -2026,6 +2045,7 @@ dependencies = [ "checksum serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)" = "633e97856567e518b59ffb2ad7c7a4fd4c5d91d9c7f32dd38a27b2bf7e8114ea" "checksum serde_json 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)" = "574378d957d6dcdf1bbb5d562a15cbd5e644159432f84634b94e485267abbcc7" "checksum serde_test 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "110b3dbdf8607ec493c22d5d947753282f3bae73c0f56d322af1e8c78e4c23d5" +"checksum serde_test 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)" = "70807e147558b5253cb70f55d343db1d07204d773087c96d0f35fced295dba82" "checksum serde_urlencoded 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d48f9f99cd749a2de71d29da5f948de7f2764cc5a9d7f3c97e3514d4ee6eabf2" "checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" "checksum signal-hook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1f272d1b7586bec132ed427f532dd418d8beca1ca7f2caf7df35569b1415a4b4" diff --git a/Cargo.toml b/Cargo.toml index 10e6c6e94..b43f33505 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,9 +15,10 @@ actix-web = "0.7" config = "0.9" chrono = "0.4" dotenv = "0.13" -failure = "0.1" +failure = "0.1.5" futures = "0.1" hashbrown = "0.1" +humantime = "1.2.0" lazy_static = "1.2" regex = "1.1" serde = { version = "1.0", features = ["derive"] } @@ -30,3 +31,6 @@ slog-async = "2.3" slog-json = "2.3" slog-scope = "4.1" toml = "0.4" + +[dev-dependencies] +serde_test = "1.0.89" diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..a80805c51 --- /dev/null +++ b/Makefile @@ -0,0 +1,99 @@ +###################### +# Project parameters # +###################### + +CARGO_HOME ?= $(strip $(shell dirname $$(dirname $$(which cargo)))) +RUST_VER ?= "1.33" + + + + +########### +# Aliases # +########### + +lint: cargo.lint + + +fmt: cargo.fmt + + +# Run all project tests. +# +# Usage: +# make test + +test: test.unit + + + + +# Lint Rust sources with clippy. +# +# Usage: +# make cargo.lint [dockerized=(no|yes)] + +cargo.lint: +ifeq ($(dockerized),yes) + docker run --rm --network=host -v "$(PWD)":/app -w /app \ + -v "$(abspath $(CARGO_HOME))/registry":/usr/local/cargo/registry\ + rust:$(RUST_VER) \ + make cargo.lint dockerized=no pre-install=yes +else +ifeq ($(pre-install),yes) + rustup component add clippy +endif + cargo clippy -- -D clippy::pedantic -D warnings +endif + + + + +# Run Rust unit tests of project. +# +# Usage: +# make test.unit [dockerized=(no|yes)] + +test.unit: +ifeq ($(dockerized),yes) + docker run --rm --network=host -v "$(PWD)":/app -w /app \ + -v "$(abspath $(CARGO_HOME))/registry":/usr/local/cargo/registry\ + rust:$(RUST_VER) \ + make test.unit dockerized=no +else + cargo test --all +endif + + + + +# Format Rust sources with rustfmt. +# +# Usage: +# make cargo.fmt [check=(no|yes)] +# [dockerized=(no|yes)] + +cargo.fmt: +ifeq ($(dockerized),yes) + docker pull rustlang/rust:nightly + docker run --rm --network=host -v "$(PWD)":/app -w /app \ + -v "$(abspath $(CARGO_HOME))/registry":/usr/local/cargo/registry\ + rustlang/rust:nightly \ + make cargo.fmt check='$(check)' dockerized=no pre-install=yes +else +ifeq ($(pre-install),yes) + rustup component add rustfmt +endif + cargo +nightly fmt --all $(if $(call eq,$(check),yes),-- --check,) +endif + + + + + +################## +# .PHONY section # +################## + +.PHONY: cargo cargo.fmt cargo.lint \ + test test.e2e test.unit diff --git a/src/api/client/server.rs b/src/api/client/server.rs index 1de4aad95..ad45ee2d2 100644 --- a/src/api/client/server.rs +++ b/src/api/client/server.rs @@ -15,8 +15,8 @@ use crate::{ }, control::Id as MemberId, }, + conf::server::Server, log::prelude::*, - settings::server::Server, }; /// Parameters of new WebSocket connection creation HTTP request. @@ -105,11 +105,8 @@ mod test { use hashbrown::HashMap; use crate::{ - api::{ - client::{session, Room}, - control::Member, - }, - settings::Settings, + api::{client::Room, control::Member}, + conf::Conf, }; use super::*; @@ -130,11 +127,11 @@ mod test { } /// Creates test WebSocket server of Client API which can handle requests. - fn ws_server() -> test::TestServer { + fn ws_server(conf: Conf) -> test::TestServer { test::TestServer::with_factory(move || { App::with_state(Context { rooms: room(), - config: Settings::new().unwrap().server, + config: conf.server.clone(), }) .resource("/ws/{room_id}/{member_id}/{credentials}", |r| { r.method(http::Method::GET).with(ws_index) @@ -144,7 +141,7 @@ mod test { #[test] fn responses_with_pong() { - let mut server = ws_server(); + let mut server = ws_server(Conf::new().unwrap()); let (read, mut write) = server.ws_at("/ws/1/1/caller_credentials").unwrap(); @@ -155,7 +152,8 @@ mod test { #[test] fn disconnects_on_idle() { - let mut server = ws_server(); + let conf = Conf::new().unwrap(); + let mut server = ws_server(conf.clone()); let (read, mut write) = server.ws_at("/ws/1/1/caller_credentials").unwrap(); @@ -163,7 +161,9 @@ mod test { let (item, read) = server.execute(read.into_future()).unwrap(); assert_eq!(item, Some(ws::Message::Text(r#"{"pong":33}"#.into()))); - thread::sleep(session::CLIENT_IDLE_TIMEOUT.add(Duration::from_secs(1))); + thread::sleep( + conf.server.client_idle_timeout.add(Duration::from_secs(1)), + ); let (item, _) = server.execute(read.into_future()).unwrap(); assert_eq!( diff --git a/src/conf/duration.rs b/src/conf/duration.rs new file mode 100644 index 000000000..1a54f40e5 --- /dev/null +++ b/src/conf/duration.rs @@ -0,0 +1,126 @@ +/// Provides deserialize [`time::Duration`] from string. +use std::fmt; +use std::time::Duration; + +use serde::de::{self, Unexpected}; +use serde::Serializer; + +struct DurationFromStringVisitor; + +pub fn deserialize<'de, D>(d: D) -> Result +where + D: de::Deserializer<'de>, +{ + Ok(d.deserialize_str(DurationFromStringVisitor)?) +} + +impl<'de> de::Visitor<'de> for DurationFromStringVisitor { + type Value = Duration; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "a string representation of duration") + } + + fn visit_str(self, value: &str) -> Result + where + E: de::Error, + { + let dur = humantime::parse_duration(value).map_err(|_| { + de::Error::invalid_value(Unexpected::Str(value), &self) + })?; + Ok(dur) + } +} + +pub fn serialize(d: &Duration, s: S) -> Result +where + S: Serializer, +{ + s.serialize_str(&format!("{}", humantime::format_duration(*d))) +} + +#[cfg(test)] +mod test { + use serde_derive::{Deserialize, Serialize}; + use serde_test::{assert_de_tokens, assert_ser_tokens, Token}; + use std::time::Duration; + + #[derive(Serialize, Deserialize, Debug, PartialEq)] + struct S { + #[serde(serialize_with = "super::serialize")] + #[serde(deserialize_with = "super::deserialize")] + dur: Duration, + } + + #[test] + fn test_de() { + let valid = vec![ + ("17nsec", Duration::new(0, 17)), + ("17nanos", Duration::new(0, 17)), + ("33ns", Duration::new(0, 33)), + ("3usec", Duration::new(0, 3000)), + ("78us", Duration::new(0, 78000)), + ("31msec", Duration::new(0, 31000000)), + ("31millis", Duration::new(0, 31000000)), + ("6ms", Duration::new(0, 6000000)), + ("3000s", Duration::new(3000, 0)), + ("300sec", Duration::new(300, 0)), + ("300secs", Duration::new(300, 0)), + ("50seconds", Duration::new(50, 0)), + ("1second", Duration::new(1, 0)), + ("100m", Duration::new(6000, 0)), + ("12min", Duration::new(720, 0)), + ("12mins", Duration::new(720, 0)), + ("1minute", Duration::new(60, 0)), + ("7minutes", Duration::new(420, 0)), + ("2h", Duration::new(7200, 0)), + ("7hr", Duration::new(25200, 0)), + ("7hrs", Duration::new(25200, 0)), + ("1hour", Duration::new(3600, 0)), + ("24hours", Duration::new(86400, 0)), + ("1day", Duration::new(86400, 0)), + ("2days", Duration::new(172800, 0)), + ("365d", Duration::new(31536000, 0)), + ("1week", Duration::new(604800, 0)), + ("7weeks", Duration::new(4233600, 0)), + ("52w", Duration::new(31449600, 0)), + ("1month", Duration::new(2630016, 0)), + ("3months", Duration::new(3 * 2630016, 0)), + ("12M", Duration::new(31560192, 0)), + ("1year", Duration::new(31557600, 0)), + ("7years", Duration::new(7 * 31557600, 0)), + ("17y", Duration::new(536479200, 0)), + ]; + + valid.into_iter().for_each(|(formatted, dur)| { + let s = S { dur }; + + assert_de_tokens( + &s, + &[ + Token::Struct { name: "S", len: 1 }, + Token::Str("dur"), + Token::Str(formatted), + Token::StructEnd, + ], + ); + }); + } + + #[test] + fn test_ser() { + let s = S { + dur: Duration::new(236179457, 45500), + }; + + assert_ser_tokens( + &s, + &[ + Token::Struct { name: "S", len: 1 }, + Token::Str("dur"), + Token::Str("7years 5months 24days 14h 36m 17s 45us 500ns"), + Token::StructEnd, + ], + ); + } +} diff --git a/src/conf/mod.rs b/src/conf/mod.rs new file mode 100644 index 000000000..b86b75d81 --- /dev/null +++ b/src/conf/mod.rs @@ -0,0 +1,146 @@ +/// Provides application configuration options. +/// +/// Configuration options can be parsed from config files in TOML format. +use config::{ + Config, ConfigError, Environment, File, FileFormat, Source, Value, +}; +use failure::Error; +use serde_derive::{Deserialize, Serialize}; +use std::collections::HashMap; + +mod duration; +pub mod server; + +static APP_CONF_PATH_CMD_ARG_NAME: &str = "--conf"; +static APP_CONF_PATH_ENV_VAR_NAME: &str = "MEDEA_CONF"; + +/// Settings represents all configuration setting of application. +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +pub struct Conf { + /// Represents [`Server`] configuration section. + pub server: server::Server, +} + +impl Source for Conf { + fn clone_into_box(&self) -> Box { + Box::new((*self).clone()) + } + + fn collect(&self) -> Result, ConfigError> { + let serialized = toml::to_string(self).unwrap(); + File::from_str(serialized.as_str(), FileFormat::Toml).collect() + } +} + +impl Conf { + pub fn new() -> Result { + use std::env; + + let mut cfg = Config::new(); + + cfg.merge(Self::default())?; + + if let Some(path) = get_conf_file_name( + env::var(APP_CONF_PATH_ENV_VAR_NAME), + env::args(), + ) { + cfg.merge(File::with_name(&path))?; + } + + cfg.merge(Environment::with_prefix("MEDEA").separator("__"))?; + + let s: Self = cfg.try_into()?; + Ok(s) + } +} + +fn get_conf_file_name( + env_var: Result, + cmd_args: T, +) -> Option +where + T: Iterator + std::fmt::Debug, +{ + if let Ok(path) = env_var { + Some(path) + } else { + let mut args = cmd_args.skip_while(|x| x != APP_CONF_PATH_CMD_ARG_NAME); + if args.next().is_some() { + args.next() + } else { + None + } + } +} + +#[cfg(test)] +mod test { + use super::get_conf_file_name; + use crate::conf::{ + Conf, APP_CONF_PATH_CMD_ARG_NAME, APP_CONF_PATH_ENV_VAR_NAME, + }; + use std::time::Duration; + + #[test] + fn get_conf_file_name_none() { + let file = get_conf_file_name( + Err(std::env::VarError::NotPresent), + Vec::new().into_iter(), + ); + assert_eq!(file, None); + } + + #[test] + fn get_conf_file_name_env() { + let file = get_conf_file_name( + Ok("env_path".to_owned()), + Vec::new().into_iter(), + ); + assert_eq!(file, Some("env_path".to_owned())); + } + + #[test] + fn get_conf_file_name_arg() { + let file = get_conf_file_name( + Err(std::env::VarError::NotPresent), + vec![APP_CONF_PATH_CMD_ARG_NAME.to_owned(), "arg_path".to_owned()] + .into_iter(), + ); + assert_eq!(file, Some("arg_path".to_owned())); + } + + #[test] + fn get_conf_file_name_both_env_overrides() { + let file = get_conf_file_name( + Ok("env_path".to_owned()), + vec![APP_CONF_PATH_CMD_ARG_NAME.to_owned(), "arg_path".to_owned()] + .into_iter(), + ); + assert_eq!(file, Some("env_path".to_owned())); + } + + #[test] + fn ensure_file_overrides_defaults() { + let defaults = Conf::new().unwrap(); + let test_config_file_path = + "ensure_file_overrides_defaults_test_config.toml"; + + let data = format!("[server]\nclient_idle_timeout = \"55s\""); + std::fs::write(test_config_file_path, data).unwrap(); + std::env::set_var(APP_CONF_PATH_ENV_VAR_NAME, test_config_file_path); + + let new_config = Conf::new().unwrap(); + + std::env::remove_var(APP_CONF_PATH_ENV_VAR_NAME); + std::fs::remove_file(test_config_file_path).unwrap(); + + assert_eq!( + new_config.server.client_idle_timeout, + Duration::from_secs(55) + ); + assert_ne!( + new_config.server.client_idle_timeout, + defaults.server.client_idle_timeout + ); + } +} diff --git a/src/settings/server.rs b/src/conf/server.rs similarity index 88% rename from src/settings/server.rs rename to src/conf/server.rs index 919ddd7be..18810520f 100644 --- a/src/settings/server.rs +++ b/src/conf/server.rs @@ -2,7 +2,7 @@ use std::time::Duration; use serde_derive::{Deserialize, Serialize}; -use crate::settings::duration; +use crate::conf::duration; /// Server represents [`Server`] configuration section. #[derive(Clone, Debug, Deserialize, Serialize)] @@ -15,8 +15,8 @@ pub struct Server { /// Default returns default configuration parameters of [`Server`] section. impl Default for Server { - fn default() -> Server { - Server { + fn default() -> Self { + Self { client_idle_timeout: Duration::from_secs(10), } } diff --git a/src/main.rs b/src/main.rs index ce0d9c907..cdd0b3ec5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,21 +3,22 @@ use actix::prelude::*; use dotenv::dotenv; use hashbrown::HashMap; +use log::prelude::*; use crate::{ api::{ client::{server, Room, RoomsRepository}, control::Member, }, - settings::Settings, + conf::Conf, }; #[macro_use] mod utils; mod api; +mod conf; mod log; -mod settings; fn main() { dotenv().ok(); @@ -39,7 +40,9 @@ fn main() { let rooms = hashmap! {1 => room}; let rooms_repo = RoomsRepository::new(rooms); - let config = Settings::new().unwrap(); + let config = Conf::new().unwrap(); + + info!("{:?}", config); server::run(rooms_repo, config.server); let _ = sys.run(); diff --git a/src/settings/duration.rs b/src/settings/duration.rs deleted file mode 100644 index 695666f6c..000000000 --- a/src/settings/duration.rs +++ /dev/null @@ -1,54 +0,0 @@ -/// Provides deserialize [`time::Duration`] from string. -use std::fmt; -use std::time::Duration; - -use lazy_static::*; -use regex::Regex; -use serde::de::{self, Unexpected}; -use serde::Serializer; - -lazy_static! { - static ref REGEX_DURATION: Regex = - Regex::new(r"^(?P\d+)m|(?P\d+)s$").unwrap(); -} - -struct DurationFromStringVisitor; - -pub fn deserialize<'de, D>(d: D) -> Result -where - D: de::Deserializer<'de>, -{ - Ok(d.deserialize_str(DurationFromStringVisitor)?) -} - -impl<'de> de::Visitor<'de> for DurationFromStringVisitor { - type Value = Duration; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "a string representation of duration") - } - - fn visit_str(self, value: &str) -> Result - where - E: de::Error, - { - let caps = REGEX_DURATION - .captures(value) - .ok_or(de::Error::invalid_value(Unexpected::Str(value), &self))?; - let m = caps - .name("minutes") - .map_or(0, |s| s.as_str().parse::().unwrap()); - let s = caps - .name("seconds") - .map_or(0, |s| s.as_str().parse::().unwrap()); - - Ok(Duration::from_secs(m * 60 + s)) - } -} - -pub fn serialize(d: &Duration, s: S) -> Result -where - S: Serializer, -{ - s.serialize_str(format!("{}s", d.as_secs()).as_str()) -} diff --git a/src/settings/mod.rs b/src/settings/mod.rs deleted file mode 100644 index 3da49b14d..000000000 --- a/src/settings/mod.rs +++ /dev/null @@ -1,30 +0,0 @@ -/// Provides application configuration options. -/// -/// Configuration options can be parsed from config files in TOML format. -use config::{Config, Environment, File, FileFormat}; -use failure::Error; -use serde_derive::{Deserialize, Serialize}; -use toml::to_string; - -mod duration; -pub mod server; - -/// Settings represents all configuration setting of application. -#[derive(Debug, Default, Deserialize, Serialize)] -pub struct Settings { - /// Represents [`Server`] configuration section. - pub server: server::Server, -} - -impl Settings { - pub fn new() -> Result { - let mut cfg = Config::new(); - let defaults = to_string(&Settings::default())?; - cfg.merge(File::from_str(defaults.as_str(), FileFormat::Toml))?; - cfg.merge(File::with_name("config"))?; - cfg.merge(Environment::with_prefix("conf").separator("__"))?; - - let s: Settings = cfg.try_into()?; - Ok(s) - } -} From 29461bac77a9bc4038b3e5c11cb83b7167cdee8d Mon Sep 17 00:00:00 2001 From: Kirguir Date: Tue, 26 Mar 2019 11:16:43 +0200 Subject: [PATCH 06/20] Add docs --- src/conf/mod.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/conf/mod.rs b/src/conf/mod.rs index b86b75d81..650e1e20a 100644 --- a/src/conf/mod.rs +++ b/src/conf/mod.rs @@ -33,6 +33,12 @@ impl Source for Conf { } impl Conf { + /// Creates new [`Conf`] and applies values from such sources + /// and in that order: + /// - default values; + /// - configuration file, the name of which is given as a command line + /// parameter or environment variable; + /// - environment variables; pub fn new() -> Result { use std::env; @@ -54,6 +60,7 @@ impl Conf { } } +/// Returns the name of the configuration file, if defined. fn get_conf_file_name( env_var: Result, cmd_args: T, From 41b33eeb2f93427ceaefb88d2686799ffc0cf812 Mon Sep 17 00:00:00 2001 From: alexlapa Date: Tue, 26 Mar 2019 17:45:55 +0200 Subject: [PATCH 07/20] refactor, extend tests --- Cargo.lock | 23 +++++++++++++-- Cargo.toml | 4 +-- src/api/client/server.rs | 31 ++++++++++++-------- src/conf/mod.rs | 61 +++++++++++++++++++++++++++++++--------- src/conf/rpc.rs | 23 +++++++++++++++ src/conf/server.rs | 57 ++++++++++++++++++++++++++++++------- src/main.rs | 2 +- 7 files changed, 160 insertions(+), 41 deletions(-) create mode 100644 src/conf/rpc.rs diff --git a/Cargo.lock b/Cargo.lock index d78b8f597..fbedce62e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -719,12 +719,12 @@ dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)", "serde_test 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serial_test 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serial_test_derive 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "slog-async 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "slog-envlogger 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1269,6 +1269,23 @@ dependencies = [ "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "serial_test" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serial_test_derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "sha1" version = "0.6.0" @@ -2047,6 +2064,8 @@ dependencies = [ "checksum serde_test 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "110b3dbdf8607ec493c22d5d947753282f3bae73c0f56d322af1e8c78e4c23d5" "checksum serde_test 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)" = "70807e147558b5253cb70f55d343db1d07204d773087c96d0f35fced295dba82" "checksum serde_urlencoded 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d48f9f99cd749a2de71d29da5f948de7f2764cc5a9d7f3c97e3514d4ee6eabf2" +"checksum serial_test 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50bfbc39343545618d97869d77f38ed43e48dd77432717dbc7ed39d797f3ecbe" +"checksum serial_test_derive 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "89dd85be2e2ad75b041c9df2892ac078fa6e0b90024028b2b9fb4125b7530f01" "checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" "checksum signal-hook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1f272d1b7586bec132ed427f532dd418d8beca1ca7f2caf7df35569b1415a4b4" "checksum siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" diff --git a/Cargo.toml b/Cargo.toml index b43f33505..832cc2343 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,8 +19,6 @@ failure = "0.1.5" futures = "0.1" hashbrown = "0.1" humantime = "1.2.0" -lazy_static = "1.2" -regex = "1.1" serde = { version = "1.0", features = ["derive"] } serde_derive = "1.0" serde_json = "1.0" @@ -34,3 +32,5 @@ toml = "0.4" [dev-dependencies] serde_test = "1.0.89" +serial_test = "0.2.0" +serial_test_derive = "0.2.0" diff --git a/src/api/client/server.rs b/src/api/client/server.rs index ad45ee2d2..caf7a3842 100644 --- a/src/api/client/server.rs +++ b/src/api/client/server.rs @@ -15,7 +15,7 @@ use crate::{ }, control::Id as MemberId, }, - conf::server::Server, + conf::{rpc::Rpc, Conf}, log::prelude::*, }; @@ -56,7 +56,7 @@ fn ws_index( WsSession::new( info.member_id, room, - state.config.client_idle_timeout, + state.config.idle_timeout, ), ), Err(MemberNotExists) => Ok(HttpResponse::NotFound().into()), @@ -73,22 +73,24 @@ pub struct Context { pub rooms: RoomsRepository, /// Settings of application. - pub config: Server, + pub config: Rpc, } /// Starts HTTP server for handling WebSocket connections of Client API. -pub fn run(rooms: RoomsRepository, config: Server) { +pub fn run(rooms: RoomsRepository, config: Conf) { + let server_addr = config.server.get_bind_addr(); + server::new(move || { App::with_state(Context { rooms: rooms.clone(), - config: config.clone(), + config: config.rpc.clone(), }) .middleware(middleware::Logger::default()) .resource("/ws/{room_id}/{member_id}/{credentials}", |r| { r.method(http::Method::GET).with(ws_index) }) }) - .bind("0.0.0.0:8080") + .bind(server_addr) .unwrap() .start(); @@ -110,6 +112,7 @@ mod test { }; use super::*; + use crate::conf::server::Server; /// Creates [`RoomsRepository`] for tests filled with a single [`Room`]. fn room() -> RoomsRepository { @@ -131,7 +134,7 @@ mod test { test::TestServer::with_factory(move || { App::with_state(Context { rooms: room(), - config: conf.server.clone(), + config: conf.rpc.clone(), }) .resource("/ws/{room_id}/{member_id}/{credentials}", |r| { r.method(http::Method::GET).with(ws_index) @@ -141,7 +144,7 @@ mod test { #[test] fn responses_with_pong() { - let mut server = ws_server(Conf::new().unwrap()); + let mut server = ws_server(Conf::default()); let (read, mut write) = server.ws_at("/ws/1/1/caller_credentials").unwrap(); @@ -152,7 +155,13 @@ mod test { #[test] fn disconnects_on_idle() { - let conf = Conf::new().unwrap(); + let conf = Conf { + rpc: Rpc { + idle_timeout: Duration::new(1, 0), + }, + server: Server::default(), + }; + let mut server = ws_server(conf.clone()); let (read, mut write) = server.ws_at("/ws/1/1/caller_credentials").unwrap(); @@ -161,9 +170,7 @@ mod test { let (item, read) = server.execute(read.into_future()).unwrap(); assert_eq!(item, Some(ws::Message::Text(r#"{"pong":33}"#.into()))); - thread::sleep( - conf.server.client_idle_timeout.add(Duration::from_secs(1)), - ); + thread::sleep(conf.rpc.idle_timeout.add(Duration::from_secs(1))); let (item, _) = server.execute(read.into_future()).unwrap(); assert_eq!( diff --git a/src/conf/mod.rs b/src/conf/mod.rs index 650e1e20a..630c5ce7a 100644 --- a/src/conf/mod.rs +++ b/src/conf/mod.rs @@ -9,6 +9,7 @@ use serde_derive::{Deserialize, Serialize}; use std::collections::HashMap; mod duration; +pub mod rpc; pub mod server; static APP_CONF_PATH_CMD_ARG_NAME: &str = "--conf"; @@ -18,6 +19,7 @@ static APP_CONF_PATH_ENV_VAR_NAME: &str = "MEDEA_CONF"; #[derive(Clone, Debug, Default, Deserialize, Serialize)] pub struct Conf { /// Represents [`Server`] configuration section. + pub rpc: rpc::Rpc, pub server: server::Server, } @@ -53,7 +55,7 @@ impl Conf { cfg.merge(File::with_name(&path))?; } - cfg.merge(Environment::with_prefix("MEDEA").separator("__"))?; + cfg.merge(Environment::with_prefix("MEDEA").separator("."))?; let s: Self = cfg.try_into()?; Ok(s) @@ -86,6 +88,7 @@ mod test { use crate::conf::{ Conf, APP_CONF_PATH_CMD_ARG_NAME, APP_CONF_PATH_ENV_VAR_NAME, }; + use serial_test_derive::serial; use std::time::Duration; #[test] @@ -127,12 +130,12 @@ mod test { } #[test] - fn ensure_file_overrides_defaults() { - let defaults = Conf::new().unwrap(); - let test_config_file_path = - "ensure_file_overrides_defaults_test_config.toml"; + #[serial] + fn file_overrides_defaults() { + let defaults = Conf::default(); + let test_config_file_path = "test_config.toml"; - let data = format!("[server]\nclient_idle_timeout = \"55s\""); + let data = format!("[rpc]\nidle_timeout = \"45s\""); std::fs::write(test_config_file_path, data).unwrap(); std::env::set_var(APP_CONF_PATH_ENV_VAR_NAME, test_config_file_path); @@ -141,13 +144,43 @@ mod test { std::env::remove_var(APP_CONF_PATH_ENV_VAR_NAME); std::fs::remove_file(test_config_file_path).unwrap(); - assert_eq!( - new_config.server.client_idle_timeout, - Duration::from_secs(55) - ); - assert_ne!( - new_config.server.client_idle_timeout, - defaults.server.client_idle_timeout - ); + assert_eq!(new_config.rpc.idle_timeout, Duration::from_secs(45)); + assert_ne!(new_config.rpc.idle_timeout, defaults.rpc.idle_timeout); + } + + #[test] + #[serial] + fn env_overrides_defaults() { + let defaults = Conf::default(); + + std::env::set_var("MEDEA_RPC.IDLE_TIMEOUT", "46s"); + let new_config = Conf::new().unwrap(); + std::env::remove_var("MEDEA_RPC.IDLE_TIMEOUT"); + + assert_eq!(new_config.rpc.idle_timeout, Duration::from_secs(46)); + assert_ne!(new_config.rpc.idle_timeout, defaults.rpc.idle_timeout); + } + + #[test] + #[serial] + fn env_overrides_file() { + let test_config_file_path = "test_config.toml"; + + let data = format!("[rpc]\nidle_timeout = \"47s\""); + std::fs::write(test_config_file_path, data).unwrap(); + std::env::set_var(APP_CONF_PATH_ENV_VAR_NAME, test_config_file_path); + + let file_config = Conf::new().unwrap(); + + std::env::set_var("MEDEA_RPC.IDLE_TIMEOUT", "48s"); + let file_env_config = Conf::new().unwrap(); + + std::env::remove_var(APP_CONF_PATH_ENV_VAR_NAME); + std::fs::remove_file(test_config_file_path).unwrap(); + std::env::remove_var("MEDEA_RPC.IDLE_TIMEOUT"); + + assert_eq!(file_config.rpc.idle_timeout, Duration::from_secs(47)); + + assert_eq!(file_env_config.rpc.idle_timeout, Duration::from_secs(48)); } } diff --git a/src/conf/rpc.rs b/src/conf/rpc.rs new file mode 100644 index 000000000..7c02006e9 --- /dev/null +++ b/src/conf/rpc.rs @@ -0,0 +1,23 @@ +use std::time::Duration; + +use serde_derive::{Deserialize, Serialize}; + +use crate::conf::duration; + +/// Server represents [`Server`] configuration section. +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct Rpc { + /// Timeout for [`WsSession`] to wait ping message from [`Web Client`]. + #[serde(serialize_with = "duration::serialize")] + #[serde(deserialize_with = "duration::deserialize")] + pub idle_timeout: Duration, +} + +/// Default returns default configuration parameters of [`Server`] section. +impl Default for Rpc { + fn default() -> Self { + Self { + idle_timeout: Duration::from_secs(10), + } + } +} diff --git a/src/conf/server.rs b/src/conf/server.rs index 18810520f..6ff9a47c7 100644 --- a/src/conf/server.rs +++ b/src/conf/server.rs @@ -1,23 +1,60 @@ -use std::time::Duration; - use serde_derive::{Deserialize, Serialize}; - -use crate::conf::duration; +use std::net::{IpAddr, Ipv4Addr}; /// Server represents [`Server`] configuration section. #[derive(Clone, Debug, Deserialize, Serialize)] pub struct Server { - /// Timeout for [`WsSession`] to wait ping message from [`Web Client`]. - #[serde(serialize_with = "duration::serialize")] - #[serde(deserialize_with = "duration::deserialize")] - pub client_idle_timeout: Duration, + pub bind_ip: IpAddr, + pub bind_port: u16, } -/// Default returns default configuration parameters of [`Server`] section. impl Default for Server { fn default() -> Self { Self { - client_idle_timeout: Duration::from_secs(10), + bind_ip: IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), + bind_port: 8080, } } } + +impl Server { + pub fn get_bind_addr(&self) -> impl std::net::ToSocketAddrs { + (self.bind_ip, self.bind_port) + } +} + +#[cfg(test)] +mod test { + use crate::conf::Conf; + + use serial_test_derive::serial; + use std::net::{Ipv4Addr, SocketAddr, ToSocketAddrs as _}; + + #[test] + #[serial] + fn override_defaults_and_get_bind_addr() { + let default_conf = Conf::default(); + + std::env::set_var("MEDEA_SERVER.BIND_IP", "5.5.5.5"); + std::env::set_var("MEDEA_SERVER.BIND_PORT", "1234"); + + let env_conf = Conf::new().unwrap(); + + assert_ne!(default_conf.server.bind_ip, env_conf.server.bind_ip); + assert_ne!(default_conf.server.bind_port, env_conf.server.bind_port); + + assert_eq!(env_conf.server.bind_ip, Ipv4Addr::new(5, 5, 5, 5)); + assert_eq!(env_conf.server.bind_port, 1234); + + let addr: SocketAddr = env_conf + .server + .get_bind_addr() + .to_socket_addrs() + .unwrap() + .into_iter() + .next() + .unwrap(); + + assert_eq!(addr, "5.5.5.5:1234".parse().unwrap()); + } +} diff --git a/src/main.rs b/src/main.rs index cdd0b3ec5..ba48cf02e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -44,6 +44,6 @@ fn main() { info!("{:?}", config); - server::run(rooms_repo, config.server); + server::run(rooms_repo, config); let _ = sys.run(); } From 0878ebb70a92aca1877ed085fcf8812dd1a16576 Mon Sep 17 00:00:00 2001 From: tyranron Date: Fri, 29 Mar 2019 17:39:20 +0200 Subject: [PATCH 08/20] Some corrections --- Cargo.toml | 10 +++++----- src/conf/server.rs | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 832cc2343..a9e43e583 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,10 +15,10 @@ actix-web = "0.7" config = "0.9" chrono = "0.4" dotenv = "0.13" -failure = "0.1.5" +failure = "0.1" futures = "0.1" hashbrown = "0.1" -humantime = "1.2.0" +humantime = "1.2" serde = { version = "1.0", features = ["derive"] } serde_derive = "1.0" serde_json = "1.0" @@ -31,6 +31,6 @@ slog-scope = "4.1" toml = "0.4" [dev-dependencies] -serde_test = "1.0.89" -serial_test = "0.2.0" -serial_test_derive = "0.2.0" +serde_test = "1.0" +serial_test = "0.2" +serial_test_derive = "0.2" diff --git a/src/conf/server.rs b/src/conf/server.rs index 6ff9a47c7..93a153691 100644 --- a/src/conf/server.rs +++ b/src/conf/server.rs @@ -1,6 +1,7 @@ -use serde_derive::{Deserialize, Serialize}; use std::net::{IpAddr, Ipv4Addr}; +use serde_derive::{Deserialize, Serialize}; + /// Server represents [`Server`] configuration section. #[derive(Clone, Debug, Deserialize, Serialize)] pub struct Server { From 3a959afedd3c6b33e2e67eaabe950c28d74c50fb Mon Sep 17 00:00:00 2001 From: alexlapa Date: Fri, 29 Mar 2019 19:34:47 +0200 Subject: [PATCH 09/20] fix serde_derive import --- Cargo.lock | 1 - Cargo.toml | 1 - src/conf/duration.rs | 2 +- src/conf/mod.rs | 2 +- src/conf/rpc.rs | 2 +- src/conf/server.rs | 2 +- 6 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fbedce62e..7b165ada8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -720,7 +720,6 @@ dependencies = [ "hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)", "serde_test 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serial_test 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index a9e43e583..8daad2abd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,6 @@ futures = "0.1" hashbrown = "0.1" humantime = "1.2" serde = { version = "1.0", features = ["derive"] } -serde_derive = "1.0" serde_json = "1.0" slog = "2.4" slog-envlogger = "2.1" diff --git a/src/conf/duration.rs b/src/conf/duration.rs index 1a54f40e5..82795a641 100644 --- a/src/conf/duration.rs +++ b/src/conf/duration.rs @@ -41,7 +41,7 @@ where #[cfg(test)] mod test { - use serde_derive::{Deserialize, Serialize}; + use serde::{Deserialize, Serialize}; use serde_test::{assert_de_tokens, assert_ser_tokens, Token}; use std::time::Duration; diff --git a/src/conf/mod.rs b/src/conf/mod.rs index 630c5ce7a..82d633ce1 100644 --- a/src/conf/mod.rs +++ b/src/conf/mod.rs @@ -5,7 +5,7 @@ use config::{ Config, ConfigError, Environment, File, FileFormat, Source, Value, }; use failure::Error; -use serde_derive::{Deserialize, Serialize}; +use serde::{Deserialize, Serialize}; use std::collections::HashMap; mod duration; diff --git a/src/conf/rpc.rs b/src/conf/rpc.rs index 7c02006e9..741616cd3 100644 --- a/src/conf/rpc.rs +++ b/src/conf/rpc.rs @@ -1,6 +1,6 @@ use std::time::Duration; -use serde_derive::{Deserialize, Serialize}; +use serde::{Deserialize, Serialize}; use crate::conf::duration; diff --git a/src/conf/server.rs b/src/conf/server.rs index 93a153691..1c03e3664 100644 --- a/src/conf/server.rs +++ b/src/conf/server.rs @@ -1,6 +1,6 @@ use std::net::{IpAddr, Ipv4Addr}; -use serde_derive::{Deserialize, Serialize}; +use serde::{Deserialize, Serialize}; /// Server represents [`Server`] configuration section. #[derive(Clone, Debug, Deserialize, Serialize)] From 7596c792b97fffa1552f1ea769fdad869927b420 Mon Sep 17 00:00:00 2001 From: alexlapa Date: Fri, 29 Mar 2019 20:04:48 +0200 Subject: [PATCH 10/20] use smart_default --- Cargo.lock | 12 ++++++++++++ Cargo.toml | 1 + src/conf/duration.rs | 5 ++--- src/conf/mod.rs | 12 +++++++----- src/conf/rpc.rs | 17 +++++------------ src/conf/server.rs | 18 ++++++------------ 6 files changed, 33 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7b165ada8..15f0fade7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -730,6 +730,7 @@ dependencies = [ "slog-json 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "slog-scope 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "slog-stdlog 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "smart-default 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1390,6 +1391,16 @@ dependencies = [ "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "smart-default" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.25 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "socket2" version = "0.3.8" @@ -2077,6 +2088,7 @@ dependencies = [ "checksum slog-stdlog 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ac42f8254ae996cc7d640f9410d3b048dcdf8887a10df4d5d4c44966de24c4a8" "checksum slog-term 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5951a808c40f419922ee014c15b6ae1cd34d963538b57d8a4778b9ca3fff1e0b" "checksum smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b73ea3738b47563803ef814925e69be00799a8c07420be8b996f8e98fb2336db" +"checksum smart-default 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fae090012788f95156fc33f43631242480f311cca6bf7f600943eba14ae032ed" "checksum socket2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c4d11a52082057d87cb5caa31ad812f4504b97ab44732cd8359df2e9ff9f48e7" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b639411d0b9c738748b5397d5ceba08e648f4f1992231aa859af1a017f31f60b" diff --git a/Cargo.toml b/Cargo.toml index 8daad2abd..7dc20ba4a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ slog-stdlog = "3.0" slog-async = "2.3" slog-json = "2.3" slog-scope = "4.1" +smart-default = "0.5" toml = "0.4" [dev-dependencies] diff --git a/src/conf/duration.rs b/src/conf/duration.rs index 82795a641..3d8d2d57d 100644 --- a/src/conf/duration.rs +++ b/src/conf/duration.rs @@ -1,10 +1,9 @@ /// Provides deserialize [`time::Duration`] from string. -use std::fmt; -use std::time::Duration; - use serde::de::{self, Unexpected}; use serde::Serializer; +use std::{fmt, time::Duration}; + struct DurationFromStringVisitor; pub fn deserialize<'de, D>(d: D) -> Result diff --git a/src/conf/mod.rs b/src/conf/mod.rs index 82d633ce1..bae29d211 100644 --- a/src/conf/mod.rs +++ b/src/conf/mod.rs @@ -1,22 +1,24 @@ /// Provides application configuration options. /// /// Configuration options can be parsed from config files in TOML format. +mod duration; +pub mod rpc; +pub mod server; + use config::{ Config, ConfigError, Environment, File, FileFormat, Source, Value, }; use failure::Error; use serde::{Deserialize, Serialize}; -use std::collections::HashMap; +use smart_default::*; -mod duration; -pub mod rpc; -pub mod server; +use std::collections::HashMap; static APP_CONF_PATH_CMD_ARG_NAME: &str = "--conf"; static APP_CONF_PATH_ENV_VAR_NAME: &str = "MEDEA_CONF"; /// Settings represents all configuration setting of application. -#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[derive(Clone, Debug, Deserialize, Serialize, SmartDefault)] pub struct Conf { /// Represents [`Server`] configuration section. pub rpc: rpc::Rpc, diff --git a/src/conf/rpc.rs b/src/conf/rpc.rs index 741616cd3..f14ed7195 100644 --- a/src/conf/rpc.rs +++ b/src/conf/rpc.rs @@ -1,23 +1,16 @@ -use std::time::Duration; - use serde::{Deserialize, Serialize}; +use smart_default::*; + +use std::time::Duration; use crate::conf::duration; /// Server represents [`Server`] configuration section. -#[derive(Clone, Debug, Deserialize, Serialize)] +#[derive(Clone, Debug, Deserialize, Serialize, SmartDefault)] pub struct Rpc { /// Timeout for [`WsSession`] to wait ping message from [`Web Client`]. #[serde(serialize_with = "duration::serialize")] #[serde(deserialize_with = "duration::deserialize")] + #[default(Duration::from_secs(10))] pub idle_timeout: Duration, } - -/// Default returns default configuration parameters of [`Server`] section. -impl Default for Rpc { - fn default() -> Self { - Self { - idle_timeout: Duration::from_secs(10), - } - } -} diff --git a/src/conf/server.rs b/src/conf/server.rs index 1c03e3664..7aac9a95d 100644 --- a/src/conf/server.rs +++ b/src/conf/server.rs @@ -1,23 +1,17 @@ -use std::net::{IpAddr, Ipv4Addr}; - use serde::{Deserialize, Serialize}; +use smart_default::*; + +use std::net::{IpAddr, Ipv4Addr}; /// Server represents [`Server`] configuration section. -#[derive(Clone, Debug, Deserialize, Serialize)] +#[derive(Clone, Debug, Deserialize, Serialize, SmartDefault)] pub struct Server { + #[default(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)))] pub bind_ip: IpAddr, + #[default(8080)] pub bind_port: u16, } -impl Default for Server { - fn default() -> Self { - Self { - bind_ip: IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), - bind_port: 8080, - } - } -} - impl Server { pub fn get_bind_addr(&self) -> impl std::net::ToSocketAddrs { (self.bind_ip, self.bind_port) From e14e091a506c3433d32927e4c169f3e05307ed4f Mon Sep 17 00:00:00 2001 From: alexlapa Date: Fri, 29 Mar 2019 20:44:47 +0200 Subject: [PATCH 11/20] use serde-humantime --- Cargo.lock | 11 ++++ Cargo.toml | 6 ++ src/conf/duration.rs | 125 ------------------------------------------ src/conf/mod.rs | 9 +-- src/conf/rpc.rs | 8 +-- src/conf/server.rs | 6 +- src/utils/duration.rs | 44 +++++++++++++++ src/utils/mod.rs | 2 + 8 files changed, 75 insertions(+), 136 deletions(-) delete mode 100644 src/conf/duration.rs create mode 100644 src/utils/duration.rs diff --git a/Cargo.lock b/Cargo.lock index 15f0fade7..2c5dbb056 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -720,6 +720,7 @@ dependencies = [ "hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", + "serde-humantime 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)", "serde_test 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serial_test 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1222,6 +1223,15 @@ dependencies = [ "serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "serde-humantime" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "serde_derive" version = "1.0.87" @@ -2069,6 +2079,7 @@ dependencies = [ "checksum serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8" "checksum serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)" = "0e732ed5a5592c17d961555e3b552985baf98d50ce418b7b655f31f6ba7eb1b7" "checksum serde-hjson 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0b833c5ad67d52ced5f5938b2980f32a9c1c5ef047f0b4fb3127e7a423c76153" +"checksum serde-humantime 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c367b5dafa12cef19c554638db10acde90d5e9acea2b80e1ad98b00f88068f7d" "checksum serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)" = "633e97856567e518b59ffb2ad7c7a4fd4c5d91d9c7f32dd38a27b2bf7e8114ea" "checksum serde_json 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)" = "574378d957d6dcdf1bbb5d562a15cbd5e644159432f84634b94e485267abbcc7" "checksum serde_test 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "110b3dbdf8607ec493c22d5d947753282f3bae73c0f56d322af1e8c78e4c23d5" diff --git a/Cargo.toml b/Cargo.toml index 7dc20ba4a..fd2f6c5e1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ repository = "https://github.com/instrumentisto/medea" [dependencies] actix = "0.7" actix-web = "0.7" + config = "0.9" chrono = "0.4" dotenv = "0.13" @@ -19,18 +20,23 @@ failure = "0.1" futures = "0.1" hashbrown = "0.1" humantime = "1.2" + serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" +serde-humantime = "0.1.1" + slog = "2.4" slog-envlogger = "2.1" slog-stdlog = "3.0" slog-async = "2.3" slog-json = "2.3" slog-scope = "4.1" + smart-default = "0.5" toml = "0.4" [dev-dependencies] serde_test = "1.0" + serial_test = "0.2" serial_test_derive = "0.2" diff --git a/src/conf/duration.rs b/src/conf/duration.rs deleted file mode 100644 index 3d8d2d57d..000000000 --- a/src/conf/duration.rs +++ /dev/null @@ -1,125 +0,0 @@ -/// Provides deserialize [`time::Duration`] from string. -use serde::de::{self, Unexpected}; -use serde::Serializer; - -use std::{fmt, time::Duration}; - -struct DurationFromStringVisitor; - -pub fn deserialize<'de, D>(d: D) -> Result -where - D: de::Deserializer<'de>, -{ - Ok(d.deserialize_str(DurationFromStringVisitor)?) -} - -impl<'de> de::Visitor<'de> for DurationFromStringVisitor { - type Value = Duration; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "a string representation of duration") - } - - fn visit_str(self, value: &str) -> Result - where - E: de::Error, - { - let dur = humantime::parse_duration(value).map_err(|_| { - de::Error::invalid_value(Unexpected::Str(value), &self) - })?; - Ok(dur) - } -} - -pub fn serialize(d: &Duration, s: S) -> Result -where - S: Serializer, -{ - s.serialize_str(&format!("{}", humantime::format_duration(*d))) -} - -#[cfg(test)] -mod test { - use serde::{Deserialize, Serialize}; - use serde_test::{assert_de_tokens, assert_ser_tokens, Token}; - use std::time::Duration; - - #[derive(Serialize, Deserialize, Debug, PartialEq)] - struct S { - #[serde(serialize_with = "super::serialize")] - #[serde(deserialize_with = "super::deserialize")] - dur: Duration, - } - - #[test] - fn test_de() { - let valid = vec![ - ("17nsec", Duration::new(0, 17)), - ("17nanos", Duration::new(0, 17)), - ("33ns", Duration::new(0, 33)), - ("3usec", Duration::new(0, 3000)), - ("78us", Duration::new(0, 78000)), - ("31msec", Duration::new(0, 31000000)), - ("31millis", Duration::new(0, 31000000)), - ("6ms", Duration::new(0, 6000000)), - ("3000s", Duration::new(3000, 0)), - ("300sec", Duration::new(300, 0)), - ("300secs", Duration::new(300, 0)), - ("50seconds", Duration::new(50, 0)), - ("1second", Duration::new(1, 0)), - ("100m", Duration::new(6000, 0)), - ("12min", Duration::new(720, 0)), - ("12mins", Duration::new(720, 0)), - ("1minute", Duration::new(60, 0)), - ("7minutes", Duration::new(420, 0)), - ("2h", Duration::new(7200, 0)), - ("7hr", Duration::new(25200, 0)), - ("7hrs", Duration::new(25200, 0)), - ("1hour", Duration::new(3600, 0)), - ("24hours", Duration::new(86400, 0)), - ("1day", Duration::new(86400, 0)), - ("2days", Duration::new(172800, 0)), - ("365d", Duration::new(31536000, 0)), - ("1week", Duration::new(604800, 0)), - ("7weeks", Duration::new(4233600, 0)), - ("52w", Duration::new(31449600, 0)), - ("1month", Duration::new(2630016, 0)), - ("3months", Duration::new(3 * 2630016, 0)), - ("12M", Duration::new(31560192, 0)), - ("1year", Duration::new(31557600, 0)), - ("7years", Duration::new(7 * 31557600, 0)), - ("17y", Duration::new(536479200, 0)), - ]; - - valid.into_iter().for_each(|(formatted, dur)| { - let s = S { dur }; - - assert_de_tokens( - &s, - &[ - Token::Struct { name: "S", len: 1 }, - Token::Str("dur"), - Token::Str(formatted), - Token::StructEnd, - ], - ); - }); - } - - #[test] - fn test_ser() { - let s = S { - dur: Duration::new(236179457, 45500), - }; - - assert_ser_tokens( - &s, - &[ - Token::Struct { name: "S", len: 1 }, - Token::Str("dur"), - Token::Str("7years 5months 24days 14h 36m 17s 45us 500ns"), - Token::StructEnd, - ], - ); - } -} diff --git a/src/conf/mod.rs b/src/conf/mod.rs index bae29d211..cd98d413f 100644 --- a/src/conf/mod.rs +++ b/src/conf/mod.rs @@ -1,7 +1,6 @@ /// Provides application configuration options. /// /// Configuration options can be parsed from config files in TOML format. -mod duration; pub mod rpc; pub mod server; @@ -86,13 +85,15 @@ where #[cfg(test)] mod test { - use super::get_conf_file_name; + use serial_test_derive::serial; + + use std::time::Duration; + use crate::conf::{ Conf, APP_CONF_PATH_CMD_ARG_NAME, APP_CONF_PATH_ENV_VAR_NAME, }; - use serial_test_derive::serial; - use std::time::Duration; + use super::get_conf_file_name; #[test] fn get_conf_file_name_none() { let file = get_conf_file_name( diff --git a/src/conf/rpc.rs b/src/conf/rpc.rs index f14ed7195..df4d9cb25 100644 --- a/src/conf/rpc.rs +++ b/src/conf/rpc.rs @@ -3,14 +3,12 @@ use smart_default::*; use std::time::Duration; -use crate::conf::duration; - /// Server represents [`Server`] configuration section. -#[derive(Clone, Debug, Deserialize, Serialize, SmartDefault)] +#[derive(Clone, Debug, Serialize, Deserialize, SmartDefault)] pub struct Rpc { /// Timeout for [`WsSession`] to wait ping message from [`Web Client`]. - #[serde(serialize_with = "duration::serialize")] - #[serde(deserialize_with = "duration::deserialize")] + #[serde(deserialize_with = "serde_humantime::deserialize")] + #[serde(serialize_with = "crate::utils::duration::serialize")] #[default(Duration::from_secs(10))] pub idle_timeout: Duration, } diff --git a/src/conf/server.rs b/src/conf/server.rs index 7aac9a95d..e2c3fa1d5 100644 --- a/src/conf/server.rs +++ b/src/conf/server.rs @@ -13,18 +13,20 @@ pub struct Server { } impl Server { - pub fn get_bind_addr(&self) -> impl std::net::ToSocketAddrs { + pub fn get_bind_addr(&self) -> (IpAddr, u16) { (self.bind_ip, self.bind_port) } } #[cfg(test)] mod test { - use crate::conf::Conf; use serial_test_derive::serial; + use std::net::{Ipv4Addr, SocketAddr, ToSocketAddrs as _}; + use crate::conf::Conf; + #[test] #[serial] fn override_defaults_and_get_bind_addr() { diff --git a/src/utils/duration.rs b/src/utils/duration.rs new file mode 100644 index 000000000..c3b1effd8 --- /dev/null +++ b/src/utils/duration.rs @@ -0,0 +1,44 @@ +/// Provides Serde serializer for [`std::time::Duration`] via the +/// `humantime` crate . +use serde::Serializer; + +use std::time::Duration; + +/// Serializes a `Duration` via the humantime crate. +pub fn serialize(d: &Duration, s: S) -> Result +where + S: Serializer, +{ + s.serialize_str(&format!("{}", humantime::format_duration(*d))) +} + +#[cfg(test)] +mod test { + use serde::{Deserialize, Serialize}; + use serde_test::{assert_ser_tokens, Token}; + + use std::time::Duration; + + #[derive(Serialize, Deserialize, Debug, PartialEq)] + struct S { + #[serde(serialize_with = "super::serialize")] + dur: Duration, + } + + #[test] + fn test_ser() { + let s = S { + dur: Duration::new(236179457, 45500), + }; + + assert_ser_tokens( + &s, + &[ + Token::Struct { name: "S", len: 1 }, + Token::Str("dur"), + Token::Str("7years 5months 24days 14h 36m 17s 45us 500ns"), + Token::StructEnd, + ], + ); + } +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index cfc1b0155..88dd40b50 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,5 +1,7 @@ //! Helper utils used in project. +pub mod duration; + /// Creates new [`::hashbrown::HashMap`] from a list of key-value pairs. /// /// ## Example From 463c6a94a76dff08d6abce1f965a900942ed1164 Mon Sep 17 00:00:00 2001 From: alexlapa Date: Fri, 29 Mar 2019 20:55:39 +0200 Subject: [PATCH 12/20] reexports in conf::Conf --- src/api/client/server.rs | 5 ++--- src/conf/mod.rs | 13 ++++++++----- src/conf/server.rs | 2 +- src/main.rs | 16 ++++++++-------- 4 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/api/client/server.rs b/src/api/client/server.rs index caf7a3842..989021e6e 100644 --- a/src/api/client/server.rs +++ b/src/api/client/server.rs @@ -15,7 +15,7 @@ use crate::{ }, control::Id as MemberId, }, - conf::{rpc::Rpc, Conf}, + conf::{Conf, Rpc}, log::prelude::*, }; @@ -108,11 +108,10 @@ mod test { use crate::{ api::{client::Room, control::Member}, - conf::Conf, + conf::{Conf, Server}, }; use super::*; - use crate::conf::server::Server; /// Creates [`RoomsRepository`] for tests filled with a single [`Room`]. fn room() -> RoomsRepository { diff --git a/src/conf/mod.rs b/src/conf/mod.rs index cd98d413f..96118ce9a 100644 --- a/src/conf/mod.rs +++ b/src/conf/mod.rs @@ -11,6 +11,9 @@ use failure::Error; use serde::{Deserialize, Serialize}; use smart_default::*; +pub use self::server::Server; +pub use self::rpc::Rpc; + use std::collections::HashMap; static APP_CONF_PATH_CMD_ARG_NAME: &str = "--conf"; @@ -42,7 +45,7 @@ impl Conf { /// - configuration file, the name of which is given as a command line /// parameter or environment variable; /// - environment variables; - pub fn new() -> Result { + pub fn parse() -> Result { use std::env; let mut cfg = Config::new(); @@ -142,7 +145,7 @@ mod test { std::fs::write(test_config_file_path, data).unwrap(); std::env::set_var(APP_CONF_PATH_ENV_VAR_NAME, test_config_file_path); - let new_config = Conf::new().unwrap(); + let new_config = Conf::parse().unwrap(); std::env::remove_var(APP_CONF_PATH_ENV_VAR_NAME); std::fs::remove_file(test_config_file_path).unwrap(); @@ -157,7 +160,7 @@ mod test { let defaults = Conf::default(); std::env::set_var("MEDEA_RPC.IDLE_TIMEOUT", "46s"); - let new_config = Conf::new().unwrap(); + let new_config = Conf::parse().unwrap(); std::env::remove_var("MEDEA_RPC.IDLE_TIMEOUT"); assert_eq!(new_config.rpc.idle_timeout, Duration::from_secs(46)); @@ -173,10 +176,10 @@ mod test { std::fs::write(test_config_file_path, data).unwrap(); std::env::set_var(APP_CONF_PATH_ENV_VAR_NAME, test_config_file_path); - let file_config = Conf::new().unwrap(); + let file_config = Conf::parse().unwrap(); std::env::set_var("MEDEA_RPC.IDLE_TIMEOUT", "48s"); - let file_env_config = Conf::new().unwrap(); + let file_env_config = Conf::parse().unwrap(); std::env::remove_var(APP_CONF_PATH_ENV_VAR_NAME); std::fs::remove_file(test_config_file_path).unwrap(); diff --git a/src/conf/server.rs b/src/conf/server.rs index e2c3fa1d5..cd1e9d6af 100644 --- a/src/conf/server.rs +++ b/src/conf/server.rs @@ -35,7 +35,7 @@ mod test { std::env::set_var("MEDEA_SERVER.BIND_IP", "5.5.5.5"); std::env::set_var("MEDEA_SERVER.BIND_PORT", "1234"); - let env_conf = Conf::new().unwrap(); + let env_conf = Conf::parse().unwrap(); assert_ne!(default_conf.server.bind_ip, env_conf.server.bind_ip); assert_ne!(default_conf.server.bind_port, env_conf.server.bind_port); diff --git a/src/main.rs b/src/main.rs index ba48cf02e..b2781d636 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,12 @@ //! Medea media server application. +#[macro_use] +mod utils; + +mod api; +mod conf; +mod log; + use actix::prelude::*; use dotenv::dotenv; use hashbrown::HashMap; @@ -13,13 +20,6 @@ use crate::{ conf::Conf, }; -#[macro_use] -mod utils; - -mod api; -mod conf; -mod log; - fn main() { dotenv().ok(); let logger = log::new_dual_logger(std::io::stdout(), std::io::stderr()); @@ -40,7 +40,7 @@ fn main() { let rooms = hashmap! {1 => room}; let rooms_repo = RoomsRepository::new(rooms); - let config = Conf::new().unwrap(); + let config = Conf::parse().unwrap(); info!("{:?}", config); From 548b4631eaab82f0b664b432624ff8bb6307a555 Mon Sep 17 00:00:00 2001 From: alexlapa Date: Fri, 29 Mar 2019 21:44:56 +0200 Subject: [PATCH 13/20] make clippy happy --- src/conf/mod.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/conf/mod.rs b/src/conf/mod.rs index 96118ce9a..983eb442e 100644 --- a/src/conf/mod.rs +++ b/src/conf/mod.rs @@ -9,10 +9,9 @@ use config::{ }; use failure::Error; use serde::{Deserialize, Serialize}; -use smart_default::*; -pub use self::server::Server; pub use self::rpc::Rpc; +pub use self::server::Server; use std::collections::HashMap; @@ -20,7 +19,7 @@ static APP_CONF_PATH_CMD_ARG_NAME: &str = "--conf"; static APP_CONF_PATH_ENV_VAR_NAME: &str = "MEDEA_CONF"; /// Settings represents all configuration setting of application. -#[derive(Clone, Debug, Deserialize, Serialize, SmartDefault)] +#[derive(Clone, Debug, Deserialize, Serialize, Default)] pub struct Conf { /// Represents [`Server`] configuration section. pub rpc: rpc::Rpc, From 66ec28b79965457a3f5eaadce8424166210d28c9 Mon Sep 17 00:00:00 2001 From: alexlapa Date: Mon, 1 Apr 2019 16:07:47 +0300 Subject: [PATCH 14/20] use serde-humantime fork --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- src/conf/rpc.rs | 3 +-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2c5dbb056..fee0992fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -720,7 +720,7 @@ dependencies = [ "hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", - "serde-humantime 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde-humantime 0.1.1 (git+https://github.com/tailhook/serde-humantime?branch=serde_wrapper)", "serde_json 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)", "serde_test 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serial_test 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1226,7 +1226,7 @@ dependencies = [ [[package]] name = "serde-humantime" version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" +source = "git+https://github.com/tailhook/serde-humantime?branch=serde_wrapper#36b86d5ca09db3caf2edb06e0d46b505d0915792" dependencies = [ "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2079,7 +2079,7 @@ dependencies = [ "checksum serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8" "checksum serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)" = "0e732ed5a5592c17d961555e3b552985baf98d50ce418b7b655f31f6ba7eb1b7" "checksum serde-hjson 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0b833c5ad67d52ced5f5938b2980f32a9c1c5ef047f0b4fb3127e7a423c76153" -"checksum serde-humantime 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c367b5dafa12cef19c554638db10acde90d5e9acea2b80e1ad98b00f88068f7d" +"checksum serde-humantime 0.1.1 (git+https://github.com/tailhook/serde-humantime?branch=serde_wrapper)" = "" "checksum serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)" = "633e97856567e518b59ffb2ad7c7a4fd4c5d91d9c7f32dd38a27b2bf7e8114ea" "checksum serde_json 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)" = "574378d957d6dcdf1bbb5d562a15cbd5e644159432f84634b94e485267abbcc7" "checksum serde_test 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "110b3dbdf8607ec493c22d5d947753282f3bae73c0f56d322af1e8c78e4c23d5" diff --git a/Cargo.toml b/Cargo.toml index fd2f6c5e1..47ed57593 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ humantime = "1.2" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -serde-humantime = "0.1.1" +serde-humantime = { git = "https://github.com/tailhook/serde-humantime", branch = "serde_wrapper" } slog = "2.4" slog-envlogger = "2.1" diff --git a/src/conf/rpc.rs b/src/conf/rpc.rs index df4d9cb25..4a7db1611 100644 --- a/src/conf/rpc.rs +++ b/src/conf/rpc.rs @@ -7,8 +7,7 @@ use std::time::Duration; #[derive(Clone, Debug, Serialize, Deserialize, SmartDefault)] pub struct Rpc { /// Timeout for [`WsSession`] to wait ping message from [`Web Client`]. - #[serde(deserialize_with = "serde_humantime::deserialize")] - #[serde(serialize_with = "crate::utils::duration::serialize")] + #[serde(with = "serde_humantime")] #[default(Duration::from_secs(10))] pub idle_timeout: Duration, } From 0c03debd45ac54cecc370190abbafc0e98a170c0 Mon Sep 17 00:00:00 2001 From: alexlapa Date: Mon, 1 Apr 2019 21:03:16 +0300 Subject: [PATCH 15/20] refactor --- src/conf/server.rs | 2 +- src/utils/duration.rs | 44 ------------------------------------------- 2 files changed, 1 insertion(+), 45 deletions(-) delete mode 100644 src/utils/duration.rs diff --git a/src/conf/server.rs b/src/conf/server.rs index cd1e9d6af..8d942736a 100644 --- a/src/conf/server.rs +++ b/src/conf/server.rs @@ -13,7 +13,7 @@ pub struct Server { } impl Server { - pub fn get_bind_addr(&self) -> (IpAddr, u16) { + pub fn get_bind_addr(&self) -> impl std::net::ToSocketAddrs { (self.bind_ip, self.bind_port) } } diff --git a/src/utils/duration.rs b/src/utils/duration.rs deleted file mode 100644 index c3b1effd8..000000000 --- a/src/utils/duration.rs +++ /dev/null @@ -1,44 +0,0 @@ -/// Provides Serde serializer for [`std::time::Duration`] via the -/// `humantime` crate . -use serde::Serializer; - -use std::time::Duration; - -/// Serializes a `Duration` via the humantime crate. -pub fn serialize(d: &Duration, s: S) -> Result -where - S: Serializer, -{ - s.serialize_str(&format!("{}", humantime::format_duration(*d))) -} - -#[cfg(test)] -mod test { - use serde::{Deserialize, Serialize}; - use serde_test::{assert_ser_tokens, Token}; - - use std::time::Duration; - - #[derive(Serialize, Deserialize, Debug, PartialEq)] - struct S { - #[serde(serialize_with = "super::serialize")] - dur: Duration, - } - - #[test] - fn test_ser() { - let s = S { - dur: Duration::new(236179457, 45500), - }; - - assert_ser_tokens( - &s, - &[ - Token::Struct { name: "S", len: 1 }, - Token::Str("dur"), - Token::Str("7years 5months 24days 14h 36m 17s 45us 500ns"), - Token::StructEnd, - ], - ); - } -} From a3114132cead9234815cf8aa14558062bd03376e Mon Sep 17 00:00:00 2001 From: alexlapa Date: Mon, 1 Apr 2019 21:03:48 +0300 Subject: [PATCH 16/20] quickfix --- src/utils/mod.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 88dd40b50..cfc1b0155 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,7 +1,5 @@ //! Helper utils used in project. -pub mod duration; - /// Creates new [`::hashbrown::HashMap`] from a list of key-value pairs. /// /// ## Example From 72b814a08e405b24412c10957f33a6acc80a27ad Mon Sep 17 00:00:00 2001 From: alexlapa Date: Tue, 2 Apr 2019 16:11:08 +0300 Subject: [PATCH 17/20] revert not relevant changes, update docs --- src/api/client/session.rs | 3 ++- src/conf/mod.rs | 5 +++-- src/conf/rpc.rs | 5 +++-- src/conf/server.rs | 4 +++- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/api/client/session.rs b/src/api/client/session.rs index a25a4aa0a..b2409b08e 100644 --- a/src/api/client/session.rs +++ b/src/api/client/session.rs @@ -192,8 +192,8 @@ impl StreamHandler for WsSession { ); match msg { ws::Message::Text(text) => { + self.reset_idle_timeout(ctx); if let Ok(msg) = serde_json::from_str::(&text) { - self.reset_idle_timeout(ctx); ctx.notify(msg); } } @@ -219,6 +219,7 @@ impl StreamHandler for WsSession { }), )); ctx.close(reason); + ctx.stop(); } } _ => error!( diff --git a/src/conf/mod.rs b/src/conf/mod.rs index 983eb442e..7d62a8053 100644 --- a/src/conf/mod.rs +++ b/src/conf/mod.rs @@ -18,7 +18,7 @@ use std::collections::HashMap; static APP_CONF_PATH_CMD_ARG_NAME: &str = "--conf"; static APP_CONF_PATH_ENV_VAR_NAME: &str = "MEDEA_CONF"; -/// Settings represents all configuration setting of application. +/// Holds application config. #[derive(Clone, Debug, Deserialize, Serialize, Default)] pub struct Conf { /// Represents [`Server`] configuration section. @@ -26,6 +26,7 @@ pub struct Conf { pub server: server::Server, } +/// Allows merging ['Conf'] into ['config::Config']. impl Source for Conf { fn clone_into_box(&self) -> Box { Box::new((*self).clone()) @@ -43,7 +44,7 @@ impl Conf { /// - default values; /// - configuration file, the name of which is given as a command line /// parameter or environment variable; - /// - environment variables; + /// - environment variables. pub fn parse() -> Result { use std::env; diff --git a/src/conf/rpc.rs b/src/conf/rpc.rs index 4a7db1611..6aafa4eb5 100644 --- a/src/conf/rpc.rs +++ b/src/conf/rpc.rs @@ -3,10 +3,11 @@ use smart_default::*; use std::time::Duration; -/// Server represents [`Server`] configuration section. +/// RPC connection settings. #[derive(Clone, Debug, Serialize, Deserialize, SmartDefault)] pub struct Rpc { - /// Timeout for [`WsSession`] to wait ping message from [`Web Client`]. + /// Duration, after which remote RPC client will be considered idle if no + /// heartbeat messages received. #[serde(with = "serde_humantime")] #[default(Duration::from_secs(10))] pub idle_timeout: Duration, diff --git a/src/conf/server.rs b/src/conf/server.rs index 8d942736a..ce041285b 100644 --- a/src/conf/server.rs +++ b/src/conf/server.rs @@ -6,13 +6,16 @@ use std::net::{IpAddr, Ipv4Addr}; /// Server represents [`Server`] configuration section. #[derive(Clone, Debug, Deserialize, Serialize, SmartDefault)] pub struct Server { + /// IP to bind to. #[default(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)))] pub bind_ip: IpAddr, + /// Port to bind to. #[default(8080)] pub bind_port: u16, } impl Server { + /// Builds ['std::net::ToSocketAddrs'] from ['bind_ip'] and ['bind_port'] pub fn get_bind_addr(&self) -> impl std::net::ToSocketAddrs { (self.bind_ip, self.bind_port) } @@ -20,7 +23,6 @@ impl Server { #[cfg(test)] mod test { - use serial_test_derive::serial; use std::net::{Ipv4Addr, SocketAddr, ToSocketAddrs as _}; From 880af87a5816ef759103f50a631b8a5156c793c1 Mon Sep 17 00:00:00 2001 From: alexlapa Date: Tue, 2 Apr 2019 17:13:33 +0300 Subject: [PATCH 18/20] revert not relevant changes, update docs --- Makefile | 16 +++++++++++++++- src/conf/mod.rs | 8 ++++---- src/conf/rpc.rs | 3 ++- src/conf/server.rs | 9 +++++---- src/main.rs | 6 +++--- src/utils/mod.rs | 2 +- 6 files changed, 30 insertions(+), 14 deletions(-) diff --git a/Makefile b/Makefile index a80805c51..80e3f8ea7 100644 --- a/Makefile +++ b/Makefile @@ -28,6 +28,7 @@ test: test.unit + # Lint Rust sources with clippy. # # Usage: @@ -48,6 +49,19 @@ endif +# Generate project documentation of Rust sources. +# +# Usage: +# make docs [open=(yes|no)] [clean=(no|yes)] + +docs: +ifeq ($(clean),yes) + @rm -rf target/doc/ +endif + cargo +nightly doc $(if $(call eq,$(open),no),,--open) + + + # Run Rust unit tests of project. # @@ -96,4 +110,4 @@ endif ################## .PHONY: cargo cargo.fmt cargo.lint \ - test test.e2e test.unit + docs test test.e2e test.unit diff --git a/src/conf/mod.rs b/src/conf/mod.rs index 7d62a8053..5d510dbd6 100644 --- a/src/conf/mod.rs +++ b/src/conf/mod.rs @@ -1,6 +1,5 @@ -/// Provides application configuration options. -/// -/// Configuration options can be parsed from config files in TOML format. +//! Provides application configuration options. + pub mod rpc; pub mod server; @@ -21,8 +20,9 @@ static APP_CONF_PATH_ENV_VAR_NAME: &str = "MEDEA_CONF"; /// Holds application config. #[derive(Clone, Debug, Deserialize, Serialize, Default)] pub struct Conf { - /// Represents [`Server`] configuration section. + /// HTTP server settings. pub rpc: rpc::Rpc, + /// RPC connection settings. pub server: server::Server, } diff --git a/src/conf/rpc.rs b/src/conf/rpc.rs index 6aafa4eb5..067d91f38 100644 --- a/src/conf/rpc.rs +++ b/src/conf/rpc.rs @@ -1,3 +1,4 @@ +//! RPC connection settings. use serde::{Deserialize, Serialize}; use smart_default::*; @@ -7,7 +8,7 @@ use std::time::Duration; #[derive(Clone, Debug, Serialize, Deserialize, SmartDefault)] pub struct Rpc { /// Duration, after which remote RPC client will be considered idle if no - /// heartbeat messages received. + /// heartbeat messages received. Defaults to **10s**. #[serde(with = "serde_humantime")] #[default(Duration::from_secs(10))] pub idle_timeout: Duration, diff --git a/src/conf/server.rs b/src/conf/server.rs index ce041285b..d9c5f7b9a 100644 --- a/src/conf/server.rs +++ b/src/conf/server.rs @@ -1,21 +1,22 @@ +//! HTTP server settings. use serde::{Deserialize, Serialize}; use smart_default::*; use std::net::{IpAddr, Ipv4Addr}; -/// Server represents [`Server`] configuration section. +/// HTTP server settings. #[derive(Clone, Debug, Deserialize, Serialize, SmartDefault)] pub struct Server { - /// IP to bind to. + /// IP to bind HTTP server to. Defaults to **0.0.0.0**. #[default(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)))] pub bind_ip: IpAddr, - /// Port to bind to. + /// Port to bind HTTP server to. Defaults to **8080**. #[default(8080)] pub bind_port: u16, } impl Server { - /// Builds ['std::net::ToSocketAddrs'] from ['bind_ip'] and ['bind_port'] + /// Builds [std::net::ToSocketAddrs] from **bind_ip** and **bind_port**. pub fn get_bind_addr(&self) -> impl std::net::ToSocketAddrs { (self.bind_ip, self.bind_port) } diff --git a/src/main.rs b/src/main.rs index b2781d636..fd42507b1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,9 +3,9 @@ #[macro_use] mod utils; -mod api; -mod conf; -mod log; +pub mod api; +pub mod conf; +pub mod log; use actix::prelude::*; use dotenv::dotenv; diff --git a/src/utils/mod.rs b/src/utils/mod.rs index cfc1b0155..72c835079 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,6 +1,6 @@ //! Helper utils used in project. -/// Creates new [`::hashbrown::HashMap`] from a list of key-value pairs. +/// Creates new [hashbrown::HashMap] from a list of key-value pairs. /// /// ## Example /// From a9f3264ee5845a9e8f2045ad0bc870f1c1e01e17 Mon Sep 17 00:00:00 2001 From: alexlapa Date: Tue, 2 Apr 2019 17:14:41 +0300 Subject: [PATCH 19/20] makefile formatting fix --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 80e3f8ea7..5c2809bc3 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,6 @@ test: test.unit - # Lint Rust sources with clippy. # # Usage: @@ -49,6 +48,7 @@ endif + # Generate project documentation of Rust sources. # # Usage: From 4e77125820489618d8990bd7bc882d7fc8829fee Mon Sep 17 00:00:00 2001 From: tyranron Date: Fri, 5 Apr 2019 19:29:48 +0300 Subject: [PATCH 20/20] Corrections --- .env | 1 + Cargo.lock | 10 --- Cargo.toml | 10 +-- Makefile | 96 +++++++++++------------- config.default.toml | 5 -- config.toml | 6 ++ src/api/client/session.rs | 6 +- src/conf/mod.rs | 154 +++++++++++++++++++++----------------- src/conf/rpc.rs | 6 +- src/conf/server.rs | 47 ++++++------ src/utils/mod.rs | 2 +- 11 files changed, 169 insertions(+), 174 deletions(-) delete mode 100644 config.default.toml diff --git a/.env b/.env index a7bcd3f21..307d41263 100644 --- a/.env +++ b/.env @@ -1 +1,2 @@ RUST_LOG=debug +MEDEA_CONF=config.toml diff --git a/Cargo.lock b/Cargo.lock index fee0992fc..6c816c0f8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -722,7 +722,6 @@ dependencies = [ "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", "serde-humantime 0.1.1 (git+https://github.com/tailhook/serde-humantime?branch=serde_wrapper)", "serde_json 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_test 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serial_test 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serial_test_derive 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1260,14 +1259,6 @@ dependencies = [ "serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "serde_test" -version = "1.0.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "serde_urlencoded" version = "0.5.4" @@ -2083,7 +2074,6 @@ dependencies = [ "checksum serde_derive 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)" = "633e97856567e518b59ffb2ad7c7a4fd4c5d91d9c7f32dd38a27b2bf7e8114ea" "checksum serde_json 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)" = "574378d957d6dcdf1bbb5d562a15cbd5e644159432f84634b94e485267abbcc7" "checksum serde_test 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "110b3dbdf8607ec493c22d5d947753282f3bae73c0f56d322af1e8c78e4c23d5" -"checksum serde_test 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)" = "70807e147558b5253cb70f55d343db1d07204d773087c96d0f35fced295dba82" "checksum serde_urlencoded 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d48f9f99cd749a2de71d29da5f948de7f2764cc5a9d7f3c97e3514d4ee6eabf2" "checksum serial_test 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50bfbc39343545618d97869d77f38ed43e48dd77432717dbc7ed39d797f3ecbe" "checksum serial_test_derive 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "89dd85be2e2ad75b041c9df2892ac078fa6e0b90024028b2b9fb4125b7530f01" diff --git a/Cargo.toml b/Cargo.toml index 47ed57593..f22a09ceb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,6 @@ repository = "https://github.com/instrumentisto/medea" [dependencies] actix = "0.7" actix-web = "0.7" - config = "0.9" chrono = "0.4" dotenv = "0.13" @@ -20,23 +19,20 @@ failure = "0.1" futures = "0.1" hashbrown = "0.1" humantime = "1.2" - serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -serde-humantime = { git = "https://github.com/tailhook/serde-humantime", branch = "serde_wrapper" } - slog = "2.4" slog-envlogger = "2.1" slog-stdlog = "3.0" slog-async = "2.3" slog-json = "2.3" slog-scope = "4.1" - smart-default = "0.5" toml = "0.4" +[dependencies.serde-humantime] + git = "https://github.com/tailhook/serde-humantime" + branch = "serde_wrapper" [dev-dependencies] -serde_test = "1.0" - serial_test = "0.2" serial_test_derive = "0.2" diff --git a/Makefile b/Makefile index 5c2809bc3..83895d5a1 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,22 @@ +############################### +# Common defaults/definitions # +############################### + +comma := , + +# Checks two given strings for equality. +eq = $(if $(or $(1),$(2)),$(and $(findstring $(1),$(2)),\ + $(findstring $(2),$(1))),1) + + + + ###################### # Project parameters # ###################### CARGO_HOME ?= $(strip $(shell dirname $$(dirname $$(which cargo)))) -RUST_VER ?= "1.33" +RUST_VER ?= 1.33 @@ -12,49 +25,54 @@ RUST_VER ?= "1.33" # Aliases # ########### +docs: docs.rust + + lint: cargo.lint fmt: cargo.fmt -# Run all project tests. -# -# Usage: -# make test - test: test.unit +################## +# Cargo commands # +################## + +# Format Rust sources with rustfmt. +# +# Usage: +# make cargo.fmt [check=(no|yes)] + +cargo.fmt: + cargo +nightly fmt --all $(if $(call eq,$(check),yes),-- --check,) + + # Lint Rust sources with clippy. # # Usage: -# make cargo.lint [dockerized=(no|yes)] +# make cargo.lint cargo.lint: -ifeq ($(dockerized),yes) - docker run --rm --network=host -v "$(PWD)":/app -w /app \ - -v "$(abspath $(CARGO_HOME))/registry":/usr/local/cargo/registry\ - rust:$(RUST_VER) \ - make cargo.lint dockerized=no pre-install=yes -else -ifeq ($(pre-install),yes) - rustup component add clippy -endif cargo clippy -- -D clippy::pedantic -D warnings -endif +########################## +# Documentation commands # +########################## + # Generate project documentation of Rust sources. # # Usage: -# make docs [open=(yes|no)] [clean=(no|yes)] +# make docs.rust [open=(yes|no)] [clean=(no|yes)] -docs: +docs.rust: ifeq ($(clean),yes) @rm -rf target/doc/ endif @@ -63,44 +81,17 @@ endif +#################### +# Testing commands # +#################### + # Run Rust unit tests of project. # # Usage: -# make test.unit [dockerized=(no|yes)] +# make test.unit test.unit: -ifeq ($(dockerized),yes) - docker run --rm --network=host -v "$(PWD)":/app -w /app \ - -v "$(abspath $(CARGO_HOME))/registry":/usr/local/cargo/registry\ - rust:$(RUST_VER) \ - make test.unit dockerized=no -else cargo test --all -endif - - - - -# Format Rust sources with rustfmt. -# -# Usage: -# make cargo.fmt [check=(no|yes)] -# [dockerized=(no|yes)] - -cargo.fmt: -ifeq ($(dockerized),yes) - docker pull rustlang/rust:nightly - docker run --rm --network=host -v "$(PWD)":/app -w /app \ - -v "$(abspath $(CARGO_HOME))/registry":/usr/local/cargo/registry\ - rustlang/rust:nightly \ - make cargo.fmt check='$(check)' dockerized=no pre-install=yes -else -ifeq ($(pre-install),yes) - rustup component add rustfmt -endif - cargo +nightly fmt --all $(if $(call eq,$(check),yes),-- --check,) -endif - @@ -110,4 +101,5 @@ endif ################## .PHONY: cargo cargo.fmt cargo.lint \ - docs test test.e2e test.unit + docs docs.rust \ + test test.unit diff --git a/config.default.toml b/config.default.toml deleted file mode 100644 index ebf1a99ce..000000000 --- a/config.default.toml +++ /dev/null @@ -1,5 +0,0 @@ -[server] -# Timeout for websocket session to wait message from [`Web Client`]. -# -# Default: -# idle_timeout = "10s" diff --git a/config.toml b/config.toml index e69de29bb..e8c24fe68 100644 --- a/config.toml +++ b/config.toml @@ -0,0 +1,6 @@ +[server] +# Duration, after which remote RPC client will be considered idle if no +# heartbeat messages received. +# +# Default: +# idle_timeout = "10s" diff --git a/src/api/client/session.rs b/src/api/client/session.rs index b2409b08e..6698439c2 100644 --- a/src/api/client/session.rs +++ b/src/api/client/session.rs @@ -31,11 +31,9 @@ pub struct WsSession { /// Handle for watchdog which checks whether WebSocket client became /// idle (no `ping` messages received during [`idle_timeout`]). /// - /// This one should be renewed on received ping WebSocket message - /// from client. + /// This one should be renewed on received `ping` message from client. idle_handler: Option, - - /// Timeout of receiving ping messages from client. + /// Timeout of receiving `ping` messages from client. idle_timeout: Duration, /// Indicates whether WebSocket connection is closed by server ot by diff --git a/src/conf/mod.rs b/src/conf/mod.rs index 5d510dbd6..6aa2a296e 100644 --- a/src/conf/mod.rs +++ b/src/conf/mod.rs @@ -3,6 +3,8 @@ pub mod rpc; pub mod server; +use std::env; + use config::{ Config, ConfigError, Environment, File, FileFormat, Source, Value, }; @@ -14,7 +16,11 @@ pub use self::server::Server; use std::collections::HashMap; +/// CLI argument that is responsible for holding application configuration +/// file path. static APP_CONF_PATH_CMD_ARG_NAME: &str = "--conf"; +/// Environment variable that is responsible for holding application +/// configuration file path. static APP_CONF_PATH_ENV_VAR_NAME: &str = "MEDEA_CONF"; /// Holds application config. @@ -26,7 +32,9 @@ pub struct Conf { pub server: server::Server, } -/// Allows merging ['Conf'] into ['config::Config']. +/// Allows merging [`Conf`] into [`config::Config`]. +// TODO: Remove after the following issue is resolved: +// https://github.com/mehcode/config-rs/issues/60#issuecomment-443241600 impl Source for Conf { fn clone_into_box(&self) -> Box { Box::new((*self).clone()) @@ -39,23 +47,19 @@ impl Source for Conf { } impl Conf { - /// Creates new [`Conf`] and applies values from such sources - /// and in that order: + /// Creates new [`Conf`] and applies values from the following sources + /// (in the following order): /// - default values; /// - configuration file, the name of which is given as a command line - /// parameter or environment variable; + /// parameter or environment variable; /// - environment variables. pub fn parse() -> Result { - use std::env; - + // TODO: use Config::try_from(&Self::default()) when the issue is fixed: + // https://github.com/mehcode/config-rs/issues/60 let mut cfg = Config::new(); - cfg.merge(Self::default())?; - if let Some(path) = get_conf_file_name( - env::var(APP_CONF_PATH_ENV_VAR_NAME), - env::args(), - ) { + if let Some(path) = get_conf_file_name(env::args()) { cfg.merge(File::with_name(&path))?; } @@ -66,74 +70,86 @@ impl Conf { } } -/// Returns the name of the configuration file, if defined. -fn get_conf_file_name( - env_var: Result, - cmd_args: T, -) -> Option +/// Returns the path to the configuration file, if it's set via CLI `args` +/// or environment variables. +fn get_conf_file_name(args: T) -> Option where - T: Iterator + std::fmt::Debug, + T: IntoIterator, { - if let Ok(path) = env_var { - Some(path) - } else { - let mut args = cmd_args.skip_while(|x| x != APP_CONF_PATH_CMD_ARG_NAME); - if args.next().is_some() { - args.next() - } else { - None - } + // First, check CLI arguments as they have the highest priority. + let mut args = args + .into_iter() + .skip_while(|x| x != APP_CONF_PATH_CMD_ARG_NAME); + if args.next().is_some() { + return args.next().filter(|v| !v.is_empty()); } + + // Then check env var. + env::var(APP_CONF_PATH_ENV_VAR_NAME) + .ok() + .filter(|v| !v.is_empty()) } #[cfg(test)] -mod test { - use serial_test_derive::serial; +mod get_conf_file_name_spec { + use super::*; - use std::time::Duration; - - use crate::conf::{ - Conf, APP_CONF_PATH_CMD_ARG_NAME, APP_CONF_PATH_ENV_VAR_NAME, - }; + #[test] + fn none_if_nothing_is_set() { + env::remove_var(APP_CONF_PATH_ENV_VAR_NAME); + assert_eq!(get_conf_file_name(vec![]), None); + } - use super::get_conf_file_name; #[test] - fn get_conf_file_name_none() { - let file = get_conf_file_name( - Err(std::env::VarError::NotPresent), - Vec::new().into_iter(), + fn none_if_empty() { + env::set_var(APP_CONF_PATH_ENV_VAR_NAME, "env_path"); + assert_eq!( + get_conf_file_name(vec![ + APP_CONF_PATH_CMD_ARG_NAME.to_owned(), + "".to_owned(), + ]), + None, ); - assert_eq!(file, None); } #[test] - fn get_conf_file_name_env() { - let file = get_conf_file_name( - Ok("env_path".to_owned()), - Vec::new().into_iter(), - ); - assert_eq!(file, Some("env_path".to_owned())); + fn env_if_set() { + env::set_var(APP_CONF_PATH_ENV_VAR_NAME, "env_path"); + assert_eq!(get_conf_file_name(vec![]), Some("env_path".to_owned())); } #[test] - fn get_conf_file_name_arg() { - let file = get_conf_file_name( - Err(std::env::VarError::NotPresent), - vec![APP_CONF_PATH_CMD_ARG_NAME.to_owned(), "arg_path".to_owned()] - .into_iter(), + fn arg_if_set() { + env::remove_var(APP_CONF_PATH_ENV_VAR_NAME); + assert_eq!( + get_conf_file_name(vec![ + APP_CONF_PATH_CMD_ARG_NAME.to_owned(), + "arg_path".to_owned(), + ]), + Some("arg_path".to_owned()), ); - assert_eq!(file, Some("arg_path".to_owned())); } #[test] - fn get_conf_file_name_both_env_overrides() { - let file = get_conf_file_name( - Ok("env_path".to_owned()), - vec![APP_CONF_PATH_CMD_ARG_NAME.to_owned(), "arg_path".to_owned()] - .into_iter(), + fn arg_is_prioritized() { + env::set_var(APP_CONF_PATH_ENV_VAR_NAME, "env_path"); + assert_eq!( + get_conf_file_name(vec![ + APP_CONF_PATH_CMD_ARG_NAME.to_owned(), + "arg_path".to_owned(), + ]), + Some("arg_path".to_owned()), ); - assert_eq!(file, Some("env_path".to_owned())); } +} + +#[cfg(test)] +mod conf_parse_spec { + use std::{fs, time::Duration}; + + use serial_test_derive::serial; + + use super::*; #[test] #[serial] @@ -142,13 +158,13 @@ mod test { let test_config_file_path = "test_config.toml"; let data = format!("[rpc]\nidle_timeout = \"45s\""); - std::fs::write(test_config_file_path, data).unwrap(); - std::env::set_var(APP_CONF_PATH_ENV_VAR_NAME, test_config_file_path); + fs::write(test_config_file_path, data).unwrap(); + env::set_var(APP_CONF_PATH_ENV_VAR_NAME, test_config_file_path); let new_config = Conf::parse().unwrap(); - std::env::remove_var(APP_CONF_PATH_ENV_VAR_NAME); - std::fs::remove_file(test_config_file_path).unwrap(); + env::remove_var(APP_CONF_PATH_ENV_VAR_NAME); + fs::remove_file(test_config_file_path).unwrap(); assert_eq!(new_config.rpc.idle_timeout, Duration::from_secs(45)); assert_ne!(new_config.rpc.idle_timeout, defaults.rpc.idle_timeout); @@ -159,9 +175,9 @@ mod test { fn env_overrides_defaults() { let defaults = Conf::default(); - std::env::set_var("MEDEA_RPC.IDLE_TIMEOUT", "46s"); + env::set_var("MEDEA_RPC.IDLE_TIMEOUT", "46s"); let new_config = Conf::parse().unwrap(); - std::env::remove_var("MEDEA_RPC.IDLE_TIMEOUT"); + env::remove_var("MEDEA_RPC.IDLE_TIMEOUT"); assert_eq!(new_config.rpc.idle_timeout, Duration::from_secs(46)); assert_ne!(new_config.rpc.idle_timeout, defaults.rpc.idle_timeout); @@ -173,17 +189,17 @@ mod test { let test_config_file_path = "test_config.toml"; let data = format!("[rpc]\nidle_timeout = \"47s\""); - std::fs::write(test_config_file_path, data).unwrap(); - std::env::set_var(APP_CONF_PATH_ENV_VAR_NAME, test_config_file_path); + fs::write(test_config_file_path, data).unwrap(); + env::set_var(APP_CONF_PATH_ENV_VAR_NAME, test_config_file_path); let file_config = Conf::parse().unwrap(); - std::env::set_var("MEDEA_RPC.IDLE_TIMEOUT", "48s"); + env::set_var("MEDEA_RPC.IDLE_TIMEOUT", "48s"); let file_env_config = Conf::parse().unwrap(); - std::env::remove_var(APP_CONF_PATH_ENV_VAR_NAME); - std::fs::remove_file(test_config_file_path).unwrap(); - std::env::remove_var("MEDEA_RPC.IDLE_TIMEOUT"); + env::remove_var(APP_CONF_PATH_ENV_VAR_NAME); + fs::remove_file(test_config_file_path).unwrap(); + env::remove_var("MEDEA_RPC.IDLE_TIMEOUT"); assert_eq!(file_config.rpc.idle_timeout, Duration::from_secs(47)); diff --git a/src/conf/rpc.rs b/src/conf/rpc.rs index 067d91f38..0327e2225 100644 --- a/src/conf/rpc.rs +++ b/src/conf/rpc.rs @@ -5,11 +5,11 @@ use smart_default::*; use std::time::Duration; /// RPC connection settings. -#[derive(Clone, Debug, Serialize, Deserialize, SmartDefault)] +#[derive(Clone, Debug, Deserialize, Serialize, SmartDefault)] pub struct Rpc { /// Duration, after which remote RPC client will be considered idle if no - /// heartbeat messages received. Defaults to **10s**. - #[serde(with = "serde_humantime")] + /// heartbeat messages received. Defaults to `10s`. #[default(Duration::from_secs(10))] + #[serde(with = "serde_humantime")] pub idle_timeout: Duration, } diff --git a/src/conf/server.rs b/src/conf/server.rs index d9c5f7b9a..7cf8d6764 100644 --- a/src/conf/server.rs +++ b/src/conf/server.rs @@ -1,42 +1,50 @@ //! HTTP server settings. + +use std::net::{IpAddr, Ipv4Addr, SocketAddr, ToSocketAddrs as _}; + use serde::{Deserialize, Serialize}; use smart_default::*; -use std::net::{IpAddr, Ipv4Addr}; - /// HTTP server settings. #[derive(Clone, Debug, Deserialize, Serialize, SmartDefault)] pub struct Server { - /// IP to bind HTTP server to. Defaults to **0.0.0.0**. + /// IP address to bind HTTP server to. Defaults to `0.0.0.0`. #[default(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)))] pub bind_ip: IpAddr, - /// Port to bind HTTP server to. Defaults to **8080**. + /// Port to bind HTTP server to. Defaults to `8080`. #[default(8080)] pub bind_port: u16, } impl Server { - /// Builds [std::net::ToSocketAddrs] from **bind_ip** and **bind_port**. - pub fn get_bind_addr(&self) -> impl std::net::ToSocketAddrs { + /// Builds [`SocketAddr`] from `bind_ip` and `bind_port`. + #[inline] + pub fn get_bind_addr(&self) -> SocketAddr { (self.bind_ip, self.bind_port) + .to_socket_addrs() + .unwrap() + .next() + .unwrap() } } #[cfg(test)] -mod test { - use serial_test_derive::serial; +mod server_spec { + use std::env; - use std::net::{Ipv4Addr, SocketAddr, ToSocketAddrs as _}; + use serial_test_derive::serial; use crate::conf::Conf; + use super::*; + #[test] #[serial] - fn override_defaults_and_get_bind_addr() { + fn overrides_defaults_and_gets_bind_addr() { let default_conf = Conf::default(); - std::env::set_var("MEDEA_SERVER.BIND_IP", "5.5.5.5"); - std::env::set_var("MEDEA_SERVER.BIND_PORT", "1234"); + env::set_var("MEDEA_SERVER.BIND_IP", "5.5.5.5"); + env::set_var("MEDEA_SERVER.BIND_PORT", "1234"); let env_conf = Conf::parse().unwrap(); @@ -45,16 +53,9 @@ mod test { assert_eq!(env_conf.server.bind_ip, Ipv4Addr::new(5, 5, 5, 5)); assert_eq!(env_conf.server.bind_port, 1234); - - let addr: SocketAddr = env_conf - .server - .get_bind_addr() - .to_socket_addrs() - .unwrap() - .into_iter() - .next() - .unwrap(); - - assert_eq!(addr, "5.5.5.5:1234".parse().unwrap()); + assert_eq!( + env_conf.server.get_bind_addr(), + "5.5.5.5:1234".parse().unwrap(), + ); } } diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 72c835079..82d6712ad 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,6 +1,6 @@ //! Helper utils used in project. -/// Creates new [hashbrown::HashMap] from a list of key-value pairs. +/// Creates new [`hashbrown::HashMap`] from a list of key-value pairs. /// /// ## Example ///