From 153838772cfefe400bcf284aba09b11c9c5c0e03 Mon Sep 17 00:00:00 2001 From: Alexandre Trendel Date: Sat, 15 Jan 2022 02:55:43 +0000 Subject: [PATCH] update zbus (#434) --- Cargo.lock | 193 ++++++++++++++++++++++-------- Cargo.toml | 5 +- build-aux/clippy.sh | 2 +- cargo-sources.json | 240 ++++++++++++++++++++++++++----------- src/app/mod.rs | 2 +- src/dbus/listener.rs | 141 ++++++++++++++++++++++ src/dbus/mod.rs | 278 ++++++++++++++----------------------------- src/dbus/mpris.rs | 154 ++++++++++++++---------- src/dbus/types.rs | 119 +++++++----------- src/meson.build | 1 + 10 files changed, 683 insertions(+), 452 deletions(-) create mode 100644 src/dbus/listener.rs diff --git a/Cargo.lock b/Cargo.lock index 0e839cbd..d2be8efb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -47,9 +47,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.7.15" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" dependencies = [ "memchr", ] @@ -88,11 +88,22 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b585a98a234c46fc563103e9278c9391fde1f4e6850334da895d27edb9580f62" +[[package]] +name = "async-broadcast" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90622698a1218e0b2fb846c97b5f19a0831f6baddee73d9454156365ccfa473b" +dependencies = [ + "easy-parallel", + "event-listener", + "futures-core", +] + [[package]] name = "async-channel" -version = "1.5.1" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59740d83946db6a5af71ae25ddf9562c2b176b2ca42cf99a455f09f4a220d6b9" +checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319" dependencies = [ "concurrent-queue", "event-listener", @@ -101,16 +112,16 @@ dependencies = [ [[package]] name = "async-executor" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb877970c7b440ead138f6321a3b5395d6061183af779340b65e20c0fede9146" +checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965" dependencies = [ "async-task", "concurrent-queue", "fastrand", "futures-lite", "once_cell", - "vec-arena", + "slab", ] [[package]] @@ -167,6 +178,17 @@ dependencies = [ "event-listener", ] +[[package]] +name = "async-recursion" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7d78656ba01f1b93024b7c3a0467f1608e4be67d725749fdcd7d2c7678fd7a2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "async-std" version = "1.10.0" @@ -670,6 +692,12 @@ dependencies = [ "generic-array", ] +[[package]] +name = "easy-parallel" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6907e25393cdcc1f4f3f513d9aac1e840eb1cc341a0fccb01171f7d14d10b946" + [[package]] name = "either" version = "1.6.1" @@ -691,7 +719,17 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83c8d82922337cd23a15f88b70d8e4ef5f11da38dd7cdb55e84dd5de99695da0" dependencies = [ - "enumflags2_derive", + "enumflags2_derive 0.6.4", + "serde", +] + +[[package]] +name = "enumflags2" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a25c90b056b3f84111cf183cbeddef0d3a0bbe9a674f057e1a1533c315f24def" +dependencies = [ + "enumflags2_derive 0.7.3", "serde", ] @@ -706,6 +744,17 @@ dependencies = [ "syn", ] +[[package]] +name = "enumflags2_derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "144ec79496cbab6f84fa125dc67be9264aef22eb8a28da8454d9c33f15108da4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "env_logger" version = "0.8.4" @@ -1601,9 +1650,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.94" +version = "0.2.112" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e" +checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" [[package]] name = "libloading" @@ -1954,9 +2003,9 @@ checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" [[package]] name = "memchr" -version = "2.3.3" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" [[package]] name = "memoffset" @@ -2074,9 +2123,9 @@ dependencies = [ [[package]] name = "nix" -version = "0.19.1" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ccba0cfe4fdf15982d1674c69b1fd80bad427d293849982668dfe454bd61f2" +checksum = "fa9b4819da1bc61c0ea48b63b7bc8604064dd43013e7cc325df098d49cd7c18a" dependencies = [ "bitflags", "cc", @@ -2086,14 +2135,15 @@ dependencies = [ [[package]] name = "nix" -version = "0.20.0" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa9b4819da1bc61c0ea48b63b7bc8604064dd43013e7cc325df098d49cd7c18a" +checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" dependencies = [ "bitflags", "cc", "cfg-if 1.0.0", "libc", + "memoffset", ] [[package]] @@ -2339,6 +2389,16 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "ordered-stream" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44630c059eacfd6e08bdaa51b1db2ce33119caa4ddc1235e923109aa5f25ccb1" +dependencies = [ + "futures-core", + "pin-project-lite 0.2.4", +] + [[package]] name = "pango" version = "0.14.0" @@ -2719,9 +2779,9 @@ checksum = "2b5ceb840e4009da4841ed22a15eb49f64fdd00a2138945c5beacf506b2fb5ed" [[package]] name = "regex" -version = "1.4.6" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a26af418b574bd56588335b3a3659a65725d4e636eb1016c2f9e3b38c7cc759" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" dependencies = [ "aho-corasick", "memchr", @@ -2730,9 +2790,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.22" +version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] name = "remove_dir_all" @@ -2830,8 +2890,8 @@ dependencies = [ "sha2", "zbus 1.8.0", "zbus_macros 1.8.0", - "zvariant", - "zvariant_derive", + "zvariant 2.10.0", + "zvariant_derive 2.10.0", ] [[package]] @@ -2963,15 +3023,6 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" -[[package]] -name = "slotmap" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab3003725ae562cf995f3dc82bb99e70926e09000396816765bb6d7adbe740b1" -dependencies = [ - "version_check", -] - [[package]] name = "sluice" version = "0.5.4" @@ -3048,9 +3099,8 @@ dependencies = [ "serde_json", "thiserror", "tokio", - "zbus 2.0.0-beta.3", - "zvariant", - "zvariant_derive", + "zbus 2.0.1", + "zvariant 3.0.0", ] [[package]] @@ -3619,7 +3669,7 @@ dependencies = [ "async-io", "byteorder", "derivative", - "enumflags2", + "enumflags2 0.6.4", "fastrand", "futures", "nb-connect", @@ -3630,35 +3680,42 @@ dependencies = [ "serde", "serde_repr", "zbus_macros 1.8.0", - "zvariant", + "zvariant 2.10.0", ] [[package]] name = "zbus" -version = "2.0.0-beta.3" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e1e656194618d167524f97e88ff9bf87f2b1e8bf58f357b2a7abfdff8cc85c9" +checksum = "2ac8424f5aa1f239d2d7ecb32f9d5ffc6fcf5fb9298d2d524a7e7c8b258c3f80" dependencies = [ + "async-broadcast", + "async-channel", + "async-executor", "async-io", "async-lock", + "async-recursion", + "async-task", + "async-trait", "byteorder", "derivative", - "enumflags2", + "enumflags2 0.7.3", "event-listener", "futures-core", "futures-sink", "futures-util", "hex", - "nix 0.19.1", + "nix 0.23.1", "once_cell", + "ordered-stream", "rand 0.8.4", - "scoped-tls", "serde", "serde_repr", "sha1", - "slotmap", - "zbus_macros 2.0.0-beta.3", - "zvariant", + "static_assertions", + "zbus_macros 2.0.1", + "zbus_names", + "zvariant 3.0.0", ] [[package]] @@ -3675,16 +3732,28 @@ dependencies = [ [[package]] name = "zbus_macros" -version = "2.0.0-beta.3" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcd4cb372bc2cade3f2323e4104112dceb6819f5dd9afa98515b4e821d232932" +checksum = "3e03af45fc15e2c977161c5ffea56c43c41f425a963affd7074bf91b5bf5a8cf" dependencies = [ - "proc-macro-crate 0.1.5", + "proc-macro-crate 1.0.0", "proc-macro2", "quote", + "regex", "syn", ] +[[package]] +name = "zbus_names" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45dfcdcf87b71dad505d30cc27b1b7b88a64b6d1c435648f48f9dbc1fdc4b7e1" +dependencies = [ + "serde", + "static_assertions", + "zvariant 3.0.0", +] + [[package]] name = "zerocopy" version = "0.3.0" @@ -3713,11 +3782,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a68c7b55f2074489b7e8e07d2d0a6ee6b4f233867a653c664d8020ba53692525" dependencies = [ "byteorder", - "enumflags2", + "enumflags2 0.6.4", "libc", "serde", "static_assertions", - "zvariant_derive", + "zvariant_derive 2.10.0", +] + +[[package]] +name = "zvariant" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a946c049b2eac1a253f98e9267a8ce7a3d93be274ea146e6dd7a0965232a911" +dependencies = [ + "byteorder", + "enumflags2 0.7.3", + "libc", + "serde", + "static_assertions", + "zvariant_derive 3.0.0", ] [[package]] @@ -3731,3 +3814,15 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zvariant_derive" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28fce5afb8d639bff79b1e8cdb258a3ca22d458f4603b23d794b4cb4e878c990" +dependencies = [ + "proc-macro-crate 1.0.0", + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml index 4091a5ff..bfefb6fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,9 +63,8 @@ ref_filter_map = "^1.0.1" regex = "^1.4.6" async-std = "^1.10.0" form_urlencoded = "^1.0.1" -zbus = "^2.0.0-beta.3" -zvariant = "^2.10.0" -zvariant_derive = "^2.5.0" +zbus = "^2.0.1" +zvariant = "^3.0.0" thiserror = "^1.0.30" lazy_static = "^1.4.0" log = "0.4.14" diff --git a/build-aux/clippy.sh b/build-aux/clippy.sh index f60004bf..da649d85 100644 --- a/build-aux/clippy.sh +++ b/build-aux/clippy.sh @@ -8,4 +8,4 @@ if [[ $OFFLINE = "true" ]]; then export CARGO_HOME="$SRC"/cargo fi -cargo clippy --manifest-path "$SRC"/Cargo.toml -- -D warnings -A clippy::module_inception -A clippy::new_without_default +cargo clippy --manifest-path "$SRC"/Cargo.toml -- -D warnings -A clippy::module_inception -A clippy::new_without_default -A clippy::enum-variant-names diff --git a/cargo-sources.json b/cargo-sources.json index 785c60d5..ed2f2a84 100644 --- a/cargo-sources.json +++ b/cargo-sources.json @@ -53,15 +53,15 @@ }, { "type": "file", - "url": "https://static.crates.io/crates/aho-corasick/aho-corasick-0.7.15.crate", - "sha256": "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5", + "url": "https://static.crates.io/crates/aho-corasick/aho-corasick-0.7.18.crate", + "sha256": "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f", "dest": "cargo/vendor", - "dest-filename": "aho-corasick-0.7.15.crate" + "dest-filename": "aho-corasick-0.7.18.crate" }, { "type": "file", - "url": "data:%7B%22package%22%3A%20%227404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/aho-corasick-0.7.15", + "url": "data:%7B%22package%22%3A%20%221e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f%22%2C%20%22files%22%3A%20%7B%7D%7D", + "dest": "cargo/vendor/aho-corasick-0.7.18", "dest-filename": ".cargo-checksum.json" }, { @@ -118,28 +118,41 @@ }, { "type": "file", - "url": "https://static.crates.io/crates/async-channel/async-channel-1.5.1.crate", - "sha256": "59740d83946db6a5af71ae25ddf9562c2b176b2ca42cf99a455f09f4a220d6b9", + "url": "https://static.crates.io/crates/async-broadcast/async-broadcast-0.3.4.crate", + "sha256": "90622698a1218e0b2fb846c97b5f19a0831f6baddee73d9454156365ccfa473b", "dest": "cargo/vendor", - "dest-filename": "async-channel-1.5.1.crate" + "dest-filename": "async-broadcast-0.3.4.crate" }, { "type": "file", - "url": "data:%7B%22package%22%3A%20%2259740d83946db6a5af71ae25ddf9562c2b176b2ca42cf99a455f09f4a220d6b9%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/async-channel-1.5.1", + "url": "data:%7B%22package%22%3A%20%2290622698a1218e0b2fb846c97b5f19a0831f6baddee73d9454156365ccfa473b%22%2C%20%22files%22%3A%20%7B%7D%7D", + "dest": "cargo/vendor/async-broadcast-0.3.4", "dest-filename": ".cargo-checksum.json" }, { "type": "file", - "url": "https://static.crates.io/crates/async-executor/async-executor-1.4.0.crate", - "sha256": "eb877970c7b440ead138f6321a3b5395d6061183af779340b65e20c0fede9146", + "url": "https://static.crates.io/crates/async-channel/async-channel-1.6.1.crate", + "sha256": "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319", "dest": "cargo/vendor", - "dest-filename": "async-executor-1.4.0.crate" + "dest-filename": "async-channel-1.6.1.crate" }, { "type": "file", - "url": "data:%7B%22package%22%3A%20%22eb877970c7b440ead138f6321a3b5395d6061183af779340b65e20c0fede9146%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/async-executor-1.4.0", + "url": "data:%7B%22package%22%3A%20%222114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319%22%2C%20%22files%22%3A%20%7B%7D%7D", + "dest": "cargo/vendor/async-channel-1.6.1", + "dest-filename": ".cargo-checksum.json" + }, + { + "type": "file", + "url": "https://static.crates.io/crates/async-executor/async-executor-1.4.1.crate", + "sha256": "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965", + "dest": "cargo/vendor", + "dest-filename": "async-executor-1.4.1.crate" + }, + { + "type": "file", + "url": "data:%7B%22package%22%3A%20%22871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965%22%2C%20%22files%22%3A%20%7B%7D%7D", + "dest": "cargo/vendor/async-executor-1.4.1", "dest-filename": ".cargo-checksum.json" }, { @@ -194,6 +207,19 @@ "dest": "cargo/vendor/async-mutex-1.4.0", "dest-filename": ".cargo-checksum.json" }, + { + "type": "file", + "url": "https://static.crates.io/crates/async-recursion/async-recursion-0.3.2.crate", + "sha256": "d7d78656ba01f1b93024b7c3a0467f1608e4be67d725749fdcd7d2c7678fd7a2", + "dest": "cargo/vendor", + "dest-filename": "async-recursion-0.3.2.crate" + }, + { + "type": "file", + "url": "data:%7B%22package%22%3A%20%22d7d78656ba01f1b93024b7c3a0467f1608e4be67d725749fdcd7d2c7678fd7a2%22%2C%20%22files%22%3A%20%7B%7D%7D", + "dest": "cargo/vendor/async-recursion-0.3.2", + "dest-filename": ".cargo-checksum.json" + }, { "type": "file", "url": "https://static.crates.io/crates/async-std/async-std-1.10.0.crate", @@ -857,6 +883,19 @@ "dest": "cargo/vendor/digest-0.9.0", "dest-filename": ".cargo-checksum.json" }, + { + "type": "file", + "url": "https://static.crates.io/crates/easy-parallel/easy-parallel-3.2.0.crate", + "sha256": "6907e25393cdcc1f4f3f513d9aac1e840eb1cc341a0fccb01171f7d14d10b946", + "dest": "cargo/vendor", + "dest-filename": "easy-parallel-3.2.0.crate" + }, + { + "type": "file", + "url": "data:%7B%22package%22%3A%20%226907e25393cdcc1f4f3f513d9aac1e840eb1cc341a0fccb01171f7d14d10b946%22%2C%20%22files%22%3A%20%7B%7D%7D", + "dest": "cargo/vendor/easy-parallel-3.2.0", + "dest-filename": ".cargo-checksum.json" + }, { "type": "file", "url": "https://static.crates.io/crates/either/either-1.6.1.crate", @@ -896,6 +935,19 @@ "dest": "cargo/vendor/enumflags2-0.6.4", "dest-filename": ".cargo-checksum.json" }, + { + "type": "file", + "url": "https://static.crates.io/crates/enumflags2/enumflags2-0.7.3.crate", + "sha256": "a25c90b056b3f84111cf183cbeddef0d3a0bbe9a674f057e1a1533c315f24def", + "dest": "cargo/vendor", + "dest-filename": "enumflags2-0.7.3.crate" + }, + { + "type": "file", + "url": "data:%7B%22package%22%3A%20%22a25c90b056b3f84111cf183cbeddef0d3a0bbe9a674f057e1a1533c315f24def%22%2C%20%22files%22%3A%20%7B%7D%7D", + "dest": "cargo/vendor/enumflags2-0.7.3", + "dest-filename": ".cargo-checksum.json" + }, { "type": "file", "url": "https://static.crates.io/crates/enumflags2_derive/enumflags2_derive-0.6.4.crate", @@ -909,6 +961,19 @@ "dest": "cargo/vendor/enumflags2_derive-0.6.4", "dest-filename": ".cargo-checksum.json" }, + { + "type": "file", + "url": "https://static.crates.io/crates/enumflags2_derive/enumflags2_derive-0.7.3.crate", + "sha256": "144ec79496cbab6f84fa125dc67be9264aef22eb8a28da8454d9c33f15108da4", + "dest": "cargo/vendor", + "dest-filename": "enumflags2_derive-0.7.3.crate" + }, + { + "type": "file", + "url": "data:%7B%22package%22%3A%20%22144ec79496cbab6f84fa125dc67be9264aef22eb8a28da8454d9c33f15108da4%22%2C%20%22files%22%3A%20%7B%7D%7D", + "dest": "cargo/vendor/enumflags2_derive-0.7.3", + "dest-filename": ".cargo-checksum.json" + }, { "type": "file", "url": "https://static.crates.io/crates/env_logger/env_logger-0.8.4.crate", @@ -1938,15 +2003,15 @@ }, { "type": "file", - "url": "https://static.crates.io/crates/libc/libc-0.2.94.crate", - "sha256": "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e", + "url": "https://static.crates.io/crates/libc/libc-0.2.112.crate", + "sha256": "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125", "dest": "cargo/vendor", - "dest-filename": "libc-0.2.94.crate" + "dest-filename": "libc-0.2.112.crate" }, { "type": "file", - "url": "data:%7B%22package%22%3A%20%2218794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/libc-0.2.94", + "url": "data:%7B%22package%22%3A%20%221b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125%22%2C%20%22files%22%3A%20%7B%7D%7D", + "dest": "cargo/vendor/libc-0.2.112", "dest-filename": ".cargo-checksum.json" }, { @@ -2263,15 +2328,15 @@ }, { "type": "file", - "url": "https://static.crates.io/crates/memchr/memchr-2.3.3.crate", - "sha256": "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400", + "url": "https://static.crates.io/crates/memchr/memchr-2.4.1.crate", + "sha256": "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a", "dest": "cargo/vendor", - "dest-filename": "memchr-2.3.3.crate" + "dest-filename": "memchr-2.4.1.crate" }, { "type": "file", - "url": "data:%7B%22package%22%3A%20%223728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/memchr-2.3.3", + "url": "data:%7B%22package%22%3A%20%22308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a%22%2C%20%22files%22%3A%20%7B%7D%7D", + "dest": "cargo/vendor/memchr-2.4.1", "dest-filename": ".cargo-checksum.json" }, { @@ -2419,28 +2484,28 @@ }, { "type": "file", - "url": "https://static.crates.io/crates/nix/nix-0.19.1.crate", - "sha256": "b2ccba0cfe4fdf15982d1674c69b1fd80bad427d293849982668dfe454bd61f2", + "url": "https://static.crates.io/crates/nix/nix-0.20.0.crate", + "sha256": "fa9b4819da1bc61c0ea48b63b7bc8604064dd43013e7cc325df098d49cd7c18a", "dest": "cargo/vendor", - "dest-filename": "nix-0.19.1.crate" + "dest-filename": "nix-0.20.0.crate" }, { "type": "file", - "url": "data:%7B%22package%22%3A%20%22b2ccba0cfe4fdf15982d1674c69b1fd80bad427d293849982668dfe454bd61f2%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/nix-0.19.1", + "url": "data:%7B%22package%22%3A%20%22fa9b4819da1bc61c0ea48b63b7bc8604064dd43013e7cc325df098d49cd7c18a%22%2C%20%22files%22%3A%20%7B%7D%7D", + "dest": "cargo/vendor/nix-0.20.0", "dest-filename": ".cargo-checksum.json" }, { "type": "file", - "url": "https://static.crates.io/crates/nix/nix-0.20.0.crate", - "sha256": "fa9b4819da1bc61c0ea48b63b7bc8604064dd43013e7cc325df098d49cd7c18a", + "url": "https://static.crates.io/crates/nix/nix-0.23.1.crate", + "sha256": "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6", "dest": "cargo/vendor", - "dest-filename": "nix-0.20.0.crate" + "dest-filename": "nix-0.23.1.crate" }, { "type": "file", - "url": "data:%7B%22package%22%3A%20%22fa9b4819da1bc61c0ea48b63b7bc8604064dd43013e7cc325df098d49cd7c18a%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/nix-0.20.0", + "url": "data:%7B%22package%22%3A%20%229f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6%22%2C%20%22files%22%3A%20%7B%7D%7D", + "dest": "cargo/vendor/nix-0.23.1", "dest-filename": ".cargo-checksum.json" }, { @@ -2755,6 +2820,19 @@ "dest": "cargo/vendor/openssl-sys-0.9.56", "dest-filename": ".cargo-checksum.json" }, + { + "type": "file", + "url": "https://static.crates.io/crates/ordered-stream/ordered-stream-0.0.1.crate", + "sha256": "44630c059eacfd6e08bdaa51b1db2ce33119caa4ddc1235e923109aa5f25ccb1", + "dest": "cargo/vendor", + "dest-filename": "ordered-stream-0.0.1.crate" + }, + { + "type": "file", + "url": "data:%7B%22package%22%3A%20%2244630c059eacfd6e08bdaa51b1db2ce33119caa4ddc1235e923109aa5f25ccb1%22%2C%20%22files%22%3A%20%7B%7D%7D", + "dest": "cargo/vendor/ordered-stream-0.0.1", + "dest-filename": ".cargo-checksum.json" + }, { "type": "file", "url": "https://static.crates.io/crates/pango/pango-0.14.0.crate", @@ -3290,28 +3368,28 @@ }, { "type": "file", - "url": "https://static.crates.io/crates/regex/regex-1.4.6.crate", - "sha256": "2a26af418b574bd56588335b3a3659a65725d4e636eb1016c2f9e3b38c7cc759", + "url": "https://static.crates.io/crates/regex/regex-1.5.4.crate", + "sha256": "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461", "dest": "cargo/vendor", - "dest-filename": "regex-1.4.6.crate" + "dest-filename": "regex-1.5.4.crate" }, { "type": "file", - "url": "data:%7B%22package%22%3A%20%222a26af418b574bd56588335b3a3659a65725d4e636eb1016c2f9e3b38c7cc759%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/regex-1.4.6", + "url": "data:%7B%22package%22%3A%20%22d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461%22%2C%20%22files%22%3A%20%7B%7D%7D", + "dest": "cargo/vendor/regex-1.5.4", "dest-filename": ".cargo-checksum.json" }, { "type": "file", - "url": "https://static.crates.io/crates/regex-syntax/regex-syntax-0.6.22.crate", - "sha256": "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581", + "url": "https://static.crates.io/crates/regex-syntax/regex-syntax-0.6.25.crate", + "sha256": "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b", "dest": "cargo/vendor", - "dest-filename": "regex-syntax-0.6.22.crate" + "dest-filename": "regex-syntax-0.6.25.crate" }, { "type": "file", - "url": "data:%7B%22package%22%3A%20%22b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/regex-syntax-0.6.22", + "url": "data:%7B%22package%22%3A%20%22f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b%22%2C%20%22files%22%3A%20%7B%7D%7D", + "dest": "cargo/vendor/regex-syntax-0.6.25", "dest-filename": ".cargo-checksum.json" }, { @@ -3639,19 +3717,6 @@ "dest": "cargo/vendor/slab-0.4.2", "dest-filename": ".cargo-checksum.json" }, - { - "type": "file", - "url": "https://static.crates.io/crates/slotmap/slotmap-1.0.2.crate", - "sha256": "ab3003725ae562cf995f3dc82bb99e70926e09000396816765bb6d7adbe740b1", - "dest": "cargo/vendor", - "dest-filename": "slotmap-1.0.2.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22ab3003725ae562cf995f3dc82bb99e70926e09000396816765bb6d7adbe740b1%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/slotmap-1.0.2", - "dest-filename": ".cargo-checksum.json" - }, { "type": "file", "url": "https://static.crates.io/crates/sluice/sluice-0.5.4.crate", @@ -4525,15 +4590,15 @@ }, { "type": "file", - "url": "https://static.crates.io/crates/zbus/zbus-2.0.0-beta.3.crate", - "sha256": "3e1e656194618d167524f97e88ff9bf87f2b1e8bf58f357b2a7abfdff8cc85c9", + "url": "https://static.crates.io/crates/zbus/zbus-2.0.1.crate", + "sha256": "2ac8424f5aa1f239d2d7ecb32f9d5ffc6fcf5fb9298d2d524a7e7c8b258c3f80", "dest": "cargo/vendor", - "dest-filename": "zbus-2.0.0-beta.3.crate" + "dest-filename": "zbus-2.0.1.crate" }, { "type": "file", - "url": "data:%7B%22package%22%3A%20%223e1e656194618d167524f97e88ff9bf87f2b1e8bf58f357b2a7abfdff8cc85c9%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/zbus-2.0.0-beta.3", + "url": "data:%7B%22package%22%3A%20%222ac8424f5aa1f239d2d7ecb32f9d5ffc6fcf5fb9298d2d524a7e7c8b258c3f80%22%2C%20%22files%22%3A%20%7B%7D%7D", + "dest": "cargo/vendor/zbus-2.0.1", "dest-filename": ".cargo-checksum.json" }, { @@ -4551,15 +4616,28 @@ }, { "type": "file", - "url": "https://static.crates.io/crates/zbus_macros/zbus_macros-2.0.0-beta.3.crate", - "sha256": "fcd4cb372bc2cade3f2323e4104112dceb6819f5dd9afa98515b4e821d232932", + "url": "https://static.crates.io/crates/zbus_macros/zbus_macros-2.0.1.crate", + "sha256": "3e03af45fc15e2c977161c5ffea56c43c41f425a963affd7074bf91b5bf5a8cf", "dest": "cargo/vendor", - "dest-filename": "zbus_macros-2.0.0-beta.3.crate" + "dest-filename": "zbus_macros-2.0.1.crate" }, { "type": "file", - "url": "data:%7B%22package%22%3A%20%22fcd4cb372bc2cade3f2323e4104112dceb6819f5dd9afa98515b4e821d232932%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/zbus_macros-2.0.0-beta.3", + "url": "data:%7B%22package%22%3A%20%223e03af45fc15e2c977161c5ffea56c43c41f425a963affd7074bf91b5bf5a8cf%22%2C%20%22files%22%3A%20%7B%7D%7D", + "dest": "cargo/vendor/zbus_macros-2.0.1", + "dest-filename": ".cargo-checksum.json" + }, + { + "type": "file", + "url": "https://static.crates.io/crates/zbus_names/zbus_names-2.1.0.crate", + "sha256": "45dfcdcf87b71dad505d30cc27b1b7b88a64b6d1c435648f48f9dbc1fdc4b7e1", + "dest": "cargo/vendor", + "dest-filename": "zbus_names-2.1.0.crate" + }, + { + "type": "file", + "url": "data:%7B%22package%22%3A%20%2245dfcdcf87b71dad505d30cc27b1b7b88a64b6d1c435648f48f9dbc1fdc4b7e1%22%2C%20%22files%22%3A%20%7B%7D%7D", + "dest": "cargo/vendor/zbus_names-2.1.0", "dest-filename": ".cargo-checksum.json" }, { @@ -4601,6 +4679,19 @@ "dest": "cargo/vendor/zvariant-2.10.0", "dest-filename": ".cargo-checksum.json" }, + { + "type": "file", + "url": "https://static.crates.io/crates/zvariant/zvariant-3.0.0.crate", + "sha256": "4a946c049b2eac1a253f98e9267a8ce7a3d93be274ea146e6dd7a0965232a911", + "dest": "cargo/vendor", + "dest-filename": "zvariant-3.0.0.crate" + }, + { + "type": "file", + "url": "data:%7B%22package%22%3A%20%224a946c049b2eac1a253f98e9267a8ce7a3d93be274ea146e6dd7a0965232a911%22%2C%20%22files%22%3A%20%7B%7D%7D", + "dest": "cargo/vendor/zvariant-3.0.0", + "dest-filename": ".cargo-checksum.json" + }, { "type": "file", "url": "https://static.crates.io/crates/zvariant_derive/zvariant_derive-2.10.0.crate", @@ -4614,6 +4705,19 @@ "dest": "cargo/vendor/zvariant_derive-2.10.0", "dest-filename": ".cargo-checksum.json" }, + { + "type": "file", + "url": "https://static.crates.io/crates/zvariant_derive/zvariant_derive-3.0.0.crate", + "sha256": "28fce5afb8d639bff79b1e8cdb258a3ca22d458f4603b23d794b4cb4e878c990", + "dest": "cargo/vendor", + "dest-filename": "zvariant_derive-3.0.0.crate" + }, + { + "type": "file", + "url": "data:%7B%22package%22%3A%20%2228fce5afb8d639bff79b1e8cdb258a3ca22d458f4603b23d794b4cb4e878c990%22%2C%20%22files%22%3A%20%7B%7D%7D", + "dest": "cargo/vendor/zvariant_derive-3.0.0", + "dest-filename": ".cargo-checksum.json" + }, { "type": "shell", "dest": "cargo/vendor", diff --git a/src/app/mod.rs b/src/app/mod.rs index d635e5c9..af0291a3 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -109,7 +109,7 @@ impl App { app_model: Rc, sender: UnboundedSender, ) -> Box { - Box::new(crate::dbus::start_dbus_server(app_model, sender).expect("could not start server")) + Box::new(crate::dbus::start_dbus_server(app_model, sender)) } fn make_window( diff --git a/src/dbus/listener.rs b/src/dbus/listener.rs new file mode 100644 index 00000000..bda57021 --- /dev/null +++ b/src/dbus/listener.rs @@ -0,0 +1,141 @@ +use futures::channel::mpsc::UnboundedSender; +use std::rc::Rc; + +use crate::app::{ + components::EventListener, + models::SongDescription, + state::{PlaybackEvent, RepeatMode}, + AppEvent, AppModel, +}; + +use super::types::{LoopStatus, PlaybackStatus, TrackMetadata}; + +#[derive(Debug)] +pub enum MprisStateUpdate { + SetVolume(f64), + SetCurrentTrack { + has_prev: bool, + current: Option, + has_next: bool, + }, + SetPositionMs(u128), + SetLoopStatus { + has_prev: bool, + loop_status: LoopStatus, + has_next: bool, + }, + SetShuffled(bool), + SetPlaying(PlaybackStatus), +} + +pub struct AppPlaybackStateListener { + app_model: Rc, + sender: UnboundedSender, +} + +impl AppPlaybackStateListener { + pub fn new(app_model: Rc, sender: UnboundedSender) -> Self { + Self { app_model, sender } + } + + fn make_track_meta(&self) -> Option { + self.app_model + .get_state() + .playback + .current_song() + .cloned() + .map( + |SongDescription { + id, + title, + artists, + album, + duration, + art, + .. + }| TrackMetadata { + id: format!("/dev/alextren/Spot/Track/{}", id), + length: 1000 * duration as u64, + title, + album: album.name, + artist: artists.into_iter().map(|a| a.name).collect(), + art, + }, + ) + } + + fn has_prev_next(&self) -> (bool, bool) { + let state = self.app_model.get_state(); + ( + state.playback.prev_song().is_some(), + state.playback.next_song().is_some(), + ) + } + + fn is_shuffled(&self) -> bool { + let state = self.app_model.get_state(); + state.playback.is_shuffled() + } + + fn loop_status(&self) -> LoopStatus { + let state = self.app_model.get_state(); + match state.playback.repeat_mode() { + RepeatMode::None => LoopStatus::None, + RepeatMode::Song => LoopStatus::Track, + RepeatMode::Playlist => LoopStatus::Playlist, + } + } + + fn update_for(&self, event: &PlaybackEvent) -> Option { + match event { + PlaybackEvent::PlaybackPaused => { + Some(MprisStateUpdate::SetPlaying(PlaybackStatus::Paused)) + } + PlaybackEvent::PlaybackResumed => { + Some(MprisStateUpdate::SetPlaying(PlaybackStatus::Playing)) + } + PlaybackEvent::PlaybackStopped => { + Some(MprisStateUpdate::SetPlaying(PlaybackStatus::Stopped)) + } + PlaybackEvent::TrackChanged(_) => { + let current = self.make_track_meta(); + let (has_prev, has_next) = self.has_prev_next(); + Some(MprisStateUpdate::SetCurrentTrack { + has_prev, + has_next, + current, + }) + } + PlaybackEvent::RepeatModeChanged(_) => { + let loop_status = self.loop_status(); + let (has_prev, has_next) = self.has_prev_next(); + Some(MprisStateUpdate::SetLoopStatus { + has_prev, + has_next, + loop_status, + }) + } + PlaybackEvent::ShuffleChanged => { + Some(MprisStateUpdate::SetShuffled(self.is_shuffled())) + } + PlaybackEvent::TrackSeeked(pos) | PlaybackEvent::SeekSynced(pos) => { + let pos = 1000 * (*pos as u128); + Some(MprisStateUpdate::SetPositionMs(pos)) + } + PlaybackEvent::VolumeSet(vol) => Some(MprisStateUpdate::SetVolume(*vol)), + _ => None, + } + } +} + +impl EventListener for AppPlaybackStateListener { + fn on_event(&mut self, event: &AppEvent) { + if let AppEvent::PlaybackEvent(event) = event { + if let Some(update) = self.update_for(event) { + self.sender + .unbounded_send(update) + .expect("Could not send event to DBUS server"); + } + } + } +} diff --git a/src/dbus/mod.rs b/src/dbus/mod.rs index b0fc8482..53bd8e17 100644 --- a/src/dbus/mod.rs +++ b/src/dbus/mod.rs @@ -1,213 +1,109 @@ -use futures::channel::mpsc::UnboundedSender; +use futures::channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender}; +use futures::StreamExt; use std::rc::Rc; use std::thread; -use zbus::fdo; +use zbus::Connection; -use crate::app::components::EventListener; -use crate::app::state::{PlaybackEvent, RepeatMode}; -use crate::app::{models::SongDescription, AppAction, AppEvent, AppModel}; +use crate::app::{AppAction, AppModel}; mod mpris; pub use mpris::*; mod types; -use types::*; -// This one wraps a connection and reads the app state -pub struct AppPlaybackStateListener { - object_server: zbus::ObjectServer, - app_model: Rc, -} - -impl AppPlaybackStateListener { - fn new( - connection: zbus::Connection, - mpris: SpotMpris, - player: SpotMprisPlayer, - app_model: Rc, - ) -> Result { - let object_server = register_mpris(&connection, mpris, player)?; - Ok(Self { - object_server, - app_model, - }) - } - - fn with_player zbus::Result<()>>(&self, f: F) -> zbus::Result<()> { - self.object_server - .with("/org/mpris/MediaPlayer2", |iface: &SpotMprisPlayer| { - f(iface) - }) - } - - fn make_track_meta(&self) -> Option { - self.app_model - .get_state() - .playback - .current_song() - .cloned() - .map( - |SongDescription { - id, - title, - artists, - album, - duration, - art, - .. - }| TrackMetadata { - id: format!("/dev/alextren/Spot/Track/{}", id), - length: 1000 * duration as u64, - title, - album: album.name, - artist: artists.into_iter().map(|a| a.name).collect(), - art, - }, - ) - } - - fn has_prev_next(&self) -> (bool, bool) { - let state = self.app_model.get_state(); - ( - state.playback.prev_song().is_some(), - state.playback.next_song().is_some(), - ) - } - - fn is_shuffled(&self) -> bool { - let state = self.app_model.get_state(); - state.playback.is_shuffled() - } - - fn loop_status(&self) -> LoopStatus { - let state = self.app_model.get_state(); - match state.playback.repeat_mode() { - RepeatMode::None => LoopStatus::None, - RepeatMode::Song => LoopStatus::Track, - RepeatMode::Playlist => LoopStatus::Playlist, - } - } -} - -impl EventListener for AppPlaybackStateListener { - fn on_event(&mut self, event: &AppEvent) { - match event { - AppEvent::PlaybackEvent(PlaybackEvent::PlaybackPaused) => { - self.with_player(|player| { - player.state.set_playing(PlaybackStatus::Paused); - player.notify_playback_status()?; - Ok(()) - }) - .unwrap(); - } - AppEvent::PlaybackEvent(PlaybackEvent::PlaybackResumed) => { - self.with_player(|player| { - player.state.set_playing(PlaybackStatus::Playing); - player.notify_playback_status()?; - Ok(()) - }) - .unwrap(); - } - AppEvent::PlaybackEvent(PlaybackEvent::PlaybackStopped) => { - self.with_player(|player| { - player.state.set_playing(PlaybackStatus::Stopped); - player.notify_playback_status()?; - Ok(()) - }) - .unwrap(); - } - AppEvent::PlaybackEvent(PlaybackEvent::TrackChanged(_)) => { - self.with_player(|player| { - let meta = self.make_track_meta(); - let (has_prev, has_next) = self.has_prev_next(); - player.state.set_current_track(meta); - player.state.set_has_prev(has_prev); - player.state.set_has_next(has_next); - player.notify_metadata_and_prev_next()?; - Ok(()) - }) - .unwrap(); - } - AppEvent::PlaybackEvent(PlaybackEvent::RepeatModeChanged(_)) => { - self.with_player(|player| { - let (has_prev, has_next) = self.has_prev_next(); - player.state.set_loop_status(self.loop_status()); - player.loop_status_changed()?; - player.state.set_has_prev(has_prev); - player.state.set_has_next(has_next); - player.notify_metadata_and_prev_next()?; - Ok(()) - }) - .unwrap(); - } - AppEvent::PlaybackEvent(PlaybackEvent::ShuffleChanged) => { - self.with_player(|player| { - player.state.set_shuffled(self.is_shuffled()); - player.shuffle_changed()?; - Ok(()) - }) - .unwrap(); - } - AppEvent::PlaybackEvent(PlaybackEvent::TrackSeeked(pos)) - | AppEvent::PlaybackEvent(PlaybackEvent::SeekSynced(pos)) => { - self.with_player(|player| { - let pos = 1000 * (*pos as u128); - player.state.set_position(pos); - player.seeked(pos as i64)?; - Ok(()) - }) - .unwrap(); - } - AppEvent::PlaybackEvent(PlaybackEvent::VolumeSet(vol)) => { - self.with_player(|player| { - player.state.set_volume(*vol); - Ok(()) - }) - .unwrap(); - } - _ => {} - } - } -} +mod listener; +use listener::*; -fn register_mpris( - connection: &zbus::Connection, +#[tokio::main] +async fn dbus_server( mpris: SpotMpris, player: SpotMprisPlayer, -) -> Result { - let mut object_server = zbus::ObjectServer::new(connection); - object_server.at("/org/mpris/MediaPlayer2", mpris)?; - object_server.at("/org/mpris/MediaPlayer2", player)?; - Ok(object_server) + receiver: UnboundedReceiver, +) -> zbus::Result<()> { + let connection = Connection::session().await?; + connection + .object_server() + .at("/org/mpris/MediaPlayer2", mpris) + .await?; + connection + .object_server() + .at("/org/mpris/MediaPlayer2", player) + .await?; + connection + .request_name("org.mpris.MediaPlayer2.Spot") + .await?; + + receiver + .for_each(|update| async { + if let Ok(player_ref) = connection + .object_server() + .interface::<_, SpotMprisPlayer>("/org/mpris/MediaPlayer2") + .await + { + let mut player = player_ref.get_mut().await; + let ctxt = player_ref.signal_context(); + let res: zbus::Result<()> = match update { + MprisStateUpdate::SetVolume(volume) => { + player.state_mut().set_volume(volume); + player.volume_changed(ctxt).await + } + MprisStateUpdate::SetCurrentTrack { + has_prev, + has_next, + current, + } => { + player.state_mut().set_has_prev(has_prev); + player.state_mut().set_has_next(has_next); + player.state_mut().set_current_track(current); + player + .notify_current_track_changed(ctxt.to_owned()) + .await + .map_err(|e| zbus::Error::FDO(Box::new(e))) + } + MprisStateUpdate::SetPositionMs(position) => { + player.state_mut().set_position(position); + Ok(()) + } + MprisStateUpdate::SetLoopStatus { + has_prev, + has_next, + loop_status, + } => { + player.state_mut().set_has_prev(has_prev); + player.state_mut().set_has_next(has_next); + player.state_mut().set_loop_status(loop_status); + player + .notify_loop_status(ctxt.to_owned()) + .await + .map_err(|e| zbus::Error::FDO(Box::new(e))) + } + MprisStateUpdate::SetShuffled(shuffled) => { + player.state_mut().set_shuffled(shuffled); + player.shuffle_changed(ctxt).await + } + MprisStateUpdate::SetPlaying(status) => { + player.state_mut().set_playing(status); + player.playback_status_changed(ctxt).await + } + }; + res.expect("Signal emission failed"); + } + }) + .await; + + Ok(()) } pub fn start_dbus_server( app_model: Rc, sender: UnboundedSender, -) -> Result { - let state = SharedMprisState::new(); - - let connection = zbus::Connection::new_session()?; - fdo::DBusProxy::new(&connection)?.request_name( - "org.mpris.MediaPlayer2.Spot", - fdo::RequestNameFlags::AllowReplacement.into(), - )?; - +) -> AppPlaybackStateListener { let mpris = SpotMpris::new(sender.clone()); - let player = SpotMprisPlayer::new(state, sender); + let player = SpotMprisPlayer::new(sender); - let mpris_clone = mpris.clone(); - let player_clone = player.clone(); - let conn_clone = connection.clone(); + let (sender, receiver) = unbounded(); - thread::spawn(move || { - let mut object_server = register_mpris(&conn_clone, mpris_clone, player_clone).unwrap(); - loop { - if let Err(err) = object_server.try_handle_next() { - error!("{}", err); - } - } - }); + thread::spawn(move || dbus_server(mpris, player, receiver)); - AppPlaybackStateListener::new(connection, mpris, player, app_model) + AppPlaybackStateListener::new(app_model, sender) } diff --git a/src/dbus/mpris.rs b/src/dbus/mpris.rs index c666e553..f709bab7 100644 --- a/src/dbus/mpris.rs +++ b/src/dbus/mpris.rs @@ -1,12 +1,13 @@ #![allow(non_snake_case)] #![allow(unused_variables)] +use std::collections::HashMap; +use std::convert::TryInto; + use futures::channel::mpsc::UnboundedSender; -use std::convert::{Into, TryInto}; -use zbus::dbus_interface; use zbus::fdo::{Error, Result}; -use zbus::ObjectServer; -use zvariant::ObjectPath; +use zbus::{dbus_interface, Interface, SignalContext}; +use zvariant::{ObjectPath, Value}; use super::types::*; use crate::app::state::RepeatMode; @@ -71,21 +72,27 @@ impl SpotMpris { } } -#[derive(Clone)] pub struct SpotMprisPlayer { - pub state: SharedMprisState, + state: MprisState, sender: UnboundedSender, } impl SpotMprisPlayer { - pub fn new(state: SharedMprisState, sender: UnboundedSender) -> Self { - Self { state, sender } + pub fn new(sender: UnboundedSender) -> Self { + Self { + state: MprisState::new(), + sender, + } + } + + pub fn state_mut(&mut self) -> &mut MprisState { + &mut self.state } } #[dbus_interface(interface = "org.mpris.MediaPlayer2.Player")] impl SpotMprisPlayer { - pub fn next(&mut self) -> Result<()> { + pub fn next(&self) -> Result<()> { self.sender .unbounded_send(PlaybackAction::Next.into()) .map_err(|_| Error::Failed("Could not send action".to_string())) @@ -107,48 +114,62 @@ impl SpotMprisPlayer { .map_err(|_| Error::Failed("Could not send action".to_string())) } - pub fn play_pause(&mut self) -> Result<()> { + pub fn play_pause(&self) -> Result<()> { self.sender .unbounded_send(PlaybackAction::TogglePlay.into()) .map_err(|_| Error::Failed("Could not send action".to_string())) } - pub fn notify_playback_status(&self) -> zbus::Result<()> { - let invalidated: Vec = vec![]; - let mut changed = std::collections::HashMap::new(); - changed.insert( - "PlaybackStatus", - zvariant::Value::from(self.playback_status()), - ); - ObjectServer::local_node_emit_signal( - None, - "org.freedesktop.DBus.Properties", - "PropertiesChanged", - &("org.mpris.MediaPlayer2.Player", changed, invalidated), + pub async fn notify_current_track_changed( + &self, + #[zbus(signal_context)] ctxt: SignalContext<'_>, + ) -> Result<()> { + let metadata = Value::from(self.metadata()); + let can_go_next = Value::from(self.can_go_next()); + let can_go_previous = Value::from(self.can_go_previous()); + + zbus::fdo::Properties::properties_changed( + &ctxt, + Self::name(), + &HashMap::from([ + ("Metadata", &metadata), + ("CanGoNext", &can_go_next), + ("CanGoPrevious", &can_go_previous), + ]), + &[], ) - } - - pub fn notify_metadata_and_prev_next(&self) -> zbus::Result<()> { - let invalidated: Vec = vec![]; - let mut changed = std::collections::HashMap::new(); - changed.insert("Metadata", zvariant::Value::from(self.metadata())); - changed.insert("CanGoNext", zvariant::Value::from(self.can_go_next())); - changed.insert( - "CanGoPrevious", - zvariant::Value::from(self.can_go_previous()), - ); - ObjectServer::local_node_emit_signal( - None, - "org.freedesktop.DBus.Properties", - "PropertiesChanged", - &("org.mpris.MediaPlayer2.Player", changed, invalidated), + .await?; + + Ok(()) + } + + pub async fn notify_loop_status( + &self, + #[zbus(signal_context)] ctxt: SignalContext<'_>, + ) -> Result<()> { + let loop_status = Value::from(self.loop_status()); + let can_go_next = Value::from(self.can_go_next()); + let can_go_previous = Value::from(self.can_go_previous()); + + zbus::fdo::Properties::properties_changed( + &ctxt, + Self::name(), + &HashMap::from([ + ("LoopStatus", &loop_status), + ("CanGoNext", &can_go_next), + ("CanGoPrevious", &can_go_previous), + ]), + &[], ) + .await?; + + Ok(()) } - fn previous(&mut self) -> Result<()> { + pub fn previous(&self) -> Result<()> { self.sender .unbounded_send(PlaybackAction::Previous.into()) - .map_err(|_| zbus::fdo::Error::Failed("Could not send action".to_string())) + .map_err(|_| Error::Failed("Could not send action".to_string())) } pub fn seek(&self, Offset: i64) -> Result<()> { @@ -164,7 +185,7 @@ impl SpotMprisPlayer { let new_pos: u32 = (new_pos) .try_into() - .map_err(|_| zbus::fdo::Error::Failed("Could not parse position".to_string()))?; + .map_err(|_| Error::Failed("Could not parse position".to_string()))?; // As per spec, if new position is past the length of the song skip to // the next song @@ -175,7 +196,7 @@ impl SpotMprisPlayer { } else { self.sender .unbounded_send(PlaybackAction::Seek(new_pos).into()) - .map_err(|_| zbus::fdo::Error::Failed("Could not send action".to_string())) + .map_err(|_| Error::Failed("Could not send action".to_string())) } } @@ -188,9 +209,11 @@ impl SpotMprisPlayer { return Ok(()); } - let length: i64 = self.metadata().length.try_into().map_err(|_| { - zbus::fdo::Error::Failed("Could not cast length (too large)".to_string()) - })?; + let length: i64 = self + .metadata() + .length + .try_into() + .map_err(|_| Error::Failed("Could not cast length (too large)".to_string()))?; if Position > length { return Ok(()); @@ -198,11 +221,11 @@ impl SpotMprisPlayer { let pos: u32 = (Position / 1000) .try_into() - .map_err(|_| zbus::fdo::Error::Failed("Could not parse position".to_string()))?; + .map_err(|_| Error::Failed("Could not parse position".to_string()))?; self.sender .unbounded_send(PlaybackAction::Seek(pos).into()) - .map_err(|_| zbus::fdo::Error::Failed("Could not send action".to_string())) + .map_err(|_| Error::Failed("Could not send action".to_string())) } pub fn stop(&self) -> Result<()> { @@ -210,8 +233,7 @@ impl SpotMprisPlayer { } #[dbus_interface(signal)] - #[rustfmt::skip] - pub fn seeked(&self, Position: i64) -> zbus::Result<()>; + pub async fn seeked(ctxt: &SignalContext<'_>, Position: i64) -> zbus::Result<()>; #[dbus_interface(property)] pub fn can_control(&self) -> bool { @@ -250,14 +272,17 @@ impl SpotMprisPlayer { #[dbus_interface(property)] pub fn metadata(&self) -> TrackMetadata { - self.state.current_track().unwrap_or(TrackMetadata { - id: String::new(), - length: 0, - title: "Not playing".to_string(), - artist: vec![], - album: String::new(), - art: None, - }) + self.state + .current_track() + .cloned() + .unwrap_or_else(|| TrackMetadata { + id: String::new(), + length: 0, + title: "Not playing".to_string(), + artist: vec![], + album: String::new(), + art: None, + }) } #[dbus_interface(property)] @@ -276,7 +301,7 @@ impl SpotMprisPlayer { } #[dbus_interface(property)] - pub fn set_loop_status(&self, value: LoopStatus) -> Result<()> { + pub fn set_loop_status(&self, value: LoopStatus) -> zbus::Result<()> { let mode = match value { LoopStatus::None => RepeatMode::None, LoopStatus::Track => RepeatMode::Song, @@ -284,7 +309,8 @@ impl SpotMprisPlayer { }; self.sender .unbounded_send(PlaybackAction::SetRepeatMode(mode).into()) - .map_err(|_| zbus::fdo::Error::Failed("Could not send action".to_string())) + .map_err(|_| Error::Failed("Could not send action".to_string()))?; + Ok(()) } #[dbus_interface(property)] @@ -306,10 +332,11 @@ impl SpotMprisPlayer { } #[dbus_interface(property)] - pub fn set_shuffle(&self, value: bool) -> Result<()> { + pub fn set_shuffle(&self, value: bool) -> zbus::Result<()> { self.sender .unbounded_send(PlaybackAction::ToggleShuffle.into()) - .map_err(|_| zbus::fdo::Error::Failed("Could not send action".to_string())) + .map_err(|_| Error::Failed("Could not send action".to_string()))?; + Ok(()) } #[dbus_interface(property)] @@ -318,12 +345,13 @@ impl SpotMprisPlayer { } #[dbus_interface(property)] - pub fn set_volume(&self, value: f64) -> Result<()> { + pub fn set_volume(&self, value: f64) -> zbus::Result<()> { // As per spec, if new volume less than 0 round to 0 // also, we don't support volume higher than 100% at the moment. let volume = value.clamp(0.0, 1.0); self.sender .unbounded_send(PlaybackAction::SetVolume(value).into()) - .map_err(|_| zbus::fdo::Error::Failed("Could not send action".to_string())) + .map_err(|_| Error::Failed("Could not send action".to_string()))?; + Ok(()) } } diff --git a/src/dbus/types.rs b/src/dbus/types.rs index 6895427f..aea0429b 100644 --- a/src/dbus/types.rs +++ b/src/dbus/types.rs @@ -1,5 +1,4 @@ use std::convert::{Into, TryFrom}; -use std::sync::{Arc, Mutex}; use std::time::Instant; use zvariant::Type; use zvariant::{Dict, Signature, Str, Value}; @@ -82,6 +81,7 @@ impl PositionMicros { rate, } } + fn current(&self) -> u128 { let current_progress = self.last_resume_instant.map(|ri| { let elapsed = ri.elapsed().as_micros() as f32; @@ -106,7 +106,7 @@ impl PositionMicros { } } -#[derive(Clone)] +#[derive(Debug, Clone)] pub struct TrackMetadata { pub id: String, pub length: u64, @@ -144,7 +144,7 @@ impl From for Value<'_> { } } -struct MprisState { +pub struct MprisState { status: PlaybackStatus, loop_status: LoopStatus, volume: f64, @@ -155,12 +155,9 @@ struct MprisState { has_next: bool, } -#[derive(Clone)] -pub struct SharedMprisState(Arc>); - -impl SharedMprisState { +impl MprisState { pub fn new() -> Self { - Self(Arc::new(Mutex::new(MprisState { + Self { status: PlaybackStatus::Stopped, loop_status: LoopStatus::None, shuffled: false, @@ -169,113 +166,83 @@ impl SharedMprisState { has_prev: false, has_next: false, volume: 1f64, - }))) + } } pub fn volume(&self) -> f64 { - self.0 - .lock() - .map(|s| s.volume) - .map_err(|e| error!("Failed to get volume: {:?}", e)) - .unwrap_or(1.0f64) + self.volume } - pub fn set_volume(&self, volume: f64) { - if let Ok(mut state) = self.0.lock() { - (*state).volume = volume; - } + pub fn set_volume(&mut self, volume: f64) { + self.volume = volume; } pub fn status(&self) -> PlaybackStatus { - self.0 - .lock() - .map(|s| s.status) - .unwrap_or(PlaybackStatus::Stopped) + self.status } pub fn loop_status(&self) -> LoopStatus { - self.0 - .lock() - .map(|s| s.loop_status) - .unwrap_or(LoopStatus::None) + self.loop_status } pub fn is_shuffled(&self) -> bool { - self.0.lock().ok().map(|s| s.shuffled).unwrap_or(false) + self.shuffled } - pub fn current_track(&self) -> Option { - self.0.lock().ok().and_then(|s| s.metadata.clone()) + pub fn current_track(&self) -> Option<&TrackMetadata> { + self.metadata.as_ref() } pub fn has_prev(&self) -> bool { - self.0.lock().ok().map(|s| s.has_prev).unwrap_or(false) + self.has_prev } pub fn has_next(&self) -> bool { - self.0.lock().ok().map(|s| s.has_next).unwrap_or(false) + self.has_next } - pub fn set_has_prev(&self, has_prev: bool) { - if let Ok(mut state) = self.0.lock() { - (*state).has_prev = has_prev; - } + pub fn set_has_prev(&mut self, has_prev: bool) { + self.has_prev = has_prev; } - pub fn set_has_next(&self, has_next: bool) { - if let Ok(mut state) = self.0.lock() { - (*state).has_next = has_next; - } + pub fn set_has_next(&mut self, has_next: bool) { + self.has_next = has_next; } - pub fn set_current_track(&self, track: Option) { - if let Ok(mut state) = self.0.lock() { - let playing = state.status == PlaybackStatus::Playing; - (*state).metadata = track; - (*state).position.set(0, playing); - } + pub fn set_current_track(&mut self, track: Option) { + let playing = self.status == PlaybackStatus::Playing; + self.metadata = track; + self.position.set(0, playing); } pub fn position(&self) -> u128 { - self.0 - .lock() - .ok() - .map(|s| s.position.current()) - .unwrap_or(0) + self.position.current() } - pub fn set_position(&self, position: u128) { - if let Ok(mut state) = self.0.lock() { - let playing = state.status == PlaybackStatus::Playing; - (*state).position.set(position, playing); - } + pub fn set_position(&mut self, position: u128) { + let playing = self.status == PlaybackStatus::Playing; + self.position.set(position, playing); } - pub fn set_loop_status(&self, loop_status: LoopStatus) { - if let Ok(mut state) = self.0.lock() { - (*state).loop_status = loop_status; - } + pub fn set_loop_status(&mut self, loop_status: LoopStatus) { + self.loop_status = loop_status; } - pub fn set_shuffled(&self, shuffled: bool) { - if let Ok(mut state) = self.0.lock() { - (*state).shuffled = shuffled; - } + pub fn set_shuffled(&mut self, shuffled: bool) { + self.shuffled = shuffled; } - pub fn set_playing(&self, status: PlaybackStatus) { - if let Ok(mut state) = self.0.lock() { - (*state).status = status; - match status { - PlaybackStatus::Playing => { - (*state).position.resume(); - } - PlaybackStatus::Paused => { - (*state).position.pause(); - } - PlaybackStatus::Stopped => { - (*state).position.set(0, false); - } + pub fn set_playing(&mut self, status: PlaybackStatus) { + self.status = status; + match status { + PlaybackStatus::Playing => { + self.position.resume(); + } + PlaybackStatus::Paused => { + self.position.pause(); + } + PlaybackStatus::Stopped => { + self.position.set(0, false); } } } diff --git a/src/meson.build b/src/meson.build index e4899d3f..f48fdbb5 100644 --- a/src/meson.build +++ b/src/meson.build @@ -70,6 +70,7 @@ sources = files( './api/cache.rs', './dbus/types.rs', './dbus/mpris.rs', +'./dbus/listener.rs', './dbus/mod.rs', './config.rs', './app/rng.rs',