diff --git a/Cargo.lock b/Cargo.lock index 3c19030..ca0c737 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -50,17 +50,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "async-trait" -version = "0.1.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.39", -] - [[package]] name = "atty" version = "0.2.14" @@ -105,6 +94,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + [[package]] name = "bumpalo" version = "3.14.0" @@ -149,7 +144,7 @@ dependencies = [ "js-sys", "num-traits", "wasm-bindgen", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -182,7 +177,7 @@ checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ "ansi_term", "atty", - "bitflags", + "bitflags 1.3.2", "strsim", "textwrap", "unicode-width", @@ -244,12 +239,45 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "env_logger" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + [[package]] name = "equivalent" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "eyre" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6267a1fa6f59179ea4afc8e50fd8612a3cc60bc858f786ff877a4a8cb042799" +dependencies = [ + "indenter", + "once_cell", +] + [[package]] name = "fnv" version = "1.0.7" @@ -265,43 +293,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "futures" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-async-stream" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "379790776b0d953337df4ab7ecc51936c66ea112484cad7912907b1d34253ebf" -dependencies = [ - "futures-async-stream-macro", - "futures-core", - "pin-project", -] - -[[package]] -name = "futures-async-stream-macro" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5df2c13d48c8cb8a3ec093ede6f0f4482f327d7bb781120c5fb483ef0f17e758" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.39", -] - [[package]] name = "futures-channel" version = "0.3.29" @@ -309,7 +300,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" dependencies = [ "futures-core", - "futures-sink", ] [[package]] @@ -318,34 +308,6 @@ version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" -[[package]] -name = "futures-executor" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" - -[[package]] -name = "futures-macro" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.39", -] - [[package]] name = "futures-sink" version = "0.3.29" @@ -364,16 +326,10 @@ version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" dependencies = [ - "futures-channel", "futures-core", - "futures-io", - "futures-macro", - "futures-sink", "futures-task", - "memchr", "pin-project-lite", "pin-utils", - "slab", ] [[package]] @@ -476,6 +432,12 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "hyper" version = "0.14.27" @@ -547,6 +509,12 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + [[package]] name = "indexmap" version = "2.1.0" @@ -572,6 +540,17 @@ dependencies = [ "serde", ] +[[package]] +name = "is-terminal" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +dependencies = [ + "hermit-abi 0.3.3", + "rustix", + "windows-sys 0.48.0", +] + [[package]] name = "itoa" version = "1.0.10" @@ -608,6 +587,12 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "linux-raw-sys" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" + [[package]] name = "local-ip-address" version = "0.5.6" @@ -617,7 +602,7 @@ dependencies = [ "libc", "neli", "thiserror", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -667,7 +652,7 @@ checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" dependencies = [ "libc", "wasi", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -782,26 +767,6 @@ dependencies = [ "siphasher", ] -[[package]] -name = "pin-project" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.39", -] - [[package]] name = "pin-project-lite" version = "0.2.13" @@ -820,6 +785,16 @@ version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +[[package]] +name = "pretty_env_logger" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "865724d4dbe39d9f3dd3b52b88d859d66bcb2d6a0acfd5ea68a65fb66d4bdc1c" +dependencies = [ + "env_logger", + "log", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -967,6 +942,19 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +[[package]] +name = "rustix" +version = "0.38.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" +dependencies = [ + "bitflags 2.4.1", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + [[package]] name = "rustls" version = "0.21.7" @@ -1002,15 +990,15 @@ dependencies = [ name = "rustybar" version = "0.1.0" dependencies = [ - "async-trait", "chrono", "chrono-tz", "dbus", "dbus-tokio", - "futures", - "futures-async-stream", + "eyre", "local-ip-address", + "log", "maxminddb", + "pretty_env_logger", "reqwest", "serde", "serde_json", @@ -1133,7 +1121,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1200,7 +1188,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation", "system-configuration-sys", ] @@ -1215,6 +1203,15 @@ dependencies = [ "libc", ] +[[package]] +name = "termcolor" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" +dependencies = [ + "winapi-util", +] + [[package]] name = "textwrap" version = "0.11.0" @@ -1273,7 +1270,7 @@ dependencies = [ "pin-project-lite", "socket2 0.5.5", "tokio-macros", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1571,6 +1568,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -1583,7 +1589,7 @@ version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -1592,7 +1598,16 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", ] [[package]] @@ -1601,13 +1616,28 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] [[package]] @@ -1616,42 +1646,84 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + [[package]] name = "winnow" version = "0.5.26" @@ -1668,5 +1740,5 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ "cfg-if", - "windows-sys", + "windows-sys 0.48.0", ] diff --git a/Cargo.toml b/Cargo.toml index dca0764..eb6770e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,15 +8,15 @@ edition = "2018" check_latency = [] [dependencies] -async-trait = "0.1" chrono = "0.4" chrono-tz = "0.8" dbus = "0.9" dbus-tokio = "0.7" -futures = "0.3" -futures-async-stream = "0.2" +eyre = "0.6" local-ip-address = "0.5" +log = "0.4" maxminddb = "0.23" +pretty_env_logger = "0.5" reqwest = { version = "0.11", features = ["rustls-tls"], default-features = false } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/flake.lock b/flake.lock index d726e80..98141a1 100644 --- a/flake.lock +++ b/flake.lock @@ -1,33 +1,12 @@ { "nodes": { - "fenix": { - "inputs": { - "nixpkgs": [ - "nixpkgs" - ], - "rust-analyzer-src": [] - }, - "locked": { - "lastModified": 1702189261, - "narHash": "sha256-TN6gE1eZddDhAoRrScV6Wji1Nk3uqMIDjGwN5ZesAZk=", - "owner": "nix-community", - "repo": "fenix", - "rev": "cae060dbaf53430bb2b549ced0affd54d40e6cee", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "fenix", - "type": "github" - } - }, "nixpkgs": { "locked": { - "lastModified": 1702206697, - "narHash": "sha256-vE9oEx3Y8TO5MnWwFlmopjHd1JoEBno+EhsfUCq5iR8=", + "lastModified": 1702272962, + "narHash": "sha256-D+zHwkwPc6oYQ4G3A1HuadopqRwUY/JkMwHz1YF7j4Q=", "owner": "nixos", "repo": "nixpkgs", - "rev": "29d6c96900b9b576c2fb89491452f283aa979819", + "rev": "e97b3e4186bcadf0ef1b6be22b8558eab1cdeb5d", "type": "github" }, "original": { @@ -39,7 +18,6 @@ }, "root": { "inputs": { - "fenix": "fenix", "nixpkgs": "nixpkgs", "utils": "utils" } diff --git a/flake.nix b/flake.nix index 2f32738..a181cf9 100644 --- a/flake.nix +++ b/flake.nix @@ -4,43 +4,31 @@ inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; utils.url = "github:numtide/flake-utils"; - fenix = { - url = "github:nix-community/fenix"; - inputs.nixpkgs.follows = "nixpkgs"; - # We don't need rust-analyzer so don't clone it - inputs.rust-analyzer-src.follows = ""; - }; }; - outputs = { self, nixpkgs, utils, fenix }: + outputs = { self, nixpkgs, utils }: let supportedSystems = [ "x86_64-linux" "aarch64-linux" ]; in (utils.lib.eachSystem supportedSystems (system: - let - pkgs = import nixpkgs { - inherit system; - overlays = [ fenix.overlays.default ]; - }; - toolchain = pkgs.fenix.complete; - rustPlatform = - pkgs.makeRustPlatform { inherit (toolchain) cargo rustc; }; + let pkgs = import nixpkgs { inherit system; }; in rec { - packages.rustybar = rustPlatform.buildRustPackage { - name = "rustybar"; - version = "0.1"; - src = ./.; - cargoLock.lockFile = ./Cargo.lock; - doCheck = false; - nativeBuildInputs = with pkgs; [ pkg-config ]; - buildInputs = with pkgs; [ dbus ]; + packages.rustybar = with pkgs; + rustPlatform.buildRustPackage { + name = "rustybar"; + version = "0.1"; + src = ./.; + cargoLock.lockFile = ./Cargo.lock; + doCheck = false; + nativeBuildInputs = [ pkg-config ]; + buildInputs = [ dbus ]; - meta = with pkgs.lib; { - homepage = "https://github.com/mildlyfunctionalgays/rustybar"; - description = "swaybar/i3bar command in Rust"; - maintainers = with maintainers; [ artemist ]; - license = with licenses; [ mit ]; - platforms = supportedSystems; + meta = with lib; { + homepage = "https://github.com/mildlyfunctionalgays/rustybar"; + description = "swaybar/i3bar command in Rust"; + maintainers = with maintainers; [ artemist ]; + license = with licenses; [ mit ]; + platforms = supportedSystems; + }; }; - }; defaultPackage = packages.rustybar; apps.rustybar = utils.lib.mkApp { drv = packages.rustybar; }; @@ -52,12 +40,13 @@ pkg-config dbus libfaketime - toolchain.cargo - toolchain.rustc - toolchain.rustfmt - toolchain.clippy + rustPackages.cargo + rustPackages.rustc + rustPackages.rustfmt + rustPackages.clippy ]; - RUST_SRC_PATH = "${toolchain.rust-src}/lib/rustlib"; + RUST_SRC_PATH = + "${rustPackages.rustPlatform.rustLibSrc}/lib/rustlib"; }; devShell = devShells.rustybar; diff --git a/src/async_iter.rs b/src/async_iter.rs deleted file mode 100644 index 9aeb3d9..0000000 --- a/src/async_iter.rs +++ /dev/null @@ -1,50 +0,0 @@ -use async_trait::async_trait; -use futures::stream::{self, BoxStream}; - -#[async_trait] -pub trait AsyncIter { - type Item; - async fn next(&mut self) -> Option; - - fn into_stream<'a>(self) -> BoxStream<'a, Self::Item> - where - Self: Sized + Send + 'a, - { - Box::pin(stream::unfold(self, |mut iter| async { - let value = iter.next().await?; - Some((value, iter)) - })) - } -} - -#[cfg(test)] -mod test { - use super::*; - use futures::{executor, StreamExt}; - - struct Numbers(usize); - impl Numbers { - fn new() -> Self { - Numbers(0) - } - } - - #[async_trait] - impl AsyncIter for Numbers { - type Item = usize; - - async fn next(&mut self) -> Option { - self.0 = self.0.checked_add(1)?; - Some(self.0) - } - } - #[test] - fn test_numbers() { - let a = async { - let vec1: Vec<_> = Numbers::new().into_stream().take(10).collect().await; - let vec2: Vec<_> = (1..=10).into_iter().collect(); - assert_eq!(vec1, vec2); - }; - executor::block_on(a); - } -} diff --git a/src/config.rs b/src/config.rs index fae88d8..cd24912 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,11 +1,14 @@ +use crate::output::OutputChannel; +use crate::tile::TileData; use crate::tiles; -use crate::tiles::TileResult; + use dbus::nonblock::SyncConnection; -use futures::{stream::BoxStream, Stream}; +use log::error; +use log::warn; use serde::{Deserialize, Deserializer}; use smart_default::SmartDefault; use std::env::var; -use std::io; + use std::path::Path; use std::path::PathBuf; use std::sync::Arc; @@ -13,13 +16,14 @@ use std::time::Duration; use structopt::StructOpt; use tokio::fs::File; use tokio::io::AsyncReadExt; -use tokio_stream::StreamExt; +use tokio::sync::mpsc; +use tokio::task::JoinHandle; #[derive(Deserialize, Clone, Debug, Default)] #[serde(default)] pub struct Config { pub default: DefaultSection, - pub tile: Box<[TileConfig]>, + pub tile: Vec, } #[derive(Deserialize, Clone, Debug, Default)] @@ -27,7 +31,7 @@ pub struct DefaultSection { pub spacing: Option, } -fn deserialize_duration<'de, D>(deserializer: D) -> Result, D::Error> +fn deserialize_duration<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, { @@ -41,24 +45,16 @@ where "ms" => Duration::from_secs_f64(number / 1000f64), _ => unimplemented!(), }; - Ok(Some(duration)) -} - -#[derive(Deserialize, Clone, Debug)] -pub struct TileConfig { - #[serde(flatten)] - config_type: TileConfigType, - #[serde(deserialize_with = "deserialize_duration", default)] - update: Option, + Ok(duration) } #[derive(Deserialize, Clone, Debug)] #[serde(tag = "type", rename_all = "snake_case")] -pub enum TileConfigType { +pub enum TileConfig { Battery(BatteryConfig), - Memory, - Load, - Hostname, + Memory(MemoryConfig), + Load(LoadConfig), + Hostname(HostnameConfig), UtcTime(UtcTimeConfig), SystemTime(SystemTimeConfig), LocalTime(LocalTimeConfig), @@ -71,6 +67,33 @@ pub enum TileConfigType { pub struct BatteryConfig { #[default("BAT0")] pub battery: Box, + #[serde(deserialize_with = "deserialize_duration")] + #[default(_code = "Duration::from_secs(30)")] + pub update: Duration, +} + +#[derive(SmartDefault, Deserialize, Clone, Debug)] +#[serde(default)] +pub struct MemoryConfig { + #[serde(deserialize_with = "deserialize_duration")] + #[default(_code = "Duration::from_secs(30)")] + pub update: Duration, +} + +#[derive(SmartDefault, Deserialize, Clone, Debug)] +#[serde(default)] +pub struct LoadConfig { + #[serde(deserialize_with = "deserialize_duration")] + #[default(_code = "Duration::from_secs(30)")] + pub update: Duration, +} + +#[derive(SmartDefault, Deserialize, Clone, Debug)] +#[serde(default)] +pub struct HostnameConfig { + #[serde(deserialize_with = "deserialize_duration")] + #[default(_code = "Duration::from_secs(3600)")] + pub update: Duration, } #[derive(SmartDefault, Deserialize, Clone, Debug)] @@ -78,6 +101,9 @@ pub struct BatteryConfig { pub struct IwdConfig { #[default("wlan0")] pub interface: Box, + #[serde(deserialize_with = "deserialize_duration")] + #[default(_code = "Duration::from_secs(5)")] + pub update: Duration, } #[derive(SmartDefault, Deserialize, Clone, Debug)] @@ -87,6 +113,7 @@ pub struct UtcTimeConfig { pub format: Box, #[default("%H:%M:%S")] pub short_format: Box, + // No update field, update on the minute or second } #[derive(SmartDefault, Deserialize, Clone, Debug)] @@ -96,6 +123,7 @@ pub struct SystemTimeConfig { pub format: Box, #[default("%H:%M:%S %Z")] pub short_format: Box, + // No update field, update on the minute or second } #[derive(SmartDefault, Deserialize, Clone, Debug)] @@ -106,11 +134,13 @@ pub struct LocalTimeConfig { #[default("%H:%M:%S %Z")] pub short_format: Box, pub geoip_path: Option>, + #[serde(deserialize_with = "deserialize_duration")] #[default(_code = "Duration::from_secs(3600)")] pub update_interval: Duration, pub fallback_zone: Option>, #[default("https://myip.wtf/text")] pub ip_addr_api: Box, + // No update field, update on the minute or second } #[derive(SmartDefault, Deserialize, Clone, Debug)] @@ -118,6 +148,7 @@ pub struct LocalTimeConfig { pub struct InternetTimeConfig { #[default(2)] pub precision: u8, + // No update field, update on the, uuh, wtf is metric time } #[derive(Debug, StructOpt)] @@ -131,7 +162,7 @@ struct Args { pub config: Option, } -pub async fn read_config() -> Result> { +pub async fn read_config() -> eyre::Result { let args = Args::from_args(); let config_path = match args.config { Some(config) => config, @@ -147,10 +178,7 @@ pub async fn read_config() -> Result> { .iter() .collect() } else { - return Err(Box::new(io::Error::new( - io::ErrorKind::NotFound, - "Could not find RUSTYBAR_CONFIG, XDG_CONFIG_HOME, or HOME environment variables" - ))); + eyre::bail!("Could not find RUSTYBAR_CONFIG, XDG_CONFIG_HOME, or HOME environment variables"); } } }; @@ -163,38 +191,28 @@ pub async fn read_config() -> Result> { Ok(toml::from_str(std::str::from_utf8(&config_contents)?)?) } -pub fn process_tile( - tile: &TileConfig, - connection: &Arc, -) -> BoxStream<'static, TileResult> { - let five_secs = Duration::from_secs(5); - match &tile.config_type { - TileConfigType::Battery(c) => wrap( - tiles::battery_stream(c.clone()), - tile.update.or(Some(five_secs)), - ), - TileConfigType::Hostname => wrap(tiles::hostname_stream(connection.as_ref()), tile.update), - TileConfigType::Load => wrap(tiles::load_stream(), tile.update.or(Some(five_secs))), - TileConfigType::Memory => wrap(tiles::memory_stream(), tile.update.or(Some(five_secs))), - TileConfigType::UtcTime(c) => wrap(tiles::utc_time_stream(c.clone()), tile.update), - TileConfigType::Iwd(c) => wrap( - tiles::iwd_stream(connection.clone(), c.clone()), - tile.update.or(Some(five_secs)), - ), - TileConfigType::SystemTime(c) => wrap(tiles::system_time_stream(c.clone()), tile.update), - TileConfigType::LocalTime(c) => wrap(tiles::local_time_stream(c.clone()), tile.update), - TileConfigType::InternetTime(c) => { - wrap(tiles::internet_time_stream(c.clone()), tile.update) +pub fn launch_tile( + tile: TileConfig, + sender: mpsc::Sender, + tile_id: usize, + dbus_conn: Arc, +) -> JoinHandle<()> { + tokio::spawn(async move { + let output_chan = OutputChannel::with_random_uuid(sender, tile_id); + let result = match tile { + TileConfig::Battery(c) => tiles::battery(c, output_chan).await, + TileConfig::Hostname(c) => tiles::hostname(c, output_chan, dbus_conn).await, + TileConfig::Load(c) => tiles::load(c, output_chan).await, + TileConfig::Memory(c) => tiles::memory(c, output_chan).await, + TileConfig::UtcTime(c) => tiles::utc_time(c, output_chan).await, + TileConfig::Iwd(c) => tiles::iwd(c, output_chan, dbus_conn).await, + TileConfig::SystemTime(c) => tiles::system_time(c, output_chan).await, + TileConfig::LocalTime(c) => tiles::local_time(c, output_chan).await, + TileConfig::InternetTime(c) => tiles::internet_time(c, output_chan).await, + }; + match result { + Ok(_) => warn!("Tile {} exited without error", tile_id), + Err(e) => error!("Tile {} exited with error: {:?}", tile_id, e), } - } -} - -fn wrap<'a, S>(stream: S, duration: Option) -> BoxStream<'a, TileResult> -where - S: Stream + Send + 'a, -{ - match duration { - Some(duration) => Box::pin(stream.throttle(duration)), - None => Box::pin(stream), - } + }) } diff --git a/src/main.rs b/src/main.rs index 7bf3f63..8f6552b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,71 +1,38 @@ -#![feature(coroutines)] -#![feature(never_type)] -#![feature(proc_macro_hygiene)] -#![feature(stmt_expr_attributes)] -#![feature(ip)] - -mod async_iter; mod config; mod output; mod tile; mod tiles; use dbus_tokio::connection::new_system_sync; -use futures::channel::mpsc::{channel, Sender}; -use futures::{stream::BoxStream, StreamExt}; -use std::fmt::Debug; -use std::sync::Arc; -use uuid::Uuid; + +use tokio::sync::mpsc; #[tokio::main] -async fn main() -> Result> { - let config = config::read_config().await?; +async fn main() -> eyre::Result<()> { + let mut config = config::read_config().await?; - // We can't do much until we have a D-Bus connection so just do it synchronously - let (resource, conn) = new_system_sync()?; + pretty_env_logger::init(); - // Now start listening on our D-Bus connection + let (resource, dbus_conn) = new_system_sync()?; tokio::spawn(async { let err = resource.await; panic!("Lost connection to D-Bus: {}", err); }); - let (sender, receiver) = channel(1024); + let (sender, receiver) = mpsc::channel(1024); let tiles: Vec<_> = config .tile - .iter() - .map(|tile| config::process_tile(tile, &conn)) + .drain(..) .enumerate() - .map(|(index, stream)| spawn_stream(index, stream, sender.clone())) + .map(|(sender_id, tile)| { + config::launch_tile(tile, sender.clone(), sender_id, dbus_conn.clone()) + }) .collect(); let num_tiles = tiles.len(); drop(sender); - output::launch(num_tiles, receiver, config.default).await? -} - -fn spawn_stream( - index: usize, - stream: BoxStream<'static, Result>, - sender: Sender>, -) where - E: Debug + Send, -{ - tokio::spawn(async move { - let instance: Arc = Uuid::new_v4().to_string().into(); - let stream = stream.map(|block: Result<_, _>| { - Ok(block.map(|block| tile::TileData { - block: tile::Block { - instance: instance.clone(), - ..block - }, - sender_id: index, - })) - }); - let future = stream.forward(sender); - future.await - }); + output::run(num_tiles, receiver).await } diff --git a/src/output.rs b/src/output.rs index 1657ee6..a8d5ab9 100644 --- a/src/output.rs +++ b/src/output.rs @@ -1,38 +1,58 @@ -use crate::config::DefaultSection; -use crate::tile::TileData; -use futures::channel::mpsc::Receiver; -use futures::StreamExt; -use tokio::io::{self, AsyncWriteExt}; +use crate::tile::{Block, TileData}; +use eyre::OptionExt; +use std::sync::Arc; +use tokio::{ + io::{self, AsyncWriteExt}, + sync::mpsc, +}; +use uuid::Uuid; -pub async fn launch( - num_tiles: usize, - mut receiver: Receiver>, - _default: DefaultSection, -) -> io::Result -where - E: Send + std::fmt::Debug, -{ +pub struct OutputChannel { + sender: mpsc::Sender, + sender_id: usize, + instance: Arc, +} + +impl OutputChannel { + pub fn with_random_uuid(sender: mpsc::Sender, sender_id: usize) -> Self { + Self { + sender, + sender_id, + instance: Uuid::new_v4().to_string().into(), + } + } + + pub async fn send(&self, mut block: Block) -> Result<(), mpsc::error::SendError> { + block.instance = self.instance.clone(); + self.sender + .send(TileData { + block, + sender_id: self.sender_id, + }) + .await + } +} + +pub async fn run(num_tiles: usize, mut receiver: mpsc::Receiver) -> eyre::Result<()> { let mut stdout = io::stdout(); stdout.write_all(b"{ \"version\": 1 }\n[").await?; let mut blocks = Vec::new(); blocks.resize_with(num_tiles, Default::default); loop { - match receiver.next().await.unwrap() { - Ok(message) => { - if message.sender_id < num_tiles { - blocks[message.sender_id] = Some(message.block); - } else { - eprintln!("Invalid message with sender id {}", message.sender_id); - continue; - } - let mut serialized = serde_json::to_vec(&blocks).unwrap(); - serialized.extend_from_slice(b",\n"); - stdout.write_all(&serialized).await?; - } - Err(err) => { - eprintln!("Error in tile: {:?}", err); - } + let message = receiver + .recv() + .await + .ok_or_eyre("No more messages to recieve")?; + + if message.sender_id < num_tiles { + blocks[message.sender_id] = Some(message.block); + } else { + eprintln!("Invalid message with sender id {}", message.sender_id); + continue; } + let mut serialized = serde_json::to_vec(&blocks).unwrap(); + serialized.extend_from_slice(b",\n"); + stdout.write_all(&serialized).await?; } } diff --git a/src/tiles/battery.rs b/src/tiles/battery.rs index ba3f0cf..7fded58 100644 --- a/src/tiles/battery.rs +++ b/src/tiles/battery.rs @@ -1,14 +1,13 @@ use crate::config::BatteryConfig; +use crate::output::OutputChannel; use crate::tile::Block; -use futures::future::try_join3; -use futures_async_stream::try_stream; -use std::error::Error; + use std::path::Path; use tokio::fs::{try_exists, File}; use tokio::io::AsyncReadExt; +use tokio::try_join; -#[try_stream(ok = Block, error = Box)] -pub async fn battery_stream(config: BatteryConfig) { +pub async fn battery(config: BatteryConfig, output: OutputChannel) -> eyre::Result<()> { let base_dir = Path::new("/sys/class/power_supply").join(&*config.battery); let file_prefix = if try_exists(base_dir.join("energy_now")).await? { "energy_" @@ -18,6 +17,7 @@ pub async fn battery_stream(config: BatteryConfig) { let now_path = base_dir.join(file_prefix.to_owned() + "now"); let full_path = base_dir.join(file_prefix.to_owned() + "full"); + let mut interval = tokio::time::interval(config.update); loop { let charge_now = async { let mut raw = String::new(); @@ -26,7 +26,7 @@ pub async fn battery_stream(config: BatteryConfig) { .read_to_string(&mut raw) .await?; let charge: u32 = raw.trim_end().parse()?; - Result::<_, Box>::Ok(charge) + eyre::Result::<_>::Ok(charge) }; let charge_total = async { let mut raw = String::new(); @@ -35,7 +35,7 @@ pub async fn battery_stream(config: BatteryConfig) { .read_to_string(&mut raw) .await?; let charge: u32 = raw.trim_end().parse()?; - Result::<_, Box>::Ok(charge) + eyre::Result::<_>::Ok(charge) }; let status = async { let mut raw = String::new(); @@ -44,16 +44,19 @@ pub async fn battery_stream(config: BatteryConfig) { .read_to_string(&mut raw) .await?; raw.truncate(raw.trim_end().len()); - Result::<_, Box>::Ok(raw) + eyre::Result::<_>::Ok(raw) }; - let (charge_now, charge_total, status) = - try_join3(charge_now, charge_total, status).await?; + let (charge_now, charge_total, status) = try_join!(charge_now, charge_total, status)?; let percentage = charge_now * 100 / charge_total; - yield Block { - full_text: format!("{}% {}", percentage, status).into(), - short_text: format!("{}%", percentage).into_boxed_str().into(), - name: "battery".into(), - ..Default::default() - }; + output + .send(Block { + full_text: format!("{}% {}", percentage, status).into(), + short_text: format!("{}%", percentage).into_boxed_str().into(), + name: "battery".into(), + ..Default::default() + }) + .await?; + + interval.tick().await; } } diff --git a/src/tiles/hostname.rs b/src/tiles/hostname.rs index 2455e76..c4be8a5 100644 --- a/src/tiles/hostname.rs +++ b/src/tiles/hostname.rs @@ -1,26 +1,34 @@ +use crate::config::HostnameConfig; +use crate::output::OutputChannel; use crate::tile::Block; -use crate::tiles::TileResult; use dbus::nonblock::stdintf::org_freedesktop_dbus::Properties; use dbus::nonblock::{Proxy, SyncConnection}; -use futures::stream::Stream; -use futures_async_stream::try_stream; +use std::sync::Arc; use std::time::Duration; -pub fn hostname_stream(connection: &SyncConnection) -> impl Stream { +pub async fn hostname( + config: HostnameConfig, + output: OutputChannel, + dbus_conn: Arc, +) -> eyre::Result<()> { let proxy = Proxy::new( "org.freedesktop.hostname1", "/org/freedesktop/hostname1", Duration::from_secs(5), - connection, + dbus_conn, ); - let reply = proxy.get("org.freedesktop.hostname1", "Hostname"); - #[try_stream] - async move { + let mut interval = tokio::time::interval(config.update); + loop { + let reply = proxy.get("org.freedesktop.hostname1", "Hostname"); let hostname: String = reply.await?; - yield Block { - full_text: hostname.into(), - name: "hostname".into(), - ..Default::default() - }; + output + .send(Block { + full_text: hostname.into(), + name: "hostname".into(), + ..Default::default() + }) + .await?; + + interval.tick().await; } } diff --git a/src/tiles/internet_time.rs b/src/tiles/internet_time.rs index f60070e..3ac36e7 100644 --- a/src/tiles/internet_time.rs +++ b/src/tiles/internet_time.rs @@ -1,12 +1,10 @@ -use super::TileResult; use crate::config::InternetTimeConfig; +use crate::output::OutputChannel; use crate::tile::Block; use chrono::prelude::*; -use futures_async_stream::stream; use tokio::time::sleep; -#[stream(item = TileResult)] -pub async fn internet_time_stream(config: InternetTimeConfig) { +pub async fn internet_time(config: InternetTimeConfig, output: OutputChannel) -> eyre::Result<()> { // "BMT" is actually just UTC+1 let offset = FixedOffset::east_opt(60 * 60).unwrap(); let factor = 10f64.powi(config.precision.into()); @@ -17,19 +15,21 @@ pub async fn internet_time_stream(config: InternetTimeConfig) { let seconds = now.num_seconds_from_midnight() as f64 + (now.nanosecond() as f64) / 1_000_000_000f64; let internet_time = seconds / 86.4; - yield Ok(Block { - full_text: format!( - "@{time:0width$.prec$}", - time = internet_time, - // 3 digits + and decimal point - width = config.precision as usize + 4, - prec = config.precision as usize - ) - .into_boxed_str(), - short_text: Some(format!("@{:03.0}", internet_time).into_boxed_str()), - name: "internet_time".into(), - ..Default::default() - }); + output + .send(Block { + full_text: format!( + "@{time:0width$.prec$}", + time = internet_time, + // 3 digits + and decimal point + width = config.precision as usize + 4, + prec = config.precision as usize + ) + .into_boxed_str(), + short_text: Some(format!("@{:03.0}", internet_time).into_boxed_str()), + name: "internet_time".into(), + ..Default::default() + }) + .await?; // In normal (non-metric) seconds let difference = (1f64 - (internet_time * factor).fract()) / factor * 86.4; diff --git a/src/tiles/iwd.rs b/src/tiles/iwd.rs index 4250dc1..d36eb5e 100644 --- a/src/tiles/iwd.rs +++ b/src/tiles/iwd.rs @@ -1,12 +1,11 @@ use crate::config::IwdConfig; +use crate::output::OutputChannel; use crate::tile::Block; -use crate::tiles::TileResult; use dbus::arg::{PropMap, RefArg}; use dbus::nonblock::stdintf::org_freedesktop_dbus::ObjectManager; use dbus::nonblock::{Proxy, SyncConnection}; use dbus::Path; -use futures::stream::Stream; -use futures_async_stream::try_stream; +use eyre::OptionExt; use std::collections::HashMap; use std::sync::Arc; use std::time::Duration; @@ -29,39 +28,43 @@ fn get_interface_path( None } -pub fn iwd_stream( - connection: Arc, +pub async fn iwd( config: IwdConfig, -) -> impl Stream { - let root_proxy = Proxy::new("net.connman.iwd", "/", Duration::from_secs(5), connection); - #[try_stream] - async move { - loop { - let managed_objects = root_proxy.get_managed_objects().await?; - let interface_path = get_interface_path(&managed_objects, &config.interface) - .ok_or("Couldn't find interface")?; - let station_path = managed_objects - .get(&interface_path) - .and_then(|object| object.get("net.connman.iwd.Station")) - .and_then(|interface| interface.get("ConnectedNetwork")) - .and_then(|network| network.as_str()) - .and_then(|s| Path::from_slice(s).ok()); - let text = if let Some(path) = station_path { - let network_name = managed_objects - .get(&path) - .and_then(|object| object.get("net.connman.iwd.Network")) - .and_then(|network| network.get("Name")) - .and_then(|name| name.as_str()) - .ok_or("Unable to get network name")?; - format!("{}: {}", &config.interface, network_name) - } else { - format!("{}: disconnected", &config.interface) - }; - yield Block { + output: OutputChannel, + dbus_conn: Arc, +) -> eyre::Result<()> { + let root_proxy = Proxy::new("net.connman.iwd", "/", Duration::from_secs(5), dbus_conn); + + let mut interval = tokio::time::interval(config.update); + loop { + let managed_objects = root_proxy.get_managed_objects().await?; + let interface_path = get_interface_path(&managed_objects, &config.interface) + .ok_or_eyre("Couldn't find interface")?; + let station_path = managed_objects + .get(&interface_path) + .and_then(|object| object.get("net.connman.iwd.Station")) + .and_then(|interface| interface.get("ConnectedNetwork")) + .and_then(|network| network.as_str()) + .and_then(|s| Path::from_slice(s).ok()); + let text = if let Some(path) = station_path { + let network_name = managed_objects + .get(&path) + .and_then(|object| object.get("net.connman.iwd.Network")) + .and_then(|network| network.get("Name")) + .and_then(|name| name.as_str()) + .ok_or_eyre("Unable to get network name")?; + format!("{}: {}", &config.interface, network_name) + } else { + format!("{}: disconnected", &config.interface) + }; + output + .send(Block { full_text: text.into(), name: config.interface.clone(), ..Default::default() - }; - } + }) + .await?; + + interval.tick().await; } } diff --git a/src/tiles/load.rs b/src/tiles/load.rs index 8a3de9e..9b4e026 100644 --- a/src/tiles/load.rs +++ b/src/tiles/load.rs @@ -1,20 +1,24 @@ +use crate::config::LoadConfig; +use crate::output::OutputChannel; use crate::tile::Block; -use futures_async_stream::try_stream; -use std::error::Error; use tokio::fs::File; use tokio::io::AsyncReadExt; -#[try_stream(ok = Block, error = Box)] -pub async fn load_stream() { +pub async fn load(config: LoadConfig, output: OutputChannel) -> eyre::Result<()> { + let mut interval = tokio::time::interval(config.update); loop { let mut raw = String::new(); let mut file = File::open("/proc/loadavg").await?; file.read_to_string(&mut raw).await?; let (load, _rest) = raw.split_at(raw.find(' ').unwrap_or(0)); - yield Block { - full_text: load.into(), - name: "load".into(), - ..Default::default() - }; + output + .send(Block { + full_text: load.into(), + name: "load".into(), + ..Default::default() + }) + .await?; + + interval.tick().await; } } diff --git a/src/tiles/local_time.rs b/src/tiles/local_time.rs index 45d8333..64971f1 100644 --- a/src/tiles/local_time.rs +++ b/src/tiles/local_time.rs @@ -1,9 +1,9 @@ use crate::config::LocalTimeConfig; +use crate::output::OutputChannel; use crate::tile::Block; use chrono::prelude::*; -use futures_async_stream::try_stream; use maxminddb::geoip2; -use std::error::Error; + use std::net::IpAddr; use std::str::FromStr; use tokio::sync::watch; @@ -13,10 +13,7 @@ struct State { pub tz: Option, } -async fn request_ipv4( - client: &reqwest::Client, - api: &str, -) -> Result> { +async fn request_ipv4(client: &reqwest::Client, api: &str) -> eyre::Result { let response = client.get(api).send().await?; let text = response.text().await?; Ok(IpAddr::from_str(text.trim())?) @@ -28,16 +25,10 @@ fn lookup_timezone(db: &maxminddb::Reader>, addr: Option) -> Opt chrono_tz::Tz::from_str(tz_name).ok() } -async fn find_time_zone( - config: LocalTimeConfig, - sender: watch::Sender, -) -> Result> { +async fn find_time_zone(config: LocalTimeConfig, sender: watch::Sender) -> eyre::Result<()> { // TODO: Add error messages; let Some(geoip_path) = &config.geoip_path else { - return Err(Box::new(std::io::Error::new( - std::io::ErrorKind::NotFound, - "geoip path not specified", - ))); + eyre::bail!("geoip path not specified"); }; let db_reader = maxminddb::Reader::open_readfile(geoip_path)?; @@ -75,10 +66,9 @@ async fn find_time_zone( } } -#[try_stream(ok = Block, error = Box)] -pub async fn local_time_stream(config: LocalTimeConfig) { +pub async fn local_time(config: LocalTimeConfig, output: OutputChannel) -> eyre::Result<()> { let fallback_tz = if let Some(tz_name) = &config.fallback_zone { - Some(chrono_tz::Tz::from_str(tz_name)?) + chrono_tz::Tz::from_str(tz_name).ok() } else { None }; @@ -92,19 +82,25 @@ pub async fn local_time_stream(config: LocalTimeConfig) { if tz_thread.is_finished() { tz_thread.await??; + eyre::bail!("timezone thread finished"); } - if let Some(tz) = { + // We're blocking the tz thread while we have the ref, so keep it as short as possible + let maybe_tz = { let state = receiver.borrow_and_update(); state.tz - } { + }; + + if let Some(tz) = maybe_tz { let local_now = utc_now.with_timezone(&tz); - yield Block { - full_text: local_now.format(&config.format).to_string().into(), - short_text: Some(local_now.format(&config.short_format).to_string().into()), - name: "local_time".into(), - ..Default::default() - }; + output + .send(Block { + full_text: local_now.format(&config.format).to_string().into(), + short_text: Some(local_now.format(&config.short_format).to_string().into()), + name: "local_time".into(), + ..Default::default() + }) + .await?; } // It would take more resources to get time again, and we want to err on the side of // "wait a few µs too long" rather than too short. diff --git a/src/tiles/memory.rs b/src/tiles/memory.rs index cd4f566..b2c5058 100644 --- a/src/tiles/memory.rs +++ b/src/tiles/memory.rs @@ -1,6 +1,6 @@ +use crate::config::MemoryConfig; +use crate::output::OutputChannel; use crate::tile::Block; -use futures_async_stream::try_stream; -use std::error::Error; use std::{io, str, u64}; use tokio::fs::File; use tokio::io::AsyncReadExt; @@ -18,7 +18,7 @@ fn prettify_kib(kib: u64) -> Box { format!("{} {}iB", mem, unit).into_boxed_str() } -fn extract_value(line: &str) -> Result> { +fn extract_value(line: &str) -> eyre::Result { let mut parts = line.split_whitespace(); parts.next(); Ok(parts @@ -27,8 +27,8 @@ fn extract_value(line: &str) -> Result)] -pub async fn memory_stream() { +pub async fn memory(config: MemoryConfig, output: OutputChannel) -> eyre::Result<()> { + let mut interval = tokio::time::interval(config.update); loop { let mut raw = [0u8; 256]; let mut file = File::open("/proc/meminfo").await?; @@ -50,11 +50,15 @@ pub async fn memory_stream() { let full_text = format!("{} avail / {}", mem_avail, mem_total).into_boxed_str(); let short_text = format!("{} / {}", mem_avail, mem_total).into_boxed_str(); - yield Block { - full_text, - short_text: Some(short_text), - name: "memory".into(), - ..Default::default() - }; + output + .send(Block { + full_text, + short_text: Some(short_text), + name: "memory".into(), + ..Default::default() + }) + .await?; + + interval.tick().await; } } diff --git a/src/tiles/mod.rs b/src/tiles/mod.rs index c44b5f8..07345db 100644 --- a/src/tiles/mod.rs +++ b/src/tiles/mod.rs @@ -7,17 +7,12 @@ pub mod local_time; pub mod memory; pub mod system_time; pub mod utc_time; -pub use battery::battery_stream; -pub use hostname::hostname_stream; -pub use internet_time::internet_time_stream; -pub use iwd::iwd_stream; -pub use load::load_stream; -pub use local_time::local_time_stream; -pub use memory::memory_stream; -pub use system_time::system_time_stream; -pub use utc_time::utc_time_stream; - -use crate::tile::Block; -use std::error::Error; - -pub type TileResult = Result>; +pub use battery::battery; +pub use hostname::hostname; +pub use internet_time::internet_time; +pub use iwd::iwd; +pub use load::load; +pub use local_time::local_time; +pub use memory::memory; +pub use system_time::system_time; +pub use utc_time::utc_time; diff --git a/src/tiles/system_time.rs b/src/tiles/system_time.rs index 5ec89f5..a6e4822 100644 --- a/src/tiles/system_time.rs +++ b/src/tiles/system_time.rs @@ -1,20 +1,20 @@ -use super::TileResult; use crate::config::SystemTimeConfig; +use crate::output::OutputChannel; use crate::tile::Block; use chrono::prelude::*; -use futures_async_stream::stream; use tokio::time::sleep; -#[stream(item = TileResult)] -pub async fn system_time_stream(config: SystemTimeConfig) { +pub async fn system_time(config: SystemTimeConfig, output: OutputChannel) -> eyre::Result<()> { loop { let now = Local::now(); - yield Ok(Block { - full_text: now.format(&config.format).to_string().into(), - short_text: Some(now.format(&config.short_format).to_string().into()), - name: "system_time".into(), - ..Default::default() - }); + output + .send(Block { + full_text: now.format(&config.format).to_string().into(), + short_text: Some(now.format(&config.short_format).to_string().into()), + name: "system_time".into(), + ..Default::default() + }) + .await?; // It would take more resources to get time again, and we want to err on the side of // "wait a few µs too long" rather than too short. diff --git a/src/tiles/utc_time.rs b/src/tiles/utc_time.rs index 70a1456..5f73ee3 100644 --- a/src/tiles/utc_time.rs +++ b/src/tiles/utc_time.rs @@ -1,20 +1,20 @@ -use super::TileResult; use crate::config::UtcTimeConfig; +use crate::output::OutputChannel; use crate::tile::Block; use chrono::prelude::*; -use futures_async_stream::stream; use tokio::time::sleep; -#[stream(item = TileResult)] -pub async fn utc_time_stream(config: UtcTimeConfig) { +pub async fn utc_time(config: UtcTimeConfig, output: OutputChannel) -> eyre::Result<()> { loop { let now = Utc::now(); - yield Ok(Block { - full_text: now.format(&config.format).to_string().into(), - short_text: Some(now.format(&config.short_format).to_string().into()), - name: "utc_time".into(), - ..Default::default() - }); + output + .send(Block { + full_text: now.format(&config.format).to_string().into(), + short_text: Some(now.format(&config.short_format).to_string().into()), + name: "utc_time".into(), + ..Default::default() + }) + .await?; // It would take more resources to get time again, and we want to err on the side of // "wait a few µs too long" rather than too short.