diff --git a/Cargo.lock b/Cargo.lock index a2e6a7d..aceb10d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2889,8 +2889,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d941b405bd2322993887859a8ee6ac9134945a24ec5ec763a8a962fc64dfec2d" dependencies = [ "doctest-file", + "futures-core", "libc", "recvmsg", + "tokio", "widestring", "windows-sys 0.52.0", ] @@ -3342,6 +3344,17 @@ version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e53debba6bda7a793e5f99b8dacf19e626084f525f7829104ba9898f367d85ff" +[[package]] +name = "mio" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + [[package]] name = "moveit" version = "0.6.0" @@ -5235,6 +5248,16 @@ dependencies = [ "serde", ] +[[package]] +name = "socket2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + [[package]] name = "stable_deref_trait" version = "1.2.1" @@ -5638,6 +5661,45 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +[[package]] +name = "tokio" +version = "1.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" +dependencies = [ + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "tokio-util" +version = "0.7.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + [[package]] name = "toml" version = "0.8.2" @@ -6297,16 +6359,18 @@ dependencies = [ ] [[package]] -name = "wayvr_ipc" +name = "wayvr-ipc" version = "0.1.0" -source = "git+https://github.com/olekolek1000/wayvr-ipc.git?rev=a72587d23f3bb8624d9aeb1f13c0a21e65350f51#a72587d23f3bb8624d9aeb1f13c0a21e65350f51" dependencies = [ "anyhow", "bytes", + "interprocess", "log", "serde", "serde_json", "smallvec", + "tokio", + "tokio-util", ] [[package]] @@ -6606,6 +6670,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + [[package]] name = "windows-sys" version = "0.61.2" @@ -6639,13 +6712,30 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link 0.2.1", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + [[package]] name = "windows-threading" version = "0.1.0" @@ -6667,6 +6757,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -6679,6 +6775,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -6691,12 +6793,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -6709,6 +6823,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -6721,6 +6841,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" @@ -6733,6 +6859,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -6745,6 +6877,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + [[package]] name = "winit" version = "0.30.12" @@ -6899,7 +7037,7 @@ dependencies = [ "vulkano-shaders", "wayland-client", "wayland-egl", - "wayvr_ipc", + "wayvr-ipc", "wgui", "winit", "wlx-capture", diff --git a/Cargo.toml b/Cargo.toml index 5c89cda..dd28db1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ members = [ "wlx-overlay-s", "wlx-capture", "dash-frontend", + "wayvr-ipc", ] resolver = "3" diff --git a/wayvr-ipc/Cargo.lock b/wayvr-ipc/Cargo.lock new file mode 100644 index 0000000..59143c9 --- /dev/null +++ b/wayvr-ipc/Cargo.lock @@ -0,0 +1,390 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "anyhow" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" + +[[package]] +name = "backtrace" +version = "0.3.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets", +] + +[[package]] +name = "bytes" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "doctest-file" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aac81fa3e28d21450aa4d2ac065992ba96a1d7303efbce51a95f4fd175b67562" + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "interprocess" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "894148491d817cb36b6f778017b8ac46b17408d522dd90f539d677ea938362eb" +dependencies = [ + "doctest-file", + "futures-core", + "libc", + "recvmsg", + "tokio", + "widestring", + "windows-sys", +] + +[[package]] +name = "itoa" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" + +[[package]] +name = "libc" +version = "0.2.169" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "miniz_oxide" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +dependencies = [ + "libc", + "wasi", + "windows-sys", +] + +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "proc-macro2" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "recvmsg" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3edd4d5d42c92f0a659926464d4cce56b562761267ecf0f469d85b7de384175" + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "serde" +version = "1.0.217" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.217" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.135" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "socket2" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "syn" +version = "2.0.96" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tokio" +version = "1.43.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "tokio-macros", + "windows-sys", +] + +[[package]] +name = "tokio-macros" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-util" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "unicode-ident" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wayvr-ipc" +version = "0.1.0" +dependencies = [ + "anyhow", + "bytes", + "interprocess", + "log", + "serde", + "serde_json", + "smallvec", + "tokio", + "tokio-util", +] + +[[package]] +name = "widestring" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/wayvr-ipc/Cargo.toml b/wayvr-ipc/Cargo.toml new file mode 100644 index 0000000..392a6f0 --- /dev/null +++ b/wayvr-ipc/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "wayvr-ipc" +version = "0.1.0" +edition = "2024" + +[dependencies] +bytes = "1.9.0" +smallvec = "1.13.2" +serde = { version = "1", features = ["derive"] } +anyhow = "1.0.93" +log = "0.4.22" + +# client-only deps +interprocess = { version = "2.2.2", features = ["tokio"], optional = true } +tokio = { version = "1.42.0", features = ["macros"], optional = true } +tokio-util = { version = "0.7.13", optional = true } +serde_json = "1.0.135" + +[features] +default = ["client"] +client = ["dep:tokio", "dep:tokio-util", "dep:interprocess"] diff --git a/wayvr-ipc/LICENSE.txt b/wayvr-ipc/LICENSE.txt new file mode 100644 index 0000000..de54ca7 --- /dev/null +++ b/wayvr-ipc/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Aleksander + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/wayvr-ipc/README.md b/wayvr-ipc/README.md new file mode 100644 index 0000000..1b26803 --- /dev/null +++ b/wayvr-ipc/README.md @@ -0,0 +1,9 @@ +# WayVR Protocol Specification & Client Implementation + +This repository contains the IPC specification and client implementation for the WayVR Server protocol (which is used in wlx-overlay-s). The primary purpose is to enable communication between applications and the WayVR server, offering a range of API functions. + +[WayVR Server README](https://github.com/galister/wlx-overlay-s/tree/main/contrib/wayvr) + +## Usage + +[Example WayVR IPC Client usage in WayVR Dashboard](https://github.com/olekolek1000/wayvr-dashboard/blob/master/src-tauri/src/frontend_ipc.rs) diff --git a/wayvr-ipc/rustfmt.toml b/wayvr-ipc/rustfmt.toml new file mode 100644 index 0000000..39694dc --- /dev/null +++ b/wayvr-ipc/rustfmt.toml @@ -0,0 +1,2 @@ +tab_spaces = 2 +hard_tabs = true \ No newline at end of file diff --git a/wayvr-ipc/src/client.rs b/wayvr-ipc/src/client.rs new file mode 100644 index 0000000..46cd0d2 --- /dev/null +++ b/wayvr-ipc/src/client.rs @@ -0,0 +1,496 @@ +use bytes::BufMut; +use interprocess::local_socket::{ + self, + tokio::{prelude::*, Stream}, + GenericNamespaced, +}; +use serde::Serialize; +use smallvec::SmallVec; +use std::sync::{Arc, Weak}; +use tokio::{ + io::{AsyncReadExt, AsyncWriteExt}, + sync::Mutex, +}; +use tokio_util::sync::CancellationToken; + +use crate::{ + gen_id, + ipc::{self, Serial}, + packet_client::{self, PacketClient}, + packet_server::{self, PacketServer}, + util::notifier::Notifier, +}; + +pub struct QueuedPacket { + notifier: Notifier, + serial: Serial, + packet: Option, +} + +gen_id!( + QueuedPacketVec, + QueuedPacket, + QueuedPacketCell, + QueuedPacketHandle +); + +#[derive(Debug, Serialize, Clone)] +pub struct AuthInfo { + pub runtime: String, +} + +type SignalFunc = Box bool + Send>; + +pub struct WayVRClient { + receiver: ReceiverMutex, + sender: SenderMutex, + cancel_token: CancellationToken, + exiting: bool, + queued_packets: QueuedPacketVec, + pub auth: Option, // Some if authenticated + pub on_signal: Option, +} + +pub async fn send_packet(sender: &SenderMutex, data: &[u8]) -> anyhow::Result<()> { + let mut bytes = bytes::BytesMut::new(); + + // packet size + bytes.put_u32(data.len() as u32); + + // packet data + bytes.put_slice(data); + + sender.lock().await.write_all(&bytes).await?; + + Ok(()) +} + +pub type WayVRClientMutex = Arc>; +pub type WayVRClientWeak = Weak>; + +type ReceiverMutex = Arc>; +type SenderMutex = Arc>; + +async fn client_runner(client: WayVRClientMutex) -> anyhow::Result<()> { + loop { + WayVRClient::tick(client.clone()).await?; + } +} + +type Payload = SmallVec<[u8; 64]>; + +async fn read_payload( + conn: &mut local_socket::tokio::RecvHalf, + size: u32, +) -> anyhow::Result { + let mut payload = Payload::new(); + payload.resize(size as usize, 0); + conn.read_exact(&mut payload).await?; + Ok(payload) +} + +macro_rules! bail_unexpected_response { + () => { + anyhow::bail!("unexpected response"); + }; +} + +// Send and wait for a response from the server +macro_rules! send_and_wait { + ($client_mtx:expr, $serial:expr, $packet_to_send:expr, $expected_response_type:ident) => {{ + let result = + WayVRClient::queue_wait_packet($client_mtx, $serial, &ipc::data_encode($packet_to_send)) + .await?; + if let PacketServer::$expected_response_type(_, res) = result { + res + } else { + bail_unexpected_response!(); + } + }}; +} + +// Send without expecting any response +macro_rules! send_only { + ($client_mtx:expr, $packet_to_send:expr) => {{ + WayVRClient::send_payload($client_mtx, &ipc::data_encode($packet_to_send)).await?; + }}; +} + +impl WayVRClient { + pub fn set_signal_handler(&mut self, on_signal: SignalFunc) { + self.on_signal = Some(on_signal); + } + + pub async fn new(client_name: &str) -> anyhow::Result { + let printname = "/tmp/wayvr_ipc.sock"; + let name = printname.to_ns_name::()?; + + let stream = match Stream::connect(name).await { + Ok(c) => c, + Err(e) => { + anyhow::bail!("Failed to connect to the WayVR IPC: {}", e) + } + }; + let (receiver, sender) = stream.split(); + + let receiver = Arc::new(Mutex::new(receiver)); + let sender = Arc::new(Mutex::new(sender)); + + let cancel_token = CancellationToken::new(); + + let client = Arc::new(Mutex::new(Self { + receiver, + sender: sender.clone(), + exiting: false, + cancel_token: cancel_token.clone(), + queued_packets: QueuedPacketVec::new(), + auth: None, + on_signal: None, + })); + + WayVRClient::start_runner(client.clone(), cancel_token); + + // Send handshake to the server + send_packet( + &sender, + &ipc::data_encode(&PacketClient::Handshake(packet_client::Handshake { + client_name: String::from(client_name), + magic: String::from(ipc::CONNECTION_MAGIC), + protocol_version: ipc::PROTOCOL_VERSION, + })), + ) + .await?; + + Ok(client) + } + + fn start_runner(client: WayVRClientMutex, cancel_token: CancellationToken) { + tokio::spawn(async move { + tokio::select! { + _ = cancel_token.cancelled() => { + log::info!("Exiting IPC runner gracefully"); + } + e = client_runner(client.clone()) => { + log::info!("IPC Runner failed: {:?}", e); + } + } + }); + } + + async fn tick(client_mtx: WayVRClientMutex) -> anyhow::Result<()> { + let receiver = { + let client = client_mtx.lock().await; + client.receiver.clone() + }; + + // read packet + let packet = { + let mut receiver = receiver.lock().await; + let packet_size = receiver.read_u32().await?; + log::trace!("packet size {}", packet_size); + if packet_size > 128 * 1024 { + anyhow::bail!("packet size too large (> 128 KiB)"); + } + let payload = read_payload(&mut receiver, packet_size).await?; + let packet: PacketServer = ipc::data_decode(&payload)?; + packet + }; + + { + let mut client = client_mtx.lock().await; + + if let PacketServer::HandshakeSuccess(success) = &packet { + if client.auth.is_some() { + anyhow::bail!("Got handshake response twice"); + } + + client.auth = Some(AuthInfo { + runtime: success.runtime.clone(), + }); + + log::info!( + "Authenticated. Server runtime name: \"{}\"", + success.runtime + ); + } + + if let PacketServer::Disconnect(disconnect) = &packet { + anyhow::bail!("Server disconnected us. Reason: {}", disconnect.reason); + } + + if client.auth.is_none() { + anyhow::bail!( + "Server tried to send us a packet which is not a HandshakeSuccess or Disconnect" + ); + } + + if let PacketServer::WvrStateChanged(_) = &packet { + if let Some(on_signal) = &mut client.on_signal { + if (*on_signal)(&packet) { + // Signal consumed + return Ok(()); + } + } + } + + // queue packet to read if it contains a serial response + if let Some(serial) = packet.serial() { + for qpacket in &mut client.queued_packets.vec { + let Some(qpacket) = qpacket else { + continue; + }; + + let qpacket = &mut qpacket.obj; + if qpacket.serial != *serial { + continue; //skip + } + + // found response serial, fill it and notify the receiver + qpacket.packet = Some(packet); + let notifier = qpacket.notifier.clone(); + + drop(client); + notifier.notify(); + break; + } + } + } + + Ok(()) + } + + // Send packet without feedback + async fn send_payload(client_mtx: WayVRClientMutex, payload: &[u8]) -> anyhow::Result<()> { + let client = client_mtx.lock().await; + let sender = client.sender.clone(); + drop(client); + send_packet(&sender, payload).await?; + Ok(()) + } + + async fn queue_wait_packet( + client_mtx: WayVRClientMutex, + serial: Serial, + payload: &[u8], + ) -> anyhow::Result { + let notifier = Notifier::new(); + + // Send packet to the server + let queued_packet_handle = { + let mut client = client_mtx.lock().await; + let handle = client.queued_packets.add(QueuedPacket { + notifier: notifier.clone(), + packet: None, // will be filled after notify + serial, + }); + + let sender = client.sender.clone(); + + drop(client); + + send_packet(&sender, payload).await?; + handle + }; + + // Wait for response message + notifier.wait().await; + + // Fetch response packet + { + let mut client = client_mtx.lock().await; + + let cell = client + .queued_packets + .get_mut(&queued_packet_handle) + .ok_or(anyhow::anyhow!( + "missing packet cell, this shouldn't happen" + ))?; + + let Some(packet) = cell.packet.take() else { + anyhow::bail!("packet is None, this shouldn't happen"); + }; + + client.queued_packets.remove(&queued_packet_handle); + + Ok(packet) + } + } + + pub async fn fn_wvr_display_list( + client: WayVRClientMutex, + serial: Serial, + ) -> anyhow::Result> { + Ok( + send_and_wait!( + client, + serial, + &PacketClient::WvrDisplayList(serial), + WvrDisplayListResponse + ) + .list, + ) + } + + pub async fn fn_wvr_display_get( + client: WayVRClientMutex, + serial: Serial, + handle: packet_server::WvrDisplayHandle, + ) -> anyhow::Result> { + Ok(send_and_wait!( + client, + serial, + &PacketClient::WvrDisplayGet(serial, handle), + WvrDisplayGetResponse + )) + } + + pub async fn fn_wvr_display_remove( + client: WayVRClientMutex, + serial: Serial, + handle: packet_server::WvrDisplayHandle, + ) -> anyhow::Result<()> { + send_and_wait!( + client, + serial, + &PacketClient::WvrDisplayRemove(serial, handle), + WvrDisplayRemoveResponse + ) + .map_err(|e| anyhow::anyhow!("{}", e)) + } + + pub async fn fn_wvr_display_create( + client: WayVRClientMutex, + serial: Serial, + params: packet_client::WvrDisplayCreateParams, + ) -> anyhow::Result { + Ok(send_and_wait!( + client, + serial, + &PacketClient::WvrDisplayCreate(serial, params), + WvrDisplayCreateResponse + )) + } + + pub async fn fn_wvr_display_set_visible( + client: WayVRClientMutex, + handle: packet_server::WvrDisplayHandle, + visible: bool, + ) -> anyhow::Result<()> { + send_only!(client, &PacketClient::WvrDisplaySetVisible(handle, visible)); + Ok(()) + } + + pub async fn fn_wvr_display_set_layout( + client: WayVRClientMutex, + handle: packet_server::WvrDisplayHandle, + layout: packet_server::WvrDisplayWindowLayout, + ) -> anyhow::Result<()> { + send_only!( + client, + &PacketClient::WvrDisplaySetWindowLayout(handle, layout) + ); + Ok(()) + } + + pub async fn fn_wvr_display_window_list( + client: WayVRClientMutex, + serial: Serial, + handle: packet_server::WvrDisplayHandle, + ) -> anyhow::Result>> { + Ok( + send_and_wait!( + client, + serial, + &PacketClient::WvrDisplayWindowList(serial, handle), + WvrDisplayWindowListResponse + ) + .map(|res| res.list), + ) + } + + pub async fn fn_wvr_window_set_visible( + client: WayVRClientMutex, + handle: packet_server::WvrWindowHandle, + visible: bool, + ) -> anyhow::Result<()> { + send_only!(client, &PacketClient::WvrWindowSetVisible(handle, visible)); + Ok(()) + } + + pub async fn fn_wvr_process_list( + client: WayVRClientMutex, + serial: Serial, + ) -> anyhow::Result> { + Ok( + send_and_wait!( + client, + serial, + &PacketClient::WvrProcessList(serial), + WvrProcessListResponse + ) + .list, + ) + } + + pub async fn fn_wvr_process_get( + client: WayVRClientMutex, + serial: Serial, + handle: packet_server::WvrProcessHandle, + ) -> anyhow::Result> { + Ok(send_and_wait!( + client, + serial, + &PacketClient::WvrProcessGet(serial, handle), + WvrProcessGetResponse + )) + } + + pub async fn fn_wvr_process_terminate( + client: WayVRClientMutex, + handle: packet_server::WvrProcessHandle, + ) -> anyhow::Result<()> { + send_only!(client, &PacketClient::WvrProcessTerminate(handle)); + Ok(()) + } + + pub async fn fn_wvr_process_launch( + client: WayVRClientMutex, + serial: Serial, + params: packet_client::WvrProcessLaunchParams, + ) -> anyhow::Result { + send_and_wait!( + client, + serial, + &PacketClient::WvrProcessLaunch(serial, params), + WvrProcessLaunchResponse + ) + .map_err(|e| anyhow::anyhow!("{}", e)) + } + + pub async fn fn_wlx_input_state( + client: WayVRClientMutex, + serial: Serial, + ) -> anyhow::Result { + Ok(send_and_wait!( + client, + serial, + &PacketClient::WlxInputState(serial), + WlxInputStateResponse + )) + } + + pub async fn fn_wlx_haptics( + client: WayVRClientMutex, + params: packet_client::WlxHapticsParams, + ) -> anyhow::Result<()> { + send_only!(client, &PacketClient::WlxHaptics(params)); + Ok(()) + } +} + +impl Drop for WayVRClient { + fn drop(&mut self) { + self.exiting = true; + self.cancel_token.cancel(); + } +} diff --git a/wayvr-ipc/src/ipc.rs b/wayvr-ipc/src/ipc.rs new file mode 100644 index 0000000..4a29e4f --- /dev/null +++ b/wayvr-ipc/src/ipc.rs @@ -0,0 +1,42 @@ +use std::sync::{Arc, Mutex as SyncMutex}; + +pub type Serial = u64; + +#[derive(Clone, Default)] +pub struct SerialGenerator { + serial: Arc>, +} + +impl SerialGenerator { + pub fn new() -> SerialGenerator { + Self { + serial: Arc::new(SyncMutex::new(0)), + } + } + + pub fn increment_get(&self) -> Serial { + let mut serial = self.serial.lock().unwrap(); + let cur = *serial; + *serial += 1; + cur + } +} + +pub const PROTOCOL_VERSION: u32 = 3; +pub const CONNECTION_MAGIC: &str = "wayvr_ipc"; + +pub fn data_encode(data: &T) -> Vec +where + T: serde::Serialize, +{ + let str = serde_json::to_string(&data).unwrap(); + log::debug!("serialized data: {}", str); + str.into_bytes() +} + +pub fn data_decode(data: &[u8]) -> anyhow::Result +where + T: for<'a> serde::Deserialize<'a>, +{ + Ok(serde_json::from_str::(std::str::from_utf8(data)?)?) +} diff --git a/wayvr-ipc/src/lib.rs b/wayvr-ipc/src/lib.rs new file mode 100644 index 0000000..b7ccffb --- /dev/null +++ b/wayvr-ipc/src/lib.rs @@ -0,0 +1,7 @@ +pub mod ipc; +pub mod packet_client; +pub mod packet_server; +mod util; + +#[cfg(feature = "client")] +pub mod client; diff --git a/wayvr-ipc/src/packet_client.rs b/wayvr-ipc/src/packet_client.rs new file mode 100644 index 0000000..5378f93 --- /dev/null +++ b/wayvr-ipc/src/packet_client.rs @@ -0,0 +1,71 @@ +// Contents of this file should be the same as on wlx-overlay-s. + +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; + +use super::{ipc::Serial, packet_server}; + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct Handshake { + pub protocol_version: u32, // always set to PROTOCOL_VERSION + pub magic: String, // always set to CONNECTION_MAGIC + pub client_name: String, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub enum AttachTo { + None, + HandLeft, + HandRight, + Head, + Stage, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct WvrProcessLaunchParams { + pub name: String, + pub exec: String, + pub target_display: packet_server::WvrDisplayHandle, + pub env: Vec, + pub args: String, + pub userdata: HashMap, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct WvrDisplayCreateParams { + pub width: u16, + pub height: u16, + pub name: String, + pub scale: Option, + pub attach_to: AttachTo, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct WlxHapticsParams { + pub intensity: f32, + pub duration: f32, + pub frequency: f32, +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum PacketClient { + Handshake(Handshake), + WvrDisplayCreate(Serial, WvrDisplayCreateParams), + WvrDisplayGet(Serial, packet_server::WvrDisplayHandle), + WvrDisplayList(Serial), + WvrDisplayRemove(Serial, packet_server::WvrDisplayHandle), + WvrDisplaySetVisible(packet_server::WvrDisplayHandle, bool), + WvrDisplayWindowList(Serial, packet_server::WvrDisplayHandle), + WvrDisplaySetWindowLayout( + packet_server::WvrDisplayHandle, + packet_server::WvrDisplayWindowLayout, + ), + WvrWindowSetVisible(packet_server::WvrWindowHandle, bool), + WvrProcessGet(Serial, packet_server::WvrProcessHandle), + WvrProcessLaunch(Serial, WvrProcessLaunchParams), + WvrProcessList(Serial), + WvrProcessTerminate(packet_server::WvrProcessHandle), + WlxHaptics(WlxHapticsParams), + WlxInputState(Serial), +} diff --git a/wayvr-ipc/src/packet_server.rs b/wayvr-ipc/src/packet_server.rs new file mode 100644 index 0000000..f25ae8e --- /dev/null +++ b/wayvr-ipc/src/packet_server.rs @@ -0,0 +1,163 @@ +// Contents of this file should be the same as on wlx-overlay-s. + +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; + +use super::ipc::Serial; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ServerInfo {} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct HandshakeSuccess { + pub runtime: String, // Runtime name, for example "wlx-overlay-s" +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Disconnect { + pub reason: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] +pub struct WvrDisplayHandle { + pub idx: u32, + pub generation: u64, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] +pub struct WvrProcessHandle { + pub idx: u32, + pub generation: u64, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] +pub struct WvrWindowHandle { + pub idx: u32, + pub generation: u64, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct WvrDisplay { + pub width: u16, + pub height: u16, + pub name: String, + pub visible: bool, + pub handle: WvrDisplayHandle, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct WvrWindow { + pub pos_x: i32, + pub pos_y: i32, + pub size_x: u32, + pub size_y: u32, + pub visible: bool, + pub handle: WvrWindowHandle, + pub process_handle: WvrProcessHandle, + pub display_handle: WvrDisplayHandle, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct WvrDisplayList { + pub list: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct WvrWindowList { + pub list: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct WvrProcess { + pub name: String, + pub display_handle: WvrDisplayHandle, + pub handle: WvrProcessHandle, + pub userdata: HashMap, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct WvrProcessList { + pub list: Vec, +} + +#[derive(Default, Clone, PartialEq, Debug, Serialize, Deserialize)] +pub struct Margins { + pub left: u16, + pub right: u16, + pub top: u16, + pub bottom: u16, +} + +#[derive(Default, Clone, PartialEq, Debug, Serialize, Deserialize)] +pub struct StackingOptions { + pub margins_first: Margins, + pub margins_rest: Margins, +} + +#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] +pub enum WvrDisplayWindowLayout { + Tiling, + Stacking(StackingOptions), +} + +#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] +pub enum WvrStateChanged { + DisplayCreated, + DisplayRemoved, + ProcessCreated, + ProcessRemoved, + WindowCreated, + WindowRemoved, + DashboardShown, + DashboardHidden, +} + +#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] +pub struct WlxInputStatePointer { + pub pos: [f32; 3], +} + +#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] +pub struct WlxInputState { + pub hmd_pos: [f32; 3], + pub left: WlxInputStatePointer, + pub right: WlxInputStatePointer, +} + +// "Wvr" prefixes are WayVR-specific + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum PacketServer { + Disconnect(Disconnect), + HandshakeSuccess(HandshakeSuccess), + WlxInputStateResponse(Serial, WlxInputState), + WvrDisplayCreateResponse(Serial, WvrDisplayHandle), + WvrDisplayGetResponse(Serial, Option), + WvrDisplayListResponse(Serial, WvrDisplayList), + WvrDisplayRemoveResponse(Serial, Result<(), String>), + WvrDisplayWindowListResponse(Serial, Option), + WvrProcessGetResponse(Serial, Option), + WvrProcessLaunchResponse(Serial, Result), + WvrProcessListResponse(Serial, WvrProcessList), + WvrStateChanged(WvrStateChanged), +} + +impl PacketServer { + pub fn serial(&self) -> Option<&Serial> { + match self { + PacketServer::Disconnect(_) => None, + PacketServer::HandshakeSuccess(_) => None, + PacketServer::WlxInputStateResponse(serial, _) => Some(serial), + PacketServer::WvrDisplayCreateResponse(serial, _) => Some(serial), + PacketServer::WvrDisplayGetResponse(serial, _) => Some(serial), + PacketServer::WvrDisplayListResponse(serial, _) => Some(serial), + PacketServer::WvrDisplayRemoveResponse(serial, _) => Some(serial), + PacketServer::WvrDisplayWindowListResponse(serial, _) => Some(serial), + PacketServer::WvrProcessGetResponse(serial, _) => Some(serial), + PacketServer::WvrProcessLaunchResponse(serial, _) => Some(serial), + PacketServer::WvrProcessListResponse(serial, _) => Some(serial), + PacketServer::WvrStateChanged(_) => None, + } + } +} diff --git a/wayvr-ipc/src/util/handle.rs b/wayvr-ipc/src/util/handle.rs new file mode 100644 index 0000000..a408d41 --- /dev/null +++ b/wayvr-ipc/src/util/handle.rs @@ -0,0 +1,173 @@ +#[macro_export] +macro_rules! gen_id { + ( + $container_name:ident, + $instance_name:ident, + $cell_name:ident, + $handle_name:ident) => { + //ThingCell + pub struct $cell_name { + pub obj: $instance_name, + pub generation: u64, + } + + //ThingVec + pub struct $container_name { + // Vec> + pub vec: Vec>, + + cur_generation: u64, + } + + //ThingHandle + #[derive(Default, Clone, Copy, PartialEq, Hash, Eq)] + pub struct $handle_name { + idx: u32, + generation: u64, + } + + #[allow(dead_code)] + impl $handle_name { + pub fn reset(&mut self) { + self.generation = 0; + } + + pub fn is_set(&self) -> bool { + self.generation > 0 + } + + pub fn id(&self) -> u32 { + self.idx + } + + pub fn new(idx: u32, generation: u64) -> Self { + Self { idx, generation } + } + } + + //ThingVec + #[allow(dead_code)] + impl $container_name { + pub fn new() -> Self { + Self { + vec: Vec::new(), + cur_generation: 0, + } + } + + pub fn iter(&self, callback: &dyn Fn($handle_name, &$instance_name)) { + for (idx, opt_cell) in self.vec.iter().enumerate() { + if let Some(cell) = opt_cell { + let handle = $container_name::get_handle(&cell, idx); + callback(handle, &cell.obj); + } + } + } + + pub fn iter_mut( + &mut self, + callback: &mut dyn FnMut($handle_name, &mut $instance_name), + ) { + for (idx, opt_cell) in self.vec.iter_mut().enumerate() { + if let Some(cell) = opt_cell { + let handle = $container_name::get_handle(&cell, idx); + callback(handle, &mut cell.obj); + } + } + } + + pub fn get_handle(cell: &$cell_name, idx: usize) -> $handle_name { + $handle_name { + idx: idx as u32, + generation: cell.generation, + } + } + + fn find_unused_idx(&mut self) -> Option { + for (num, obj) in self.vec.iter().enumerate() { + if obj.is_none() { + return Some(num as u32); + } + } + None + } + + pub fn add(&mut self, obj: $instance_name) -> $handle_name { + self.cur_generation += 1; + let generation = self.cur_generation; + + let unused_idx = self.find_unused_idx(); + + let idx = if let Some(idx) = unused_idx { + idx + } else { + self.vec.len() as u32 + }; + + let handle = $handle_name { idx, generation }; + + let cell = $cell_name { obj, generation }; + + if let Some(idx) = unused_idx { + self.vec[idx as usize] = Some(cell); + } else { + self.vec.push(Some(cell)) + } + + handle + } + + pub fn remove(&mut self, handle: &$handle_name) { + // Out of bounds, ignore + if handle.idx as usize >= self.vec.len() { + return; + } + + // Remove only if the generation matches + if let Some(cell) = &self.vec[handle.idx as usize] { + if cell.generation == handle.generation { + self.vec[handle.idx as usize] = None; + } + } + } + + pub fn get(&self, handle: &$handle_name) -> Option<&$instance_name> { + // Out of bounds, ignore + if handle.idx as usize >= self.vec.len() { + return None; + } + + if let Some(cell) = &self.vec[handle.idx as usize] { + if cell.generation == handle.generation { + return Some(&cell.obj); + } + } + + None + } + + pub fn get_mut(&mut self, handle: &$handle_name) -> Option<&mut $instance_name> { + // Out of bounds, ignore + if handle.idx as usize >= self.vec.len() { + return None; + } + + if let Some(cell) = &mut self.vec[handle.idx as usize] { + if cell.generation == handle.generation { + return Some(&mut cell.obj); + } + } + + None + } + } + }; +} + +/* Example usage: +gen_id!(ThingVec, ThingInstance, ThingCell, ThingHandle); + +struct ThingInstance {} + +impl ThingInstance {} + */ diff --git a/wayvr-ipc/src/util/mod.rs b/wayvr-ipc/src/util/mod.rs new file mode 100644 index 0000000..cf2f06f --- /dev/null +++ b/wayvr-ipc/src/util/mod.rs @@ -0,0 +1,4 @@ +pub mod handle; + +#[cfg(feature = "client")] +pub mod notifier; diff --git a/wayvr-ipc/src/util/notifier.rs b/wayvr-ipc/src/util/notifier.rs new file mode 100644 index 0000000..b985cc5 --- /dev/null +++ b/wayvr-ipc/src/util/notifier.rs @@ -0,0 +1,25 @@ +use std::sync::Arc; + +use tokio::sync::Notify; + +// Copyable wrapped Notify struct for easier usage +#[derive(Default, Clone)] +pub struct Notifier { + notifier: Arc, +} + +impl Notifier { + pub fn new() -> Self { + Self { + notifier: Arc::new(Notify::new()), + } + } + + pub fn notify(&self) { + self.notifier.notify_waiters(); + } + + pub async fn wait(&self) { + self.notifier.notified().await; + } +} diff --git a/wlx-overlay-s/Cargo.lock b/wlx-overlay-s/Cargo.lock index 75dcea5..553ade9 100644 --- a/wlx-overlay-s/Cargo.lock +++ b/wlx-overlay-s/Cargo.lock @@ -5551,19 +5551,6 @@ dependencies = [ "pkg-config", ] -[[package]] -name = "wayvr_ipc" -version = "0.1.0" -source = "git+https://github.com/olekolek1000/wayvr-ipc.git?rev=a72587d23f3bb8624d9aeb1f13c0a21e65350f51#a72587d23f3bb8624d9aeb1f13c0a21e65350f51" -dependencies = [ - "anyhow", - "bytes", - "log", - "serde", - "serde_json", - "smallvec", -] - [[package]] name = "web-sys" version = "0.3.77" @@ -6206,7 +6193,7 @@ dependencies = [ "uuid", "wayland-client", "wayland-egl", - "wayvr_ipc", + "wayvr-ipc", "wgui", "winit", "wlx-capture", diff --git a/wlx-overlay-s/Cargo.toml b/wlx-overlay-s/Cargo.toml index 0e41aaf..b78667a 100644 --- a/wlx-overlay-s/Cargo.toml +++ b/wlx-overlay-s/Cargo.toml @@ -96,7 +96,7 @@ uuid = { version = "1.19.0", features = ["v4", "fast-rng"], optional = true } wayland-client = { workspace = true, optional = true } wayland-egl = { version = "0.32.8", optional = true } bytes = { version = "1.11.0", optional = true } -wayvr_ipc = { git = "https://github.com/olekolek1000/wayvr-ipc.git", rev = "a72587d23f3bb8624d9aeb1f13c0a21e65350f51", default-features = false, optional = true } +wayvr-ipc = { path = "../wayvr-ipc", default-features = false, optional = true } rust-embed = { workspace = true } signal-hook = "0.3.18" ################################ @@ -121,6 +121,6 @@ wayvr = [ "dep:wayland-client", "dep:wayland-egl", "dep:bytes", - "dep:wayvr_ipc", + "dep:wayvr-ipc", ] as-raw-xcb-connection = []