From be0fe9f2d9f3e6e2ed3eebc2f0cc887423bebb3e Mon Sep 17 00:00:00 2001 From: Ferdinand Schober Date: Fri, 13 Oct 2023 13:57:33 +0200 Subject: [PATCH] Support event consumer on KDE! (portal backend) (#31) * Support event consumer on KDE! (portal backend) Support for KDE event emulation using the remote-desktop xdg-desktop-portal * fix scrolling (TODO: smooth / kinetic scrolling) * windows: fix compilation errors * Update README.md --- Cargo.lock | 550 ++++++++++++++++++++- Cargo.toml | 6 +- README.md | 205 ++++---- src/backend/consumer/libei.rs | 4 +- src/backend/consumer/windows.rs | 4 +- src/backend/consumer/wlroots.rs | 4 +- src/backend/consumer/x11.rs | 4 +- src/backend/consumer/xdg_desktop_portal.rs | 92 +++- src/consumer.rs | 28 +- src/event/server.rs | 53 +- src/main.rs | 8 +- 11 files changed, 807 insertions(+), 151 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d2a5437..809f1e1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -32,6 +32,109 @@ version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +[[package]] +name = "ashpd" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3affe251686bd936a0afb74b9693e8bf2f193d51da1b9a45d3f1303a9bd2cc7" +dependencies = [ + "enumflags2", + "futures-channel", + "futures-util", + "once_cell", + "rand", + "serde", + "serde_repr", + "tokio", + "url", + "zbus", +] + +[[package]] +name = "async-broadcast" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c48ccdbf6ca6b121e0f586cbc0e73ae440e56c67c30fa0873b4e110d9c26d2b" +dependencies = [ + "event-listener", + "futures-core", +] + +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener", + "futures-core", +] + +[[package]] +name = "async-io" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" +dependencies = [ + "async-lock", + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-lite", + "log", + "parking", + "polling", + "rustix 0.37.24", + "slab", + "socket2 0.4.9", + "waker-fn", +] + +[[package]] +name = "async-lock" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" +dependencies = [ + "event-listener", +] + +[[package]] +name = "async-process" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a9d28b1d97e08915212e2e45310d47854eafa69600756fc735fb788f75199c9" +dependencies = [ + "async-io", + "async-lock", + "autocfg", + "blocking", + "cfg-if", + "event-listener", + "futures-lite", + "rustix 0.37.24", + "signal-hook", + "windows-sys", +] + +[[package]] +name = "async-recursion" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.37", +] + +[[package]] +name = "async-task" +version = "4.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9441c6b2fe128a7c2bf680a44c34d0df31ce09e5b7e401fcca3faa483dbc921" + [[package]] name = "async-trait" version = "0.1.73" @@ -43,6 +146,12 @@ dependencies = [ "syn 2.0.37", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "autocfg" version = "1.1.0" @@ -76,6 +185,37 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "blocking" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c36a4d0d48574b3dd360b4b7d95cc651d2b6557b6402848a27d4b228a473e2a" +dependencies = [ + "async-channel", + "async-lock", + "async-task", + "fastrand 2.0.0", + "futures-io", + "futures-lite", + "piper", + "tracing", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes" version = "1.5.0" @@ -132,12 +272,70 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "concurrent-queue" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f057a694a54f12365049b0958a1685bb52d567f5593b355fbf685838e873d400" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "cpufeatures" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +dependencies = [ + "libc", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "data-encoding" version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + [[package]] name = "dlib" version = "0.5.2" @@ -165,6 +363,27 @@ dependencies = [ "syn 2.0.37", ] +[[package]] +name = "enumflags2" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5998b4f30320c9d93aed72f63af821bfdac50465b75428fce77b48ec482c3939" +dependencies = [ + "enumflags2_derive", + "serde", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f95e2801cd355d4a1a3e3953ce6ee5ae9603a5c833455343a8bfe3f44d418246" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.37", +] + [[package]] name = "env_logger" version = "0.10.0" @@ -205,6 +424,21 @@ dependencies = [ "libc", ] +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + [[package]] name = "fastrand" version = "2.0.0" @@ -262,6 +496,21 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +[[package]] +name = "futures-lite" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +dependencies = [ + "fastrand 1.9.0", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + [[package]] name = "futures-macro" version = "0.3.28" @@ -273,6 +522,12 @@ dependencies = [ "syn 2.0.37", ] +[[package]] +name = "futures-sink" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" + [[package]] name = "futures-task" version = "0.3.28" @@ -287,6 +542,7 @@ checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ "futures-core", "futures-macro", + "futures-sink", "futures-task", "pin-project-lite", "pin-utils", @@ -351,6 +607,16 @@ dependencies = [ "system-deps", ] +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" version = "0.2.10" @@ -590,6 +856,12 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "hostname" version = "0.3.1" @@ -627,6 +899,15 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + [[package]] name = "io-lifetimes" version = "1.0.11" @@ -644,7 +925,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" dependencies = [ - "socket2", + "socket2 0.5.4", "widestring", "windows-sys", "winreg", @@ -663,7 +944,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi", - "rustix", + "rustix 0.38.13", "windows-sys", ] @@ -678,6 +959,8 @@ name = "lan-mouse" version = "0.3.3" dependencies = [ "anyhow", + "ashpd", + "async-trait", "env_logger", "glib-build-tools", "gtk4", @@ -754,6 +1037,12 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + [[package]] name = "linux-raw-sys" version = "0.4.7" @@ -882,6 +1171,16 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +[[package]] +name = "ordered-stream" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" +dependencies = [ + "futures-core", + "pin-project-lite", +] + [[package]] name = "pango" version = "0.18.0" @@ -907,6 +1206,12 @@ dependencies = [ "system-deps", ] +[[package]] +name = "parking" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e52c774a4c39359c1d1c52e43f73dd91a75a614652c825408eec30c95a9b2067" + [[package]] name = "parking_lot" version = "0.12.1" @@ -948,12 +1253,39 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "piper" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4" +dependencies = [ + "atomic-waker", + "fastrand 2.0.0", + "futures-io", +] + [[package]] name = "pkg-config" version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +[[package]] +name = "polling" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" +dependencies = [ + "autocfg", + "bitflags 1.3.2", + "cfg-if", + "concurrent-queue", + "libc", + "log", + "pin-project-lite", + "windows-sys", +] + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -1120,6 +1452,20 @@ dependencies = [ "semver", ] +[[package]] +name = "rustix" +version = "0.37.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4279d76516df406a8bd37e7dff53fd37d1a093f997a3c34a5c21658c126db06d" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.8", + "windows-sys", +] + [[package]] name = "rustix" version = "0.38.13" @@ -1129,7 +1475,7 @@ dependencies = [ "bitflags 2.4.0", "errno", "libc", - "linux-raw-sys", + "linux-raw-sys 0.4.7", "windows-sys", ] @@ -1188,6 +1534,17 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_repr" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8725e1dfadb3a50f7e5ce0b1a540466f6ed3fe7a0fca2ac2b8b831d31316bd00" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.37", +] + [[package]] name = "serde_spanned" version = "0.6.3" @@ -1197,6 +1554,36 @@ dependencies = [ "serde", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "signal-hook" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + [[package]] name = "slab" version = "0.4.9" @@ -1212,6 +1599,16 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" +[[package]] +name = "socket2" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "socket2" version = "0.5.4" @@ -1222,6 +1619,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "syn" version = "1.0.109" @@ -1270,9 +1673,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" dependencies = [ "cfg-if", - "fastrand", + "fastrand 2.0.0", "redox_syscall", - "rustix", + "rustix 0.38.13", "windows-sys", ] @@ -1332,8 +1735,10 @@ dependencies = [ "mio", "num_cpus", "pin-project-lite", - "socket2", + "signal-hook-registry", + "socket2 0.5.4", "tokio-macros", + "tracing", "windows-sys", ] @@ -1460,6 +1865,22 @@ dependencies = [ "trust-dns-proto", ] +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "uds_windows" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce65604324d3cce9b966701489fbd0cf318cb1f7bd9dd07ac9a4ee6fb791930d" +dependencies = [ + "tempfile", + "winapi", +] + [[package]] name = "unicode-bidi" version = "0.3.13" @@ -1490,6 +1911,7 @@ dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] [[package]] @@ -1504,6 +1926,12 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "waker-fn" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690" + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -1741,3 +2169,113 @@ dependencies = [ "libc", "pkg-config", ] + +[[package]] +name = "xdg-home" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2769203cd13a0c6015d515be729c526d041e9cf2c0cc478d57faee85f40c6dcd" +dependencies = [ + "nix", + "winapi", +] + +[[package]] +name = "zbus" +version = "3.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31de390a2d872e4cd04edd71b425e29853f786dc99317ed72d73d6fcf5ebb948" +dependencies = [ + "async-broadcast", + "async-process", + "async-recursion", + "async-trait", + "byteorder", + "derivative", + "enumflags2", + "event-listener", + "futures-core", + "futures-sink", + "futures-util", + "hex", + "nix", + "once_cell", + "ordered-stream", + "rand", + "serde", + "serde_repr", + "sha1", + "static_assertions", + "tokio", + "tracing", + "uds_windows", + "winapi", + "xdg-home", + "zbus_macros", + "zbus_names", + "zvariant", +] + +[[package]] +name = "zbus_macros" +version = "3.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d1794a946878c0e807f55a397187c11fc7a038ba5d868e7db4f3bd7760bc9d" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "regex", + "syn 1.0.109", + "zvariant_utils", +] + +[[package]] +name = "zbus_names" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb80bb776dbda6e23d705cf0123c3b95df99c4ebeaec6c2599d4a5419902b4a9" +dependencies = [ + "serde", + "static_assertions", + "zvariant", +] + +[[package]] +name = "zvariant" +version = "3.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44b291bee0d960c53170780af148dca5fa260a63cdd24f1962fa82e03e53338c" +dependencies = [ + "byteorder", + "enumflags2", + "libc", + "serde", + "static_assertions", + "url", + "zvariant_derive", +] + +[[package]] +name = "zvariant_derive" +version = "3.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "934d7a7dfc310d6ee06c87ffe88ef4eca7d3e37bb251dece2ef93da8f17d8ecd" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", + "zvariant_utils", +] + +[[package]] +name = "zvariant_utils" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7234f0d811589db492d16893e3f21e8e2fd282e6d01b0cddee310322062cc200" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] diff --git a/Cargo.toml b/Cargo.toml index 7b6037b..2a0e1a7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,8 @@ log = "0.4.20" env_logger = "0.10.0" libc = "0.2.148" serde_json = "1.0.107" -tokio = {version = "1.32.0", features = ["io-util", "macros", "net", "rt", "sync" ] } +tokio = {version = "1.32.0", features = ["io-util", "macros", "net", "rt", "sync", "signal"] } +async-trait = "0.1.73" [target.'cfg(unix)'.dependencies] wayland-client = { version="0.30.2", optional = true } @@ -34,6 +35,7 @@ wayland-protocols-plasma = { version="0.1.0", features=["client"], optional = tr x11 = { version = "2.21.0", features = ["xlib", "xtest"], optional = true } gtk = { package = "gtk4", version = "0.7.2", features = ["v4_6"], optional = true } adw = { package = "libadwaita", version = "0.5.2", features = ["v1_1"], optional = true } +ashpd = { version = "0.6.2", default-features = false, features = ["tokio"], optional = true } [target.'cfg(windows)'.dependencies] winapi = { version = "0.3.9", features = ["winuser"] } @@ -56,6 +58,6 @@ wayland = [ "dep:wayland-protocols-misc", "dep:wayland-protocols-plasma" ] x11 = [ "dep:x11" ] -xdg_desktop_portal = [] +xdg_desktop_portal = ["dep:ashpd"] libei = [] gtk = ["dep:gtk", "dep:adw"] diff --git a/README.md b/README.md index b3d99c1..ce6becf 100644 --- a/README.md +++ b/README.md @@ -1,54 +1,29 @@ # Lan Mouse +- _Now with a gtk frontend_ -![image](https://github.com/ferdinandschober/lan-mouse/assets/40996949/ccb33815-4357-4c8d-a5d2-8897ab626a08) - + Goal of this project is to be an open-source replacement for proprietary tools like [Synergy](https://symless.com/synergy), [Share Mouse](https://www.sharemouse.com/de/). Focus lies on performance and a clean, manageable implementation that can easily be expanded to support additional backends like e.g. Android, iOS, ... . -Of course ***blazingly fast™*** and stable, because it's written in rust. +***blazingly fast™*** and ***stable™***, because it's written in rust. For an alternative (with slightly different goals) you may check out [Input Leap](https://github.com/input-leap). -_Now with a gtk frontend_ +## OS Support -## Configuration -Configuration is done through the file `config.toml`, -which must be located in the current working directory when -executing lan-mouse. +The following table shows support for Event receiving and event Emitting +on different operating systems: -### Example config -A config file could look like this: - -```toml -# example configuration - -# optional port (defaults to 4242) -port = 4242 -# # optional frontend -> defaults to gtk if available -# # possible values are "cli" and "gtk" -# frontend = "gtk" - -# define a client on the right side with host name "iridium" -[right] -# hostname -host_name = "iridium" -# optional list of (known) ip addresses -ips = ["192.168.178.156"] - -# define a client on the left side with IP address 192.168.178.189 -[left] -# The hostname is optional: When no hostname is specified, -# at least one ip address needs to be specified. -host_name = "thorium" -# ips for ethernet and wifi -ips = ["192.168.178.189", "192.168.178.172"] -# optional port -port = 4242 -``` - -Where `left` can be either `left`, `right`, `top` or `bottom`. +| Backend | Event Receiving | Event Emitting | +|---------------------------|--------------------------|--------------------------------------| +| Wayland (wlroots) | :heavy_check_mark: | :heavy_check_mark: | +| Wayland (KDE) | :heavy_check_mark: | :heavy_check_mark: | +| Wayland (Gnome) | TODO (libei support) | TODO (wlr-layer-shell not supported) | +| X11 | (WIP) | TODO | +| Windows | (:heavy_check_mark:) | TODO | +| MacOS | TODO (I dont own a Mac) | TODO (I dont own a Mac) | ## Build and Run @@ -81,79 +56,42 @@ an executable with just support for wayland: cargo build --no-default-features --features wayland ``` -## OS Support +## Configuration +To automatically load clients on startup, the file `config.toml` is parsed. +(must be in the directory where lan-mouse is executed). -The following table shows support for Event receiving and event Emitting -on different operating systems: +### Example config -| Backend | Event Receiving | Event Emitting | -|---------------------------|--------------------------|--------------------------------------| -| Wayland (wlroots) | :heavy_check_mark: | :heavy_check_mark: | -| Wayland (KDE) | WIP | :heavy_check_mark: | -| Wayland (Gnome) | TODO (libei support) | TODO (wlr-layer-shell not supported) | -| X11 | WIP | TODO | -| Windows | needs improvements | TODO | -| MacOS | TODO (I dont own a Mac) | TODO (I dont own a Mac) | +```toml +# example configuration -## Wayland compositor support -### Input Emulation (for receiving events) -On wayland input-emulation is in an early/unstable state as of writing this. +# optional port (defaults to 4242) +port = 4242 +# # optional frontend -> defaults to gtk if available +# # possible values are "cli" and "gtk" +# frontend = "gtk" -Different compositors have different ways of enabling input emulation: +# define a client on the right side with host name "iridium" +[right] +# hostname +host_name = "iridium" +# optional list of (known) ip addresses +ips = ["192.168.178.156"] -Most wlroots-based compositors like Hyprland and Sway support the following -unstable wayland protocols for keyboard and mouse emulation: -- [virtual-keyboard-unstable-v1](https://wayland.app/protocols/virtual-keyboard-unstable-v1) -- [wlr-virtual-pointer-unstable-v1](https://wayland.app/protocols/wlr-virtual-pointer-unstable-v1) are used to emulate input on wlroots compositors +# define a client on the left side with IP address 192.168.178.189 +[left] +# The hostname is optional: When no hostname is specified, +# at least one ip address needs to be specified. +host_name = "thorium" +# ips for ethernet and wifi +ips = ["192.168.178.189", "192.168.178.172"] +# optional port +port = 4242 +``` -KDE also has a protocol for input emulation ([kde-fake-input](https://wayland.app/protocols/kde-fake-input)), it is however not exposed to -third party apps, so the recommended way of enabling input emulation in KDE is the -[freedesktop remote-desktop-portal](https://flatpak.github.io/xdg-desktop-portal/#gdbus-org.freedesktop.portal.RemoteDesktop). +Where `left` can be either `left`, `right`, `top` or `bottom`. -Gnome uses [libei](https://gitlab.freedesktop.org/libinput/libei) for input emulation, -which has the goal to become the general approach for emulating Input on wayland. - -| Required Protocols (Event Receiving) | Sway | Kwin | Gnome | -|----------------------------------------|--------------------|----------------------|----------------------| -| wlr-virtual-pointer-unstable-v1 | :heavy_check_mark: | :x: | :x: | -| virtual-keyboard-unstable-v1 | :heavy_check_mark: | :x: | :x: | -| ~fake-input~ | :x: | ~:heavy_check_mark:~ | :x: | - -### Input capture - -To capture mouse and keyboard input, a few things are necessary: -- Displaying an immovable surface at screen edges -- Locking the mouse in place -- (optionally but highly recommended) reading unaccelerated mouse input - -| Required Protocols (Event Emitting) | Sway | Kwin | Gnome | -|----------------------------------------|--------------------|----------------------|----------------------| -| pointer-constraints-unstable-v1 | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | -| relative-pointer-unstable-v1 | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | -| keyboard-shortcuts-inhibit-unstable-v1 | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | -| wlr-layer-shell-unstable-v1 | :heavy_check_mark: | :heavy_check_mark: | :x: | - -The [zwlr\_virtual\_pointer\_manager\_v1](wlr-virtual-pointer-unstable-v1) is required -to display surfaces on screen edges and used to display the immovable window on -both wlroots based compositors and KDE. - -Gnome unfortunately does not support this protocol -and [likely won't ever support it](https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/1141). - -So there is currently no way of doing this in Wayland, aside from a custom Gnome-Shell -extension, which is not a very elegant solution. - -This is to be looked into in the future. - -~In order for layershell surfaces to be able to lock the pointer using the pointer\_constraints protocol [this patch](https://github.com/swaywm/sway/pull/7178) needs to be applied to sway.~ -(this works natively on sway versions >= 1.8) - -## Windows support -Currently windows can receive mouse and keyboard events, -event producing on windows is WIP. - - -## TODOS +## Roadmap - [x] Capture the actual mouse events on the server side via a wayland client and send them to the client - [x] Mouse grabbing - [x] Window with absolute position -> wlr\_layer\_shell @@ -219,3 +157,60 @@ would be a better choice for the future and could also help for WIFI connections Sending key and mouse event data over the local network might not be the biggest security concern but in any public network or business environment it's *QUITE* a problem to basically broadcast your keystrokes. - There should be an encryption layer below the application to enable a secure link. - The encryption keys could be generated by the graphical frontend. + + +## Wayland support +### Input Emulation (for receiving events) +On wayland input-emulation is in an early/unstable state as of writing this. + +For this reason a suitable backend is chosen based on the active desktop environment / compositor. + +Different compositors have different ways of enabling input emulation: + +#### Wlroots +Most wlroots-based compositors like Hyprland and Sway support the following +unstable wayland protocols for keyboard and mouse emulation: +- [virtual-keyboard-unstable-v1](https://wayland.app/protocols/virtual-keyboard-unstable-v1) +- [wlr-virtual-pointer-unstable-v1](https://wayland.app/protocols/wlr-virtual-pointer-unstable-v1) + +#### KDE +KDE also has a protocol for input emulation ([kde-fake-input](https://wayland.app/protocols/kde-fake-input)), +it is however not exposed to third party applications. + +The recommended way to emulate input on KDE is the +[freedesktop remote-desktop-portal](https://flatpak.github.io/xdg-desktop-portal/#gdbus-org.freedesktop.portal.RemoteDesktop). + +#### Gnome (TODO) +Gnome uses [libei](https://gitlab.freedesktop.org/libinput/libei) for input emulation, +which has the goal to become the general approach for emulating Input on wayland. + + +### Input capture + +To capture mouse and keyboard input, a few things are necessary: +- Displaying an immovable surface at screen edges +- Locking the mouse in place +- (optionally but highly recommended) reading unaccelerated mouse input + +| Required Protocols (Event Emitting) | Sway | Kwin | Gnome | +|----------------------------------------|--------------------|----------------------|----------------------| +| pointer-constraints-unstable-v1 | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | +| relative-pointer-unstable-v1 | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | +| keyboard-shortcuts-inhibit-unstable-v1 | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | +| wlr-layer-shell-unstable-v1 | :heavy_check_mark: | :heavy_check_mark: | :x: | + +The [zwlr\_virtual\_pointer\_manager\_v1](wlr-virtual-pointer-unstable-v1) is required +to display surfaces on screen edges and used to display the immovable window on +both wlroots based compositors and KDE. + +Gnome unfortunately does not support this protocol +and [likely won't ever support it](https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/1141). + +So there is currently no way of doing this in Wayland, aside from a custom Gnome-Shell +extension, which is not a very elegant solution. + +This is to be looked into in the future. + +~In order for layershell surfaces to be able to lock the pointer using the pointer\_constraints protocol [this patch](https://github.com/swaywm/sway/pull/7178) needs to be applied to sway.~ +(this works natively on sway versions >= 1.8) + diff --git a/src/backend/consumer/libei.rs b/src/backend/consumer/libei.rs index 2d94add..db5e37c 100644 --- a/src/backend/consumer/libei.rs +++ b/src/backend/consumer/libei.rs @@ -1,4 +1,4 @@ -use crate::consumer::EventConsumer; +use crate::consumer::SyncConsumer; pub struct LibeiConsumer {} @@ -6,7 +6,7 @@ impl LibeiConsumer { pub fn new() -> Self { Self { } } } -impl EventConsumer for LibeiConsumer { +impl SyncConsumer for LibeiConsumer { fn consume(&mut self, _: crate::event::Event, _: crate::client::ClientHandle) { log::error!("libei backend not yet implemented!"); todo!() diff --git a/src/backend/consumer/windows.rs b/src/backend/consumer/windows.rs index b2f3d58..04a3b4b 100644 --- a/src/backend/consumer/windows.rs +++ b/src/backend/consumer/windows.rs @@ -1,4 +1,4 @@ -use crate::{event::{KeyboardEvent, PointerEvent}, consumer::EventConsumer}; +use crate::{event::{KeyboardEvent, PointerEvent}, consumer::SyncConsumer}; use winapi::{ self, um::winuser::{INPUT, INPUT_MOUSE, LPINPUT, MOUSEEVENTF_MOVE, MOUSEINPUT, @@ -25,7 +25,7 @@ impl WindowsConsumer { pub fn new() -> Self { Self { } } } -impl EventConsumer for WindowsConsumer { +impl SyncConsumer for WindowsConsumer { fn consume(&mut self, event: Event, _: ClientHandle) { match event { Event::Pointer(pointer_event) => match pointer_event { diff --git a/src/backend/consumer/wlroots.rs b/src/backend/consumer/wlroots.rs index da7b87e..7aa6a25 100644 --- a/src/backend/consumer/wlroots.rs +++ b/src/backend/consumer/wlroots.rs @@ -1,7 +1,7 @@ use wayland_client::WEnum; use wayland_client::backend::WaylandError; use crate::client::{ClientHandle, ClientEvent}; -use crate::consumer::EventConsumer; +use crate::consumer::SyncConsumer; use std::collections::HashMap; use std::io; use std::os::fd::OwnedFd; @@ -140,7 +140,7 @@ impl State { } } -impl EventConsumer for WlrootsConsumer { +impl SyncConsumer for WlrootsConsumer { fn consume(&mut self, event: Event, client_handle: ClientHandle) { if let Some(virtual_input) = self.state.input_for_client.get(&client_handle) { if self.last_flush_failed { diff --git a/src/backend/consumer/x11.rs b/src/backend/consumer/x11.rs index c0dc83e..768b37a 100644 --- a/src/backend/consumer/x11.rs +++ b/src/backend/consumer/x11.rs @@ -3,7 +3,7 @@ use x11::{xlib, xtest}; use crate::{ client::ClientHandle, - event::Event, consumer::EventConsumer, + event::Event, consumer::SyncConsumer, }; pub struct X11Consumer { @@ -30,7 +30,7 @@ impl X11Consumer { } } -impl EventConsumer for X11Consumer { +impl SyncConsumer for X11Consumer { fn consume(&mut self, event: Event, _: ClientHandle) { match event { Event::Pointer(pointer_event) => match pointer_event { diff --git a/src/backend/consumer/xdg_desktop_portal.rs b/src/backend/consumer/xdg_desktop_portal.rs index 85df116..0c716c2 100644 --- a/src/backend/consumer/xdg_desktop_portal.rs +++ b/src/backend/consumer/xdg_desktop_portal.rs @@ -1,15 +1,91 @@ -use crate::consumer::EventConsumer; +use async_trait::async_trait; +use anyhow::Result; +use ashpd::{desktop::{remote_desktop::{RemoteDesktop, DeviceType, KeyState, Axis}, Session}, WindowIdentifier}; -pub struct DesktopPortalConsumer {} +use crate::consumer::AsyncConsumer; -impl DesktopPortalConsumer { - pub fn new() -> Self { Self { } } +pub struct DesktopPortalConsumer<'a> { + proxy: RemoteDesktop<'a>, + session: Session<'a>, } -impl EventConsumer for DesktopPortalConsumer { - fn consume(&mut self, _: crate::event::Event, _: crate::client::ClientHandle) { - log::error!("xdg_desktop_portal backend not yet implemented!"); +impl<'a> DesktopPortalConsumer<'a> { + pub async fn new() -> Result> { + let proxy = RemoteDesktop::new().await?; + let session = proxy.create_session().await?; + proxy + .select_devices(&session, DeviceType::Keyboard | DeviceType::Pointer) + .await?; + + let _ = proxy + .start(&session, &WindowIdentifier::default()) + .await? + .response()?; + + Ok(Self { proxy, session }) + } +} + +#[async_trait] +impl<'a> AsyncConsumer for DesktopPortalConsumer<'a> { + async fn consume(&mut self, event: crate::event::Event, _client: crate::client::ClientHandle) { + match event { + crate::event::Event::Pointer(p) => { + match p { + crate::event::PointerEvent::Motion { time: _, relative_x, relative_y } => { + if let Err(e) = self.proxy.notify_pointer_motion(&self.session, relative_x, relative_y).await { + log::warn!("{e}"); + } + }, + crate::event::PointerEvent::Button { time: _, button, state } => { + let state = match state { + 0 => KeyState::Released, + _ => KeyState::Pressed, + }; + if let Err(e) = self.proxy.notify_pointer_button(&self.session, button as i32, state).await { + log::warn!("{e}"); + } + }, + crate::event::PointerEvent::Axis { time: _, axis, value } => { + let axis = match axis { + 0 => Axis::Vertical, + _ => Axis::Horizontal, + }; + // TODO smooth scrolling + if let Err(e) = self.proxy.notify_pointer_axis_discrete(&self.session, axis, value as i32).await { + log::warn!("{e}"); + } + + }, + crate::event::PointerEvent::Frame { } => {}, + } + }, + crate::event::Event::Keyboard(k) => { + match k { + crate::event::KeyboardEvent::Key { time: _, key, state } => { + let state = match state { + 0 => KeyState::Released, + _ => KeyState::Pressed, + }; + if let Err(e) = self.proxy.notify_keyboard_keycode(&self.session, key as i32, state).await { + log::warn!("{e}"); + } + }, + crate::event::KeyboardEvent::Modifiers { .. } => { + // ignore + }, + } + }, + _ => {}, + } } - fn notify(&mut self, _: crate::client::ClientEvent) {} + async fn notify(&mut self, _client: crate::client::ClientEvent) { } + + async fn destroy(&mut self) { + log::debug!("closing remote desktop session"); + if let Err(e) = self.session.close().await { + log::error!("failed to close remote desktop session: {e}"); + } + } } diff --git a/src/consumer.rs b/src/consumer.rs index 07b03bc..882faab 100644 --- a/src/consumer.rs +++ b/src/consumer.rs @@ -1,3 +1,5 @@ +use async_trait::async_trait; + #[cfg(unix)] use std::env; @@ -13,7 +15,12 @@ enum Backend { Libei, } -pub trait EventConsumer { +pub enum EventConsumer { + Sync(Box), + Async(Box), +} + +pub trait SyncConsumer { /// Event corresponding to an abstract `client_handle` fn consume(&mut self, event: Event, client_handle: ClientHandle); @@ -21,9 +28,16 @@ pub trait EventConsumer { fn notify(&mut self, client_event: ClientEvent); } -pub fn create() -> Result> { +#[async_trait] +pub trait AsyncConsumer { + async fn consume(&mut self, event: Event, client_handle: ClientHandle); + async fn notify(&mut self, client_event: ClientEvent); + async fn destroy(&mut self); +} + +pub async fn create() -> Result { #[cfg(windows)] - return Ok(Box::new(consumer::windows::WindowsConsumer::new())); + return Ok(EventConsumer::Sync(Box::new(consumer::windows::WindowsConsumer::new()))); #[cfg(unix)] let backend = match env::var("XDG_SESSION_TYPE") { @@ -75,25 +89,25 @@ pub fn create() -> Result> { #[cfg(not(feature = "libei"))] panic!("feature libei not enabled"); #[cfg(feature = "libei")] - Ok(Box::new(consumer::libei::LibeiConsumer::new())) + Ok(EventConsumer::Sync(Box::new(consumer::libei::LibeiConsumer::new()))) }, Backend::RemoteDesktopPortal => { #[cfg(not(feature = "xdg_desktop_portal"))] panic!("feature xdg_desktop_portal not enabled"); #[cfg(feature = "xdg_desktop_portal")] - Ok(Box::new(consumer::xdg_desktop_portal::DesktopPortalConsumer::new())) + Ok(EventConsumer::Async(Box::new(consumer::xdg_desktop_portal::DesktopPortalConsumer::new().await?))) }, Backend::Wlroots => { #[cfg(not(feature = "wayland"))] panic!("feature wayland not enabled"); #[cfg(feature = "wayland")] - Ok(Box::new(consumer::wlroots::WlrootsConsumer::new()?)) + Ok(EventConsumer::Sync(Box::new(consumer::wlroots::WlrootsConsumer::new()?))) }, Backend::X11 => { #[cfg(not(feature = "x11"))] panic!("feature x11 not enabled"); #[cfg(feature = "x11")] - Ok(Box::new(consumer::x11::X11Consumer::new())) + Ok(EventConsumer::Sync(Box::new(consumer::x11::X11Consumer::new()))) }, } } diff --git a/src/event/server.rs b/src/event/server.rs index acf1439..2ccf82b 100644 --- a/src/event/server.rs +++ b/src/event/server.rs @@ -1,6 +1,6 @@ use std::{error::Error, io::Result, collections::HashSet, time::{Duration, Instant}, net::IpAddr}; use log; -use tokio::{net::UdpSocket, io::ReadHalf, sync::mpsc::{Sender, Receiver}}; +use tokio::{net::UdpSocket, io::ReadHalf, signal, sync::mpsc::{Sender, Receiver}}; #[cfg(unix)] use tokio::net::UnixStream; @@ -26,7 +26,7 @@ pub struct Server { client_manager: ClientManager, state: State, frontend: FrontendListener, - consumer: Box, + consumer: EventConsumer, producer: Box, socket: UdpSocket, frontend_rx: Receiver, @@ -37,7 +37,7 @@ impl Server { pub async fn new( port: u16, frontend: FrontendListener, - consumer: Box, + consumer: EventConsumer, producer: Box, ) -> anyhow::Result { @@ -102,6 +102,10 @@ impl Server { } } } + _ = signal::ctrl_c() => { + log::info!("terminating gracefully ..."); + break; + } } } @@ -135,9 +139,18 @@ impl Server { } } } + _ = signal::ctrl_c() => { + log::info!("terminating gracefully ..."); + break; + } } } + // destroy consumer + if let EventConsumer::Async(c) = &mut self.consumer { + c.destroy().await; + } + Ok(()) } @@ -164,22 +177,31 @@ impl Server { client } - pub fn activate_client(&mut self, client: ClientHandle, active: bool) { + pub async fn activate_client(&mut self, client: ClientHandle, active: bool) { if let Some(state) = self.client_manager.get_mut(client) { state.active = active; if state.active { self.producer.notify(ClientEvent::Create(client, state.client.pos)); - self.consumer.notify(ClientEvent::Create(client, state.client.pos)); + match &mut self.consumer { + EventConsumer::Sync(consumer) => consumer.notify(ClientEvent::Create(client, state.client.pos)), + EventConsumer::Async(consumer) => consumer.notify(ClientEvent::Create(client, state.client.pos)).await, + } } else { self.producer.notify(ClientEvent::Destroy(client)); - self.consumer.notify(ClientEvent::Destroy(client)); + match &mut self.consumer { + EventConsumer::Sync(consumer) => consumer.notify(ClientEvent::Destroy(client)), + EventConsumer::Async(consumer) => consumer.notify(ClientEvent::Destroy(client)).await, + } } } } pub async fn remove_client(&mut self, client: ClientHandle) -> Option { self.producer.notify(ClientEvent::Destroy(client)); - self.consumer.notify(ClientEvent::Destroy(client)); + match &mut self.consumer { + EventConsumer::Sync(consumer) => consumer.notify(ClientEvent::Destroy(client)), + EventConsumer::Async(consumer) => consumer.notify(ClientEvent::Destroy(client)).await, + } if let Some(client) = self.client_manager.remove_client(client).map(|s| s.client.handle) { let notify = FrontendNotify::NotifyClientDelete(client); log::debug!("{notify:?}"); @@ -208,9 +230,15 @@ impl Server { state.client.pos = pos; if state.active { self.producer.notify(ClientEvent::Destroy(client)); - self.consumer.notify(ClientEvent::Destroy(client)); + match &mut self.consumer { + EventConsumer::Sync(consumer) => consumer.notify(ClientEvent::Destroy(client)), + EventConsumer::Async(consumer) => consumer.notify(ClientEvent::Destroy(client)).await, + } self.producer.notify(ClientEvent::Create(client, pos)); - self.consumer.notify(ClientEvent::Create(client, pos)); + match &mut self.consumer { + EventConsumer::Sync(consumer) => consumer.notify(ClientEvent::Create(client, pos)), + EventConsumer::Async(consumer) => consumer.notify(ClientEvent::Create(client, pos)).await, + } } // update port @@ -294,7 +322,10 @@ impl Server { } State::Receiving => { // consume event - self.consumer.consume(event, handle); + match &mut self.consumer { + EventConsumer::Sync(consumer) => consumer.consume(event, handle), + EventConsumer::Async(consumer) => consumer.consume(event, handle).await, + } // let the server know we are still alive once every second let last_replied = state.last_replied; @@ -421,7 +452,7 @@ impl Server { log::debug!("frontend: {event:?}"); match event { FrontendEvent::AddClient(hostname, port, pos) => { self.add_client(hostname, HashSet::new(), port, pos).await; }, - FrontendEvent::ActivateClient(client, active) => self.activate_client(client, active), + FrontendEvent::ActivateClient(client, active) => self.activate_client(client, active).await, FrontendEvent::DelClient(client) => { self.remove_client(client).await; }, FrontendEvent::UpdateClient(client, hostname, port, pos) => self.update_client(client, hostname, port, pos).await, FrontendEvent::Enumerate() => self.enumerate().await, diff --git a/src/main.rs b/src/main.rs index 54e0b58..d780bd5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -27,10 +27,6 @@ pub fn run() -> Result<(), Box> { // parse config file let config = Config::new()?; - // start producing and consuming events - let producer = producer::create()?; - let consumer = consumer::create()?; - let runtime = tokio::runtime::Builder::new_current_thread() .enable_io() .enable_time() @@ -38,6 +34,10 @@ pub fn run() -> Result<(), Box> { // run async event loop runtime.block_on(LocalSet::new().run_until(async { + // start producing and consuming events + let producer = producer::create()?; + let consumer = consumer::create().await?; + // create frontend communication adapter let frontend_adapter = FrontendListener::new().await?;