From c2363b0bceb7bc5cce6d2ef218ae98df2e1cb82e Mon Sep 17 00:00:00 2001 From: Wanjohi <71614375+wanjohiryan@users.noreply.github.com> Date: Wed, 29 Jan 2025 04:16:27 +0300 Subject: [PATCH] =?UTF-8?q?=E2=AD=90=20feat:=20Add=20protobuf=20(#171)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a second attempt to add protobuf to Nestri, after the first one failed --------- Co-authored-by: Philipp Neumann <3daquawolf@gmail.com> Co-authored-by: DatCaptainHorse --- Cargo.lock | 654 +++++++++++++--- .../www/src/routes/(play)/play/[id]/index.tsx | 2 +- apps/www/src/routes/watch/[id]/index.tsx | 303 ++++++++ buf.gen.yaml | 17 + bun.lockb | Bin 757560 -> 0 bytes containers/master.Containerfile | 206 ----- key_ssh | 53 ++ packages/input/package.json | 7 + packages/input/src/keyboard.ts | 73 +- packages/input/src/latency.ts | 7 +- packages/input/src/messages.ts | 36 - packages/input/src/mouse.ts | 117 ++- .../input/src/proto/latency_tracker_pb.ts | 60 ++ packages/input/src/proto/messages_pb.ts | 62 ++ packages/input/src/proto/types_pb.ts | 272 +++++++ packages/input/src/types.ts | 52 -- packages/input/src/webrtc-stream.ts | 14 +- packages/relay/go.mod | 23 +- packages/relay/go.sum | 64 +- packages/relay/internal/datachannel.go | 24 +- packages/relay/internal/egress.go | 28 +- packages/relay/internal/http.go | 3 +- packages/relay/internal/ingest.go | 9 +- packages/relay/internal/latency.go | 80 +- packages/relay/internal/messages.go | 109 +-- .../internal/proto/latency_tracker.pb.go | 203 +++++ packages/relay/internal/proto/messages.pb.go | 207 +++++ packages/relay/internal/proto/types.pb.go | 713 ++++++++++++++++++ packages/relay/internal/websocket.go | 40 +- packages/server/Cargo.toml | 10 +- packages/server/src/args/app_args.rs | 5 +- packages/server/src/latency.rs | 2 +- packages/server/src/main.rs | 1 + packages/server/src/messages.rs | 69 +- packages/server/src/nestrisink/imp.rs | 169 +++-- packages/server/src/proto.rs | 1 + packages/server/src/proto/proto.rs | 139 ++++ packages/server/src/websocket.rs | 29 +- protobufs/buf.yaml | 7 + protobufs/latency_tracker.proto | 17 + protobufs/messages.proto | 18 + protobufs/types.proto | 63 ++ 42 files changed, 3114 insertions(+), 854 deletions(-) create mode 100644 apps/www/src/routes/watch/[id]/index.tsx create mode 100644 buf.gen.yaml delete mode 100755 bun.lockb delete mode 100644 containers/master.Containerfile create mode 100644 key_ssh create mode 100644 packages/input/src/proto/latency_tracker_pb.ts create mode 100644 packages/input/src/proto/messages_pb.ts create mode 100644 packages/input/src/proto/types_pb.ts delete mode 100644 packages/input/src/types.ts create mode 100644 packages/relay/internal/proto/latency_tracker.pb.go create mode 100644 packages/relay/internal/proto/messages.pb.go create mode 100644 packages/relay/internal/proto/types.pb.go create mode 100644 packages/server/src/proto.rs create mode 100644 packages/server/src/proto/proto.rs create mode 100644 protobufs/buf.yaml create mode 100644 protobufs/latency_tracker.proto create mode 100644 protobufs/messages.proto create mode 100644 protobufs/types.proto diff --git a/Cargo.lock b/Cargo.lock index b16cadae..9fd807b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -978,15 +978,6 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" -[[package]] -name = "crc32fast" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" -dependencies = [ - "cfg-if", -] - [[package]] name = "crypto-bigint" version = "0.5.5" @@ -994,7 +985,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ "generic-array", - "rand_core", + "rand_core 0.6.4", "subtle", "zeroize", ] @@ -1006,7 +997,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", - "rand_core", + "rand_core 0.6.4", "typenum", ] @@ -1116,7 +1107,7 @@ dependencies = [ "serde", "serde_json", "tokio", - "webrtc", + "webrtc 0.11.0", ] [[package]] @@ -1183,7 +1174,7 @@ dependencies = [ "hkdf", "pem-rfc7468", "pkcs8", - "rand_core", + "rand_core 0.6.4", "sec1", "subtle", "zeroize", @@ -1226,7 +1217,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ - "rand_core", + "rand_core 0.6.4", "subtle", ] @@ -1242,16 +1233,6 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" -[[package]] -name = "flate2" -version = "1.0.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - [[package]] name = "fnv" version = "1.0.7" @@ -1397,10 +1378,22 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "wasm-bindgen", ] +[[package]] +name = "getrandom" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.13.3+wasi-0.2.2", + "windows-targets 0.52.6", +] + [[package]] name = "ghash" version = "0.5.1" @@ -1509,7 +1502,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", - "rand_core", + "rand_core 0.6.4", "subtle", ] @@ -1562,11 +1555,11 @@ dependencies = [ "livekit-api", "livekit-protocol", "parse_link_header", - "rand", + "rand 0.8.5", "reqwest 0.11.27", "serde", "serde_json", - "thiserror 2.0.3", + "thiserror 2.0.11", "tokio", "tokio-native-tls", "tokio-stream", @@ -1593,7 +1586,7 @@ dependencies = [ "serde", "serde_json", "test-log", - "thiserror 2.0.3", + "thiserror 2.0.11", "tokio", "tokio-native-tls", "tracing", @@ -1634,7 +1627,7 @@ dependencies = [ "serde", "serde_bytes", "smallvec", - "thiserror 2.0.3", + "thiserror 2.0.11", ] [[package]] @@ -1803,7 +1796,7 @@ dependencies = [ "gstreamer", "gstreamer-app", "gstreamer-video", - "thiserror 2.0.3", + "thiserror 2.0.11", ] [[package]] @@ -1819,7 +1812,7 @@ dependencies = [ "gstreamer-video-sys", "libc", "serde", - "thiserror 2.0.3", + "thiserror 2.0.11", ] [[package]] @@ -2363,14 +2356,34 @@ dependencies = [ "bytes", "log", "portable-atomic", - "rand", - "rtcp", - "rtp", + "rand 0.8.5", + "rtcp 0.11.0", + "rtp 0.11.0", "thiserror 1.0.69", "tokio", "waitgroup", - "webrtc-srtp", - "webrtc-util", + "webrtc-srtp 0.13.0", + "webrtc-util 0.9.0", +] + +[[package]] +name = "interceptor" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ab04c530fd82e414e40394cabe5f0ebfe30d119f10fe29d6e3561926af412e" +dependencies = [ + "async-trait", + "bytes", + "log", + "portable-atomic", + "rand 0.8.5", + "rtcp 0.12.0", + "rtp 0.12.0", + "thiserror 1.0.69", + "tokio", + "waitgroup", + "webrtc-srtp 0.14.0", + "webrtc-util 0.10.0", ] [[package]] @@ -2510,7 +2523,7 @@ dependencies = [ "livekit-protocol", "log", "parking_lot", - "prost", + "prost 0.12.6", "reqwest 0.11.27", "scopeguard", "serde", @@ -2531,8 +2544,8 @@ dependencies = [ "parking_lot", "pbjson", "pbjson-types", - "prost", - "prost-types", + "prost 0.12.6", + "prost-types 0.12.6", "serde", "thiserror 1.0.69", "tokio", @@ -2626,7 +2639,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", ] @@ -2683,7 +2696,6 @@ version = "0.1.0" dependencies = [ "chrono", "clap", - "flate2", "futures-util", "gst-plugin-webrtc", "gstreamer", @@ -2691,15 +2703,16 @@ dependencies = [ "log", "num-derive", "num-traits", - "rand", + "prost 0.13.4", + "prost-types 0.13.4", + "rand 0.9.0", "regex", "rustls 0.23.19", "serde", "serde_json", "tokio", - "tokio-tungstenite 0.24.0", - "tokio-util", - "webrtc", + "tokio-tungstenite 0.26.1", + "webrtc 0.12.0", ] [[package]] @@ -2981,8 +2994,8 @@ checksum = "2580e33f2292d34be285c5bc3dba5259542b083cfad6037b6d70345f24dcb735" dependencies = [ "heck 0.4.1", "itertools 0.11.0", - "prost", - "prost-types", + "prost 0.12.6", + "prost-types 0.12.6", ] [[package]] @@ -2995,7 +3008,7 @@ dependencies = [ "chrono", "pbjson", "pbjson-build", - "prost", + "prost 0.12.6", "prost-build", "serde", ] @@ -3113,7 +3126,7 @@ version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -3160,7 +3173,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" dependencies = [ "bytes", - "prost-derive", + "prost-derive 0.12.6", +] + +[[package]] +name = "prost" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c0fef6c4230e4ccf618a35c59d7ede15dea37de8427500f50aff708806e42ec" +dependencies = [ + "bytes", + "prost-derive 0.13.4", ] [[package]] @@ -3177,8 +3200,8 @@ dependencies = [ "once_cell", "petgraph", "prettyplease", - "prost", - "prost-types", + "prost 0.12.6", + "prost-types 0.12.6", "regex", "syn 2.0.90", "tempfile", @@ -3197,13 +3220,35 @@ dependencies = [ "syn 2.0.90", ] +[[package]] +name = "prost-derive" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "157c5a9d7ea5c2ed2d9fb8f495b64759f7816c7eaea54ba3978f0d63000162e3" +dependencies = [ + "anyhow", + "itertools 0.13.0", + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "prost-types" version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9091c90b0a32608e984ff2fa4091273cbdd755d54935c51d520887f4a1dbd5b0" dependencies = [ - "prost", + "prost 0.12.6", +] + +[[package]] +name = "prost-types" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc2f1e56baa61e93533aebc21af4d2134b70f66275e0fcdf3cbe43d77ff7e8fc" +dependencies = [ + "prost 0.13.4", ] [[package]] @@ -3222,8 +3267,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.0", + "zerocopy 0.8.14", ] [[package]] @@ -3233,7 +3289,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.0", ] [[package]] @@ -3242,7 +3308,17 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.15", +] + +[[package]] +name = "rand_core" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff" +dependencies = [ + "getrandom 0.3.1", + "zerocopy 0.8.14", ] [[package]] @@ -3419,7 +3495,7 @@ checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", "cfg-if", - "getrandom", + "getrandom 0.2.15", "libc", "spin", "untrusted", @@ -3434,7 +3510,18 @@ checksum = "fc9f775ff89c5fe7f0cc0abafb7c57688ae25ce688f1a52dd88e277616c76ab2" dependencies = [ "bytes", "thiserror 1.0.69", - "webrtc-util", + "webrtc-util 0.9.0", +] + +[[package]] +name = "rtcp" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8306430fb118b7834bbee50e744dc34826eca1da2158657a3d6cbc70e24c2096" +dependencies = [ + "bytes", + "thiserror 1.0.69", + "webrtc-util 0.10.0", ] [[package]] @@ -3445,10 +3532,25 @@ checksum = "6870f09b5db96f8b9e7290324673259fd15519ebb7d55acf8e7eb044a9ead6af" dependencies = [ "bytes", "portable-atomic", - "rand", + "rand 0.8.5", "serde", "thiserror 1.0.69", - "webrtc-util", + "webrtc-util 0.9.0", +] + +[[package]] +name = "rtp" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e68baca5b6cb4980678713f0d06ef3a432aa642baefcbfd0f4dd2ef9eb5ab550" +dependencies = [ + "bytes", + "memchr", + "portable-atomic", + "rand 0.8.5", + "serde", + "thiserror 1.0.69", + "webrtc-util 0.10.0", ] [[package]] @@ -3637,7 +3739,19 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13254db766b17451aced321e7397ebf0a446ef0c8d2942b6e67a95815421093f" dependencies = [ - "rand", + "rand 0.8.5", + "substring", + "thiserror 1.0.69", + "url", +] + +[[package]] +name = "sdp" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02a526161f474ae94b966ba622379d939a8fe46c930eebbadb73e339622599d5" +dependencies = [ + "rand 0.8.5", "substring", "thiserror 1.0.69", "url", @@ -3801,7 +3915,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "digest", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -3882,13 +3996,32 @@ dependencies = [ "crc", "lazy_static", "md-5", - "rand", + "rand 0.8.5", "ring", "subtle", "thiserror 1.0.69", "tokio", "url", - "webrtc-util", + "webrtc-util 0.9.0", +] + +[[package]] +name = "stun" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea256fb46a13f9204e9dee9982997b2c3097db175a9fddaa8350310d03c4d5a3" +dependencies = [ + "base64 0.22.1", + "crc", + "lazy_static", + "md-5", + "rand 0.8.5", + "ring", + "subtle", + "thiserror 1.0.69", + "tokio", + "url", + "webrtc-util 0.10.0", ] [[package]] @@ -4072,11 +4205,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.3" +version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa" +checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" dependencies = [ - "thiserror-impl 2.0.3", + "thiserror-impl 2.0.11", ] [[package]] @@ -4092,9 +4225,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.3" +version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568" +checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" dependencies = [ "proc-macro2", "quote", @@ -4262,16 +4395,16 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.24.0" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" +checksum = "be4bf6fecd69fcdede0ec680aaf474cdab988f9de6bc73d3758f0160e3b7025a" dependencies = [ "futures-util", "log", "native-tls", "tokio", "tokio-native-tls", - "tungstenite 0.24.0", + "tungstenite 0.26.1", ] [[package]] @@ -4408,7 +4541,7 @@ dependencies = [ "httparse", "log", "native-tls", - "rand", + "rand 0.8.5", "sha1", "thiserror 1.0.69", "url", @@ -4427,7 +4560,7 @@ dependencies = [ "http 1.1.0", "httparse", "log", - "rand", + "rand 0.8.5", "sha1", "thiserror 1.0.69", "url", @@ -4447,13 +4580,32 @@ dependencies = [ "httparse", "log", "native-tls", - "rand", + "rand 0.8.5", "sha1", "thiserror 1.0.69", "url", "utf-8", ] +[[package]] +name = "tungstenite" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413083a99c579593656008130e29255e54dcaae495be556cc26888f211648c24" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http 1.1.0", + "httparse", + "log", + "native-tls", + "rand 0.8.5", + "sha1", + "thiserror 2.0.11", + "utf-8", +] + [[package]] name = "turn" version = "0.8.0" @@ -4466,13 +4618,34 @@ dependencies = [ "log", "md-5", "portable-atomic", - "rand", + "rand 0.8.5", "ring", - "stun", + "stun 0.6.0", "thiserror 1.0.69", "tokio", "tokio-util", - "webrtc-util", + "webrtc-util 0.9.0", +] + +[[package]] +name = "turn" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0044fdae001dd8a1e247ea6289abf12f4fcea1331a2364da512f9cd680bbd8cb" +dependencies = [ + "async-trait", + "base64 0.22.1", + "futures", + "log", + "md-5", + "portable-atomic", + "rand 0.8.5", + "ring", + "stun 0.7.0", + "thiserror 1.0.69", + "tokio", + "tokio-util", + "webrtc-util 0.10.0", ] [[package]] @@ -4571,7 +4744,7 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" dependencies = [ - "getrandom", + "getrandom 0.2.15", ] [[package]] @@ -4659,6 +4832,15 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi" +version = "0.13.3+wasi-0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +dependencies = [ + "wit-bindgen-rt", +] + [[package]] name = "wasm-bindgen" version = "0.2.97" @@ -4748,37 +4930,81 @@ dependencies = [ "bytes", "cfg-if", "hex", - "interceptor", + "interceptor 0.12.0", "lazy_static", "log", "portable-atomic", - "rand", + "rand 0.8.5", "rcgen", "regex", "ring", - "rtcp", - "rtp", + "rtcp 0.11.0", + "rtp 0.11.0", "rustls 0.23.19", - "sdp", + "sdp 0.6.2", "serde", "serde_json", "sha2", "smol_str", - "stun", + "stun 0.6.0", "thiserror 1.0.69", "time", "tokio", - "turn", + "turn 0.8.0", "url", "waitgroup", - "webrtc-data", - "webrtc-dtls", - "webrtc-ice", - "webrtc-mdns", - "webrtc-media", - "webrtc-sctp", - "webrtc-srtp", - "webrtc-util", + "webrtc-data 0.9.0", + "webrtc-dtls 0.10.0", + "webrtc-ice 0.11.0", + "webrtc-mdns 0.7.0", + "webrtc-media 0.8.0", + "webrtc-sctp 0.10.0", + "webrtc-srtp 0.13.0", + "webrtc-util 0.9.0", +] + +[[package]] +name = "webrtc" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30367074d9f18231d28a74fab0120856b2b665da108d71a12beab7185a36f97b" +dependencies = [ + "arc-swap", + "async-trait", + "bytes", + "cfg-if", + "hex", + "interceptor 0.13.0", + "lazy_static", + "log", + "portable-atomic", + "rand 0.8.5", + "rcgen", + "regex", + "ring", + "rtcp 0.12.0", + "rtp 0.12.0", + "rustls 0.23.19", + "sdp 0.7.0", + "serde", + "serde_json", + "sha2", + "smol_str", + "stun 0.7.0", + "thiserror 1.0.69", + "time", + "tokio", + "turn 0.9.0", + "url", + "waitgroup", + "webrtc-data 0.10.0", + "webrtc-dtls 0.11.0", + "webrtc-ice 0.12.0", + "webrtc-mdns 0.8.0", + "webrtc-media 0.9.0", + "webrtc-sctp 0.11.0", + "webrtc-srtp 0.14.0", + "webrtc-util 0.10.0", ] [[package]] @@ -4792,8 +5018,23 @@ dependencies = [ "portable-atomic", "thiserror 1.0.69", "tokio", - "webrtc-sctp", - "webrtc-util", + "webrtc-sctp 0.10.0", + "webrtc-util 0.9.0", +] + +[[package]] +name = "webrtc-data" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dec93b991efcd01b73c5b3503fa8adba159d069abe5785c988ebe14fcf8f05d1" +dependencies = [ + "bytes", + "log", + "portable-atomic", + "thiserror 1.0.69", + "tokio", + "webrtc-sctp 0.11.0", + "webrtc-util 0.10.0", ] [[package]] @@ -4816,8 +5057,8 @@ dependencies = [ "p256", "p384", "portable-atomic", - "rand", - "rand_core", + "rand 0.8.5", + "rand_core 0.6.4", "rcgen", "ring", "rustls 0.23.19", @@ -4828,7 +5069,44 @@ dependencies = [ "subtle", "thiserror 1.0.69", "tokio", - "webrtc-util", + "webrtc-util 0.9.0", + "x25519-dalek", + "x509-parser", +] + +[[package]] +name = "webrtc-dtls" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c9b89fc909f9da0499283b1112cd98f72fec28e55a54a9e352525ca65cd95c" +dependencies = [ + "aes", + "aes-gcm", + "async-trait", + "bincode", + "byteorder", + "cbc", + "ccm", + "der-parser 9.0.0", + "hkdf", + "hmac", + "log", + "p256", + "p384", + "portable-atomic", + "rand 0.8.5", + "rand_core 0.6.4", + "rcgen", + "ring", + "rustls 0.23.19", + "sec1", + "serde", + "sha1", + "sha2", + "subtle", + "thiserror 1.0.69", + "tokio", + "webrtc-util 0.10.0", "x25519-dalek", "x509-parser", ] @@ -4844,18 +5122,43 @@ dependencies = [ "crc", "log", "portable-atomic", - "rand", + "rand 0.8.5", "serde", "serde_json", - "stun", + "stun 0.6.0", "thiserror 1.0.69", "tokio", - "turn", + "turn 0.8.0", "url", "uuid", "waitgroup", - "webrtc-mdns", - "webrtc-util", + "webrtc-mdns 0.7.0", + "webrtc-util 0.9.0", +] + +[[package]] +name = "webrtc-ice" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0348b28b593f7709ac98d872beb58c0009523df652c78e01b950ab9c537ff17d" +dependencies = [ + "arc-swap", + "async-trait", + "crc", + "log", + "portable-atomic", + "rand 0.8.5", + "serde", + "serde_json", + "stun 0.7.0", + "thiserror 1.0.69", + "tokio", + "turn 0.9.0", + "url", + "uuid", + "waitgroup", + "webrtc-mdns 0.8.0", + "webrtc-util 0.10.0", ] [[package]] @@ -4868,7 +5171,20 @@ dependencies = [ "socket2", "thiserror 1.0.69", "tokio", - "webrtc-util", + "webrtc-util 0.9.0", +] + +[[package]] +name = "webrtc-mdns" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6dfe9686c6c9c51428da4de415cb6ca2dc0591ce2b63212e23fd9cccf0e316b" +dependencies = [ + "log", + "socket2", + "thiserror 1.0.69", + "tokio", + "webrtc-util 0.10.0", ] [[package]] @@ -4879,8 +5195,21 @@ checksum = "1c15b20e98167b22949abc1c20eca7c6d814307d187068fe7a48f0b87a4f6d46" dependencies = [ "byteorder", "bytes", - "rand", - "rtp", + "rand 0.8.5", + "rtp 0.11.0", + "thiserror 1.0.69", +] + +[[package]] +name = "webrtc-media" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e153be16b8650021ad3e9e49ab6e5fa9fb7f6d1c23c213fd8bbd1a1135a4c704" +dependencies = [ + "byteorder", + "bytes", + "rand 0.8.5", + "rtp 0.12.0", "thiserror 1.0.69", ] @@ -4896,10 +5225,28 @@ dependencies = [ "crc", "log", "portable-atomic", - "rand", + "rand 0.8.5", "thiserror 1.0.69", "tokio", - "webrtc-util", + "webrtc-util 0.9.0", +] + +[[package]] +name = "webrtc-sctp" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5faf3846ec4b7e64b56338d62cbafe084aa79806b0379dff5cc74a8b7a2b3063" +dependencies = [ + "arc-swap", + "async-trait", + "bytes", + "crc", + "log", + "portable-atomic", + "rand 0.8.5", + "thiserror 1.0.69", + "tokio", + "webrtc-util 0.10.0", ] [[package]] @@ -4916,13 +5263,36 @@ dependencies = [ "ctr", "hmac", "log", - "rtcp", - "rtp", + "rtcp 0.11.0", + "rtp 0.11.0", "sha1", "subtle", "thiserror 1.0.69", "tokio", - "webrtc-util", + "webrtc-util 0.9.0", +] + +[[package]] +name = "webrtc-srtp" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "771db9993712a8fb3886d5be4613ebf27250ef422bd4071988bf55f1ed1a64fa" +dependencies = [ + "aead", + "aes", + "aes-gcm", + "byteorder", + "bytes", + "ctr", + "hmac", + "log", + "rtcp 0.12.0", + "rtp 0.12.0", + "sha1", + "subtle", + "thiserror 1.0.69", + "tokio", + "webrtc-util 0.10.0", ] [[package]] @@ -4940,7 +5310,28 @@ dependencies = [ "log", "nix 0.26.4", "portable-atomic", - "rand", + "rand 0.8.5", + "thiserror 1.0.69", + "tokio", + "winapi", +] + +[[package]] +name = "webrtc-util" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1438a8fd0d69c5775afb4a71470af92242dbd04059c61895163aa3c1ef933375" +dependencies = [ + "async-trait", + "bitflags 1.3.2", + "bytes", + "ipnet", + "lazy_static", + "libc", + "log", + "nix 0.26.4", + "portable-atomic", + "rand 0.8.5", "thiserror 1.0.69", "tokio", "winapi", @@ -5186,6 +5577,15 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "wit-bindgen-rt" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +dependencies = [ + "bitflags 2.6.0", +] + [[package]] name = "write16" version = "1.0.0" @@ -5205,7 +5605,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" dependencies = [ "curve25519-dalek", - "rand_core", + "rand_core 0.6.4", "serde", "zeroize", ] @@ -5274,7 +5674,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "byteorder", - "zerocopy-derive", + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a367f292d93d4eab890745e75a778da40909cab4d6ff8173693812f79c4a2468" +dependencies = [ + "zerocopy-derive 0.8.14", ] [[package]] @@ -5288,6 +5697,17 @@ dependencies = [ "syn 2.0.90", ] +[[package]] +name = "zerocopy-derive" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3931cb58c62c13adec22e38686b559c86a30565e16ad6e8510a337cedc611e1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "zerofrom" version = "0.1.5" diff --git a/apps/www/src/routes/(play)/play/[id]/index.tsx b/apps/www/src/routes/(play)/play/[id]/index.tsx index 868361f8..4352f4f0 100644 --- a/apps/www/src/routes/(play)/play/[id]/index.tsx +++ b/apps/www/src/routes/(play)/play/[id]/index.tsx @@ -18,7 +18,7 @@ export default component$(() => { video = document.createElement("video"); video.id = "stream-video-player"; video.style.visibility = "hidden"; - const webrtc = new WebRTCStream("http://localhost:8088", id, (mediaStream) => { + const webrtc = new WebRTCStream("https://relay.dathorse.com", id, (mediaStream) => { if (video && mediaStream && (video as HTMLVideoElement).srcObject === null) { console.log("Setting mediastream"); (video as HTMLVideoElement).srcObject = mediaStream; diff --git a/apps/www/src/routes/watch/[id]/index.tsx b/apps/www/src/routes/watch/[id]/index.tsx new file mode 100644 index 00000000..ee4b3904 --- /dev/null +++ b/apps/www/src/routes/watch/[id]/index.tsx @@ -0,0 +1,303 @@ +import { useLocation } from "@builder.io/qwik-city"; +import {WebRTCStream } from "@nestri/input" +import { component$, useSignal, useVisibleTask$ } from "@builder.io/qwik"; + +export default component$(() => { + const id = useLocation().params.id; + const canvas = useSignal(); + + // eslint-disable-next-line qwik/no-use-visible-task + useVisibleTask$(({ track }) => { + track(() => canvas.value); + + if (!canvas.value) return; // Ensure canvas is available + + // Create video element and make it output to canvas (TODO: improve this) + let video = document.getElementById("webrtc-video-player"); + if (!video) { + video = document.createElement("video"); + video.id = "stream-video-player"; + video.style.visibility = "hidden"; + new WebRTCStream("https://relay.dathorse.com", id, (mediaStream) => { + if (video && mediaStream && (video as HTMLVideoElement).srcObject === null) { + console.log("Setting mediastream"); + (video as HTMLVideoElement).srcObject = mediaStream; + + // @ts-ignore + window.hasstream = true; + // @ts-ignore + window.roomOfflineElement?.remove(); + // @ts-ignore + window.playbtnelement?.remove(); + + const playbtn = document.createElement("button"); + playbtn.style.position = "absolute"; + playbtn.style.left = "50%"; + playbtn.style.top = "50%"; + playbtn.style.transform = "translateX(-50%) translateY(-50%)"; + playbtn.style.width = "12rem"; + playbtn.style.height = "6rem"; + playbtn.style.borderRadius = "1rem"; + playbtn.style.backgroundColor = "rgb(175, 50, 50)"; + playbtn.style.color = "black"; + playbtn.style.fontSize = "1.5em"; + playbtn.textContent = "< Start >"; + + playbtn.onclick = () => { + playbtn.remove(); + (video as HTMLVideoElement).play().then(() => { + if (canvas.value) { + canvas.value.width = (video as HTMLVideoElement).videoWidth; + canvas.value.height = (video as HTMLVideoElement).videoHeight; + + const ctx = canvas.value.getContext("2d"); + const renderer = () => { + // @ts-ignore + if (ctx && window.hasstream) { + ctx.drawImage((video as HTMLVideoElement), 0, 0); + (video as HTMLVideoElement).requestVideoFrameCallback(renderer); + } + } + (video as HTMLVideoElement).requestVideoFrameCallback(renderer); + } + }); + }; + document.body.append(playbtn); + // @ts-ignore + window.playbtnelement = playbtn; + } else if (mediaStream === null) { + console.log("MediaStream is null, Room is offline"); + // @ts-ignore + window.playbtnelement?.remove(); + // @ts-ignore + window.roomOfflineElement?.remove(); + // Add a message to the screen + const offline = document.createElement("div"); + offline.style.position = "absolute"; + offline.style.left = "50%"; + offline.style.top = "50%"; + offline.style.transform = "translateX(-50%) translateY(-50%)"; + offline.style.width = "auto"; + offline.style.height = "auto"; + offline.style.color = "lightgray"; + offline.style.fontSize = "2em"; + offline.textContent = "Offline"; + document.body.append(offline); + // @ts-ignore + window.roomOfflineElement = offline; + // @ts-ignore + window.hasstream = false; + // Clear canvas if it has been set + if (canvas.value) { + const ctx = canvas.value.getContext("2d"); + if (ctx) ctx.clearRect(0, 0, canvas.value.width, canvas.value.height); + } + } else if ((video as HTMLVideoElement).srcObject !== null) { + console.log("Setting new mediastream"); + (video as HTMLVideoElement).srcObject = mediaStream; + // @ts-ignore + window.hasstream = true; + // Start video rendering + (video as HTMLVideoElement).play().then(() => { + // @ts-ignore + window.roomOfflineElement?.remove(); + if (canvas.value) { + canvas.value.width = (video as HTMLVideoElement).videoWidth; + canvas.value.height = (video as HTMLVideoElement).videoHeight; + + const ctx = canvas.value.getContext("2d"); + const renderer = () => { + // @ts-ignore + if (ctx && window.hasstream) { + ctx.drawImage((video as HTMLVideoElement), 0, 0); + (video as HTMLVideoElement).requestVideoFrameCallback(renderer); + } + } + (video as HTMLVideoElement).requestVideoFrameCallback(renderer); + } + }); + } + }); + } + }) + + return ( + { + // @ts-ignore + if (canvas.value && window.hasstream && !window.nestriLock) { + await canvas.value.requestFullscreen() + if (document.fullscreenElement !== null) { + // @ts-ignore + if ('keyboard' in window.navigator && 'lock' in window.navigator.keyboard) { + const keys = [ + "AltLeft", + "AltRight", + "Tab", + "Escape", + "ContextMenu", + "MetaLeft", + "MetaRight" + ]; + console.log("requesting keyboard lock"); + // @ts-ignore + window.navigator.keyboard.lock(keys).then( + () => { + console.log("keyboard lock success"); + // @ts-ignore + window.nestriLock = true; + } + ).catch( + (e: any) => { + console.log("keyboard lock failed: ", e); + // @ts-ignore + window.nestriLock = false; + } + ) + } else { + console.log("keyboard lock not supported, navigator is: ", window.navigator, navigator); + // @ts-ignore + window.nestriLock = undefined; + } + } + } + }} + //TODO: go full screen, then lock on "landscape" screen-orientation on mobile + class="aspect-video h-full w-full object-contain max-h-screen" /> + ) +}) + +{/** + .spinningCircleInner_b6db20 { + transform: rotate(280deg); + } + .inner_b6db20 { + position: relative; + display: inline-flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + contain: paint; + } */ +} + +{/* */ +} +// .loadingPopout_a8c724 { +// background-color: var(--background-secondary); +// display: flex; +// justify-content: center; +// padding: 8px; +// } + +// .circular_b6db20 { +// animation: spinner-spinning-circle-rotate_b6db20 2s linear infinite; +// height: 100%; +// width: 100%; +// } + +// 100% { +// transform: rotate(360deg); +// } + + +{/* .path3_b6db20 { + animation-delay: .23s; + stroke: var(--text-brand); +} +.path_b6db20 { + animation: spinner-spinning-circle-dash_b6db20 2s ease-in-out infinite; + stroke-dasharray: 1, 200; + stroke-dashoffset: 0; + fill: none; + stroke-width: 6; + stroke-miterlimit: 10; + stroke-linecap: round; + stroke: var(--brand-500); +} +circle[Attributes Style] { + cx: 50; + cy: 50; + r: 20; +} +user agent stylesheet +:not(svg) { + transform-origin: 0px 0px; +} */ +} + + +// .path2_b6db20 { +// animation-delay: .15s; +// stroke: var(--text-brand); +// opacity: .6; +// } +// .path_b6db20 { +// animation: spinner-spinning-circle-dash_b6db20 2s ease-in-out infinite; +// stroke-dasharray: 1, 200; +// stroke-dashoffset: 0; +// fill: none; +// stroke-width: 6; +// stroke-miterlimit: 10; +// stroke-linecap: round; +// stroke: var(--brand-500); +// } +// circle[Attributes Style] { +// cx: 50; +// cy: 50; +// r: 20; + + +// function throttle(func, limit) { +// let inThrottle; +// return function(...args) { +// if (!inThrottle) { +// func.apply(this, args); +// inThrottle = true; +// setTimeout(() => inThrottle = false, limit); +// } +// } +// } + +// // Use it like this: +// const throttledMouseMove = throttle((x, y) => { +// websocket.send(JSON.stringify({ +// type: 'mousemove', +// x: x, +// y: y +// })); +// }, 16); // ~60fps + +// use std::time::Instant; + +// // Add these to your AppState +// struct AppState { +// pipeline: Arc>, +// last_mouse_move: Arc>, // Add this +// } + +// // Then in your MouseMove handler: +// InputMessage::MouseMove { x, y } => { +// let mut last_move = state.last_mouse_move.lock().unwrap(); +// let now = Instant::now(); + +// // Only process if coordinates are different or enough time has passed +// if (last_move.0 != x || last_move.1 != y) && +// (now.duration_since(last_move.2).as_millis() > 16) { // ~60fps + +// println!("Mouse moved to x: {}, y: {}", x, y); + +// let structure = gst::Structure::builder("MouseMoveRelative") +// .field("pointer_x", x as f64) +// .field("pointer_y", y as f64) +// .build(); + +// let event = gst::event::CustomUpstream::new(structure); +// pipeline.send_event(event); + +// // Update last position and time +// *last_move = (x, y, now); +// } +// } diff --git a/buf.gen.yaml b/buf.gen.yaml new file mode 100644 index 00000000..b420ec62 --- /dev/null +++ b/buf.gen.yaml @@ -0,0 +1,17 @@ +version: v2 +inputs: + - directory: protobufs +plugins: + # TypeScript (frontend) + - remote: buf.build/bufbuild/es + out: packages/input/src/proto + opt: target=ts + + # Golang (relay) + - remote: buf.build/protocolbuffers/go + out: packages/relay/internal/proto + opt: paths=source_relative + + # Rust (nestri-server) + - remote: buf.build/community/neoeinstein-prost + out: packages/server/src/proto diff --git a/bun.lockb b/bun.lockb deleted file mode 100755 index 6a396664a34a9c0ca71a7a8f13cde20b54c1f185..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 757560 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�iiE}x@XI*%QiYa^n+NjR=2-ccg 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 ?MVJmyoz%j6F#IchGCz^a;Y$u8 z)S%Z5Dcu?&gjJ;>w4uQ zc~OQ&VqQ4zwZFu7JZp9u8!YLcyWq<^Hxc6`>Qsv>HNNl^R%w_MeB(qB_@OCLCTj`Di+ua3jXxFA|^_8fKixGT~JuOm@haCq+@pIx0gUMND$NNZ8+B zCu_$D4@PUyy8rfzejdip6dvgaoNs;vUFGZaSopP_QAZuekBTvuX;I>bH?;H=OI{9K zmhRo_VLv8{=n3Q=sE`Dr`A2@iP<~i4dz#D=n9g~a;NuH0@dn!040L13DTl;$G=G0B zmqo+B4)xtG$`#u6gizJes<>G3dYD4d)bQo8D!)S96-rkTZxtfpi;NFN8F3~wz=d5s zG=K$MbI{GZV;Jtmu>55mQq7}z&?GV2f|)7~g*}+Xo_lQdnQXNnDe=v{hmK+^d(?6N z`dpR$4L`r72PWC^F6{4C#{mVvwE*4m#aaY6gvLmsOVhC;i7cT_u2??r%*N1f>xIgw zj3!lWp&Iavq53Cf~$9e2QW4NK5XTrKuson%eN^Uf;K zn%y*;>|31AgA0CHg1}C+s;VA&mw1SBS&%os`*1;4k0Rc+q{)ZbOwBkHLr+#W?6Ugz zruhH+;uGkeAcib6x2_LDs;chw+|*Xl9za+=W^(H9oK-G5n};lWi1*r#|NYXC+Lwg% zAo*<5fwE>dYITz<x=Mq8m?ixYiAYbLL5 z5FKz~{k|=)80#WEj0y3$jxg$w(l}?3Mj_j~%2MEc$m7`m>Q2wkd27%$;F)i1Y}KA? zdGy6Yb-nnMoGXAu$>8JT)uO!B)HOM;phtoLhlf_@Iq>I!k2KWSKP~xJ);+dIhF#iI zvfn3g{9psR_dDVAavGImJ?WSl#T{oz6G6SISca(E9|jfE9?q|HZRhQr8XcVS^j&sC z?^T7P9_%qqqu{=SzE};~~D+(_c-QzcAh{M&}JLY%(fZMoKJ&@YSJF+u+;T4py7V5Q&+Zwd} zy~i+2JwK_l?DK@IQvc@Jndl|pI)E;8KkN@mX{ckX4l=w&PF-E7P`1<5`M*axa=rWe zk&+f^d0Kkbn|*V{w-%4cd@mUUCGy2Fw$a+Qa#NqOAIl-Y{?`$7(deZME0MoOvl?7W zsJi_OhmaQkq*wptA#N}j+3kywJ0I+&2aPYmr8iAz6<_n2lEdBMRtN88Q{nctrsV+s zM36wMac&&0|gD8_BRkAGPqlC z9if=$`y>~Glfe} zp=(@`7KPc1)O=-(=5~Xo_BtxYFER6|OVnFb`j)fw%mVD!T|ifa)2M4^uql$CCDgZ= z@;Xv4>*3hQXywD9g^MNf>Hyn3ju z67pEZ9>6H!FZaSC6i+6p;87UkL21icu)x8Mb=bdoe$VE)e{cs~;SM~ zno#b1UZ}K@;?ZUY_D;6cdnNnxYiKdHcO~1oYoX*O+|I?p4blbnwp1~l2No)Qrb~+8 zJ_&Eo<@wzDL2fgKf(s%3a0L>t26n8l6mBT#?bR~j<(JIqc#(Q0bB$lm-WW{j{yzKIu*9d$25u28@^v`pFQKe#Ke3^R_qEnSS>de&7W^2p$H7Vw+dX~46s*XQ1_ zAK^1gNMmX-&1_HhD_3EmV_dv|y#Aou)wJ?)nWtSIaw;OE7*gAzqW#-}TVeC&w8kd& z2z<8dLx=;ai263#%zXQPtQPAoyG}+9D_tm~lo(CD@+o{5;0Ay$X1FzH`At3w)^H<1 zrXvOtT9ta4a+IjmtE%t%lXG}v+X{jiFk2Y1$XswV68(H@&|J$3Ca{T{4n=xvefyMh0!_VG$N+kR%fG<^>vs?jr6c5*2lRZj`z z4FO#)lPPlZs~Y%{UF7-ump;rUJrU?=_+Pg2cLRzd%ZFysp*O5$thHvl*UsM*q(w6w zP4d6d*Uw?={NWOXM)T_ea6>^?uw2P|pFYO(N$S=<3-T-=)*oFo!|hmZ<|}KM!ojBU z%7JF7kn#wx?}T-#>pF>Z>WlC$y}|5uk`lOJQubVMe?S=MuAik2L$%p@*(1=WeS+>+ zKw$f<_UAEroDQKwT;g%u9+wZ}d*1?EeJtyp9E^R8*lgnMH!0E`er)aniT0mD|Lpbp zZ=Mwny47aN{3FRFnU*TQxE2V$jL#H!Ierh`YHf#r?~vOpeNSTDwME^ghxL?iLs8Sz zs>V|T*F%;@Fj$~|8H`Lp1=b5cgRaEEN7#mYhZLhSA9=f<^nR{yPED;$V>8w^oc1+F z!@~Lk%T~_NG5RQDq>;7T)$Ld~d3~)-81=!;StRZQ^Te?G&ie(5eCXtm$7rDKoXcQPVCIW)!Re zZY1amr~E-WElGr+UkrVq=OUv2elqbTx37FBd)(e&+gjG+n+`iNZm->x=(nw2!M0ZN z2j;O()KQiOp5P1{@`A1Beb~?aP88^p4`VNFA#CNDopX+9dU5ZKxvYOA?eFXUO;ycs z_gy571nw)_+u)$yQ~nF2kk3#aZIF$~R)J!uRKpzecz(1nK;CH3Wl3)xj@|zSQ|_y) zA1WrI3OtmR6%;W3mEe7*oI< zJVfKb)FE;hm$>}YM}6Jx0A9bbpzC|LPX&g@^fGcSK@;XH$qy zsX?hiR<>}gdd#eR%z~c#oqUX?mQ2vv;15;v4SNjv)csVfhf+O^KP$Lt^{D37u>Wn-zlzKp8xwcFI*jxgf2PA-Q)KgpJ7yo3bH;E+1oRsP=TwO1vf6*)UBN$d_Oo+D_ zDCQV{+dvxoMDkh9Hie-1*H4St`9fVciqZUJohF{0*FfGx&}~tm*i{lxRAr+=H0hY; zP0(UoFuL++^`sZ_CS?lPXwbIQR{SFxc`es+`P3j8$ZxmG!xZ9f=}$lr@p1H{5V&5Q z1iFfSda8fI*QvSF8?KzhiiyJ6-|CBD{p`NuG@CB-I>%{4V4X6F(T$lIxLvB}ERoDp zhkJm4DPiIz+`SXFm0}0-CW9_bFv2S`{h-r@{^EJ4cLx}Z$S_+gyQm?ut&(a8-Ar;G zGE+2`1W4MhA`s0`O00Trc!Df8ll>Mx?cXs_b$*KhZVKqSYb^V|-A4BiI)v`a>vW@k zD0(%Ha;Sn5^HB)N@NDO65SrzJC23i>yw26dE2Gq*^(T!Q?XDQ)0;<^EKegyifSU@s z4+)Nv_%+J+c8H&r#y=xQ5n=DmXbP48nJnNxUu}ullFxI@YmxQ0r zM2p9StK-|!qV8z2*zK$Zs-f8$w0fC{-rfv_dP$;5FdMKTx}WjVyz7#INBq})KBplA zbfL0#h}U?yA!eA84o1m-mS;}$rlk765Wwu;_B{G3sO;}()83mVqmT)ar+aN8g6q|R zU4y6M48PD@!oJ2is}H!Dpj#BQbQoK@-2L;#AJSUYH!{3f7giMH;s+zrOnvJeo2tZx zto^*N@05aGz7*QD(Qb5CTeswIu0WMNxys>>6@DJ~J)aMg1-f<9O`Zg)PZsw2?0XF3 zbxkX^t@+m&K3dbB$9yvW1Y4W^mM*xCa!gyAXl7~*Q1PsE2bs!hPD(ecLBEk6ki0BXBbV`RU*Sive{M^%J z`)S_2GrUi5WEK&vs}ff7=6P<1=e#+f%WS?NALx`$HYP2AeBhNc$?wHXjzskJR_?%K zzn@j3NzcdS#ga|GiC2Q))JKZ~6h{iPI$qqJCgkXF#CMBs&*RkRb0u;?mtn6%^UYF- zb9}b3hSTEsS?XdT!`pFElV9Yl1moYTJZzk3zx_-Xad!^)mzR)07N^djWucRFvuPd9 z-~N_<_xwJ=^SKgvpqu2)=}u$19W-e4j;js-fbiyFo$N(Yeo|WCyWk!ydCL9}G5o;X z+T&I|3&{eAN6U>s(!ry;XXCj*n$tyQf zXy6p~BN*n0+Tktbu0rEb=n`=$Vi|Syg>&iX%G0d$!dRI99cdOY#o^jtgRBQ@^aHU<_og9)~wZQ)C6%exEktb zTp?C|#3U)R95dfX;(6}ZpZ5oR0o~Mm#qd=HVVweBJ0&C7-zg_{;TvCDedi(@PLC?H z=y<<6ch7zFlMd6~c0jrj_S~8*{o&Sa`c+Xo`g7u+V0wrD<^5+rP9f+HxAFhLl#Sw( z9OP@It}qkaDs~HsT~+8!?CGZ_uOf9TuFC1n@91CrZFU%W?*R892W=8dWFMzwwL0jk zu?vUof3ELew+M8v`KGQ6ygaxwyhrIO&(PS-H|_kjT~gC8C`lS?x``}zkK!jRe~lu& zZpc@gHxk<3@^$7^jHEORIU*F>?S`KJ*L@!E6oc-L)lwbZCYAwb-{bB?BaY)Lle3f6 zhsq9vYwDen#lZG-c*#G5Wv=mVM{+rg@58T1Y~VNvi|o4*ozi_rQwD?qw*+(x%ua%b z%8SAf7BJ7JM+tZpBhTF#lX6#4{MS`7Z0Uth==hR+jt`lU_ojqTXG<5nCP@u{bcmy=z{>nJgZvVdC-x-;TYgG`RS zk&~uk*2sd<#eC-JTCiHP4A(zky7QhE2%TJ4CeM`zARI=&Qzk8AD5PipK!NJGPrqmO z^;fCmv;y1;(B&b>5Qr)@pzFjPnu^ypDPx|Ws*#Al4Ap-c*r(%oxi?2|Xucfg5i+vr z1M~S?B8!FV1~Y^%MvBYJX+bymEH1#U1l?g|)e`GRLYyId+Dy7rjR|7*yqX_|k))&d zOckY&KRDA4?H0%CM{~7dk#D#toExM*PBD+KNqFugU6Z4_egelORiK-*(q*^0pte@8 zV!&`5`KE;UchsvT_OB=jKIccfL)jc7Dg<*Bf!_%>3_FJk^#}317O_PJChem0=sp<2 zqYXx2%UO4B=_+PuFg>7vEOJcr@orQG@A*WH=ZlS)la;R-Q%q4A}!V!5nUtQ ziXH@IrP&ECHbq#RNIp0Do+`EJfLjB)2CwjJ4~u81J)9ee5KoJ~6LS^P9h3HX!mb(~tzO?36Jw^pxLt6qf_ zG*O+FK7-XIF@MSMI_f(a@92#@5lrvi=3=WJH=HYi?S{9!eM|f;vjwA}QL3}g#)O?TF0<}OITuHC%z#W+~I5yu)wiZ;spTtUz zsH7X3$S%*_ZuxYB>6#EfPSi!8f$e@mFjxB+i-Y|k`wiE75`nbe~8DVcNdnI%UwW*})M_=DteLZJn-c2i#WBRVy{3j7xKZ@Zp!} z?LO7vi|iao7KhGEK&5A&=$|}FY3*Kn68P94l#lfLXHisth2f;~o@^ex+NQM8AFW!N z_ki05x=z-dt%-V!9&J)7ZZ=S+LqV@01N~MetVM`EpAio?b}6D>mRNb2RB8<6>+w>K zQ>PAgRGZ*kR^U%&*7@Bwh5+t2&?RbS7}%#TjmXI|6aQ2gf>HG5D$kpc1ywgf45t{W zCE;C~L6}5Dou}2ZEy8LsiDh@kpAk$RXmuYv9yg1Z)iQwF4!XIT4sl4m9Ir&;Kdp4s z!gZ}pDhRSK5GZ!165vJCR#Sd}3zjd7z|B)m>vHVn*DhMK^c7!b5V}U)wSfKJ&+2@6=T4CEF>i54S_bCMx&^6=1>n zTQ}%RzI=O`eJ5C3zu$;J&MKFf>z({a}&x&q*efa{?bbmQ;(&Ao*T)ta>VBj7J4 zd7OzzJodTEJ{IFxkFow5Prw^Rpr9GloUaPZz>Q;H?w9e0b{$ry$8L5CNhO8P0@thi zKsVs)z}{o#Aa^lUC#Iy4S=rPnR;2b1=bghbp521yImne zw)|iv_Kr!~-oobY9-gLO#K{}Kv0zfy4&=BVD-V2XiUY!45UH~3LmG-XzN~qk2Rz>w zgP^A@=BWqOumxJB07$5Gr7+>-e#ej!{}j_*r{1)*;Yu<6Kq z*U_U2wKt-CBI8V{QgKlZhBA(&{-8C*W4)%YgNXs3^JAcE=6{1jv||aawI+|Btp5@9 z9od^(&SJ4srnm;FSpkfxP3O zyQk^!wSL6dYG|QqOofEfRmy0*(yaf*nHi^_Z%Pg;dM6I#$SOVmo1YJ?-2SVKD^gL_aASYK%)3z87 zV{yCImBI4SJhm?XDXme8zB&m+cMXfmp$ifdwX4}{2|u^BlyiCAPak>3gew8}JLo>J z!<xl_D0PK-^w=q?_4gD5a%3SBbwcGC6!VMx|LgR3Xx$=UDmNeC@>%yAehpi|24 z6s!NEbAWbH0Wu@tPJwPJG&A12GzAsG@}+4KSiG+WvF~SFd)wa9r0XOC?lkB+TxIaKwrQ^$+ z8X8hhmcL&gGsYr;D|NIcPr>MX+*Z_Zj6=VAX0_Nn(M76)R&{g=;P@#$vs)Xl?Ju;WBSqG4J7IeEaH0!3#`jW!X$RtP;&JZP13U#1q zNdz&8wWt`fQi|oejlZ6tAjV|L)zT#YzBk=SM&>@~qio;USwv`F?IiKrMB!7`zy7Z?P z2C1ige|QDRI}f_Y#^Mm1LB%BrHfE-2=kE~nu8QVAz~)xWv&XQ}b4tC{QZH;~@nOh$ zeI9V^1{W$qbE@ln;7l2<&3fCDJo#r8a2G(g4g3Ai1qaVxx)o5nR+acAX^4UE7cZRo z2=R-#{{+gzqKj+?l2geMe4J@57wEK7=42G) zSt?W&-V-vjlCjE)AE=#c*6BA+JvWcLj72Q~O`+7RfKl zp?X(BB*;AO)uQ@6Xli4o`JasM+Ttd%7~gtMo^)xP&Plz96nbexYWv!w4qbuJ;jMNK zwz>Nr;I4x1Y{}X3IxE}*<~MPlU3d-Jhm_7M^?QxqqoJ~v%Md$kK!}SL;;}4L2YQLM2KQtNb zUe6TsvB+C~8~K^bTxr;$ZH(JS*Xf5F-GFE1sTlNxQtd00LcskAx~2T@8C+bdVs>l3 zr`hL6D3@wKlnsr|d)2G{88)LamT!eIn=4=L81dh;pjds;5w!|=|Ke5}e=%F{Pu8M( ziUHuRgD#;8)H1~D#|-h)3y3_rl6Dlsm4p2jr1d-o{FuYkmyo7^H#E3oZy7i{Ci~mT zZg7cW2pm0XnPV74kKE+o>c#`^2Iz_nUtqu1)A>~!?oP!VYN^=|*Kcy`w624IFFlU> zy9pP0Zf6Ss(Fro!GB@A8%dgqg~9W6_US2>Hn`wZ-TBYp}BGw;z9Tu zn3l)_(S}!3ziAQKg13*#s0WVx!r|XHSbD82wtq6WVdsKtiq28Scx_bq;Md2^J}%1A zI9>(57qkVs!FfG=`)jpJjIE@Y@lZpl|x~QjQD-6Ywfg7W7la=;<9Dut6x>1w2`c`+}V?sYa zNyz8Ph+@SX3vllqp>1GpJrSx5ho`xac@0eF$S^7zIKgcoaca7E{ww+z9o)8osysFMr%ci^(x3A7U>Te zZ{}|)NouAW-HT*-^l--JF^G6Kk<}H4k|Ftig+pdx1-{0PEYn-d`d#6~v!fCvOHkVi+1r!DjQ*L^i~3J+(S1Nn`JgOUg-zn$qd&} z$LmoBA5a(mD1tFjX^I^^^wc#vLTl9fttpS*CPb+q_xj*N^yP3&e#stE{1acFaaYll5sd55r^XG5qBB+@ zk}k9_VapOLnLUyB3=eZ@|8xJTGyDeKpIM>eLJgCdixghla}2!!%T3*4J-$4A@+AL9 z)m?A}^+b!qrUeOUq*J=P8|iMOyF)sa?(R-OTDrR%=@bN!?(X+@ulK*!ykFp1d+jqP zX3xw%0|rNLu|E`+T7LOM}y#M-sor12%s7$gRx&pd+S{j)qxo=4JKP4DO-AG-YUmuH-lLWO-2eTb&l%|U41`G?;7gd8uMgE_ z#!s3JvMuy}Cus6f>(EQ}6+oe`8Bn&wI^8?-JZp}kIv6{2mjV%FF^Mu<)PyJUD~x#FWEZf5JFPy5|&xC8Hon_ltnp%dn@iOV2^+3TeqO0EB`(jU zSvdF?QL_{A|E}BrjNdEJwO{KWg!Ow-g+tOvMk|%danq@pvBU-U z?V!^-X8O~CVVFM)Vr>LwCM@NZHmOXGr13HPzjeL;!2jH9&~4g4vng|2)(8wK)ZjBI z4K-eL5bFOhGL}{_2$KcV7bi^!uWvV}(wGNn7w>LCRU@wo--WASC0zaFSfwESc9*EcF|qSHeE?Aw+d@ zQ6xJtVFfSzfTrtR>br5w*?;qke|^7hL6>f-FNi=_9f8egl504*PnLQI>-RLp`|sV^ zjB1^U1s&VCZ)V;*%YPWC;iwC{crm@SwlS`lYC~WnS|6DgFgE+&{Qm3vbqBhIdW?-! zL2<)8B>aPaS;cT2~OtkPm2{6}2^UDA65%BHtZ7$+f@7Qq!Vt2^b_p)54d4 zbHOhbKPrg$zw7ot&xd=^t;fMBnTamOogkJp2zh;L{Lv_SDsGns z`?b-r>`a73PbB_oV}Iex%%JnC(xZ6awIQ|Q5c%`-RJ+&PBO}t3U&H}7QH{e zFj9eYD@Gw`*(BOH{@F~vm~+lAIop5hi0-|_kZ1gb*@*?9mvz)Pr5^L{u3z8ZM<-r zn`Jrp_Tvm&!u$e@)DZ;1V>Bb%?bFf34CMU|?O0isk0Z{E)hFKt^`*GCCJy^cVBHe} z`v1L+As}GtTbu02ogOhud(RMZc}J&ZJmKp!V$M~0bFP&!@E|1oeX*Z&J{!XY6V3ee zv5mpSJl@NIP~KbJb>L7_{Cokfw?Kj}_OBd7=x7sMM@D8%sVv8tbu{B?9)Ab(@?Ha2 z&u4|{`Yg7c((Ue$%;&B!0n2TX$O5Ukoguk`B4z*VJB)Jh+zb@xA|cu2MOR7fVN$nW zP0v3-4+x!!a7oAiC7FI%l=`DiSzG*6xm)W=Ayxwk9eJR}GREE2lQK(=NU!>-_HfDb z-*?Hs{6d57XzCPJHxAJzt~mYPuM63OPvTrWTMGO{FXf2IzpphN9;H#Y1Fn=tYyY+y zsWMs)*bu?D&>P@7QJpUSx5p3xJl_HXx-QL?_+5H;X09Av^G4l)*mNTvl|~W!4A<~K zIaDiD<}McMT@5oSi;NO2yuu6q`wLb>v6eowDumt*ze#?N=qfNCU_sYxaMm&+oaZcS z)`j_9OuLHD>z{}xNInM$@3(iFnzpR?xOe$w#O77Ey2ks{lcje=Z427@pKZ{Ma8vRu z6RZRP7Y=mCtCk3S?##S2E~nqbL_Hx2h_RM} z5S>x16gSBCTT0?+gVP+|rp-n4xT`f`q3~PKiFKHNTdP;W^%i*09p$V>rLy+S9%OJf zl<*)DmUO;;>_ZWg8TMQyM6=`Vd}SEggdNFhYWspF6lzIv;77>I#|tsog8US^O@XEV z0OSDybVI~7&*e3u;`Pqjps8%*USU%P%4pELAyw5k;-(-T1OzV=gz+-$7E9>nEe-by z@Esy3R10ZS^Autat4f~UdI0WQ(5=dzDO4DBS}vxksrD~)5+SoWu1S{G=8^qLJ7-Y( zt={rfG0ijYJP}3Ay-$(rci?{WuCZNm^J9R%wY~9ufF9r?g09ogoG-UFS~{#Q0@6Rm zPq1D&W~G-?e_KOB@ESMwG+REw(#EDNeqcm2n3q()=@M7)=(Mhz=FXyzyB-R*B#?|x|SsUsX%0`5D| zg(%Z8R^Gk%g|1!~ipZ3?yA=^|<)pU64k zad9?<*B(i0xvi6<1-Pi78#yE0?Yo`ViiZV0|48bR(Zr?Op0#j+7A;IyvU0zkUmp zo8&y*rZs9o9T&Kn;|mZ@rsds|Awh;`b4Xdm*CL#WNzWmaEa@K{@{s=gq7B504!Xr; zP)bBOkpUkRp8XE9FUoTx3QBs6EuS4wB1^qcvj2=Dd-7yWSU2evW7+9i+KnY8_tV&k zlt|=#l@9ZTa0lNP7@#Y@Uk6_{n{~u$dy4=S2eEIc5h2h-s5z)MQ&!e!)kdj6RM3bB zInxj?GHXj`q3+YyehYl1>ZK_go-s2m-f}CkJ8E{9&KaX<;?u7fiR06$O9JWc3DBA zop>kjVzg=ml5MLBG5j10Lwui;K6iYIp-t!SCSTPrNUt_XsH+}5Fjc2N7TlVJ1zp_rBvW*;cu%b(^O1o^n9KW9S_v3c<)-rq+pu48Ld6{dLUL)2 zK6qZXPBc*;XkpLl!m2hH-JjkyhF#S8w}Q`gJkb3WnZ%n!+W2;rr_!6MtE&IcJ}D=* zrOD$HyrtxquaD3AHzRZt`yV53HOD`)cC_2uig@Yx))o(8(2|8?YF}Fe@#2H7S~DrB ziQJy(^kmFsuLa5Ua-!yk2xGosk14KEUY8!!*>vecwyGyzxHW1#-dw|QR6Y7h|E^a$ z!+X|mHdDgjdJ6&Qnn5^3Dy?O4y&J7x2$A`Acx^uxbVjZ$^8G!@&Iee%O`1wia)?2wnpF&8?8xRe(A~?N! z->B(+4ga^V_}};?2Hht`LgZ7un%av{>vD^#cc?enJjk$Ha61bF2)r$&q3sG`Q3fVs zXI5Qzwkp4W$MQdU3bnFkRYGMwWU^MilTDs_O2$eT9tD+-2-uh~;( z$~@TbXr)A9F8SkVA9DxcS@v>lNd4|@IjHY1=_`V35hz&ys_I*_i`#(jV^YwK%k(V6 zU?~{iRDEgWue*lNs+?Glra3f`#=U42xc1?4|ES5f{9=0lHlZQY#AQ zT;q%FXU|+mudP^9)&lfON;xY{*rpL8wG{?J?V4D~3=wgJukhRRQ5qvQYO)E?l!+mi z#xhMt5NbfYA3!&$0_#=du*kj`Rz$L)b3(;N7>4pjJH;c|XoOogkfN7dLa`Jwjh6jL8gHo{stk11=5d8sq9zmp^O6W0su%I>Ip=KYB_j zM7hpjOC+85@H6_IGT_pJu8Sr_ zOwu&=TSPYIMom~j#IsDe(j^Rg7+~!=%RO&IG;a$tiv%y6Gf+Km7|GDluy67 z=v~I%n#+d_cx(Cdsx?)-A;+z>*O+YML)V>2xOKKn6$3eI#dg#1F8{W+m92iH|dg!`KX;B^OQ$Jmz3>Jog&3~K(Q zew;>K+Pom^83Xdb2)fSx%D&QFu1(k$4TAI5_0SNtm|aad>zNqHJUve;Q=1FlY{(iB z68yt!m*)sSkp(PPd!W`Guud&ah({N)9)t4$CeW?P=Q;5%9aN}ZbK~0GyLaa=Av;9wZ-@s%{9E>n`-i62W00SoV28RCQ7!j6D>$Z1iH*FSL*h zYnt#+Yq>8R9<^#}8U$q!a`<>2ELj*<11>A*20G~r*&%Yl3o~>*APNS$`@7{J{hHx_ zY-m4xXA7ZuAb_(^?=26(j@(nf{?()YjR!W+{g95p zk`D1+Sy9NGRxf$Vc0>*ik!4&Fo^kR6bMWg*G~%_e*S$M$7=iH#+O)up;%#(sp}%pry*jZr{r z8ObjTGHM{y?`t)!KDa%yy)*pyF;Dh^;_Wrya)2(R#@V{4oA<)OVdRVzlW?Zwwzula zMap0)`%$|43K=;~PN!HBw*kdrWb9n-ZHl5AGp5&%4Rl3*=KEOh1}IU$sV;W*B znf*#qb4Nn!6R9SaDe^M4lncJ70gC}~v?dhlZoMCgBMQ>R$M2aFh5YlXkfUs^7Wn3$ z=stPepGUm|TrSW}Tn~Hh;4hD2!XCnbZ#(eo>8;`&IHgXlK@8Kl7C+kH{PZQGEbByh z`ja14*4VkW9Qdyv`e@W+nzRD)xZRge zE^q{AkbVv-t$=Cm{gK$4AK08r$ECH3sG@S`=j+5#74k>l%B@?T5vXI)<cgZmVCLH8}w0qXJ(BJcNwYciw*2wVxjkV>TY3AGo5)Sq%3N2{qq@6-5Yq^MJR z%)GUu?6`@@+9nM4_df~TW=B;FC6NR1@`3Kn=}`_zxryVw_9~3H&k%-xqv3~xJbMW_ zS2B1;bkf!bz20TmXr7U3aavBI#MzeqP39=;&bic&FfeUmb6I(S%MZGC>yd|DjNyhD zY^5z0>dx$>bmSge_E*<|Pu))*|n>5|J#|5yvtpp9s~- zUu%2;R{(Tr$^2!zskDq(nRtn@?yKqE>Iv}{jOj;qycyk~d-YX*gcERoMR5N>;YxL| z;g2Rz-mXSbMcWC}URf05(Le<5D;5OZ#{@4Hrh9!^s1~ozhu_Mzu7pR2C-d$lc86ij zbJ7FBh5m3;&04C9;liB*xus{6xd`@ORDZDY-(Goa(BG1Q^%5b_tw_TV^~B8bwZ(bI zs`yPs)u->*Kyh0+ZcrqV$$;jasr}kZ@X@DEis?PQ`w!?EV;^YN*3?l6HJhCjjAA!+ zRe(GQgKim#NkYmv{pk=>HS2?xN4etU+@M6PspkHd(X_#)2Pm-(p_J}u?Qxci+J{hF zhQC6kby>F*-#mXTd=_v_yZE<0^zV5l0=nlo&n6QSusBhjT6m&hyYJER*I)w3F_m4;pBHQHhU)tWJlC0`{Y6%U+MAfI z#Qv?v{)<-(bdy7y@rkAtx8LIaID-D`7ks+VuzLkZ56!F6r7vvb`bc_}yUl;SY9K3q zORSq}Kbvu480dm&Co^qSeQ{S9DgfkH9CYQIA5NM!N{4b7Q_=M6AKUYg&*+H-wjjSw z_8*X#rWMQ|*C6%A=NZ;i&oD!&^gvlvpSEFKk+D$c{HjWyC20U$3DC`P?|2G}dm$JO zjwyBFS%q7BL}8nyZDgN*y==cK{+k$_pkLE$J(%tJsxddgacKv6l@p=j;I zT>y@=kDwb?I-uV<5x*cz;t{5$=x>mW82Ol`rh)ygXcf|++-%HPf|HZKv+_qkeqLZk z!3dca0!iDBt(^y^8k;QPYgjfAuO#S_VzFR+RsZ3d8gDRzd04qsv}29LX*q?l`?#wx zQcjRLpI4qk;iCJL63i|*jl{*fAiAWKQQhZZM?E_DBZff+YxUq7$*xU_LXoZD{?uy%| z^ON8o{+`aJfI+wQ>qmb|JiwI!-4g4rru+QP?ZRit$YlMN!~DP(#P7X2S3y3aNzvFh z_T$>&h;w?RjIs5QN48fkv2W*GrCr$N1jd=m7R|n|h6AoF=>E*~tNZ+@{`@HtHhp#B z>&FjTOhjAER{bglP8;s4Z|-iRi85_?%{}WhMiN0e*4fp=2oXvWf6WQb^WTThQ8J}zhZt> znwQgd=wOpKs){xt*IWc48>(jW%Uw7_#~p`ZYOGHK@hX5WX|S)yEF&hYhny>YQIKX_ zV-b<7m+r{`+Nw)&^@yQNYBjGhX))jxai$FC_(B>j`h`%EvnAC7eAA@Lr!0ap=p z@sdr`rkHSSrd6bF7;ntq`AH9KDbUj+Tn|vRA{DK8=i5KOq-E|igfKiRCP|HpKZLz_ zGwo1F|F%H6AG(Zk0$e4~olj6T`@31Dt#G=Uv)s~D;a}x`GwCg(_~-qMIEB+dIE)z+ zy1f1+*CZxvb6Q*T#rSSESPl1^a5~ILAN8^J#6P?lPpQ+=wswOMF>@^-)L$nlLUsjPWU7PyV4DpDXNuo z6joaVT@WRbV?D)*|9pnWTsGo20cy!=ymY`-1KsQG7M31(L<}~{xP`0zaU;4rnT4hh z8*hziiK(ogxAwQS+X^GIwdLnFxW8-f$}z;X+xx^LH3+r>jS;Z~o1g$!9dvhfO9jY# z^I71z7C-+v>I{ug34t=_r_ZB#iiZ#KC*QKv7P`sH96g6V&qRE5cyQZTTC8%ATd-1c zAPfJ4?70HC8ld}YfY!E$;I!f3+pNNo+UJj9f}VE!p}*4*nqMlat4t{5+7PkEWX8ik zDdzq`NXmE6dc78i&?zpanjUIQaI&}qTusnD6c+74Q!u3_LP|>gvXNh}U3*@HK~bWJ~M$W>YFztNvr;qG9PtIqoJ^P}Z=dPQ|& z840PmEn&_dCxd9x*M1Q$NJun%6<1vE{!ncD+VUg}%-8T;&CUVtC(u=$h^lej!i?C4 zucEH6eDtFjGfpqn8(oW$D;C7y54(1LCN!P5hpC z6TAvygu?iaDF}VKqdvZg(RtU+1%8(pfi5>9N54a`Ps0^skg!Zf zorbr%=9QJP6b-qAjfxLvn>a@qrP@T_#urSPGbeZdNw}E3k2~KLPSu| zV}D3?R?rB2k1KN23W>Na!BufRAeN1WIee4cj$8hvcnQ;0tt=GzQ+BEc%9c6#H^4Om zU7Y2SuZPgi-k)pPynpYC&z#4iy`4K^Cini%lQoU_Csjb<1>uut=&>_g_Gyq+iE0kX zBEt@yI$=XWIZS>T(5_5x2>kY0fZ?`(VAq0(8^MGyZ%dv(D`AC57UA!(`dE!%UjA_>MzmNE*~ziE$&T@mu;h zoLP%y7M}aZOOtJO@34c4lfJ4!F!D5>QSBH5`Lzb!&=7?A^&2OJW2EofA$(FKk`%v< zzVtcH3S-`G_Xr3H@ffz*WwjR7*Rf*=X*wHUBJ7aBurtl?d-HT%Dt=BX16&)>?eRi= z-y!yB7-M7@xRHBqPgZQB;kt{z%rpeQn#DB4qwk)JwW}7+rhr+saWd)BF)I~U&^gVg zfbPFI`|SCt8E|bu_k+PjE38`^M@v}0N_ZSA${gW?kDZFgFUEB|$3@56k++O(Clb2; zm$J6vVnL^LgBoz(f^*_I9E(vsF{#mOyaCq^bW5j5=L%45Gpru%Il|Wmn-NXj$^1yF zBS}A*hN=Ce!TakveOc!cc11Te4@aqm=8&l(Bw*?o`?~jKa1(OkLp|WygRTbb>S%p* zt(Av|YgiY-#}}8eZFpAO{zU}6q}jC+fQeBRZ){k zD`|U;a0F+fb{5{t)S*V?k*pYW(%-z!}EnsK0eZ-|h|`MGb;5pwIT9bvMp05SUNJr-AfhC_?Z zXq8_w;C=?(e!j`P1|B`UHJ;2}^5Um)l#;7c{itQ3_j2}Ay8bO@aJe&IZ)?K#T#gQo zIlGI?ZIp5}%#DbTF-$czr2Boq^DWMxi@y8(-T_;2I=dV(g~GyM9T(GyS-2`g5&{?H zsHL5pU8zK}vHG3@+cUo{Xok)g`}2v78k}tU<){>@@y&d20T8bX=stgTKOAC($=MjM zW2P^^_KqCu-#c0A6DA8MsBX!TF4R?TsCyz``(&3Tq(Iq+5mY(NlL_B_j`HJqNLUQZ z;uvsUL3gMtd0IaYD>RL122akw&Kdy?{{nzb#xg0z*pGPupiXH zlt)>9xX^T5Qt$mjs%$7DS-|V&2D+}j!3G|?)1y*W9$U3R4&LYpYNB=4RhKJ`G6Szs zGF__i%b^(q+?iIojA4hd=aQ)-MLW83>0br?=1hg2_rUKcchHspdGOWZIe*bd+Sz_^ z9#WGSx$7XEXRrUDqAZe8zM=8G@NTe8#a|*hGa;S~Cae^q0p6^1|075YSJkaY6A`d} z<^j6>D|9Sn&P7vitn4SU5MfY{pLko!4G9K2rD=Vzc(Rr}b>)iFLVNAr@R7V5B>DaP z%{h4s#=f3<2*GT~sO}rMF6{}rak-Rg6&OPDd27I{QW6{+eZP@GXpRXf`+)?pQ0=dEXB`tRKYiy5$>ePVi z4Z7}C#IuS%%U2!7fq9g|NChfw%p36KE`6?AYr&0gT%-#diTjA6ST2o9^4?Xd3nM?a zo%;rpKy!C~a2w@VPe2A-AJC;#isIYNcM*MCrtFkhK&PVyn?32i&_uG2!IJGkuI8p~i3K92T%L$xh9Z}9`& z?Bs1!y%PJF9dhKq{$a!QZ#G4|NY?g73Scs6Dg%TAn54|IXy1fqBgpI1dT}DiPx#;c zb%_s?Fism=V(RV#uiF>U&E2n?N_5OBHqMl_UifPKNNB;~b~FFrEwX8L-1v5w{n{fN z2NBIwo%c14c->7J(J1%(Ie*c&ZAF_-0PKMre-Z}v`jpg|y9jE2LQ2^tK$JVC9GTFke@QwbINM9di%vfCJ`XM86QETk)4 zAM39(X)C2N2H-y30MPYhWlL5~P$mu^m>%$ofA5IFU@=GQy8BY)v*3zt&r(<0dt%3D z%gNPx5c3t;B3+=1o|GxiW?s!iDGWo52zV!GX6euF_*1Yx&-Ew|HXfNc0NKy1x~CjKnd@g?SONs2@SfyDtaRAkBT zHGU5at#>g=Fh!BEh4b?qvCFFP9x#{W_+(cLK)fNK%by&o+@XwhIEn}t3_WLtpDF78 zTj4K-(bc;*=*yHazLAmgTa?ZI2lnA4zv%DnA zXrGVSwKHyPdvTYeu*T^rhU4%v_gwdyF4uZx5ZgQBm}RXF&7YR%hrdnRkRL*>jTM}q z*zU+Xx*5;r76RNb(A7o$bZFr$#=2oCmLROw%kxVH>-Aclez~ygQC@0yq^fG>JcN!z zU|$^4j2R<{@+LO+JPMUHf(#u zS!b*y_}?yDFm^+WAqn)Y$=SY{-8A%)kip{>kF8qPEX!!bt`3YfB*6yajR0M53%iC@ zg!!cXNJn2~|H!^*qwq6Edt_gz>8e*_AsjVi^$`WQ4n5<^Slk-OxS4*Ea$t`Opv22bV3$wTb+0#9mTE|M{wyZ*Z0|NxZ zHHFWo2g8@)4bn&co^!1p@P?Zj*O!3j4x&J}ntphC2uJC{LY!{AFx);ZAYGMPOX+mR zF*a%{1j~x`c=qcM2X(&+YjQ{XbacFIYv>mze}dVTa2t9f%Y#WY-JTYiN#Uhd9QMH=uB$4}N z46a2wZv`@bAbm5Xk~+?2Kg4XFh6=c`pv%gQXc3+9){YvF)#Qv$h0U?&Y&Pc0uv_YX zdq}rO>KyDJUM~2qL=2W^{_Ai4Rr_bc)b!T0uy@UQPUN$O$Pci-9tXN`{PB>@H3vdx zT@xD(1JY^u-ph!RQ96S3jv2>G1KjLnwWia4zzER zDSJ6iK)mswJB|w9@gpiU>FB+{owsIDbn3T~#w4#{LY8`tBxoVjG&cbEDrgSq?5tN9pMqCk)qzr^EGqCBPP2u>s;u1l@ryhMVbY=FcZN z@LwPzunjlz)ZF}UUY*cCpjN7Y%}p5jPg zkaa=n2x3}D&S&Ov-anGj0$fK=1KqPGd&^}xQ(HodvXqKa1DoThEx7z~ZJNrouT7={ z7k}zY;UObgQ@^>Qm0gYewlQx_uCZ(_l;}u8;A&g3>4XO2O$XhY7qX3(>7^e|TXtt} zI$0n7?iE+1JkPM{Bf}zD9vQnys#l8H^hjQ2pCxtVHAopgqH9LqbH#sDS;MpxIY0&L zTp6J2b^P>zV_3k;T3&hdNU_fqJPy0+ncDN46^C1`VDhSv$Ejc#?wWFI$@utOXNcl2 zd`Wb+n`aS%NcRV-AY_3yAl^*S&F~}=(}~@YZ0y;{h`8!o`?>z2;k(yXAM@s_1c8D6 z(P_VbIn3{P}@XQd8K|gL;1c(T9X2TU1a~Y0ZE9K$CtLaC1SoksoR2NG>q%qj+o)r|E9} zDwAtcgF&~15o2XmcD{=*g(e2?^N#i^K__-mrL@gb#^L}o>+s;gUWE@d&DrG+;O2qu zb$c_JknabXS7uTX72#0^<0kx{^ZMqQbV6!>Mx-DjtJ`?Uc&X5gr*J6RH6O9_-|a_6 zkffpH`?}jC+o+waLZ@5e5Fn#(sHes1aZ#d=v=>tGc7dh%_dudtk$?(yLx@{qsqzHzg8Uflq0A?QBl zGTgI|y8YDOO{0f@Up#NnC~&@7K}v0cASn^%YEQ8J=lB315-ws!{WXWu|K;(QN_Nh|Va+V%>GbM+Dw!$9hs zLY6+(=--J^EvUG6@frmyG**4G9Fv;-8Rug#^dTu$f%c6(j8ND%^?Q5cK)l7Ei<`fc zxy#NsOKyf=U*G`;i@lX|N}>i$xct#1hOtn?I-()n-rUPh*DQZZnLoDsh9G<6m7Ikd z7V2kL%PGPdIpCInZsx|lp{eVI3iAM|SkF0E9?GiDK}Y;T)xjR}rf>O&qkJqlUHoYh zDNob}lIxvn><(_?sfB|0L^|s8Q~QkINWlFLy0{}dn>c>K7#%`OS@5qv)zxka`-79N z_xv_%+L05iGDEksNM&yCOU6A5s6G8=wlvV-w?;ktIRz#E-j2r^?E-Eo=pG1Y+~^rY zP2CNAm71qSQO^o?q^`K`d<$RC?*{>guQ1)k8PA}uEPBRznH8O3t`Z%#xjB%(1?`aZ zSg86U3(mXCK$k8@b=At?8%h&bKoD2XwwW*kBVZhB#{iGOa?-K znMz}FF!9X$;kxhau_N?^!>w^i$-{wo%Rx6OLH#vVOZJa0(^#Af>caJuy_U)t%-m;e z+-@2lo(7%Bq+$>8o^;yRG_ebawLP(WyiXr0W$9Hpu%HKrgHO2uw*qwOinH1^a+21Z zF5hr!a1Kv=4pbw28!~~a=%==~4Cl)wn!!5Zc-*m_-X^Z9e0!y+rrmsj*CzZldht7S zv8NZ@?^y}D21B&WwOih`6&%7d?p)Dl8gFlE7&iI5jt=3T*gj?l%^;yQH!C4v;?8+} z@EiXi+y(i0w}6~&_06u+82s#M_p++y|4MQ7wjii4Z2E=q*@VFR6Ht< zByknjaDTUPCVW&P@jw4wI&q&%*!Z!>g}NU9$I_W#sQE27nW>0UburWqkHOqbxA59$ z&l7MS@B?&rEK+q5XEW&3=kda^GgNmF)glE-7fe-*RU zB>2d5PZqk5RdP(W(&>bdBVmK@`5Mr*f$G{^JW{fw5^F7yn|RD@G({6b!yx~Cu@H># zrAj2i_NjjWeZL+;fJgmzp!mR<&L!phP;7%WtMfE}*9G=iAiuSs>yB9VJN$1zmAjcCZ$}h&Vs4nb~qJGOyn{o%=O8N~Z+H z7c5=&;@Azx{Lw63=571+IDBP$r1Qe?Gg%}#i~fp5rm4f|r- zb~d>jubI*cA+A4;1{PTwp76JEr8elDc~}FIW$621v?_sk8$kDhwE8qoi>H!BJbv`= zl`J|7C-Gf#%D!qWubMs;7y3KA_(!c6={V$S1V~Kol@{FzpJ2()L?1(g5hj23d%rgY z+(ytHCdKp1RBhnR)fZGJR<`~TAk@%SD5I@5tvZgoXCUN`OZDsQh6k-l)64}ph z^GC4ZjVf7*PLvNUsTaOHvBJf|dc;PU^qn@YsA-UZ^X_KQZU0^k$#r7F~Zy@O^K4>BnCpoBU&97WT6nTqY25vbA@pLU(!j^f0N{-Es8@uYe~M$BA2uorQazbV$IW zOmcVivCx^S7fn*f`4q@QE9h4I{;JtJmn^b)xj40wT|JGQqI2yoJaD5NQSXaap-nf? zad>C_bD@kMF0VLUQC*deY%nqV)^n`Mo64myR}>0x+d%g{!PF&N))8sSup0XQ>UA>G zle&)cABNhGeo#LY8|K9LZ|I93{PS%?4QY3pC2QC^)vKy|iBmn5S4Q)asaLgWqRepo{e3 zWH0o0=?MKXr;Lfyd5KSJS(?@knRZ4)6iRIt8fJ{1DIqJC0NJ}Kte) zV#P}EfC80arF|p6`d%2#KNNLqNK>xK3Y7+Mdq7uTGbw+{zT4~|+7`!3d>P7i+)=~x zG8Yxv=5$D%ZWo;(5^GrK6fsL_^JBW&hHS;bVwu|~3arOYtCP2>!Ea79hfpo{zs1-uFM}}&d%0TJxYTDQ1 zc}dzOLi$Cp&eaFHFzbzPQZtx)1(e22Dl9w$Qv(biMEN;br&ToVBJmWnmIhfAK8v@k zQ$S;QX~gSb7rD+mINBKXAphpa+l}*d1oF@ix_N<@2_uPtvEx%K zTZP8M(nL3g^$q|`;dvyt`fz;zwW7d_Vcj;dr)aiqOI%cF;s(;uIs;4L9h`OzMx z=6(s%suZ3F)td=dN(e2f?0q)mDPO->c%$rsd<=Uca`Ygs$}kBxFp2(BkBqb+6S=yI}EyibStMW=q!g1 zO5Ut*gcGgy&8iJAN5wZX-`_XY1^wQEQd)e1fopR}PLkc2?(8h?{)2ur!rQTmloMm* z{pZO5h<5~Z4G7@R#PZeQu}i)OG99nZbn$)(^@8-PlUDE~Jo6Zt4r=+l=p3(Wv|aV! zIp{anEGKpHs%O&_5H7$*Vs~G?3Am%6dpb3xC*YV=+vm^USNC5hf+goE*~NE9yN~Ux zMUu_FE-Y^?%uCNJP_I}rND_pjSEAH?=NnXNFYPLlj6anQ<^b*(=vpf(jV19#hunO6 zLo^m|)rlOD_eRJxOjfEc0nXHX6#57s0ZU_@*sPMaYL@N6zVZX}8{Z^;Y)}8qo@NHy zHt^iyIOvAm$n5_mcfhp&wdwI}?vCCA&m1rJ{VjE|-p@zAvY%3GP!8jK1pz&qn*x`& zUTT+(0kLc47HU4Kxh9gZB=f33yc3|yP-xPCl>{5xIZkAOap~w(hBT@coA{^G)LCSn zf8DlME|)QT)Jque*W%0a7m@vIOlO|x<6f{{Qy;;;imKfzg5<^zM5e4_#{{-DHO$3-1P0~)1C4`(2f5@Q0mFeP3v_|>Eb2@L!;IDI$XFR{}$GCq}(_5 zd4Wiq{RdsN#t6So(z^afLmrEH%%_IucQqO^X1-EzEZ}+GInZ^gw(48lOVfNScrL4t zDx*~GVt!s=Pa4yKE^p6cV$#OfT77SL0?EhqzCI&pV9ocY#>?^zl_c6XP z&+cNk1G6flrCct&)uo+c7Zd6 zPU-sUj&d+^CQPHwzB)inf|ZJO;xx}+RFSQkqHfOYw2OCpa-NB)UdaGQ=h1#>4!BF8 zTUBj)muU1w6e@&I%mCMns+oHs#B_&7voRZy80qVO8-IKKPHBxxw-OH{i(xz-Zv+%t zejpP0Hyo4E{6$h)1owL`gYIIeN~e~N26{wIwZxFN548T#@po^umotP?ghkP%#Oe@Z zljmVRF(fY=j$*;Qq$Kr>Bm6nld$L|8_@pojkq&dfYU@3*w9>eeu2fPGrRpSv_kFxT~P6 zu%gSJy$H?kj#o{uO)z4mQTTC!Q4^KZ5P{G^>+f>-yD9%xFIZS;60Y3LW7H6RpL-td zDonlFD%sT0xa91wfV&2|vF`JXh_i*+ZPq?%!-*mC0iW;>ceCM`Fr-^DtO({=J9ANK ziiIPY1Fo!c2<_EHIsFqta61!OxXt8>-~vgu0Cyd9Q*gd?8$>2&Yjt3UW90@xKx@H{yh&8ey(NR0Mwx9Ym@IGha-|2oa5M zq2E1D@`&FyX#nm9=$_OjjWOJc>1N%ID$OxdGOpn)DoPx)66>fp7_IQ@=ov?<BT}{#tvrSugfDq^%S%)|nodxsgh|77zQQhzhD5_dJGjpK8+3Pfr_NrH zFsD1ADMjDm^{k}hVxHHP!X`~7<+Sd|b~<3OjM8z0RKu0QI-|GSA>D}%?rsIcpzSwz zvu-%k!GZmtw?LPIz!Z%jFZYMTlljCB{*#J+q=xj&W1Q9gduYVV_OHTfuT-HsQZ0y= z-*oC%4@wx0nzwxgeBxoRd>OaN7IE18h3Zs;7$m^-QC?SxRVf^;K2!Q!QI_8!3pjV++Bjpyl2gs zS@rP)u63{74_#fgtE+n=gEVjyP`xIG-R18lsCLVIGv@b)M5%QjTJ=P%8t+DZ0Cxv; z8K`@<4$EX5kx7HCKUex7P8pctAqyXJbf3Vlq;WF!9+X8?KkK$k?zlQXL=tFhqUdT-J7jmh+* zeh9sVAujH(iKM&4sO^Be54sd; zSGh5y=T=`wUrV0x>T&Sv+cJk<=aa5_t1@tUv{82roJ5X3d7zHpE3bUO3wX2jw|VD} zNm|2En@bG4@0$p?2cWxwzrB#6NwdtkhQE|x;=$iz~2)k(t^Xroq!T!0~p zlHw((vJ`sxYM3gY{*qm!I>{@K@?d zjTZ2EIW0p~B{Cm0b4QDy2K&l*@v}=(ISHeB+4eA84^Opolh=+?N+rGn?h)vA?h%B* zb)joOGVz{=h+aAkE)VEksQK7?vJ*pP^PVWOGcT4b)h94|E}~&mKZFOASGrX6=87qs z8S3)l^I*IO++)x!>>e|-JZV7Wti^P>N{y!0m%^Dvz(GBaQyeG{WQEq2Jc2xYJKnG= zhayNW?Pfz=LvP8ib?z#Ur5Rp2#p49;lP91{h#IU*q@q1>aE~HjR&H$hWBmhenwiv= zyRyYzo8>D;bJx@$>}Ann*w#^D(!&Tek=!gp90#`RL30{OEurZnkoOdHg?r4QexF;i zB~g4pSkRG1gk(Dp#XfGriA<2inF}xJY~Jg!iuMyKCs$~Du-{|4;u1G#Cgb}JHMv%B zhTYC=1Gs0Pn_D8)wGAhxe(}mQWI`|}*BIby*6StT+Vtbs(se8=TQce0kZybK@??J4 zJ4yxYG5>hMC=U1y^&-V^g5J8CM!-D>-GOY`?;Q{5)QgGt-)+~aZ7X5YBKr;UO2@e` z4Mx=e9TiHXVbVvvK$w#z-%@`k&&$}M39&uw)Y-iV>U&k)1?K@5pzAB(l*M8%G1`2e zy3iBf5PRPuDeSnF=a*d2Jw%ya93j2UEj5mI+J2&2ikQif-pYd~&K8XM8)Yg+GLvW> z0o)gV3A%8<^T-WCh(0XH+gDe<%8wjjQG`xZSmNb&dz{4vDwL<4sNkuiB(mpq*nBJIf?45c_s?f;R7%5vvw#5@Q8rOUx>lo-S4K!t5aT||0E7)`KjjwaIZmk;R#}Mm1zuv^Q#=j zQIuY=Yf)v!NoGyXCjO=VXGsE^xOi$60d;xp$wUkd^aXMWQ^)0e>PAMjXlhR~7$$7ycf?wt=f85I90ZPtp>b1HV^abDAp^ow4LjeHq$DUkOc=&lJP#~tQu$7$}UK{*+zh>UWo(v*w$a0Y7koyIq> zyiZT|D*vwAurQ#Bj7nykbT-)Q0PTBpaT6~$YX0?fTMlq8e1*UN{8PCP(Bf=O2~l!50CmzZVq6(BL}E z9q9hqHN>k&{Js$+Dh@Rc7j%$!doi?MmhWTa%or}$DX`QXOg$s>>DYk!XP=;T|F_>x zPl_XE%65zs~i0`XU;Z*FMW;rIQ1ABCuL%J(J2pno_qk^6I=TikGizFoh7J6rXaV1 z{&KVTlX zeU6Wyix>v;p*p1THxjG0X*nHB;jn#q1MK>UTy*>i!D51lk==&AHT{QldzIb4B+Ho4 zY|3hb*i7tus}!t{I;LH0PQZ100^OBr-Sru)V_4ay5u6l55~k~J90^$|-!0*y8RjTRTk z`vSTj&a<(<-@MWk7odn=XVtHwM^6%el~{k{=5&@^OTuxXt!C!%&p5Ht@sut#8!!rd zLV3GfFS6kZh+C7S68p#kxUZm_*PdprOP$wni0@l~O2zxur5OpCZG})wVBf?Yln~@D z=;%X}ZL+uFx}RW(iT(98n|(oA@yRCIZ}2DK8;4;p;J$$_?q3QByw~C0fYdV9%Wd)o zrcyb^ha?hP|Inbck z<)=1{f~95t^JbPQsz1jU&XNjnAwkz{qB+Q7S-%AWWy?)y{i95V*ni{se-k8jO_dj( zmvB^3pUmI%!d8%yGpqZ>Mcae+F|n`q!N@qWRbjI=0{-ASEfnZtP1od{75t)l(K&PZ zo*Jf@rZz^{uG8?}$Iy?EpOPfk;2CW@KKNuiy6ODlgN*E8x!jqrlp8UiPO{eP9Mq)% z|KFfNcbF}1k7X0~bpTG!F zOirb;JW|5ZtUIF&2h&U9R)9LdfNrd%rO=DwPv~KXoapXqN&XkNEj7|9#L%w9`?)By zMq;gGbg!WM=hD$ziE?Cy(~yHLlVMNCf;H`Yqm^ZcFaH1+7IdRulkawfweSaj+%Ko- zFiallsN2?*H^*p)RdbaO>J%zW!5!9btuQbvx|~pyta~&X_}0B*I=ThZ{broGR80U} zIM8*9sU_I;Zj=(armTPW!Sq;e3}S_G35Wd7DM4Q{zq>=9A$LycTl6>;r0*{a2`^TZ zbeb6NRe|v~j;r)=0XR3ng$G@i9s9O)8uZJxj4W=lRiC&WbbM6xe`Bn>yrfX&_9f{l zE38nSqO6yH<0y?gVo0+WonbJojfolF8RK;I5FGpjTm;Z9HYTly$Q>*!R-}zUq^v#C z*sHJ~=YD9yo7)RN3ur;r+*DG#_40U7i@tFtb-H4z| z`Ky}u*OZIAig+EeNSAFZ#>T0);Od<$mZC08i)lv+f1B_hC_J?6_TWgwfdJy!#zF|X ziM`Up0Y-!nn#OnF}i*9g&hV-OYeOU~r|>v#E)*Z>y=bV=b( zSNf_FSw-kLx?D2MZ{NN~71K#2&ufc?iWhEfTj4(OoUy2uO} z`%}sL{7j7Brb53QHrh!9KAe;h=3G!PAvPg+kKlmRv9_OHxB=eszV+kqv&KJZWxHFL zlW3W7+DOMdz{LPvNro5vYV;_7>9Qq>Gl!{nN%Zav$fZ%El7G^3?!d zfi=gGYRal*ZbvQO3thaV)M~5bDp@UX|0E{px^w=%ibq>mGkrH|NuoYwH)bEnvHX5K zisjlu<%>q6D(>G!?BaClr;!Y-B9#4xNZ&vA473+-uUMXG>5C1T;65fS&=uLK_PV!E zrr$7!aXBP@8Y@=7AJ&($_iKf$T{-S|+X{c#_*Bnk@%^t}tV2(LU2|a-%MAj%qsM$H zTOMz06L`KdHs}TsyZYr*oS4;xAZE;De?J+&tQY9cpnUG%@RSseGr(c)fX;IBxJu9I z7x3|bgWjl}gxIB`@{3r$o@bGO>7M}VivzlCb1}`AVSjcxGV5yLi!H7-ta*=6Jw1sl zJ*$Y6IERdElSp2}L$unngO?sdN%R&bBv93`df$de%5J2O^W+Et7Z-Fdq~_3=I>XoZ zF_}5OGK({ulD2v4&6*dI?eEFbT(S$+uRJMO#f=sHnm8i-HCB2uCx8DAehkF z+?(dQ^gy16?>BmW3eK*C>{SN75QX=X3p1loR)k2EMk7LRT8)Ex(_-b9+jJx8aX+#G_!^gHd7V8@Q|TclIkx4 zc}YO`oWV8em{9zBZe?*3gZGQ-{lQ_?nw%|Tw6ug1Qufm*ZAa+%dbih?yv3Xs-okGh?Pm@i;HY8 z|MKmrZtX>(>xS^gPqdTNkYnAB;wgRWaaeD183o&PfV^a&d;it7nSNKGbcp!(nS>Kw zmx=NjTwy`66w-Knm9V*n!Cd6`8P88&c1I<>CpV1xo3;dOt0%G{j^UdH|Ok zbOpn&aJELoS6fdqCJ&(wE+;9t%h|*FKS=cHc)&XAbF+#y_+GE*0of zqRm(?6O}f+GBc`$qVdIi)=b6?T0zSb4InZ7G6;$1ZLIIFVr}ZO16`kV<81rAGeVl{ zxcX$Talq;(7dc=ZaH&Bzm*(2Wz7(N%M}TF#1CvPL%MD`>Z~FBy&pn0?KXK6TQ(n{O zJ8>>JlkON8-K{&s1FoJ>z7yGS(psnA_q|GBKkFUn+8Fr!nK?gyNo1*EBFIYJwi=i> z#n>~=FI+jcPeH_0oNd#s4YB^B$ta9^n;(0xL5>|mS<@!A|Zj7P~jy0WXiNkbY;8JjLcE zdGnH6h{ry}%GvB<-yr<)!#JmghSJ|b2Yjxk1KpJ~zYjm-$HvMvH`4g=^}8go>VDM{ z-Qf(RT2S63u_l@^4!yor&Mdu;{5Pq?;b9zm5n5fM@cW(2&kyH^q5L&K9q2)K%<_6| zg@enrCS2HDV03DgokK)C=}c8`bfLN=jGeKdFPi3CB^yW?`86N zH98+ZHOh}`04@XQW)6t*BiGwBqD{MQP!94{(-C6s{XX1J^eu@STu+u$CR>>%X1$*M zcNc!NoV+D*@R#_&1j>SwobE!9yd}6a^uKS{{D0>aGlH%*rg_9EjICRhM{o|i+@;}T zn_nzjXqOB^Y+#Gx(2efG>Gp1-JZ>cpKYzgog%*gytuujQcySE;g17J4dc$BpmI-v< zg|JKZm+{)Kem*rM(w?7*Afm->#{9Y;m0--mZ|I&}JYq3=rs{#LoTaJdUq`j>*14zW zpGokdjIBN*)E+Mb)PWgv*`%x*38M%1wC>{esvsV_`~Q9wpESS7|8h$V1xf0k|xn8?;E6?J-y0f^zn9`i>^)wSvEY zE1ORv42l5uA4w%X{ZIWI*kc_-WxLGEaOLtv`T7KzYPzZdk1r)Qg1b}y^PO#0&@H(# z!|`iJlGuK;fg~U~GNM;P*PApLCDvqR`|qqoc56Va&Cf+|k= z*3`S(ziXM?XnjClHqeb2T}_*zZCP ze|mR#KoP*y{<=O)9(8y`mZ(1qv5&i zgLr#$mq({?-pj|e&GSscX+AmptRQrf9doo`Yv<9rT$3jqD%<3ywoyeWJH3$pwOZg< zjw3S5iU4pwfG&sXn)?Umub(B?Dp(R>x{gwjSarK;QFQN=ySa$V;etsT)nnkF|Ih3H zL(h{>vU(_1CwfRz@eeY`85o`i*xbQFg4V;FWQ%LcW(%5D*gw=7uljCn?(D{3>O`BU3zs1TgV0W4veeEkqI=`L>Z z3U`G-9e6-D(!i)AlH~=iD-+#1Q9xeLb>}ivKk}FV$&VF;L5g9k5b2^3-QwDSR2cYl zlEtg2=rB8ShN}s2okzM?@^zL4z~u$qWO<<^m5$Glbzy(E2cC^gKg8kPd$yx-A{*vt z88suJ-qgKc*hUU@SwcY6?1zvjKiHCr$ql%OdPtX!KIRn%`wV=b%a{CR>@8needr{X z&dW@D1F8tpmwzgaKu|O38ScA6nqQ;y4`LcaWUUsNZcJ4;m_Ft8^-%3giL1E39r#E` z|J~I8|NA;W=)zqJDoQ-J2=6bo%Q$YuX52y< zj9#@&pML2Poq#al`cQ&T{MkTM2CT0D=ng6(NX(6oR&Mv$AZEPZ`WBTy+EiAsQqNGM zl)>2*WS(V}DA<3@fv}z=L%MBO2N8H0BWzphkF)K$z!_uN2=-$ILHG19R>>%+C?-PE zEhVbK#Z@^Zu|a$P55IF=@J~f_W(1PIsJV*CCe`~bZg!7iiA5}%%76V_)neA0i>hI& zAEJRe2!SqRnxLHHcxr4s8R7Q979L8p;o%iM4zgtPth~*8%w+WE{#f%Cn98~ulVXv> zjeQpnttrZ_+y)x9JhrJ81SPN!DGa)?Z!G4E56zoN?9F*OO|`vSW(-nwc!W|Vv)BGs zQazo7hzR*#EaXWlu~;0{>*NH?nadF4nq0$&oRm+FZGS)kc||}srk8qj>B|VsFY)aY z!==C;@l}4j6rFYkhGk1!NtxTn#)wn|FX?ZSonB|fRoBJuMJtTHcy+7u*G!KgPcx2Q z0In$La_2z9|27v;8(T8O?eHM$M`7-l(t^z+{T7?&=`HscuYyg8(es_T>Bvv`9E=JA z3W+isdSm2$r@7KOd;XaI6u=b&-4xfp7Ne+u_s$BO1s;LH-|?uM(^Um)DYnZ_lWnGj zG>N~N_%LrV(I+pOsHi!*Ez_JRFfPXO4_SRBn3}Lyy9Zox(8aq;Q&aw3AHIuKzzSwo;sgYw3JPL03MyKfI&DpK zDJ+o$YW)Ir(q7I@K6S%5z_Lv|}X3L@+FHVUBTq)44`Nz|0v}UG%s*~y5kJ&%@ zloz6IhTU)l*}yAnFOEQNr5gF?TN?&H9EQkNEL~5yy>cVw2TQ(hjVdg~>YfB$fGZ8U zi#yB$Q?xKl3oW`b*=)-Xgs;-J()!b=86qwQ*_0aW0!oZWoWc<=M7~th%Zn3-`1$50Fi;bfCA{YJW8KzrEK`N1`{S8IGF3qm%X!9 zH^#4f2uh6P)PO>6fa09>WP?8URIeiLmydfT_~C)F<`;@D>}h;aOl&g)CyLHTpvVf zeJ>FI4XrYO>o7{7t0W;;y@I2R34bwY-108=RHvSfd5UXjdoe33-^^~cqG*2|QFH2D z-N}Rq!!FLhmLF^?j}$^_)uKcWe1;INS3q86(EVIp=A|KMD|+aB=pQJls*EecCxW;D z^F;)CWs?{;nvGs7&>Y2L^|;%aCL%Fib{0SWg1tV+=|`8HYpt(UDcFBg0bK=$+@j(Z zjE=9HkeDwlgW|LCTJCfN#B%CF`Yf=OCNM(zxupT4e6=BLwp8ZYc(1BHlu{Tl!e852 z+7Ui=4Q2p&RY5l*I5U{jFZrE7B-}K$1!FCAb=j+rXI!wYPlP~f7b8j4)o_7xL5K?N zL_dcCTN7?$b~exAk);3K=1>{ zcOt<4g$C%tOl9aauTAZu+q761N?J_|v$owx4D)==yU}}DE$P3og=~@?Vr%tP4j+fE zPlc*CE5d{bE|J1lss0lF>3X3I$g2suc+WyKhh@9>+r##cNC~z7ef;B`#5UhQ0-2gi z*CQK|IwSWd1e`*(a3Ayrts@eKa6eA%gL_2UOwm`ypPP^FywgLw4xfD$d(3DZe+{&C<5!GmZFK!%+G6$i zffvZD4Z4rjrzf&(vm%SjMxh>6k*qZTw*DI`3>$PS4}5oMdoFeDx9M*_9JAEt;}&Hm zOOEK#$=H5(hS-}#tH5ipqz3Dt1G?&sh86LjXpwjZ_y!9F&Sn?~1v>AS8Fudx{M7jG3HuP*4;hQWVR{jQ7|@`%GX zSapf|0CO7~9ippBLR5AHb=8|sa==K<^y-8g=URksomo6`Kn?zWJh!7$-=Yd%eLrRS!lXmA2T9Xw~?B z9)1)%x7D?npr3coQ#vLIaP>hqVpxQ9+m_q0V@&_kC+V))&N`Jar?F+CmO>sKjE`EE zZylFro<>K$gwCo-LMZ6U|LPYg+1%Rh*YPOY;i3jri#c6lxKy#uy z(&T+wK*T4gYG(7>YNj8?{&UBzHk-hFwBY$qjXsj}$SfC`OikuzOw4z3HHb2yVIZ#| z=>Eg|RjtL3qkY)8{?AkTQ#1WoPjgO)gFdOhl-`Gfg_X-~CS@@U)Z~@9Upy3JY2N7` zQ4e#sS5l8|@4C0%QG<0b0$l;dIPEVyNFi2#rIo|z(q8@$v9K8048&S&39AKgWT$BHC zE9?=X6&Z{-qAzh&Q^#Dpx$96-7($iWDZCudRm_v^PNqtILUrDRbgvx(7LV>4HjH(}En_tjNHheG&oGuS=JTRi z*?##Q_>|ymeU}$%W>AN}#1W|}u$pW{mmRkYzSm&}y0GJm{SbloC%f)rN(KoC9juvx zxaH3sO2x5I9x#96o(o?8BI=syS1~xl{+*)ZOuB?^Z%88vK+JBb8*W4V`Ucd&9CSZ@ zGpQ*YB=+k&xW#FR67#9k?TQH*!5q$EaPI9kZj?nXxG8A;UVO;++Vwg5ilit*7QtbN z51VDD`-XpB$@v*@EkO6TJjb5@-beX3|B$cS{UhRgSixw*lnzML+Pb0jb^=rbPXzUt z+=EKu>2q(w1INBJ*oRjVteieKc@^)Js188a5_DaS+HRdA6yxmK{{F#_z!7sa*~4gR zqqmq`)mbw|g8j|bp`i{S%EHj5`&GH zkhNQx8lh%eywi^OG%L&>fl$ zex=6R$+wgrZ+(PPey_-x2(5bbwAfEO2GrLYbcf!*zeP{7Nn?Z!?#}0fq=O3#;aJ@}_*$J^sv4IDnSV!TF9u^t=HWSTnQVXRsZ7YL*80=0@?Qr3wKh+8 z8iJc0Y*e?&wDA%m{By?_cB=Z0<0@~^KHJ&+0uRNOhnspNAq-47rrD8I`wFg~i)_6ZS)4#}J zFnyyjHKI%MX1lxe1QT+@=9 z@6G1lo>cs`hlI~JC<;r(H?jA6Kwd}CWl$_@V@4E<X^@oZXc{doDF!SBc&*6P>o( zQLTVZ70Ro8v2T6-?-Oa0<0jy`fUdAU%Ty^dQtL~Nm1%KrlsUvFv4L|)J3>f5o?JJ@ zj@p3|=*(OLtLW5{&{1dchBC&_Q`=1i?u%V*+R5k>IR}923c4(73gI3yWJBg6MVh>W z{v0TCw=X9Dbnfgr>}Oft{JZ++Hg}lcQedKOLUg*Bv{w{W%qDLjp@5$5;eyBL8~D}XltaS zZx0fJb(FcZSE&~2-4=Kro;&FJcq3cmWq)hDs>8)x7Pi+8UWn(x6rVB`pBXB(#(SAk z7wjin-eghhl>X;VgvzIQVQdiUVH;fgj4P~H%l<$8O%KqGdNVzG+nB^69F+4mFq73< z!u?6-;0UwPyp;5zH^>|={Zz(~bXxH9BjY1f{_Rjc2bJ7!@n6Jdt}#RSu~<(`Kz%=h zu5w4jvl#+(X8JaXUt=4y;RP68 zYoW3Yoe;J=pd2@pVgdIH=;~2KFpEOPo%#eJg%?-n(xM8#W;K&~dCDKaH9%GUHRHy2 zIx%2{?eJdcAbn4xsi$!7vhbwTJ3m!hY0ra&R0_DBpv!6}V)hTNgE&f7Czt22(8`J| zbIs43Y5qodlcX5euGqz^Kjy^2u3Z`N!%m#b{K$U?;r_16W%JsalEA(I`)^yc^w>s@Mbjklvunh*`YYGCzBzzKA~H!)G?MKfPJa zL5h5vK|>Vyp7)8LzRJ7^PK!AUtu(jJ#~8~htmG3pToXrgv(IBcZNR2Ikk3tO6UMPTf`oq^P-vjcHp>g4M#;yqqF;G zaq?k(?8`a<*vIh&-67}ZdV_xwln2N{4l^a>XB@X%ZFgPXT$di3K63SDDPCl{UnX8Q zR$NshWyUVh_*K-R-MqU;6T;t<6J)gbs40Y8NhZg;MQ9 zTI>F6=tOcLZvg13LL=n2>0eq{rxtj;ZNq9b9Op##Yt7)VR>i0>K99IwjgcdIwUqq# z1yKcLE3Vr{FA<85P3Y)!kJ=|Wm2*O00XGnI)re>&+OC;MG0__owbsP-FFgI7|ESbg!or6)HC&n&XPZ? z?JxE`W}&z~$v~HKZ*{kEeS)geya%|!pgXzXlK(w4WUwY$;9}omWG0_vMk=VmP2FQZ zc`@Y=H^eHdgwm^jZ{s%R*qjXu9EUqax4SA;(zT!;&mqA#UodY7=$1D!pGi~4S}J&6 z5Y1SNLl|Y(Ul!45s@59uYGjltP zL!_$4ci8sly~(6rJbO~meSu>|^Zb$IzD>sz{57Jo41gO6x~v}!95;+u1|<|2Cw?w= zKn4)bZB(`gLP6RopUN8X(fYD|aFG_6wU8scX8*k9X(8r3KO}KOeR`r7frZNQ3%qVo zplg9t&Z^&dG2icj7goN3WXw)m5`tb2JCa>c#S@R`oV^!5u++{HR2mG*Jn+CO+HY%kmqf>}czoiVFCA77MyR zoslB+bXJ~%oNcGqcbH9hsReIiDwa=tQ8aG7zh*NT-jr8sdaXm|X_IOV;XT5`qNPdFQK_r$e%NDe;c{a0&YC${=xf(Mn}rJ8@($vz7s@;m#+}K zaBydAPyWYsSE)C{m z;J-^E+iQGp-ThX{!M}@;Bw_})QDcvMQDRG>Zvq9F51L*oPb}{P z<3#*6QxIDCpMAPNKsPB*-Og42L4(1XHK=xT6TewoD|g1{N1p_Dup^!S=la}lOeSXX z-ATs^YWXR6AxSfw2&yfI?!J|e^VFLSDB!sriJ(ipc){t*FV8mAb8t7Vi~C(MLg}8t zjse<2CWo!S9nkhja9cTQj8(V&79$_5=?6t1Wn6tWKtb|HvZ>m1xvhSenV5!Mn4X3H%;XK{s6DvWTE&<_{1L()!D9m=Z{E0LsRLr6d;$wcqU6E#|9vh6B zJa9>HO2kBz0HuCBFM<)q@q4s3 z=wfEzIG+i+<=c=~pD|~1MyrtSi8Hg)o^04z-$dGyvL>xCq;3D0o9`~b@|>aNj}-RC ze^hC>dq^#sHAX5AgUn_?4ONLs2J&Wst{uhqE~mp_%33}tOc`o{Wr_>ebz!WCX)K6@ z-}d5XcWqIg6g9e@zDX)DH;REsNZ)t;a~CBm>?aK~i6bsLqyRS?bO$M&M~DudpJ1S^t*?De`AY9z#&9;pQAmbnSP@+=%aa*;wNs)&mr>Z}glaT4OUn%(JA zg6rTvLHBe@n%g!Tmy%^E&K{|yq@r|xEvqzkf9+N_{16GRKlTl!JI`6f*iDkZBrdP6 zY^J7QyFY9kpQTiPrc7?~8QfQq1G*D}eDb62`Fzj@yQfa6Y{-n<*Lb zxDZRL1QoK8B=)BV(z)UBZSsj*GIbYdTiM!~4ABQc|N= zc{%!OYOQ8jM?hD^$Ht-NM|yYvZygTHm-xD-wSemb_`Fj9y6Y`nyoEo)mb00@O_Mxv zO0bUG5)S0eI9lD0%E6GgKpY_KL1ZyHuI5FY*!U{>iy=pRq_g5){{`eN z1YMyYHITEyW}1`B_s@2oK2(h2t-)sN@MM}WaHjT(6bmHf(GWk;dXszc5e81@GW>XI z`0%RjTfWQa2%^=wVuAZhia@uy#rZZtNbjkJE9v4#<{VjOE>*?Ga=~tbnv%b4(l3h) zZx@>-oovfN#}DDl%zT_jKOKn@VF*n-PHhz!)osD&hhor`?$-VE!VZlU+U`ZbY49A& zw&O^QTFE-ikUjBBv^OBz58tK|*WoAAC$t6v59iPC#0IW$jfU>!Fd5ELo8^#BfI5_b z?%SI{s%8QmIn6KT3wH=eg@oJpG=U3F*_1J3D4huh&`QYr%a$ADW3y3!F7kQzPeBEIN;{zQsrG;dFap_6WmlrqIm&{&uKHcV6InSx!1N)n0p!;EbNI5fX{6XEfWux>Hlu$Z9 zYF^!j?jgLa{}=_{)JOhU463$*TGDd52GaiX34RvFp1ZHmbkq2G&$8wukqAKEa?l+< ziI)4QKdhD9*6NIu0&(ajTH!uMxv>_jyqW#)ji=7nOFYH2?u34oQ zjT`5brg)vr4#gjED?k^A>UrO|;QO$>f&>gFBSdoC8Pm_;y(g|v7Jd9d*u)2EXPLiJ z!~tXSaNi}TDmR6uh44Zgs`#@}N_iFR^vDy6$_T58&+}grD*k;RPJy;ZUE+zdCwq_m5r+rt4^@F~ZASgv zJl;zNIkC~a3}pLPHs0#w26uk8ptIiZw3vG_h4d6GYPIa2Ev&3fy{ci&SDR@e_ulcE z1q*3SjIAw#d8GllKZp8muixzB4o>!|?M(6r;QgTnbjj#Q4-#6r`9F)0rI={6=P4Vl*LOfh ze2o6cP~b?QiMSZGUo>Jjs zRiE_!-W%+YJDeq97{J{seQ_^CvY^7=jPtmpO^u~9l%9&mnGUd_vv}V~drf@n!YSNG zHh@@)xir>mwR6VDjPK6zsa0ww{lV)F85D|4)Yu)#vr0?RBpWg-!dzc~=o^Nc zYRGm~v#c*53k{(mJ#yb#jQK2+h3!KExb>iWhV)!KJ1JZsLUs(vOLelH>$zV=SoOi@ zmu}5Id(k&*Db+FVFk-AwEH4C^Fp(j2bO?;Oe_;aSoP~cd*%5NU`Edj2x>nO~{tla_ zT?m_#iu`dq#ouXQeB-0Jdm~Ae-L2yLp5Ly`J(ry)JW)*4*2a)jIcQMry(ARXWPvd9 zyW7HK6CiIR=pq@U?<7#gzV;n9sIE9wW?HVeg~%n-j>ziVhI`L_^)useJei}yNG@-? zo3`NLl%*o@FO=_KQ=Vfb=kQZ`1>c`<0$rZ&YgPoz;^C0syqk)dcvUXXAw1To>NE8d zUAFTZDa0lbB|7GFr;F!by*m+@^>Bg@4;>hkA~E{t|$(*dMee?)`wkh{9-`^z1z#FJ6ZD$b8X zHJ;#gYXMyjb-Dd~GtT;&?^B|uBSC$YP-4gW{il!}?UXc3WRt&9)lV96SXNZodc@EU z)I5dWpvtRc+G!qY8dY~RuSdags1fd*#tU(wN+;y&18>8^g}c??68ef)%P<>ag@6PW&x)YK`r18L>_p+Z(Zxu1k~ zf!{+r=ynDZ)L%WHp_amY$4-~!PKSdm-JTKQ-Td)qpQxO^rf6M!oFjJW-N!HXnq7gY zkQOsM1)Ci6gPJ3*J-f6PHEd&9%OVS<7l zR*U^g-wd{4gQ{KbWKpVB5tGQp{uF(E&#<<#1hQ9Dze2ISu`MwIj;~jQ{hhj*?XE81 zc7ZMh^{w~83E2hpqGBP1kKW$mf|ObiZ4AQa>vP1<3nHJ~WFHa==3FWA*>dBzQDeo0 z73LON!mrZ>r*9+;7D%K4w;ObO!e#TiJ4OZ;A!=q}28E18Yppha3v-k2z~3$zaeX!J z@;s1R%~dfwf=k}j`$%A7VnC@2&HR^cV3`C}XIcYX-{}Ee=j4bV7~g)eF;aw~!x*~~ z<8kRfXrx(*FB2?AO_}B!h6&T)B4@p+8nQR}*QrCD(~_ zv$$qLc<7mgYxxk*2=NBoe$d?*@sRb>9_@=~h}osh_k=o# zN;rI>l$2^#tX!h7n8$yU)NWDFL6Ej9NcCZ!-eZdj3=dU}?*7ha_ip5^78(3K`~qD( zs&r&?(d=&-+UX4X6B$N-AEf7>4AC!}Ix`Tdrc?)-$Xj(rQf48Sb&{v`YVs*)f8()F zjbX3l>BpPh!o5-ed4Gehm0ivAvxsLJLVGQ`g{aB28hh5GQ8+(*9=h2)n&D>FpZ!xV zX-)k$tD)4o`|9M>_7b z_(<|#++{xsF!v43xytS#LVCiyEq*gAc+Wa1n^+=jPb8BejO!p}9~R_)3b=!yn{-bq z(|}Yd8-VsM>EO1vGaO^xHDoQr=?MCHXK=vUDuLkF0xzx}sh|Yu6C)DJ6c;gzKoNBM z1?~+WFOr!%`20Hrx=!sSOCpK9p$3`8cNBs&ZR!z`x6A%`jlb^NEuM(dP1K6GlEq}k z2lTzxli}pesidd!yLS7U1+&vTw;jh`z~}X0&_#jbzFu%=a)#Xf0Jn~DcykP9_ZagK2nfR2hG1Fz$`nYq^94iO8%(};Isr(H-6dZ>}Kv!e-7_wBD z5xXgJ(6-F07{V=mZ2+>@h0uG^4?Wd?EKkLZwfE6kdp02&47s$%qr7CYcZ2)*$3V9MgHMu`$|$|QuT*~_vI&_42G0? z8-CO0^q+QGhNkVG>nzAF z9Sd{SJbfwauWIm0?3^i4c`5jXT?e=mpd0M4wBTP%YnraSzc0@IPF}{G2CoT+uFUFh z;FlvfZrpd`hd=Ooekq~Zl}cQWa#HRk#t_E*CZS1`@9kJb83pGplc38(gluZ8!Ftay4BxNwfBs z%5ohb?-c0b4>-UKsTtEEwcrmFMlnLCpYSaG>49~MrR1l-MLb6!EQ>DBfhqf7Nf%N2 zC(lfK@6_P;j&+X5*PAu;&`Y!+z?}x&(2rR2*2eAhExJw!dW#dMZT%GvnJwIoKNuG) zX{&NwqJv1W&Oed~D=m9OAP)C3?dK?|zE>Wvqst4AUVHdg4!AR*8=R!=clv9k-)hW8 zAYUIoc7{lwnJ|8Q#jRNE7iA@HHkv`f}>_1|8noj6{ zDK}b9<@pON)rFOIW9d(%xO|m!%++;D%lWz1PLkst99)>0dv~VE-F<$LGjdso%O!&6 zb}amlD=Czjq@m`_gZNF7^{Ul)63x>Ose^x$@}Z&AP|60z!If}engD6c8)i4oB$26X9h>EY zKDcANn1aeCC*45)Aco*R5ufvyOO>i5zpbMIp>rej{I5IGp=x+)DMFAcgiL+J;TqsB zgDw|d*#AS-T}EZ~yl=y&L!^=JPU#Mjl5UWc?vxJc6hY}my1N_clJ4&Al8)Qo*Z;HD zJg=^IpLML+vuDpfXZBpoR}lsx&371Ud~O)nhDB)CgyS9FF}7(^vIs+kg9XJS&6 zTm>IqGY$BL^T85hp1)I|dUsnE{cJ5fH`H)`y~`lUh-BSe#qY zKoy&J;_<+8=$ysE{);i0f1B0h>C2A}5u8HmA!=!R1mqWnI)9r4KfqlAU6(APtMpgT z=ULmy4_OhlbLd&$lIn}2&f{g-mMt|JvbW;(#oBs@48p&4!_Z0HEWg!TbGE@zj*iE^ zrXCFP&jj3M(AC0b-hNMLTGw8uO(V3HNhHkJeCsE$t%a^lQ&S=7l9GoL?DUfOl1Eu@j7mmqbjWCpqJrc4D(L1iNAaE|Kp4&- z>`Hr1_N&K#!>mx?z zpT*-6Hgs&w`^8#otmkybe#~;RfOsAxAzp@Im;n3x&3B{&yMVg^x?|ovEj)SYY2xGI z%su4FDIfe_Z>UIUMvN0Vz!Ag0eP{nwS2SIWR>$-d3pRTJE3{U1`<1@<41QQ_cr2`v z3^?!G1l>r}2YL?| zvfVaAB)z95P{DjJ)vBfZ{V4;;y9K(&*W`YK83H%0Z3<>E4m}rX>{V|bi~htthdUej zrG5O$<*l;O^{YzfV&O42~)h2#vO9mb9jZ@ zQ+Am`@UHK@t=Gu%b3HaxvE08%`1t$td7mw)8&WNEf62(SEjdz2sy&6dD)F!P@Hh!E z1l%3aeV1>1I)w{e{7S@)tW@@8W_)A9$F%g<2ESSin?iSNV@&@-2J%+YDm=7L{y2>F zI8}Y{^pYdm;cv7_it=@CZ@}FJT>}}(+z6M2vc0Nz)fJPlke8T^mDLjiccQGkzK`wX zqj3B-@{sRlWK$-lz{nl z;d#H(WT%dN-U&}%lBrmTKa5_cK7l;MdbJa|O>QzaaZ2`nQ&F+7BG$P{vPx_i)1^6}pZyngiu?FU6sQGrzS&tLpmMB>4m zJa1)Mg}&6Y*Dx{+o0)@kqXW=oCE{s1d!DRkNqEdu-&TiO5?V5fdY0N|{we4B2;tml zyjbb4zPw!&yYY+pI5Gh*WAah~rq*a9Jd0Nb1s@Y!Z#e{A=F0c&d-z+jukCBAu+Rr}_h)!8sM=WPP<>W$5SR7SqrvKX0?9z$6VUB0?hX7?v7*2u!t=#CV%{zB zAe}mmVLcFgrdsOS?z!rxyx1mBqWOV=Wr%V3O+o1AWXfKO!hm0JRvZ%nqhVm3>lAdS z>*yVuZ1yG~USoKjO9qeOy&yQe;S2VmAfqe@J9&#tjj1R-BAQ^Ne~(BXN!D59mv50H zZ&Hqnt&^1C+A>zHjB4={woK+GtpN7|bZ>9T z?=Rmf&Lj5A8nO_$lPj6CljoPGuG0iD<_mq%*n5u?OG}mn+dtlKjmAXsdKwCmS7Lry zbrD)@rS{n(0Q`>X5_G-!%8=4^P%Emmi;FoOYOn~>qY`LC4O%8)PK5Smcb5s_V~^v# zYA{V8*O_M^-&h8@uA1t8TW3RZdO;mktSb*{sJkrR=JckGxcd_Kvrn}J_3s?s=BEc`&E6Mb>`@;3nJ-voM0l`S6hspUh1J46LoFk7a+|%M@ zJsEPU=Lz&NogB8hgll^~9aerv4FgzzxCdR02O*mpmhFt}2jX1w@pwkBvo^Bh42G9? zJ_R+n+I$%L1cRlyW3S^_D&H<*YM}fkQOSI&6d`Um8)u)`vAIGA@;-p>ckh=I+4>0@ z<*3z>UDA#(h|~2OQn?4_UtUIe(+pXTq<3dgyt7CH&Nj!_t;4s5x=z^aW1O0>KRilY z*^YKA0`4Q|?nclJhSxBeHGCKJQ)_@>h7M}h4r;~Vk4GVM>0m9TYQG^~D}0=Pod3IL zX!bHM01C=uvw?M;CGP_Sl&urSFTi~QT|LPerFN?BEd#zHKQT#EHpHVq;(5Gp>@bUT z?+%r(F}qfDT@hyz>|NH#E#Vd2|8DR1IYR2e5E~DKObpq(1kZnX2Ho;Ad?%IWYzX>k zC^h%=-Qu}n8SM+x)uwtaAI$XkyE$fa`c+nY3{yE({OmGM2hZheo_Pd!;Wm{jMvl{8 zsi}dyFQ99iL8fqJxWlNn5zN>U^Wj{?D37b3(?Wf~g|7zd=v_b_YVI!fGj|$>cO3U; zSIZrOWPMA!^9R6NJN*{|0*3w535>uH&6L8ctRep84325&2CSl4 ziMnml4hjWw1V+=W`dg#7CHfAHCqC+sHNud&LMU5q+L;koWzcUDO2By(B=9rvBzl!iZU>-0A)={M;)TM;$llqmEuKx7byr0y7WIwB>|VI-@ZD z*;?`Bfc;yb9iTv$0=^?}rZo065+ROuc8tEQdbmhUHrGxAt@Rt3x{yT5by0sO0d@f6 zl)jr4nnt1?`D{uW}!+b~#40^GNfLnwwfX!n*-A@*s$p}Jpw*IO9F(yHW&B-294af@vx--wKelSJ{ zcoXefmQyk{gB~vktSl3?dvnCKg&w~-$LA9-GVJOPWYp_uAe~AA3$Du^!r25=JK!^3 znO$V;83QgX=nA~gg?`n0N!6>1JF{xmYm3rEi6{>ZH)4AbmyvAuY^pP9Oau=6Wdl!;Y37&fQem9I9sK%bPI3g$G?>(^nYVj0W!< zA~Qr-)}i0_@KRx>Xd;zBeHCZjr+uD5ZM-xVzv+NP=*K+uil`7cCAh~%%znE>5wZlS zS#SmcxCo%@y~~JHx%uf1a+_#Nmg4V0UgIt`H83fz?B@!-2179WEmR0~a2@T0+H8xJ z92j2}E}ERUIge=ehToCSv}|Y!04^fvM&Ulf@4y?=2u8sXX78K!%Ml*Lrw`+)I@Wgs?vHu}y4KPKhuP?#df<8t zrndsF1SNg7U%^DwHK;PKjWzU8;_C!n$N126(y=z#jEGhL;fHZ6 zQU>Hj0^Q3_Rc`sLoEFBPFKOyN-^l{Xp$Fk{APQ67Z;0mowco$N&mR8?HAi_(k~Hvsk;isddFk}j-L6Xs z3UEGg_1F33!F)mm%j!Xia$%M=&XJhh3m?XO4|9OLXrOBzh4q`uLxI;?&x#j5 zApJze6CFvo_rc0y^0mKWBr0_bHWKk3U1`#U^OlsE8lFgi_C7b2jm>_Ip!GHvO%hnw zKnLALTnz;olI#(2wp!F0SJZ6F!+cG9YgU+%RL}2Z*F6q01q4-VUT}Wyyz)VRKbNN! zJN(%23mH|$My-s2EAQ1RkQW1V%L7vnKK@kVy?IwaxhN6DCYWFINOMpmYMNVas1LU{ z$NYwk>PJv%2~yhIw~d8i_;}NE>Qr-Gmd456W2t^xU|vknbapnaB_w`!BEx32Horjq6tS@p8;I2mzcu#^JUdy zU#un5*m8q*c(U{LUva_>^H~*)Mj^zBDOfE6N_2KhcN)22f=jCt>|85N+~7WF9MFx3 zu?f}mna<;1rL0#prfeF!Qfg4CFQ-q#x1YOBPZ6^JIQPYO+nT$T`L^kokJg}t!pudg zlIKv1==jGe=%3R-UR=<%bZC*Xh{(gkan8yZO_XXeZBCG*PwI^o3Bau&gpMN*qUYxG zXH5_g;KrJ`;cTJb`bCPlC1PzE)Ad7~A(pKTaPdHQFPE?2q|2=GYg9%?JEl#ZT4##| z;@_@%NZkSXL96YS@fBH19A&u?{u3J^wdi45zCZ=>fSW|r*UF&anaB})z{LmM)_BA0 zACyO%PF||@h?20D(;*poi%e|4N`>}EqTS&5+^Ko-+>6n@Yg#+obzeu<*+=)W4&az9 zjY`q~f$wbq>!}2wD_iu;=sUZR1WEN-W+e5;pvI+s=}?`839BdyG6y2rhc0|q7^xz^ zn-AJozF3Yz5XMmA&Z}5A?1k4$wVUY-y+B?<&_xtuqi_B6@-ojO5HKxw9=1}g_qx_< zu+B=gmated-kiCqsXMpiozYSg9XSC`*WI6i7cPOm{?o|$GdBGi2JpE_1iIbxw?c&! z3n@{7`O@-sOw)dyk7yKq8G#+>AAe3Qh`*fA<`qSi6*OwSt+R`C5y6mGeekrNI+n+C zQT$D{91fo6NDR6%vMci>5+u7Pn@Ykb@e>8p-)( zS-)r2{zzfgPV+Xpx2Ln+)HBAP&b|U%zaRnK#Q}nj3?s)>UkbGa=XwQw=NC8L1B>@+ zVIpTGCp{<*!6#b!y`Ec7pQD0&M!BWFo9(`rO8@4+-zRfYY5>6=2(&LL=tlg2lEEv~ zsIHVb{Gz=svFw)NC?+b5s!iMb4igHgt*_)O-o{rI;)uZRO{6@|;q-NhcB`Ng;{19V zRg9SdLvWr-2D;)z8#hH{#%7;hp0TA)m#K&3^@`8QQB}eW+hyDuFwlf?NH9`j^9nzX zpDFOazKUAa?1tjfvt4!O=~cI%BQgW>l7sG#vEEXsohM0?g|X_-RqMZ#aHu1-B?QdX$aT)$YRQz0*f&$C4NBn)REGAr@%u}!uIrq*=feGbHYg}dykZI-u4jwE{-Z)0A&#qbO z2Y4>44v_Aav>}Pd=lPIyGSSP|fJ+6sEY+66@`t}^QJ|fUNkXL)zwLx8(#sBYR$Cvk za~`ereANx$YHil-Ad2vYM_zf9%#YcQe^sARSw;_oQQhf$1Gvi3T8!;NTRq-N>$BF%)f3_i`Nm zoB}Ql=%Tl_i;RfsnxVsM9aN*oR?Uo;`N<3X5zaC) zesS*m5bb~-naNK%<7tWCUw9-v_!8AogmZL1xPDLQAvXr(r32ky)43p@Cst9|ojuQ* z?F)vxE7L!P7ArdDXq-n@PzR4?ukzyKDJ8Z_EoJ8NlO)Ahv;D|yUpmofWRO<0FOI?f zOAoqltgDPlU%RtAxKmn04u_UA!Cm89oxT{OMo^>PzzNG_#r0~)gi(%mN6e!XGm?Mt zt0>*S^e$m;s_BTnnONun@-l#KD7G6;IJzB0l=|0@Erp48yJMd6J1ZyYfXfKFWY>g}Zvs~^_Tf;4^o#?o zI;SHOq%g#;G5YE(vW`|#B%HN{;qjJBdMg_=6=(9reWrN-9_5>l!L5zJOsmK!47g07 zD@7ES>PMtH_SO2i>O@?H8v6Iw8>@2ztj!3L_q+TB9`L-fFBxgsiBpzN9NeW1(KXwP z3;F?g{1p{t@`94M;Q2dmL03Kts*7QOI?}#H|FtR4Ese#MUN?5WjrO%J?eX@7YFeZI zbfR_SGzIA&o4D?ME46*RFe-IwVW@a3*%=-P$3-A7GwA-oZOazX@Y_?dP<)RPKu@j* z_i1J(pw*e*lfioyJ}8Z-=rd+PT>)t+>umj0*Ful9@~^RZYr12IV8Yy;xb6kOWdYrn z&w6C#)V2-W-SW@v2-FEC=Gj7p7G4vIVd*C z+ctPP%UBa(TafjD%L=+G%jMJ%3Q;XQCJ(>Jsp>MhWF%YX^Ipm*s@dibT4*pbit2)# z6>t^JQ_&&={is*W?IK@mg*v__VPy~WP&sb^TsF|1+R9^EUT7ydzQ{L6+r%GELazLy z;{KgPzMuUwq^{0Fi+teldQ?Tpz_xSQtAl|Utc+*8Hy->y$oGGe(?gHu11>x0wsrcJ zB9S}T9#0AeHz7jN&wL8brC!w{#(m>Mr&>^ITy>r#2laeW$7;}8bfHWdOBGgfy8yEX zX^@N5Av+Se3Ah}fTi~l1Tw+O)zsbl2D~o}@zE}QwVDxs!vSNu^^oty$JX9aN(C`(E zS2JHd3+9k_;QAXU=ytoS@LBmwf0Kmno|)0_XV1OnSIyFk zc_LpsF0iD*Mt?O?fKCzq6RCKpTinIvb@4n;z=P4)thA8*o~|l93%E|k1-eSD`Ja)V zeIOnt@7%JEo9%+xzs&ek9$x7Ao$JcEr!*EC{3!muU0qRyYV07hm^ObHF`iqGIujB~ zt@=(fw+YoJKjDIX?sqf+b{PaTB3u(dQ6X&pyEy#-Z$=d_wLTa}_)9N;qd0 zI8T+rh`Q^Ve7zxQUVhR`7IVkcTK@-JXW#+d7mD@n2(vo-;VQD@p{m4Gxl^AB&HZ-r zs$5aaJ&QFm_+Itfrhu64wXYA0ywg>X=W=pW%Fg1BVX|LEw@B8&_ikR$&Di6Q{<8kH zA8lm??G;PBA8$Gr!I(A6F4eZ}^$TZtwMorbTr%dx^o5e1?LHZGx(nO0)JGmycegXs z``j7_u%GdPt_uu|UL>_;c|fCd`eMOAA$e;NLZ#nIu|8}2uizNCHNpArt+XWRoSTKq zJfG_J%}W9ZktjVlqbVZ8_gXm(@IXJ~2VL@JJFeSvBrT4E89zv6$5g4U&@VD?1lF>g ziGKGxzWEr?lw;BzT@ocXwAl$<>k(KyUGNi|;V0n3a~$e|qI3V`lu4@~RM<>>tY z1;#06oelEpDH$?4@k>1$vFL}D!sG5{;&ualf2h}JW#_*!IgR8G#?-xYM>Y4+n*@V6 z*1v<#O+nD@q-NjTuwtfuLCLKPelOMiJndR#E6dw_{IJO0qlXS}Dmj=+Zt~L|yRRd$ zBizsU+aE2KQolfr=1g%sw-Igdx(R`9Vpht{Cl#Dc|D6=0?J7?VRR!m7w!}|ta)i)J8@1A~}!CQIXY!%tsQ=%f`rV??QbO3!4jg zl|(guaao_c@f_7EKPfbyFuX~>SW57fSL(rwp{AdOV$%fEhSH z69rvNlR#c=((3BkLw+o=^c9kJ%RpVO8^}Vm{nKOVGna^pB)EJYhzcqMC+EYSt9MGl z!GF(mX{B<&7$5sc`uZ6>pH>WXqeKZ5v>++z^~)Rzq+4kZp^sbN#Qd>Sr9c1HaiPI) zQf7&*M0g<9->MTs0q5J3IsU;SsR*_pD`0UtCd)_+7ieE`(Cx1Y*+^~9P`b&mdt%t0 zDHpVmW?J@=p22XSvBM;Rs!n&*t6##C5JZxx*kNg%WSdoFQN$@V+==R;IPjNl1J|=8 zKzCb?LA8h1$m05e4w>mycvc}5_XHH|yTPinS^}Z+0+-7<*jfDdZ9=wItQPOiH4e+~ z5^q*{iJ75|c>mxi$o&TLegNGllZ27Q`E63gkGoO6nV&)i8!MWVjO=%hD0apfe)e60mJ+H|uWvnL;9Pd>={WpuQnKD2IzH>a84ktew5Dy^kFC5Sl3aP9@ISR_BO66Z>`^g^D|k{jk7NI zxjkz>z}VfB*{ z*T)r^R~T$6dq7?}(AC{nRAZTG%coi{QTh_WDs}LNK_C?CkrBf98+m6MWzK6IE<~B2 z#1c&LmrhUdIZ1nEE|~Q-D4I3@-$%XaH{g4>Jm{iDr(6VJ=_)O0#&&rm9o`vfdpi$e z%|5wo5?5K?%5*2lMoL|c;AY7QOYNmYy`0d#yu7_5 zb{CdY6icvPq6oTAnF4_{gK_Y_XN^^!l+41qD{$oFxbu22QOp|N8*S;54D z*BL=Z_x*|znI_4Odhoj7TJ`fXI8Lg9?ow9q$9Of0{`AX=X=x@qThLzpUm6Q;7RsFVX|!M>TdKD0MsyQT+kcN5Zn-~jEQ2D%u(`oCc>9r@v( z{F;5c7`$t}SLCy}?7sGbl5B#^il^fkg7R5WM@J%GVd%LEoB5Uy8{Lv-fg)jS8vQX{ z;uA06s)Oz>)u{$6Y2jXCC{Ar$iv~{ZYlyGE$Oh@UI}TYP4puw|9oPrSv5n(IzTHCd z(=_|$e5dRx;C=*Mr>@c=GNL62Rd;d(Y0GYT^0MDF#SMIbs&|R8*IuFDkpg{eVDY@10@8m5jG9N+ak}09*~w?G%HGqNe51kD?V5 z*Bp{n?Ml^`3!8$AU{ZkAW!5Uk`_20v+j@KO6S*okD_vpQ08f!wQ0Zo*)=8q|bUf(_ z_+5u4=nkg;+*(yzdYjUY_i!-oB03krqd?xe2C@kO=40`>k+tuaZ+2s$nO-a*>;o^rI{qG&$ zT7~HDAUxBKh<}}EEy2hh0xlR2DZw$)FD;cWY@lP^qqsD0|Aw$EnB z{mkB`D4gh4KWcxKoC?>p>Ipc``ZK$toANvMKK!8eWh znbZd>WOn(pmrNNh=aUMN&*WJK7S5ZV4ah~dg{iQy=L`lYnNMk4<;(a%!bQXiR^>om zJvjuE4ssmK%vq=oMs1# zOvCpj8j)bRgpb{u2x}K`^+8v@q#U&wTFWCiv6Vx8G4v?Gl#~7U?ycZ%WhbPOqy2)n zjLlnW&R=hw(jrIhUHz3+Sx@0g_%#o1BnIPxi`&8XZUfN8P0u|q(|D*JeVVIiEEot{ zj^vr@$ClzUa644v@f6Oeujq!!!=$L!vw69dO<=6H-&}K~6rmV8bkbxy z6^QSd7P?hNg!2kBjG*62q8`A-p0{0F%+m-V1FkXXo=ffO8Lfyx&o?Z)RNbOq3k}U| zhiBcsLy+ok_p4#l#F32tw05JXXdZ*F_vY_wHlZ4mmooBa#>AeLgL_%8FMw+Ty8ef+ zzwNmB{TMJ8BmQLXB>qA5(%d;x7u)FXyRv57M%ucj$IrN|vR5~VR`4qU>#x#{|B#&~ zYUq9sUG`z_om2;0Q_#iJhIZ*47!_!cdAM=O{XtVn(i*LY;1*DL%0WTjvpX@@@bYtC zPKG*&-s2$34gx!)%ls3=5a*^a@3YvVi7>cN*9>%Zktra~jTs*5nR=8Q{(N}f-CrOS zIOnC;8UwLCg(|t7vhq9D#&p#N=V>ExX}sD|+<%q4V*I_wgWg6Txve?LfB&Zj0fF{+ z>yA0-GG>|7jv%Q`z9Js%@eF|DxOWQ9=z&%%tat04fn;NMA5^}~;(vJ(!bviAofE&N z+IvkT>y0nhGf{w3tS6Pb_Fp^vb1gs@i)mL8HnZjL@{fjaH00{}^M`h|SmwMrmy4w* zj+5>}ySGfwIgiVxWYSXBF9Nz(vP9CeQ)NhhcR@#|7QlQh09;GZT_C0Lljsl_Y*?LX z8+}>BJXMGLXwH^qy=79OL`zTD@|$M5z_`vJAGU1J=IzAk?I%-L|EQf|JszR2-47E8 z|IU?wfk61%4pyL>LrCCQapJ8V>t<#oC9nK#^F}%Vc8lX3&L3(y>PI5SmhmVEYRikr z$Lefl63z-*%MzaRK#O0$$vT$hG9oBG|CjgghO587)}Tv^iQOV$o=N;1!^HtNGb!SQ z0vXKzs=vxvs6JN-UuaqbNAjbM#P@+@($$K=?y_MV=LLHV`P{%;iwVS#o$`O@m%u>$ zZ!4D#=w8agWYF|Hqf4{r22Sbt5sfN)No>daV)tcAMXJSUkro86$~p?8aZ(z7U}8kYQ3=V6g9#OW>tq3RURk-5@fM z_QMZ3@-tDCs8P16r{AHAd-|Xh@3v@GȩR+;h;P(wG1Z~5=KA&~xc?LgPTqtUiX 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 I#tkX}00h(kh5!Hn diff --git a/containers/master.Containerfile b/containers/master.Containerfile deleted file mode 100644 index 14777233..00000000 --- a/containers/master.Containerfile +++ /dev/null @@ -1,206 +0,0 @@ -#! Runs the docker server that handles everything else -#****************************************************************************** -# base -#****************************************************************************** -FROM archlinux:base-20241027.0.273886 AS base -# How to run - docker run -it --rm --device /dev/dri nestri /bin/bash - DO NOT forget the ports -# TODO: Migrate XDG_RUNTIME_DIR to /run/user/1000 -# TODO: Add nestri-server to pulseaudio.conf -# TODO: Add our own entrypoint, with our very own zombie ripper 🧟🏾‍♀️ -# FIXME: Add user root to `pulse-access` group as well :D -# TODO: Test the whole damn thing - -# Update the pacman repo -RUN \ - pacman -Syu --noconfirm - -#****************************************************************************** -# builder -#****************************************************************************** - -FROM base AS builder - -RUN \ - pacman -Su --noconfirm \ - base-devel \ - git \ - sudo \ - vim - -WORKDIR /scratch - -# Allow nobody user to invoke pacman to install packages (as part of makepkg) and modify the system. -# This should never exist in a running image, just used by *-build Docker stages. -RUN \ - echo "nobody ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers; - -ENV ARTIFACTS=/artifacts \ - CARGO_TARGET_DIR=/build - -RUN \ - mkdir -p /artifacts \ - && mkdir -p /build - -RUN \ - chgrp nobody /scratch /artifacts /build \ - && chmod g+ws /scratch /artifacts /build - -#****************************************************************************** -# rust-builder -#****************************************************************************** - -FROM builder AS rust-builder - -RUN \ - pacman -Su --noconfirm \ - rustup - -RUN \ - rustup default stable - -#****************************************************************************** -# nestri-server-builder -#****************************************************************************** -# Builds nestri server binary -FROM rust-builder AS nestri-server-builder - -RUN \ - pacman -Su --noconfirm \ - wayland \ - vpl-gpu-rt \ - gstreamer \ - gst-plugin-va \ - gst-plugins-base \ - gst-plugins-good \ - mesa-utils \ - weston \ - xorg-xwayland - - -#****************************************************************************** -# nestri-server-build -#****************************************************************************** - -FROM nestri-server-builder AS nestri-server-build - -#Allow makepkg to be run as nobody. -RUN chgrp -R nobody /scratch && chmod -R g+ws /scratch - -# USER nobody - -# Perform the server build. -WORKDIR /scratch/server - -RUN \ - git clone https://github.com/nestriness/nestri - -WORKDIR /scratch/server/nestri - -RUN \ - git checkout feat/stream \ - && cargo build -j$(nproc) --release - -# COPY packages/server/build/ /scratch/server/ - -# RUN makepkg && cp *.zst "$ARTIFACTS" -#****************************************************************************** -# runtime_base_pkgs -#****************************************************************************** - -FROM base AS runtime_base_pkgs - -COPY --from=nestri-server-build /build/release/nestri-server /usr/bin/ - -#****************************************************************************** -# runtime_base -#****************************************************************************** - -FROM runtime_base_pkgs AS runtime_base - -RUN \ - pacman -Su --noconfirm \ - weston \ - sudo \ - xorg-xwayland \ - gstreamer \ - gst-plugins-base \ - gst-plugins-good \ - gst-plugin-qsv \ - gst-plugin-va \ - gst-plugin-fmp4 \ - mesa \ - # Grab GPU encoding packages - # Intel (modern VPL + VA-API) - vpl-gpu-rt \ - intel-media-driver \ - # AMD/ATI (VA-API) - libva-mesa-driver \ - # NVIDIA (proprietary) - nvidia-utils \ - # Audio - pulseaudio \ - # Supervisor - supervisor - -RUN \ - # Set up our non-root user $(nestri) - groupadd -g 1000 nestri \ - && useradd -ms /bin/bash nestri -u 1000 -g 1000 \ - && passwd -d nestri \ - # Setup Pulseaudio - && useradd -d /var/run/pulse -s /usr/bin/nologin -G audio pulse \ - && groupadd pulse-access \ - && usermod -aG audio,input,render,video,pulse-access nestri \ - && echo "nestri ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers \ - && echo "Users created" \ - # Create an empty machine-id file - && touch /etc/machine-id - -ENV \ - XDG_RUNTIME_DIR=/tmp - -#****************************************************************************** -# runtime -#****************************************************************************** - -FROM runtime_base AS runtime -# Setup supervisor # -RUN <<-EOF - echo -e " - [supervisord] - user=root - nodaemon=true - loglevel=info - logfile=/tmp/supervisord.log - pidfile=/tmp/supervisord.pid - - [program:dbus] - user=root - command=dbus-daemon --system --nofork - logfile=/tmp/dbus.log - pidfile=/tmp/dbus.pid - stopsignal=INT - autostart=true - autorestart=true - priority=1 - - [program:pulseaudio] - user=root - command=pulseaudio --daemonize=no --system --disallow-module-loading --disallow-exit --exit-idle-time=-1 - logfile=/tmp/pulseaudio.log - pidfile=/tmp/pulseaudio.pid - stopsignal=INT - autostart=true - autorestart=true - priority=10 - " | tee /etc/supervisord.conf -EOF - -RUN \ - chown -R nestri:nestri /tmp /etc/supervisord.conf - -ENV USER=nestri -USER 1000 - -CMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"] -# Debug - pactl list \ No newline at end of file diff --git a/key_ssh b/key_ssh new file mode 100644 index 00000000..d2df4f31 --- /dev/null +++ b/key_ssh @@ -0,0 +1,53 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAACFwAAAAdz +c2gtcnNhAAAAAwEAAQAAAgEAukv1aFzn29JFNplJKQnusTysRWULax8A0u9mzM1W +p1a07W+RfIvHja5AJRyzEOO8tqUdaSe3jsU/lBMax70d7DPRHOHhi782tSdGIsjf +NP+0+Rf//W4wtCEqiGsDCrI+mLYRDdD6yEbKGl6N5rNS7nFYOD5xNbrnUZkzU0Q7 +XgTl4VUzPG0C3YFYVxD1Womgn8+nVP0PB21rw0OSg5fkqp6mBC0whPGWW5a75uNS +pvuy610Etj9fs2d3+1BtlNCUFO30o+FDFbmkovvZAxfZqy8AT2E+Jpxib3LlGQmi +TSs1EgVsYoiuG64sOw9JPat4e9LHGcddgcB7ZE/9CGuLaRcrTLS22/tojl84LkC1 +0byzRThT+Gmf4NSD1Yj7c559KCSutrul8mjP1QWxpYcxYiXGCIFb/kDB8TYX4irV +HudeiGgnflSlREOZn8GUa4XNRSVYSV1bm4LpYcWGHH5sHsuK/21OuT/ZXRsV97fS +MTi3D42GWvtUYEVvyhS2RiHvRq/WabZhpP+WxJmIMfCJRQUwzKqh7vqqGepbgZDY +iIDGcHzTAVnBbygXUGvVYSoaWqaog6uDu5Voyh31lUPjXDjW0J0Mkliw/GTDHwte +2FiEbMC2rMwm9/bqeDfaQ5PY8vSaXPKZasTfgCA/bU+6imWfjkA40gPwUNemXJFa +GhkAAAc4zX7cDs1+3A4AAAAHc3NoLXJzYQAAAgEAukv1aFzn29JFNplJKQnusTys +RWULax8A0u9mzM1Wp1a07W+RfIvHja5AJRyzEOO8tqUdaSe3jsU/lBMax70d7DPR +HOHhi782tSdGIsjfNP+0+Rf//W4wtCEqiGsDCrI+mLYRDdD6yEbKGl6N5rNS7nFY +OD5xNbrnUZkzU0Q7XgTl4VUzPG0C3YFYVxD1Womgn8+nVP0PB21rw0OSg5fkqp6m +BC0whPGWW5a75uNSpvuy610Etj9fs2d3+1BtlNCUFO30o+FDFbmkovvZAxfZqy8A +T2E+Jpxib3LlGQmiTSs1EgVsYoiuG64sOw9JPat4e9LHGcddgcB7ZE/9CGuLaRcr +TLS22/tojl84LkC10byzRThT+Gmf4NSD1Yj7c559KCSutrul8mjP1QWxpYcxYiXG +CIFb/kDB8TYX4irVHudeiGgnflSlREOZn8GUa4XNRSVYSV1bm4LpYcWGHH5sHsuK +/21OuT/ZXRsV97fSMTi3D42GWvtUYEVvyhS2RiHvRq/WabZhpP+WxJmIMfCJRQUw +zKqh7vqqGepbgZDYiIDGcHzTAVnBbygXUGvVYSoaWqaog6uDu5Voyh31lUPjXDjW +0J0Mkliw/GTDHwte2FiEbMC2rMwm9/bqeDfaQ5PY8vSaXPKZasTfgCA/bU+6imWf +jkA40gPwUNemXJFaGhkAAAADAQABAAACABU3oXOJYT6/6/IT8ykhYHX/Gv+sSmig +108uxN5+ZGgaj/CazE8K/Gc+eT/AzQQXa97BX2Aijd1MybjrlBk7iLTmEeLgNvfb +hzeKiYpcpk868DmOajFK43Egdd+jkG0fb9GkqryQGH/G0C3ApxinQ8K0Vf/R3MLp +zn6UnCvXkYtbs3K+aV9wausfWBhSbh8pnYmV9NDRIW0PIT7T61PhcMGd3/qJywTZ +Hu6/dBcPvNIXyIDVzzuSbCvalOeieViBiNv5XetsNF+9DOsjE8wuYzQD3l0sDhAH +r45R35XCayGu0hSDWZy/RFUSuSbgzs6fQNGZZ+OfuR6V9XevRHo5BV94108cOezM +CAqOm7hVbI/BihH22T7urbwhqj06u1ISKo3wd3bMAtKpvvekVHwMoeqRXuBIuHwI +h/EQ/fcqyB7s51z54+Jr73zl7wljLQtAAiHncaWKKQwFbeB/rhU6YBrr/H7KsunS +zCV+qabomUBb1iSNg0KBEtNiyRiLCEuI9/eTqy4t4G9222y0W55rjMse3grC8fK7 +oEDlR1YhzcBaeNFkCn2AGJ/B/x6TSFwuw3S1tKlo7wQenl8AH5QcuzssOh+GfCP+ +5NVn54+XOqS2Zm0n8xwCBuJOgWpHu1ZXXEkS8ZB6Nd8gdqGAloNbAIuq6dUuAqKJ +4sxXmvr0oqghAAABAQDUtCStuzsUee6Lwb3I90RP3tJQ7g7f/rWxHma9PtOsqhfY +hiJLncNfURM/kasd8TgERKLv9gAQmJ4gL/ray6Bwkk1ft6wkKw2gjA8Sh1VbPxvj +13aqqJhhr7bES2hStiXpwDX10rfNeZ24PuTq5Ow8efZehqWj2JskbHWnL6Di1x6+ +p1gRSODYRlepGTi+6QZDA8NOJOYWndzN+4kwzExlserq4sBXVc3WLk9Cb52IvjUw +DXtrKvongTOz5W/L6Q4iXwKltjqxMx9JO0nZbrcywoQ8wluoecDlvTMl8mHn1vbE +3XR59O6XBpitaFM1Szdqa2u8u2apawf2D60j9pskAAABAQDnqJ7BIj9X6l0cicRv +k2wG/v8y+CC8RAxBVDtGyEbn2xmXCgJjenO3qKvAjIWbcK49yV1mZOW2d+BL3Pnt +lMk1KQCM1Ln2DK3LkI+8cvXaxFaqIzmaS6UmhPuKO5JIxf3uOIGK0xLV208tVbPx +YL5Vuy9lELoG3cGAzElHQtScBiFnAfaYyoWsEO/m6kuBM0VKOuI93QcxJk9bqxpq +BaD/duM25nLxEaGGkRq4pfUzZaMbs73ROGNCKfaPfj6HmEQsS3EFgnNz5DrD+ziZ +YWSYwxZbpnA5IQ5ZgGAbKHYLi2fxSo5phl16xbLdH7JCRo5a61TJ6fzjEugWVxCV +s+s3AAABAQDN3yYCothAAAY6gkYbmU1a0g+pVIKe7kFAYMFTMV0XVPOPYPT60uoX +/a6B6qr+wUdpclJ+RAjdkM1icYELnL5Wn6cX7r5W2QoSpyGBNLhxx0nMB1fLV6OM +nl2I/YtKl/P/6iFx7V07arNJJms1kCWcPomaD46yba/coXfhc8RX9/GTXiB9ZdMS +ZQ6ZowSlR4CQqmeCju50oLiIXstDOf+kqoPHBpHjIE46Hr9bsX95mW8QzvAwtegu +8PurDQHNmh6nHX3A2IJkFd6M2tmXOsdmeQ1246aVqvFjHhAdmXLkrhx2dmCnCfON +81IXONa2nTAOW1IpfKLC17U5yZWH8O0vAAAAAAEC +-----END OPENSSH PRIVATE KEY----- diff --git a/packages/input/package.json b/packages/input/package.json index 7a0f8c51..24c3cec7 100644 --- a/packages/input/package.json +++ b/packages/input/package.json @@ -5,5 +5,12 @@ "sideEffects": false, "exports": { ".": "./src/index.ts" + }, + "devDependencies": { + "@bufbuild/buf": "^1.50.0", + "@bufbuild/protoc-gen-es": "^2.2.3" + }, + "dependencies": { + "@bufbuild/protobuf": "^2.2.3" } } \ No newline at end of file diff --git a/packages/input/src/keyboard.ts b/packages/input/src/keyboard.ts index a5541e3d..8613826e 100644 --- a/packages/input/src/keyboard.ts +++ b/packages/input/src/keyboard.ts @@ -1,8 +1,17 @@ -import {type Input} from "./types" import {keyCodeToLinuxEventCode} from "./codes" -import {MessageInput, encodeMessage} from "./messages"; import {WebRTCStream} from "./webrtc-stream"; import {LatencyTracker} from "./latency"; +import {ProtoLatencyTracker, ProtoTimestampEntry} from "./proto/latency_tracker_pb"; +import {timestampFromDate} from "@bufbuild/protobuf/wkt"; +import {ProtoMessageBase, ProtoMessageInput, ProtoMessageInputSchema} from "./proto/messages_pb"; +import { + ProtoInput, + ProtoInputSchema, + ProtoKeyDownSchema, + ProtoKeyUpSchema, + ProtoMouseMoveSchema +} from "./proto/types_pb"; +import {create, toBinary} from "@bufbuild/protobuf"; interface Props { webrtc: WebRTCStream; @@ -15,19 +24,31 @@ export class Keyboard { protected connected!: boolean; // Store references to event listeners - private keydownListener: (e: KeyboardEvent) => void; - private keyupListener: (e: KeyboardEvent) => void; + private readonly keydownListener: (e: KeyboardEvent) => void; + private readonly keyupListener: (e: KeyboardEvent) => void; constructor({webrtc, canvas}: Props) { this.wrtc = webrtc; this.canvas = canvas; - this.keydownListener = this.createKeyboardListener("keydown", (e: any) => ({ - type: "KeyDown", - key: this.keyToVirtualKeyCode(e.code) + this.keydownListener = this.createKeyboardListener((e: any) => create(ProtoInputSchema, { + $typeName: "proto.ProtoInput", + inputType: { + case: "keyDown", + value: create(ProtoKeyDownSchema, { + type: "KeyDown", + key: this.keyToVirtualKeyCode(e.code) + }), + } })); - this.keyupListener = this.createKeyboardListener("keyup", (e: any) => ({ - type: "KeyUp", - key: this.keyToVirtualKeyCode(e.code) + this.keyupListener = this.createKeyboardListener((e: any) => create(ProtoInputSchema, { + $typeName: "proto.ProtoInput", + inputType: { + case: "keyUp", + value: create(ProtoKeyUpSchema, { + type: "KeyUp", + key: this.keyToVirtualKeyCode(e.code) + }), + } })); this.run() } @@ -59,7 +80,7 @@ export class Keyboard { } // Helper function to create and return mouse listeners - private createKeyboardListener(type: string, dataCreator: (e: Event) => Partial): (e: Event) => void { + private createKeyboardListener(dataCreator: (e: Event) => ProtoInput): (e: Event) => void { return (e: Event) => { e.preventDefault(); e.stopPropagation(); @@ -67,18 +88,34 @@ export class Keyboard { if ((e as any).repeat) return; - const data = dataCreator(e as any); // type assertion because of the way dataCreator is used - const dataString = JSON.stringify({...data, type} as Input); + const data = dataCreator(e as any); // Latency tracking const tracker = new LatencyTracker("input-keyboard"); tracker.addTimestamp("client_send"); - const message: MessageInput = { - payload_type: "input", - data: dataString, - latency: tracker, + const protoTracker: ProtoLatencyTracker = { + $typeName: "proto.ProtoLatencyTracker", + sequenceId: tracker.sequence_id, + timestamps: [], }; - this.wrtc.sendBinary(encodeMessage(message)); + for (const t of tracker.timestamps) { + protoTracker.timestamps.push({ + $typeName: "proto.ProtoTimestampEntry", + stage: t.stage, + time: timestampFromDate(t.time), + } as ProtoTimestampEntry); + } + + const message: ProtoMessageInput = { + $typeName: "proto.ProtoMessageInput", + messageBase: { + $typeName: "proto.ProtoMessageBase", + payloadType: "input", + latency: protoTracker, + } as ProtoMessageBase, + data: data, + }; + this.wrtc.sendBinary(toBinary(ProtoMessageInputSchema, message)); }; } diff --git a/packages/input/src/latency.ts b/packages/input/src/latency.ts index 3a556896..3c97ceb2 100644 --- a/packages/input/src/latency.ts +++ b/packages/input/src/latency.ts @@ -6,12 +6,10 @@ type TimestampEntry = { export class LatencyTracker { sequence_id: string; timestamps: TimestampEntry[]; - metadata?: Record; - constructor(sequence_id: string, timestamps: TimestampEntry[] = [], metadata: Record = {}) { + constructor(sequence_id: string, timestamps: TimestampEntry[] = []) { this.sequence_id = sequence_id; this.timestamps = timestamps; - this.metadata = metadata; } addTimestamp(stage: string): void { @@ -40,7 +38,6 @@ export class LatencyTracker { // Fill nanoseconds with zeros to match the expected format time: entry.time.toISOString().replace(/\.(\d+)Z$/, ".$1000000Z"), })), - metadata: this.metadata, }; } @@ -49,6 +46,6 @@ export class LatencyTracker { stage: ts.stage, time: new Date(ts.time), })); - return new LatencyTracker(json.sequence_id, timestamps, json.metadata); + return new LatencyTracker(json.sequence_id, timestamps); } } diff --git a/packages/input/src/messages.ts b/packages/input/src/messages.ts index 5d60bf07..e7c235b6 100644 --- a/packages/input/src/messages.ts +++ b/packages/input/src/messages.ts @@ -1,13 +1,7 @@ -import {gzip, ungzip} from "pako"; import {LatencyTracker} from "./latency"; export interface MessageBase { payload_type: string; -} - -export interface MessageInput extends MessageBase { - payload_type: "input"; - data: string; latency?: LatencyTracker; } @@ -41,33 +35,3 @@ export interface MessageAnswer extends MessageBase { payload_type: "answer"; answer_type: AnswerType; } - -function blobToUint8Array(blob: Blob): Promise { - return new Promise((resolve, reject) => { - const reader = new FileReader(); - reader.onloadend = () => { - const arrayBuffer = reader.result as ArrayBuffer; - resolve(new Uint8Array(arrayBuffer)); - }; - reader.onerror = reject; - reader.readAsArrayBuffer(blob); - }); -} - -export function encodeMessage(message: T): Uint8Array { - // Convert the message to JSON string - const json = JSON.stringify(message); - // Compress the JSON string using gzip - return gzip(json); -} - -export async function decodeMessage(data: Blob): Promise { - // Convert the Blob to Uint8Array - const array = await blobToUint8Array(data); - // Decompress the gzip data - const decompressed = ungzip(array); - // Convert the Uint8Array to JSON string - const json = new TextDecoder().decode(decompressed); - // Parse the JSON string - return JSON.parse(json); -} diff --git a/packages/input/src/mouse.ts b/packages/input/src/mouse.ts index 0345a522..e1848b94 100644 --- a/packages/input/src/mouse.ts +++ b/packages/input/src/mouse.ts @@ -1,8 +1,18 @@ -import {type Input} from "./types" -import {mouseButtonToLinuxEventCode} from "./codes" -import {MessageInput, encodeMessage} from "./messages"; import {WebRTCStream} from "./webrtc-stream"; import {LatencyTracker} from "./latency"; +import {ProtoMessageInput, ProtoMessageBase, ProtoMessageInputSchema} from "./proto/messages_pb"; +import { + ProtoInput, ProtoInputSchema, + ProtoMouseKeyDown, ProtoMouseKeyDownSchema, + ProtoMouseKeyUp, ProtoMouseKeyUpSchema, + ProtoMouseMove, + ProtoMouseMoveSchema, + ProtoMouseWheel, ProtoMouseWheelSchema +} from "./proto/types_pb"; +import {mouseButtonToLinuxEventCode} from "./codes"; +import {ProtoLatencyTracker, ProtoTimestampEntry} from "./proto/latency_tracker_pb"; +import {create, toBinary} from "@bufbuild/protobuf"; +import {timestampFromDate} from "@bufbuild/protobuf/wkt"; interface Props { webrtc: WebRTCStream; @@ -15,33 +25,56 @@ export class Mouse { protected connected!: boolean; // Store references to event listeners - private mousemoveListener: (e: MouseEvent) => void; - private mousedownListener: (e: MouseEvent) => void; - private mouseupListener: (e: MouseEvent) => void; - private mousewheelListener: (e: WheelEvent) => void; + private readonly mousemoveListener: (e: MouseEvent) => void; + private readonly mousedownListener: (e: MouseEvent) => void; + private readonly mouseupListener: (e: MouseEvent) => void; + private readonly mousewheelListener: (e: WheelEvent) => void; constructor({webrtc, canvas}: Props) { this.wrtc = webrtc; this.canvas = canvas; - this.mousemoveListener = this.createMouseListener("mousemove", (e: any) => ({ - type: "MouseMove", - x: e.movementX, - y: e.movementY + this.mousemoveListener = this.createMouseListener((e: any) => create(ProtoInputSchema, { + $typeName: "proto.ProtoInput", + inputType: { + case: "mouseMove", + value: create(ProtoMouseMoveSchema, { + type: "MouseMove", + x: e.movementX, + y: e.movementY + }), + } })); - this.mousedownListener = this.createMouseListener("mousedown", (e: any) => ({ - type: "MouseKeyDown", - key: this.keyToVirtualKeyCode(e.button) + this.mousedownListener = this.createMouseListener((e: any) => create(ProtoInputSchema, { + $typeName: "proto.ProtoInput", + inputType: { + case: "mouseKeyDown", + value: create(ProtoMouseKeyDownSchema, { + type: "MouseKeyDown", + key: this.keyToVirtualKeyCode(e.button) + }), + } })); - - this.mouseupListener = this.createMouseListener("mouseup", (e: any) => ({ - type: "MouseKeyUp", - key: this.keyToVirtualKeyCode(e.button) + this.mouseupListener = this.createMouseListener((e: any) => create(ProtoInputSchema, { + $typeName: "proto.ProtoInput", + inputType: { + case: "mouseKeyUp", + value: create(ProtoMouseKeyUpSchema, { + type: "MouseKeyUp", + key: this.keyToVirtualKeyCode(e.button) + }), + } })); - this.mousewheelListener = this.createMouseListener("wheel", (e: any) => ({ - type: "MouseWheel", - x: e.deltaX, - y: e.deltaY + this.mousewheelListener = this.createMouseListener((e: any) => create(ProtoInputSchema, { + $typeName: "proto.ProtoInput", + inputType: { + case: "mouseWheel", + value: create(ProtoMouseWheelSchema, { + type: "MouseWheel", + x: e.deltaX, + y: e.deltaY + }), + } })); this.run() @@ -59,10 +92,10 @@ export class Mouse { if (document.pointerLockElement == this.canvas) { this.connected = true - this.canvas.addEventListener("mousemove", this.mousemoveListener, { passive: false }); - this.canvas.addEventListener("mousedown", this.mousedownListener, { passive: false }); - this.canvas.addEventListener("mouseup", this.mouseupListener, { passive: false }); - this.canvas.addEventListener("wheel", this.mousewheelListener, { passive: false }); + this.canvas.addEventListener("mousemove", this.mousemoveListener, {passive: false}); + this.canvas.addEventListener("mousedown", this.mousedownListener, {passive: false}); + this.canvas.addEventListener("mouseup", this.mouseupListener, {passive: false}); + this.canvas.addEventListener("wheel", this.mousewheelListener, {passive: false}); } else { if (this.connected) { @@ -81,22 +114,38 @@ export class Mouse { } // Helper function to create and return mouse listeners - private createMouseListener(type: string, dataCreator: (e: Event) => Partial): (e: Event) => void { + private createMouseListener(dataCreator: (e: Event) => ProtoInput): (e: Event) => void { return (e: Event) => { e.preventDefault(); e.stopPropagation(); - const data = dataCreator(e as any); // type assertion because of the way dataCreator is used - const dataString = JSON.stringify({...data, type} as Input); + const data = dataCreator(e as any); // Latency tracking const tracker = new LatencyTracker("input-mouse"); tracker.addTimestamp("client_send"); - const message: MessageInput = { - payload_type: "input", - data: dataString, - latency: tracker, + const protoTracker: ProtoLatencyTracker = { + $typeName: "proto.ProtoLatencyTracker", + sequenceId: tracker.sequence_id, + timestamps: [], }; - this.wrtc.sendBinary(encodeMessage(message)); + for (const t of tracker.timestamps) { + protoTracker.timestamps.push({ + $typeName: "proto.ProtoTimestampEntry", + stage: t.stage, + time: timestampFromDate(t.time), + } as ProtoTimestampEntry); + } + + const message: ProtoMessageInput = { + $typeName: "proto.ProtoMessageInput", + messageBase: { + $typeName: "proto.ProtoMessageBase", + payloadType: "input", + latency: protoTracker, + } as ProtoMessageBase, + data: data, + }; + this.wrtc.sendBinary(toBinary(ProtoMessageInputSchema, message)); }; } diff --git a/packages/input/src/proto/latency_tracker_pb.ts b/packages/input/src/proto/latency_tracker_pb.ts new file mode 100644 index 00000000..f3d94771 --- /dev/null +++ b/packages/input/src/proto/latency_tracker_pb.ts @@ -0,0 +1,60 @@ +// @generated by protoc-gen-es v2.2.3 with parameter "target=ts" +// @generated from file latency_tracker.proto (package proto, syntax proto3) +/* eslint-disable */ + +import type { GenFile, GenMessage } from "@bufbuild/protobuf/codegenv1"; +import { fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv1"; +import type { Timestamp } from "@bufbuild/protobuf/wkt"; +import { file_google_protobuf_timestamp } from "@bufbuild/protobuf/wkt"; +import type { Message } from "@bufbuild/protobuf"; + +/** + * Describes the file latency_tracker.proto. + */ +export const file_latency_tracker: GenFile = /*@__PURE__*/ + fileDesc("ChVsYXRlbmN5X3RyYWNrZXIucHJvdG8SBXByb3RvIk4KE1Byb3RvVGltZXN0YW1wRW50cnkSDQoFc3RhZ2UYASABKAkSKAoEdGltZRgCIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXAiWgoTUHJvdG9MYXRlbmN5VHJhY2tlchITCgtzZXF1ZW5jZV9pZBgBIAEoCRIuCgp0aW1lc3RhbXBzGAIgAygLMhoucHJvdG8uUHJvdG9UaW1lc3RhbXBFbnRyeUIWWhRyZWxheS9pbnRlcm5hbC9wcm90b2IGcHJvdG8z", [file_google_protobuf_timestamp]); + +/** + * @generated from message proto.ProtoTimestampEntry + */ +export type ProtoTimestampEntry = Message<"proto.ProtoTimestampEntry"> & { + /** + * @generated from field: string stage = 1; + */ + stage: string; + + /** + * @generated from field: google.protobuf.Timestamp time = 2; + */ + time?: Timestamp; +}; + +/** + * Describes the message proto.ProtoTimestampEntry. + * Use `create(ProtoTimestampEntrySchema)` to create a new message. + */ +export const ProtoTimestampEntrySchema: GenMessage = /*@__PURE__*/ + messageDesc(file_latency_tracker, 0); + +/** + * @generated from message proto.ProtoLatencyTracker + */ +export type ProtoLatencyTracker = Message<"proto.ProtoLatencyTracker"> & { + /** + * @generated from field: string sequence_id = 1; + */ + sequenceId: string; + + /** + * @generated from field: repeated proto.ProtoTimestampEntry timestamps = 2; + */ + timestamps: ProtoTimestampEntry[]; +}; + +/** + * Describes the message proto.ProtoLatencyTracker. + * Use `create(ProtoLatencyTrackerSchema)` to create a new message. + */ +export const ProtoLatencyTrackerSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_latency_tracker, 1); + diff --git a/packages/input/src/proto/messages_pb.ts b/packages/input/src/proto/messages_pb.ts new file mode 100644 index 00000000..0b918b94 --- /dev/null +++ b/packages/input/src/proto/messages_pb.ts @@ -0,0 +1,62 @@ +// @generated by protoc-gen-es v2.2.3 with parameter "target=ts" +// @generated from file messages.proto (package proto, syntax proto3) +/* eslint-disable */ + +import type { GenFile, GenMessage } from "@bufbuild/protobuf/codegenv1"; +import { fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv1"; +import type { ProtoInput } from "./types_pb"; +import { file_types } from "./types_pb"; +import type { ProtoLatencyTracker } from "./latency_tracker_pb"; +import { file_latency_tracker } from "./latency_tracker_pb"; +import type { Message } from "@bufbuild/protobuf"; + +/** + * Describes the file messages.proto. + */ +export const file_messages: GenFile = /*@__PURE__*/ + fileDesc("Cg5tZXNzYWdlcy5wcm90bxIFcHJvdG8iVQoQUHJvdG9NZXNzYWdlQmFzZRIUCgxwYXlsb2FkX3R5cGUYASABKAkSKwoHbGF0ZW5jeRgCIAEoCzIaLnByb3RvLlByb3RvTGF0ZW5jeVRyYWNrZXIiYwoRUHJvdG9NZXNzYWdlSW5wdXQSLQoMbWVzc2FnZV9iYXNlGAEgASgLMhcucHJvdG8uUHJvdG9NZXNzYWdlQmFzZRIfCgRkYXRhGAIgASgLMhEucHJvdG8uUHJvdG9JbnB1dEIWWhRyZWxheS9pbnRlcm5hbC9wcm90b2IGcHJvdG8z", [file_types, file_latency_tracker]); + +/** + * @generated from message proto.ProtoMessageBase + */ +export type ProtoMessageBase = Message<"proto.ProtoMessageBase"> & { + /** + * @generated from field: string payload_type = 1; + */ + payloadType: string; + + /** + * @generated from field: proto.ProtoLatencyTracker latency = 2; + */ + latency?: ProtoLatencyTracker; +}; + +/** + * Describes the message proto.ProtoMessageBase. + * Use `create(ProtoMessageBaseSchema)` to create a new message. + */ +export const ProtoMessageBaseSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_messages, 0); + +/** + * @generated from message proto.ProtoMessageInput + */ +export type ProtoMessageInput = Message<"proto.ProtoMessageInput"> & { + /** + * @generated from field: proto.ProtoMessageBase message_base = 1; + */ + messageBase?: ProtoMessageBase; + + /** + * @generated from field: proto.ProtoInput data = 2; + */ + data?: ProtoInput; +}; + +/** + * Describes the message proto.ProtoMessageInput. + * Use `create(ProtoMessageInputSchema)` to create a new message. + */ +export const ProtoMessageInputSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_messages, 1); + diff --git a/packages/input/src/proto/types_pb.ts b/packages/input/src/proto/types_pb.ts new file mode 100644 index 00000000..689bdc1f --- /dev/null +++ b/packages/input/src/proto/types_pb.ts @@ -0,0 +1,272 @@ +// @generated by protoc-gen-es v2.2.3 with parameter "target=ts" +// @generated from file types.proto (package proto, syntax proto3) +/* eslint-disable */ + +import type { GenFile, GenMessage } from "@bufbuild/protobuf/codegenv1"; +import { fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv1"; +import type { Message } from "@bufbuild/protobuf"; + +/** + * Describes the file types.proto. + */ +export const file_types: GenFile = /*@__PURE__*/ + fileDesc("Cgt0eXBlcy5wcm90bxIFcHJvdG8iNAoOUHJvdG9Nb3VzZU1vdmUSDAoEdHlwZRgBIAEoCRIJCgF4GAIgASgFEgkKAXkYAyABKAUiNwoRUHJvdG9Nb3VzZU1vdmVBYnMSDAoEdHlwZRgBIAEoCRIJCgF4GAIgASgFEgkKAXkYAyABKAUiNQoPUHJvdG9Nb3VzZVdoZWVsEgwKBHR5cGUYASABKAkSCQoBeBgCIAEoBRIJCgF5GAMgASgFIi4KEVByb3RvTW91c2VLZXlEb3duEgwKBHR5cGUYASABKAkSCwoDa2V5GAIgASgFIiwKD1Byb3RvTW91c2VLZXlVcBIMCgR0eXBlGAEgASgJEgsKA2tleRgCIAEoBSIpCgxQcm90b0tleURvd24SDAoEdHlwZRgBIAEoCRILCgNrZXkYAiABKAUiJwoKUHJvdG9LZXlVcBIMCgR0eXBlGAEgASgJEgsKA2tleRgCIAEoBSLcAgoKUHJvdG9JbnB1dBIrCgptb3VzZV9tb3ZlGAEgASgLMhUucHJvdG8uUHJvdG9Nb3VzZU1vdmVIABIyCg5tb3VzZV9tb3ZlX2FicxgCIAEoCzIYLnByb3RvLlByb3RvTW91c2VNb3ZlQWJzSAASLQoLbW91c2Vfd2hlZWwYAyABKAsyFi5wcm90by5Qcm90b01vdXNlV2hlZWxIABIyCg5tb3VzZV9rZXlfZG93bhgEIAEoCzIYLnByb3RvLlByb3RvTW91c2VLZXlEb3duSAASLgoMbW91c2Vfa2V5X3VwGAUgASgLMhYucHJvdG8uUHJvdG9Nb3VzZUtleVVwSAASJwoIa2V5X2Rvd24YBiABKAsyEy5wcm90by5Qcm90b0tleURvd25IABIjCgZrZXlfdXAYByABKAsyES5wcm90by5Qcm90b0tleVVwSABCDAoKaW5wdXRfdHlwZUIWWhRyZWxheS9pbnRlcm5hbC9wcm90b2IGcHJvdG8z"); + +/** + * MouseMove message + * + * @generated from message proto.ProtoMouseMove + */ +export type ProtoMouseMove = Message<"proto.ProtoMouseMove"> & { + /** + * Fixed value "MouseMove" + * + * @generated from field: string type = 1; + */ + type: string; + + /** + * @generated from field: int32 x = 2; + */ + x: number; + + /** + * @generated from field: int32 y = 3; + */ + y: number; +}; + +/** + * Describes the message proto.ProtoMouseMove. + * Use `create(ProtoMouseMoveSchema)` to create a new message. + */ +export const ProtoMouseMoveSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_types, 0); + +/** + * MouseMoveAbs message + * + * @generated from message proto.ProtoMouseMoveAbs + */ +export type ProtoMouseMoveAbs = Message<"proto.ProtoMouseMoveAbs"> & { + /** + * Fixed value "MouseMoveAbs" + * + * @generated from field: string type = 1; + */ + type: string; + + /** + * @generated from field: int32 x = 2; + */ + x: number; + + /** + * @generated from field: int32 y = 3; + */ + y: number; +}; + +/** + * Describes the message proto.ProtoMouseMoveAbs. + * Use `create(ProtoMouseMoveAbsSchema)` to create a new message. + */ +export const ProtoMouseMoveAbsSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_types, 1); + +/** + * MouseWheel message + * + * @generated from message proto.ProtoMouseWheel + */ +export type ProtoMouseWheel = Message<"proto.ProtoMouseWheel"> & { + /** + * Fixed value "MouseWheel" + * + * @generated from field: string type = 1; + */ + type: string; + + /** + * @generated from field: int32 x = 2; + */ + x: number; + + /** + * @generated from field: int32 y = 3; + */ + y: number; +}; + +/** + * Describes the message proto.ProtoMouseWheel. + * Use `create(ProtoMouseWheelSchema)` to create a new message. + */ +export const ProtoMouseWheelSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_types, 2); + +/** + * MouseKeyDown message + * + * @generated from message proto.ProtoMouseKeyDown + */ +export type ProtoMouseKeyDown = Message<"proto.ProtoMouseKeyDown"> & { + /** + * Fixed value "MouseKeyDown" + * + * @generated from field: string type = 1; + */ + type: string; + + /** + * @generated from field: int32 key = 2; + */ + key: number; +}; + +/** + * Describes the message proto.ProtoMouseKeyDown. + * Use `create(ProtoMouseKeyDownSchema)` to create a new message. + */ +export const ProtoMouseKeyDownSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_types, 3); + +/** + * MouseKeyUp message + * + * @generated from message proto.ProtoMouseKeyUp + */ +export type ProtoMouseKeyUp = Message<"proto.ProtoMouseKeyUp"> & { + /** + * Fixed value "MouseKeyUp" + * + * @generated from field: string type = 1; + */ + type: string; + + /** + * @generated from field: int32 key = 2; + */ + key: number; +}; + +/** + * Describes the message proto.ProtoMouseKeyUp. + * Use `create(ProtoMouseKeyUpSchema)` to create a new message. + */ +export const ProtoMouseKeyUpSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_types, 4); + +/** + * KeyDown message + * + * @generated from message proto.ProtoKeyDown + */ +export type ProtoKeyDown = Message<"proto.ProtoKeyDown"> & { + /** + * Fixed value "KeyDown" + * + * @generated from field: string type = 1; + */ + type: string; + + /** + * @generated from field: int32 key = 2; + */ + key: number; +}; + +/** + * Describes the message proto.ProtoKeyDown. + * Use `create(ProtoKeyDownSchema)` to create a new message. + */ +export const ProtoKeyDownSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_types, 5); + +/** + * KeyUp message + * + * @generated from message proto.ProtoKeyUp + */ +export type ProtoKeyUp = Message<"proto.ProtoKeyUp"> & { + /** + * Fixed value "KeyUp" + * + * @generated from field: string type = 1; + */ + type: string; + + /** + * @generated from field: int32 key = 2; + */ + key: number; +}; + +/** + * Describes the message proto.ProtoKeyUp. + * Use `create(ProtoKeyUpSchema)` to create a new message. + */ +export const ProtoKeyUpSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_types, 6); + +/** + * Union of all Input types + * + * @generated from message proto.ProtoInput + */ +export type ProtoInput = Message<"proto.ProtoInput"> & { + /** + * @generated from oneof proto.ProtoInput.input_type + */ + inputType: { + /** + * @generated from field: proto.ProtoMouseMove mouse_move = 1; + */ + value: ProtoMouseMove; + case: "mouseMove"; + } | { + /** + * @generated from field: proto.ProtoMouseMoveAbs mouse_move_abs = 2; + */ + value: ProtoMouseMoveAbs; + case: "mouseMoveAbs"; + } | { + /** + * @generated from field: proto.ProtoMouseWheel mouse_wheel = 3; + */ + value: ProtoMouseWheel; + case: "mouseWheel"; + } | { + /** + * @generated from field: proto.ProtoMouseKeyDown mouse_key_down = 4; + */ + value: ProtoMouseKeyDown; + case: "mouseKeyDown"; + } | { + /** + * @generated from field: proto.ProtoMouseKeyUp mouse_key_up = 5; + */ + value: ProtoMouseKeyUp; + case: "mouseKeyUp"; + } | { + /** + * @generated from field: proto.ProtoKeyDown key_down = 6; + */ + value: ProtoKeyDown; + case: "keyDown"; + } | { + /** + * @generated from field: proto.ProtoKeyUp key_up = 7; + */ + value: ProtoKeyUp; + case: "keyUp"; + } | { case: undefined; value?: undefined }; +}; + +/** + * Describes the message proto.ProtoInput. + * Use `create(ProtoInputSchema)` to create a new message. + */ +export const ProtoInputSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_types, 7); + diff --git a/packages/input/src/types.ts b/packages/input/src/types.ts deleted file mode 100644 index b733b499..00000000 --- a/packages/input/src/types.ts +++ /dev/null @@ -1,52 +0,0 @@ -interface BaseInput { - timestamp?: number; // Add a timestamp for better context (optional) -} - -interface MouseMove extends BaseInput { - type: "MouseMove"; - x: number; - y: number; -} - -interface MouseMoveAbs extends BaseInput { - type: "MouseMoveAbs"; - x: number; - y: number; -} - -interface MouseWheel extends BaseInput { - type: "MouseWheel"; - x: number; - y: number; -} - -interface MouseKeyDown extends BaseInput { - type: "MouseKeyDown"; - key: number; -} - -interface MouseKeyUp extends BaseInput { - type: "MouseKeyUp"; - key: number; -} - -interface KeyDown extends BaseInput { - type: "KeyDown"; - key: number; -} - -interface KeyUp extends BaseInput { - type: "KeyUp"; - key: number; -} - - -export type Input = - | MouseMove - | MouseMoveAbs - | MouseWheel - | MouseKeyDown - | MouseKeyUp - | KeyDown - | KeyUp; - diff --git a/packages/input/src/webrtc-stream.ts b/packages/input/src/webrtc-stream.ts index ea262092..da9b7a77 100644 --- a/packages/input/src/webrtc-stream.ts +++ b/packages/input/src/webrtc-stream.ts @@ -6,8 +6,6 @@ import { MessageAnswer, JoinerType, AnswerType, - decodeMessage, - encodeMessage } from "./messages"; export class WebRTCStream { @@ -40,16 +38,16 @@ export class WebRTCStream { payload_type: "join", joiner_type: JoinerType.JoinerClient }; - this._ws!.send(encodeMessage(joinMessage)); + this._ws!.send(JSON.stringify(joinMessage)); } let iceHolder: RTCIceCandidateInit[] = []; this._ws.onmessage = async (e) => { - // allow only binary - if (typeof e.data !== "object") return; + // allow only JSON + if (typeof e.data === "object") return; if (!e.data) return; - const message = await decodeMessage(e.data); + const message = JSON.parse(e.data) as MessageBase; switch (message.payload_type) { case "sdp": if (!this._pc) { @@ -63,7 +61,7 @@ export class WebRTCStream { // Force stereo in Chromium browsers answer.sdp = this.forceOpusStereo(answer.sdp!); await this._pc!.setLocalDescription(answer); - this._ws!.send(encodeMessage({ + this._ws!.send(JSON.stringify({ payload_type: "sdp", sdp: answer })); @@ -154,7 +152,7 @@ export class WebRTCStream { payload_type: "ice", candidate: e.candidate }; - this._ws!.send(encodeMessage(message)); + this._ws!.send(JSON.stringify(message)); } } diff --git a/packages/relay/go.mod b/packages/relay/go.mod index 8b21b568..2657da28 100644 --- a/packages/relay/go.mod +++ b/packages/relay/go.mod @@ -6,26 +6,27 @@ require ( github.com/google/uuid v1.6.0 github.com/gorilla/websocket v1.5.3 github.com/pion/interceptor v0.1.37 - github.com/pion/webrtc/v4 v4.0.2 + github.com/pion/webrtc/v4 v4.0.8 + google.golang.org/protobuf v1.36.4 ) require ( - github.com/pion/datachannel v1.5.9 // indirect + github.com/pion/datachannel v1.5.10 // indirect github.com/pion/dtls/v3 v3.0.4 // indirect - github.com/pion/ice/v4 v4.0.2 // indirect - github.com/pion/logging v0.2.2 // indirect + github.com/pion/ice/v4 v4.0.5 // indirect + github.com/pion/logging v0.2.3 // indirect github.com/pion/mdns/v2 v2.0.7 // indirect github.com/pion/randutil v0.1.0 // indirect - github.com/pion/rtcp v1.2.14 // indirect - github.com/pion/rtp v1.8.9 // indirect - github.com/pion/sctp v1.8.34 // indirect - github.com/pion/sdp/v3 v3.0.9 // indirect + github.com/pion/rtcp v1.2.15 // indirect + github.com/pion/rtp v1.8.11 // indirect + github.com/pion/sctp v1.8.35 // indirect + github.com/pion/sdp/v3 v3.0.10 // indirect github.com/pion/srtp/v3 v3.0.4 // indirect github.com/pion/stun/v3 v3.0.0 // indirect github.com/pion/transport/v3 v3.0.7 // indirect github.com/pion/turn/v4 v4.0.0 // indirect github.com/wlynxg/anet v0.0.5 // indirect - golang.org/x/crypto v0.31.0 // indirect - golang.org/x/net v0.31.0 // indirect - golang.org/x/sys v0.28.0 // indirect + golang.org/x/crypto v0.32.0 // indirect + golang.org/x/net v0.34.0 // indirect + golang.org/x/sys v0.29.0 // indirect ) diff --git a/packages/relay/go.sum b/packages/relay/go.sum index 948b0702..56976d55 100644 --- a/packages/relay/go.sum +++ b/packages/relay/go.sum @@ -1,32 +1,33 @@ -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/pion/datachannel v1.5.9 h1:LpIWAOYPyDrXtU+BW7X0Yt/vGtYxtXQ8ql7dFfYUVZA= -github.com/pion/datachannel v1.5.9/go.mod h1:kDUuk4CU4Uxp82NH4LQZbISULkX/HtzKa4P7ldf9izE= +github.com/pion/datachannel v1.5.10 h1:ly0Q26K1i6ZkGf42W7D4hQYR90pZwzFOjTq5AuCKk4o= +github.com/pion/datachannel v1.5.10/go.mod h1:p/jJfC9arb29W7WrxyKbepTU20CFgyx5oLo8Rs4Py/M= github.com/pion/dtls/v3 v3.0.4 h1:44CZekewMzfrn9pmGrj5BNnTMDCFwr+6sLH+cCuLM7U= github.com/pion/dtls/v3 v3.0.4/go.mod h1:R373CsjxWqNPf6MEkfdy3aSe9niZvL/JaKlGeFphtMg= -github.com/pion/ice/v4 v4.0.2 h1:1JhBRX8iQLi0+TfcavTjPjI6GO41MFn4CeTBX+Y9h5s= -github.com/pion/ice/v4 v4.0.2/go.mod h1:DCdqyzgtsDNYN6/3U8044j3U7qsJ9KFJC92VnOWHvXg= +github.com/pion/ice/v4 v4.0.5 h1:6awVfa1jg9YsI9/Lep4TG/o3kwS1Oayr5b8xz50ibJ8= +github.com/pion/ice/v4 v4.0.5/go.mod h1:JJaoEIxUIlGDA9gaRZbwXYqI3j6VG/QchpjX+QmwN6A= github.com/pion/interceptor v0.1.37 h1:aRA8Zpab/wE7/c0O3fh1PqY0AJI3fCSEM5lRWJVorwI= github.com/pion/interceptor v0.1.37/go.mod h1:JzxbJ4umVTlZAf+/utHzNesY8tmRkM2lVmkS82TTj8Y= -github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= -github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= +github.com/pion/logging v0.2.3 h1:gHuf0zpoh1GW67Nr6Gj4cv5Z9ZscU7g/EaoC/Ke/igI= +github.com/pion/logging v0.2.3/go.mod h1:z8YfknkquMe1csOrxK5kc+5/ZPAzMxbKLX5aXpbpC90= github.com/pion/mdns/v2 v2.0.7 h1:c9kM8ewCgjslaAmicYMFQIde2H9/lrZpjBkN8VwoVtM= github.com/pion/mdns/v2 v2.0.7/go.mod h1:vAdSYNAT0Jy3Ru0zl2YiW3Rm/fJCwIeM0nToenfOJKA= github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= -github.com/pion/rtcp v1.2.14 h1:KCkGV3vJ+4DAJmvP0vaQShsb0xkRfWkO540Gy102KyE= -github.com/pion/rtcp v1.2.14/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= -github.com/pion/rtp v1.8.9 h1:E2HX740TZKaqdcPmf4pw6ZZuG8u5RlMMt+l3dxeu6Wk= -github.com/pion/rtp v1.8.9/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= -github.com/pion/sctp v1.8.34 h1:rCuD3m53i0oGxCSp7FLQKvqVx0Nf5AUAHhMRXTTQjBc= -github.com/pion/sctp v1.8.34/go.mod h1:yWkCClkXlzVW7BXfI2PjrUGBwUI0CjXJBkhLt+sdo4U= -github.com/pion/sdp/v3 v3.0.9 h1:pX++dCHoHUwq43kuwf3PyJfHlwIj4hXA7Vrifiq0IJY= -github.com/pion/sdp/v3 v3.0.9/go.mod h1:B5xmvENq5IXJimIO4zfp6LAe1fD9N+kFv+V/1lOdz8M= +github.com/pion/rtcp v1.2.15 h1:LZQi2JbdipLOj4eBjK4wlVoQWfrZbh3Q6eHtWtJBZBo= +github.com/pion/rtcp v1.2.15/go.mod h1:jlGuAjHMEXwMUHK78RgX0UmEJFV4zUKOFHR7OP+D3D0= +github.com/pion/rtp v1.8.11 h1:17xjnY5WO5hgO6SD3/NTIUPvSFw/PbLsIJyz1r1yNIk= +github.com/pion/rtp v1.8.11/go.mod h1:8uMBJj32Pa1wwx8Fuv/AsFhn8jsgw+3rUC2PfoBZ8p4= +github.com/pion/sctp v1.8.35 h1:qwtKvNK1Wc5tHMIYgTDJhfZk7vATGVHhXbUDfHbYwzA= +github.com/pion/sctp v1.8.35/go.mod h1:EcXP8zCYVTRy3W9xtOF7wJm1L1aXfKRQzaM33SjQlzg= +github.com/pion/sdp/v3 v3.0.10 h1:6MChLE/1xYB+CjumMw+gZ9ufp2DPApuVSnDT8t5MIgA= +github.com/pion/sdp/v3 v3.0.10/go.mod h1:88GMahN5xnScv1hIMTqLdu/cOcUkj6a9ytbncwMCq2E= github.com/pion/srtp/v3 v3.0.4 h1:2Z6vDVxzrX3UHEgrUyIGM4rRouoC7v+NiF1IHtp9B5M= github.com/pion/srtp/v3 v3.0.4/go.mod h1:1Jx3FwDoxpRaTh1oRV8A/6G1BnFL+QI82eK4ms8EEJQ= github.com/pion/stun/v3 v3.0.0 h1:4h1gwhWLWuZWOJIJR9s2ferRO+W3zA/b6ijOI6mKzUw= @@ -35,28 +36,23 @@ github.com/pion/transport/v3 v3.0.7 h1:iRbMH05BzSNwhILHoBoAPxoB9xQgOaJk+591KC9P1 github.com/pion/transport/v3 v3.0.7/go.mod h1:YleKiTZ4vqNxVwh77Z0zytYi7rXHl7j6uPLGhhz9rwo= github.com/pion/turn/v4 v4.0.0 h1:qxplo3Rxa9Yg1xXDxxH8xaqcyGUtbHYw4QSCvmFWvhM= github.com/pion/turn/v4 v4.0.0/go.mod h1:MuPDkm15nYSklKpN8vWJ9W2M0PlyQZqYt1McGuxG7mA= -github.com/pion/webrtc/v4 v4.0.2 h1:fBwm5/hqSUybrCWl0DDBSTDrpbkcgkqpeLmXw9CsBQA= -github.com/pion/webrtc/v4 v4.0.2/go.mod h1:moylBT2A4dNoEaYBCdV1nThM3TLwRHzWszIG+eSPaqQ= +github.com/pion/webrtc/v4 v4.0.8 h1:T1ZmnT9qxIJIt4d8XoiMOBrTClGHDDXNg9e/fh018Qc= +github.com/pion/webrtc/v4 v4.0.8/go.mod h1:HHBeUVBAC+j4ZFnYhovEFStF02Arb1EyD4G7e7HBTJw= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/wlynxg/anet v0.0.5 h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU= github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA= -golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= -golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= -golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= -golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= +golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= +golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= +golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM= +google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/packages/relay/internal/datachannel.go b/packages/relay/internal/datachannel.go index ba59fff8..ae902f00 100644 --- a/packages/relay/internal/datachannel.go +++ b/packages/relay/internal/datachannel.go @@ -2,20 +2,22 @@ package relay import ( "github.com/pion/webrtc/v4" + "google.golang.org/protobuf/proto" "log" + gen "relay/internal/proto" ) // NestriDataChannel is a custom data channel with callbacks type NestriDataChannel struct { *webrtc.DataChannel - binaryCallbacks map[string]OnMessageCallback // MessageBase type -> callback + callbacks map[string]OnMessageCallback // MessageBase type -> callback } // NewNestriDataChannel creates a new NestriDataChannel from *webrtc.DataChannel func NewNestriDataChannel(dc *webrtc.DataChannel) *NestriDataChannel { ndc := &NestriDataChannel{ - DataChannel: dc, - binaryCallbacks: make(map[string]OnMessageCallback), + DataChannel: dc, + callbacks: make(map[string]OnMessageCallback), } // Handler for incoming messages @@ -26,14 +28,14 @@ func NewNestriDataChannel(dc *webrtc.DataChannel) *NestriDataChannel { } // Decode message - var base MessageBase - if err := DecodeMessage(msg.Data, &base); err != nil { + var base gen.ProtoMessageInput + if err := proto.Unmarshal(msg.Data, &base); err != nil { log.Printf("Failed to decode binary DataChannel message, reason: %s\n", err) return } // Handle message type callback - if callback, ok := ndc.binaryCallbacks[base.PayloadType]; ok { + if callback, ok := ndc.callbacks["input"]; ok { go callback(msg.Data) } // TODO: Log unknown message type? }) @@ -48,16 +50,16 @@ func (ndc *NestriDataChannel) SendBinary(data []byte) error { // RegisterMessageCallback registers a callback for a given binary message type func (ndc *NestriDataChannel) RegisterMessageCallback(msgType string, callback OnMessageCallback) { - if ndc.binaryCallbacks == nil { - ndc.binaryCallbacks = make(map[string]OnMessageCallback) + if ndc.callbacks == nil { + ndc.callbacks = make(map[string]OnMessageCallback) } - ndc.binaryCallbacks[msgType] = callback + ndc.callbacks[msgType] = callback } // UnregisterMessageCallback removes the callback for a given binary message type func (ndc *NestriDataChannel) UnregisterMessageCallback(msgType string) { - if ndc.binaryCallbacks != nil { - delete(ndc.binaryCallbacks, msgType) + if ndc.callbacks != nil { + delete(ndc.callbacks, msgType) } } diff --git a/packages/relay/internal/egress.go b/packages/relay/internal/egress.go index c72ce201..712f0fde 100644 --- a/packages/relay/internal/egress.go +++ b/packages/relay/internal/egress.go @@ -1,8 +1,11 @@ package relay import ( + "encoding/json" "github.com/pion/webrtc/v4" + "google.golang.org/protobuf/proto" "log" + gen "relay/internal/proto" ) func participantHandler(participant *Participant, room *Room) { @@ -54,15 +57,22 @@ func participantHandler(participant *Participant, room *Room) { if room.DataChannel != nil { // If debug mode, decode and add our timestamp, otherwise just send to room if GetFlags().Debug { - var inputMsg MessageInput - if err = DecodeMessage(data, &inputMsg); err != nil { + var inputMsg gen.ProtoMessageInput + if err = proto.Unmarshal(data, &inputMsg); err != nil { log.Printf("Failed to decode input message from participant: '%s' in room: '%s' - reason: %s\n", participant.ID, room.Name, err) return } - inputMsg.LatencyTracker.AddTimestamp("relay_to_node") - // Encode and send - if data, err = EncodeMessage(inputMsg); err != nil { - log.Printf("Failed to encode input message for participant: '%s' in room: '%s' - reason: %s\n", participant.ID, room.Name, err) + + protoLat := inputMsg.GetMessageBase().GetLatency() + if protoLat != nil { + lat := LatencyTrackerFromProto(protoLat) + lat.AddTimestamp("relay_to_node") + protoLat = lat.ToProto() + } + + // Marshal and send + if data, err = proto.Marshal(&inputMsg); err != nil { + log.Printf("Failed to marshal input message for participant: '%s' in room: '%s' - reason: %s\n", participant.ID, room.Name, err) return } if err = room.DataChannel.SendBinary(data); err != nil { @@ -94,7 +104,7 @@ func participantHandler(participant *Participant, room *Room) { // ICE callback participant.WebSocket.RegisterMessageCallback("ice", func(data []byte) { var iceMsg MessageICECandidate - if err = DecodeMessage(data, &iceMsg); err != nil { + if err = json.Unmarshal(data, &iceMsg); err != nil { log.Printf("Failed to decode ICE message from participant: '%s' in room: '%s' - reason: %s\n", participant.ID, room.Name, err) return } @@ -120,7 +130,7 @@ func participantHandler(participant *Participant, room *Room) { // SDP answer callback participant.WebSocket.RegisterMessageCallback("sdp", func(data []byte) { var sdpMsg MessageSDP - if err = DecodeMessage(data, &sdpMsg); err != nil { + if err = json.Unmarshal(data, &sdpMsg); err != nil { log.Printf("Failed to decode SDP message from participant: '%s' in room: '%s' - reason: %s\n", participant.ID, room.Name, err) return } @@ -130,7 +140,7 @@ func participantHandler(participant *Participant, room *Room) { // Log callback participant.WebSocket.RegisterMessageCallback("log", func(data []byte) { var logMsg MessageLog - if err = DecodeMessage(data, &logMsg); err != nil { + if err = json.Unmarshal(data, &logMsg); err != nil { log.Printf("Failed to decode log message from participant: '%s' in room: '%s' - reason: %s\n", participant.ID, room.Name, err) return } diff --git a/packages/relay/internal/http.go b/packages/relay/internal/http.go index 7ab89d0b..2012d000 100644 --- a/packages/relay/internal/http.go +++ b/packages/relay/internal/http.go @@ -1,6 +1,7 @@ package relay import ( + "encoding/json" "github.com/gorilla/websocket" "log" "net/http" @@ -81,7 +82,7 @@ func wsHandler(w http.ResponseWriter, r *http.Request) { // Assign message handler for join request ws.RegisterMessageCallback("join", func(data []byte) { var joinMsg MessageJoin - if err = DecodeMessage(data, &joinMsg); err != nil { + if err = json.Unmarshal(data, &joinMsg); err != nil { log.Printf("Failed to decode join message: %s\n", err) return } diff --git a/packages/relay/internal/ingest.go b/packages/relay/internal/ingest.go index 2053e398..f3b6a085 100644 --- a/packages/relay/internal/ingest.go +++ b/packages/relay/internal/ingest.go @@ -1,6 +1,7 @@ package relay import ( + "encoding/json" "errors" "fmt" "github.com/pion/webrtc/v4" @@ -134,7 +135,7 @@ func ingestHandler(room *Room) { // ICE callback room.WebSocket.RegisterMessageCallback("ice", func(data []byte) { var iceMsg MessageICECandidate - if err = DecodeMessage(data, &iceMsg); err != nil { + if err = json.Unmarshal(data, &iceMsg); err != nil { log.Printf("Failed to decode ICE candidate message from ingest for room: '%s' - reason: %s\n", room.Name, err) return } @@ -165,7 +166,7 @@ func ingestHandler(room *Room) { // SDP offer callback room.WebSocket.RegisterMessageCallback("sdp", func(data []byte) { var sdpMsg MessageSDP - if err = DecodeMessage(data, &sdpMsg); err != nil { + if err = json.Unmarshal(data, &sdpMsg); err != nil { log.Printf("Failed to decode SDP message from ingest for room: '%s' - reason: %s\n", room.Name, err) return } @@ -182,7 +183,7 @@ func ingestHandler(room *Room) { // Log callback room.WebSocket.RegisterMessageCallback("log", func(data []byte) { var logMsg MessageLog - if err = DecodeMessage(data, &logMsg); err != nil { + if err = json.Unmarshal(data, &logMsg); err != nil { log.Printf("Failed to decode log message from ingest for room: '%s' - reason: %s\n", room.Name, err) return } @@ -192,7 +193,7 @@ func ingestHandler(room *Room) { // Metrics callback room.WebSocket.RegisterMessageCallback("metrics", func(data []byte) { var metricsMsg MessageMetrics - if err = DecodeMessage(data, &metricsMsg); err != nil { + if err = json.Unmarshal(data, &metricsMsg); err != nil { log.Printf("Failed to decode metrics message from ingest for room: '%s' - reason: %s\n", room.Name, err) return } diff --git a/packages/relay/internal/latency.go b/packages/relay/internal/latency.go index 9ebc31e1..152f3492 100644 --- a/packages/relay/internal/latency.go +++ b/packages/relay/internal/latency.go @@ -2,20 +2,21 @@ package relay import ( "fmt" + "google.golang.org/protobuf/types/known/timestamppb" + gen "relay/internal/proto" "time" ) type TimestampEntry struct { - Stage string `json:"stage"` - Time string `json:"time"` // ISO 8601 string + Stage string `json:"stage"` + Time time.Time `json:"time"` } // LatencyTracker provides a generic structure for measuring time taken at various stages in message processing. // It can be embedded in message structs for tracking the flow of data and calculating round-trip latency. type LatencyTracker struct { - SequenceID string `json:"sequence_id"` - Timestamps []TimestampEntry `json:"timestamps"` - Metadata map[string]string `json:"metadata,omitempty"` + SequenceID string `json:"sequence_id"` + Timestamps []TimestampEntry `json:"timestamps"` } // NewLatencyTracker initializes a new LatencyTracker with the given sequence ID @@ -23,7 +24,6 @@ func NewLatencyTracker(sequenceID string) *LatencyTracker { return &LatencyTracker{ SequenceID: sequenceID, Timestamps: make([]TimestampEntry, 0), - Metadata: make(map[string]string), } } @@ -32,7 +32,7 @@ func (lt *LatencyTracker) AddTimestamp(stage string) { lt.Timestamps = append(lt.Timestamps, TimestampEntry{ Stage: stage, // Ensure extremely precise UTC RFC3339 timestamps (down to nanoseconds) - Time: time.Now().UTC().Format(time.RFC3339Nano), + Time: time.Now().UTC(), }) } @@ -44,15 +44,11 @@ func (lt *LatencyTracker) TotalLatency() (int64, error) { var earliest, latest time.Time for _, ts := range lt.Timestamps { - t, err := time.Parse(time.RFC3339, ts.Time) - if err != nil { - return 0, err + if earliest.IsZero() || ts.Time.Before(earliest) { + earliest = ts.Time } - if earliest.IsZero() || t.Before(earliest) { - earliest = t - } - if latest.IsZero() || t.After(latest) { - latest = t + if latest.IsZero() || ts.Time.After(latest) { + latest = ts.Time } } @@ -67,14 +63,13 @@ func (lt *LatencyTracker) PainPoints(threshold time.Duration) []string { for _, ts := range lt.Timestamps { stage := ts.Stage - t := ts.Time if lastStage == "" { lastStage = stage - lastTime, _ = time.Parse(time.RFC3339, t) + lastTime = ts.Time continue } - currentTime, _ := time.Parse(time.RFC3339, t) + currentTime := ts.Time if currentTime.Sub(lastTime) > threshold { painPoints = append(painPoints, fmt.Sprintf("%s -> %s", lastStage, stage)) } @@ -87,7 +82,7 @@ func (lt *LatencyTracker) PainPoints(threshold time.Duration) []string { // StageLatency calculates the time taken between two specific stages. func (lt *LatencyTracker) StageLatency(startStage, endStage string) (time.Duration, error) { - startTime, endTime := "", "" + var startTime, endTime time.Time for _, ts := range lt.Timestamps { if ts.Stage == startStage { startTime = ts.Time @@ -97,18 +92,41 @@ func (lt *LatencyTracker) StageLatency(startStage, endStage string) (time.Durati } } - if startTime == "" || endTime == "" { + /*if startTime == "" || endTime == "" { return 0, fmt.Errorf("missing timestamps for stages: %s -> %s", startStage, endStage) - } + }*/ - start, err := time.Parse(time.RFC3339, startTime) - if err != nil { - return 0, err - } - end, err := time.Parse(time.RFC3339, endTime) - if err != nil { - return 0, err - } - - return end.Sub(start), nil + return endTime.Sub(startTime), nil +} + +func LatencyTrackerFromProto(protolt *gen.ProtoLatencyTracker) *LatencyTracker { + ret := &LatencyTracker{ + SequenceID: protolt.GetSequenceId(), + Timestamps: make([]TimestampEntry, 0), + } + + for _, ts := range protolt.GetTimestamps() { + ret.Timestamps = append(ret.Timestamps, TimestampEntry{ + Stage: ts.GetStage(), + Time: ts.GetTime().AsTime(), + }) + } + + return ret +} + +func (lt *LatencyTracker) ToProto() *gen.ProtoLatencyTracker { + ret := &gen.ProtoLatencyTracker{ + SequenceId: lt.SequenceID, + Timestamps: make([]*gen.ProtoTimestampEntry, len(lt.Timestamps)), + } + + for i, timestamp := range lt.Timestamps { + ret.Timestamps[i] = &gen.ProtoTimestampEntry{ + Stage: timestamp.Stage, + Time: timestamppb.New(timestamp.Time), + } + } + + return ret } diff --git a/packages/relay/internal/messages.go b/packages/relay/internal/messages.go index 2f102bd8..05ba5c44 100644 --- a/packages/relay/internal/messages.go +++ b/packages/relay/internal/messages.go @@ -1,27 +1,17 @@ package relay import ( - "bytes" - "compress/gzip" - "encoding/json" - "fmt" "github.com/pion/webrtc/v4" "time" ) -// OnMessageCallback is a callback for binary messages of given type +// OnMessageCallback is a callback for messages of given type type OnMessageCallback func(data []byte) // MessageBase is the base type for WS/DC messages. type MessageBase struct { - PayloadType string `json:"payload_type"` - LatencyTracker LatencyTracker `json:"latency_tracker,omitempty"` -} - -// MessageInput represents an input message. -type MessageInput struct { - MessageBase - Data string `json:"data"` + PayloadType string `json:"payload_type"` + Latency *LatencyTracker `json:"latency,omitempty"` } // MessageLog represents a log message. @@ -93,50 +83,6 @@ type MessageAnswer struct { AnswerType AnswerType `json:"answer_type"` } -// EncodeMessage encodes a message to be sent with gzip compression -func EncodeMessage(msg interface{}) ([]byte, error) { - // Marshal the message to JSON - data, err := json.Marshal(msg) - if err != nil { - return nil, fmt.Errorf("failed to encode message: %w", err) - } - - // Gzip compress the JSON - var compressedData bytes.Buffer - writer := gzip.NewWriter(&compressedData) - _, err = writer.Write(data) - if err != nil { - return nil, fmt.Errorf("failed to compress message: %w", err) - } - if err := writer.Close(); err != nil { - return nil, fmt.Errorf("failed to finalize compression: %w", err) - } - - return compressedData.Bytes(), nil -} - -// DecodeMessage decodes a message received with gzip decompression -func DecodeMessage(data []byte, target interface{}) error { - // Gzip decompress the data - reader, err := gzip.NewReader(bytes.NewReader(data)) - if err != nil { - return fmt.Errorf("failed to initialize decompression: %w", err) - } - defer func(reader *gzip.Reader) { - if err = reader.Close(); err != nil { - fmt.Printf("failed to close reader: %v\n", err) - } - }(reader) - - // Decode the JSON - err = json.NewDecoder(reader).Decode(target) - if err != nil { - return fmt.Errorf("failed to decode message: %w", err) - } - - return nil -} - // SendLogMessageWS sends a log message to the given WebSocket connection. func (ws *SafeWebSocket) SendLogMessageWS(level, message string) error { msg := MessageLog{ @@ -145,12 +91,7 @@ func (ws *SafeWebSocket) SendLogMessageWS(level, message string) error { Message: message, Time: time.Now().Format(time.RFC3339), } - encoded, err := EncodeMessage(msg) - if err != nil { - return fmt.Errorf("failed to encode log message: %w", err) - } - - return ws.SendBinary(encoded) + return ws.SendJSON(msg) } // SendMetricsMessageWS sends a metrics message to the given WebSocket connection. @@ -162,12 +103,7 @@ func (ws *SafeWebSocket) SendMetricsMessageWS(usageCPU, usageMemory float64, upt Uptime: uptime, PipelineLatency: pipelineLatency, } - encoded, err := EncodeMessage(msg) - if err != nil { - return fmt.Errorf("failed to encode metrics message: %w", err) - } - - return ws.SendBinary(encoded) + return ws.SendJSON(msg) } // SendICECandidateMessageWS sends an ICE candidate message to the given WebSocket connection. @@ -176,12 +112,7 @@ func (ws *SafeWebSocket) SendICECandidateMessageWS(candidate webrtc.ICECandidate MessageBase: MessageBase{PayloadType: "ice"}, Candidate: candidate, } - encoded, err := EncodeMessage(msg) - if err != nil { - return fmt.Errorf("failed to encode ICE candidate message: %w", err) - } - - return ws.SendBinary(encoded) + return ws.SendJSON(msg) } // SendSDPMessageWS sends an SDP message to the given WebSocket connection. @@ -190,12 +121,7 @@ func (ws *SafeWebSocket) SendSDPMessageWS(sdp webrtc.SessionDescription) error { MessageBase: MessageBase{PayloadType: "sdp"}, SDP: sdp, } - encoded, err := EncodeMessage(msg) - if err != nil { - return fmt.Errorf("failed to encode SDP message: %w", err) - } - - return ws.SendBinary(encoded) + return ws.SendJSON(msg) } // SendAnswerMessageWS sends an answer message to the given WebSocket connection. @@ -204,24 +130,5 @@ func (ws *SafeWebSocket) SendAnswerMessageWS(answer AnswerType) error { MessageBase: MessageBase{PayloadType: "answer"}, AnswerType: answer, } - encoded, err := EncodeMessage(msg) - if err != nil { - return fmt.Errorf("failed to encode answer message: %w", err) - } - - return ws.SendBinary(encoded) -} - -// SendInputMessageDC sends an input message to the given DataChannel connection. -func (ndc *NestriDataChannel) SendInputMessageDC(data string) error { - msg := MessageInput{ - MessageBase: MessageBase{PayloadType: "input"}, - Data: data, - } - encoded, err := EncodeMessage(msg) - if err != nil { - return fmt.Errorf("failed to encode input message: %w", err) - } - - return ndc.SendBinary(encoded) + return ws.SendJSON(msg) } diff --git a/packages/relay/internal/proto/latency_tracker.pb.go b/packages/relay/internal/proto/latency_tracker.pb.go new file mode 100644 index 00000000..a6bda859 --- /dev/null +++ b/packages/relay/internal/proto/latency_tracker.pb.go @@ -0,0 +1,203 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.4 +// protoc (unknown) +// source: latency_tracker.proto + +package proto + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type ProtoTimestampEntry struct { + state protoimpl.MessageState `protogen:"open.v1"` + Stage string `protobuf:"bytes,1,opt,name=stage,proto3" json:"stage,omitempty"` + Time *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=time,proto3" json:"time,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ProtoTimestampEntry) Reset() { + *x = ProtoTimestampEntry{} + mi := &file_latency_tracker_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ProtoTimestampEntry) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProtoTimestampEntry) ProtoMessage() {} + +func (x *ProtoTimestampEntry) ProtoReflect() protoreflect.Message { + mi := &file_latency_tracker_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ProtoTimestampEntry.ProtoReflect.Descriptor instead. +func (*ProtoTimestampEntry) Descriptor() ([]byte, []int) { + return file_latency_tracker_proto_rawDescGZIP(), []int{0} +} + +func (x *ProtoTimestampEntry) GetStage() string { + if x != nil { + return x.Stage + } + return "" +} + +func (x *ProtoTimestampEntry) GetTime() *timestamppb.Timestamp { + if x != nil { + return x.Time + } + return nil +} + +type ProtoLatencyTracker struct { + state protoimpl.MessageState `protogen:"open.v1"` + SequenceId string `protobuf:"bytes,1,opt,name=sequence_id,json=sequenceId,proto3" json:"sequence_id,omitempty"` + Timestamps []*ProtoTimestampEntry `protobuf:"bytes,2,rep,name=timestamps,proto3" json:"timestamps,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ProtoLatencyTracker) Reset() { + *x = ProtoLatencyTracker{} + mi := &file_latency_tracker_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ProtoLatencyTracker) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProtoLatencyTracker) ProtoMessage() {} + +func (x *ProtoLatencyTracker) ProtoReflect() protoreflect.Message { + mi := &file_latency_tracker_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ProtoLatencyTracker.ProtoReflect.Descriptor instead. +func (*ProtoLatencyTracker) Descriptor() ([]byte, []int) { + return file_latency_tracker_proto_rawDescGZIP(), []int{1} +} + +func (x *ProtoLatencyTracker) GetSequenceId() string { + if x != nil { + return x.SequenceId + } + return "" +} + +func (x *ProtoLatencyTracker) GetTimestamps() []*ProtoTimestampEntry { + if x != nil { + return x.Timestamps + } + return nil +} + +var File_latency_tracker_proto protoreflect.FileDescriptor + +var file_latency_tracker_proto_rawDesc = string([]byte{ + 0x0a, 0x15, 0x6c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x5f, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x65, + 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, + 0x5b, 0x0a, 0x13, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x67, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x74, 0x61, 0x67, 0x65, 0x12, 0x2e, 0x0a, 0x04, + 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x72, 0x0a, 0x13, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x54, 0x72, 0x61, 0x63, + 0x6b, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, + 0x63, 0x65, 0x49, 0x64, 0x12, 0x3a, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x73, + 0x42, 0x16, 0x5a, 0x14, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +}) + +var ( + file_latency_tracker_proto_rawDescOnce sync.Once + file_latency_tracker_proto_rawDescData []byte +) + +func file_latency_tracker_proto_rawDescGZIP() []byte { + file_latency_tracker_proto_rawDescOnce.Do(func() { + file_latency_tracker_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_latency_tracker_proto_rawDesc), len(file_latency_tracker_proto_rawDesc))) + }) + return file_latency_tracker_proto_rawDescData +} + +var file_latency_tracker_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_latency_tracker_proto_goTypes = []any{ + (*ProtoTimestampEntry)(nil), // 0: proto.ProtoTimestampEntry + (*ProtoLatencyTracker)(nil), // 1: proto.ProtoLatencyTracker + (*timestamppb.Timestamp)(nil), // 2: google.protobuf.Timestamp +} +var file_latency_tracker_proto_depIdxs = []int32{ + 2, // 0: proto.ProtoTimestampEntry.time:type_name -> google.protobuf.Timestamp + 0, // 1: proto.ProtoLatencyTracker.timestamps:type_name -> proto.ProtoTimestampEntry + 2, // [2:2] is the sub-list for method output_type + 2, // [2:2] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_latency_tracker_proto_init() } +func file_latency_tracker_proto_init() { + if File_latency_tracker_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_latency_tracker_proto_rawDesc), len(file_latency_tracker_proto_rawDesc)), + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_latency_tracker_proto_goTypes, + DependencyIndexes: file_latency_tracker_proto_depIdxs, + MessageInfos: file_latency_tracker_proto_msgTypes, + }.Build() + File_latency_tracker_proto = out.File + file_latency_tracker_proto_goTypes = nil + file_latency_tracker_proto_depIdxs = nil +} diff --git a/packages/relay/internal/proto/messages.pb.go b/packages/relay/internal/proto/messages.pb.go new file mode 100644 index 00000000..8faf7974 --- /dev/null +++ b/packages/relay/internal/proto/messages.pb.go @@ -0,0 +1,207 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.4 +// protoc (unknown) +// source: messages.proto + +package proto + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type ProtoMessageBase struct { + state protoimpl.MessageState `protogen:"open.v1"` + PayloadType string `protobuf:"bytes,1,opt,name=payload_type,json=payloadType,proto3" json:"payload_type,omitempty"` + Latency *ProtoLatencyTracker `protobuf:"bytes,2,opt,name=latency,proto3" json:"latency,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ProtoMessageBase) Reset() { + *x = ProtoMessageBase{} + mi := &file_messages_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ProtoMessageBase) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProtoMessageBase) ProtoMessage() {} + +func (x *ProtoMessageBase) ProtoReflect() protoreflect.Message { + mi := &file_messages_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ProtoMessageBase.ProtoReflect.Descriptor instead. +func (*ProtoMessageBase) Descriptor() ([]byte, []int) { + return file_messages_proto_rawDescGZIP(), []int{0} +} + +func (x *ProtoMessageBase) GetPayloadType() string { + if x != nil { + return x.PayloadType + } + return "" +} + +func (x *ProtoMessageBase) GetLatency() *ProtoLatencyTracker { + if x != nil { + return x.Latency + } + return nil +} + +type ProtoMessageInput struct { + state protoimpl.MessageState `protogen:"open.v1"` + MessageBase *ProtoMessageBase `protobuf:"bytes,1,opt,name=message_base,json=messageBase,proto3" json:"message_base,omitempty"` + Data *ProtoInput `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ProtoMessageInput) Reset() { + *x = ProtoMessageInput{} + mi := &file_messages_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ProtoMessageInput) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProtoMessageInput) ProtoMessage() {} + +func (x *ProtoMessageInput) ProtoReflect() protoreflect.Message { + mi := &file_messages_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ProtoMessageInput.ProtoReflect.Descriptor instead. +func (*ProtoMessageInput) Descriptor() ([]byte, []int) { + return file_messages_proto_rawDescGZIP(), []int{1} +} + +func (x *ProtoMessageInput) GetMessageBase() *ProtoMessageBase { + if x != nil { + return x.MessageBase + } + return nil +} + +func (x *ProtoMessageInput) GetData() *ProtoInput { + if x != nil { + return x.Data + } + return nil +} + +var File_messages_proto protoreflect.FileDescriptor + +var file_messages_proto_rawDesc = string([]byte{ + 0x0a, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x12, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0b, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x6c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x5f, 0x74, 0x72, + 0x61, 0x63, 0x6b, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x6b, 0x0a, 0x10, 0x50, + 0x72, 0x6f, 0x74, 0x6f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x61, 0x73, 0x65, 0x12, + 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x79, + 0x70, 0x65, 0x12, 0x34, 0x0a, 0x07, 0x6c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x72, 0x6f, 0x74, + 0x6f, 0x4c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x65, 0x72, 0x52, + 0x07, 0x6c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x22, 0x76, 0x0a, 0x11, 0x50, 0x72, 0x6f, 0x74, + 0x6f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x3a, 0x0a, + 0x0c, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x72, 0x6f, 0x74, + 0x6f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x61, 0x73, 0x65, 0x52, 0x0b, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x61, 0x73, 0x65, 0x12, 0x25, 0x0a, 0x04, 0x64, 0x61, 0x74, + 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, + 0x42, 0x16, 0x5a, 0x14, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +}) + +var ( + file_messages_proto_rawDescOnce sync.Once + file_messages_proto_rawDescData []byte +) + +func file_messages_proto_rawDescGZIP() []byte { + file_messages_proto_rawDescOnce.Do(func() { + file_messages_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_messages_proto_rawDesc), len(file_messages_proto_rawDesc))) + }) + return file_messages_proto_rawDescData +} + +var file_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_messages_proto_goTypes = []any{ + (*ProtoMessageBase)(nil), // 0: proto.ProtoMessageBase + (*ProtoMessageInput)(nil), // 1: proto.ProtoMessageInput + (*ProtoLatencyTracker)(nil), // 2: proto.ProtoLatencyTracker + (*ProtoInput)(nil), // 3: proto.ProtoInput +} +var file_messages_proto_depIdxs = []int32{ + 2, // 0: proto.ProtoMessageBase.latency:type_name -> proto.ProtoLatencyTracker + 0, // 1: proto.ProtoMessageInput.message_base:type_name -> proto.ProtoMessageBase + 3, // 2: proto.ProtoMessageInput.data:type_name -> proto.ProtoInput + 3, // [3:3] is the sub-list for method output_type + 3, // [3:3] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name +} + +func init() { file_messages_proto_init() } +func file_messages_proto_init() { + if File_messages_proto != nil { + return + } + file_types_proto_init() + file_latency_tracker_proto_init() + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_messages_proto_rawDesc), len(file_messages_proto_rawDesc)), + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_messages_proto_goTypes, + DependencyIndexes: file_messages_proto_depIdxs, + MessageInfos: file_messages_proto_msgTypes, + }.Build() + File_messages_proto = out.File + file_messages_proto_goTypes = nil + file_messages_proto_depIdxs = nil +} diff --git a/packages/relay/internal/proto/types.pb.go b/packages/relay/internal/proto/types.pb.go new file mode 100644 index 00000000..ab989112 --- /dev/null +++ b/packages/relay/internal/proto/types.pb.go @@ -0,0 +1,713 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.4 +// protoc (unknown) +// source: types.proto + +package proto + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// MouseMove message +type ProtoMouseMove struct { + state protoimpl.MessageState `protogen:"open.v1"` + Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` // Fixed value "MouseMove" + X int32 `protobuf:"varint,2,opt,name=x,proto3" json:"x,omitempty"` + Y int32 `protobuf:"varint,3,opt,name=y,proto3" json:"y,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ProtoMouseMove) Reset() { + *x = ProtoMouseMove{} + mi := &file_types_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ProtoMouseMove) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProtoMouseMove) ProtoMessage() {} + +func (x *ProtoMouseMove) ProtoReflect() protoreflect.Message { + mi := &file_types_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ProtoMouseMove.ProtoReflect.Descriptor instead. +func (*ProtoMouseMove) Descriptor() ([]byte, []int) { + return file_types_proto_rawDescGZIP(), []int{0} +} + +func (x *ProtoMouseMove) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *ProtoMouseMove) GetX() int32 { + if x != nil { + return x.X + } + return 0 +} + +func (x *ProtoMouseMove) GetY() int32 { + if x != nil { + return x.Y + } + return 0 +} + +// MouseMoveAbs message +type ProtoMouseMoveAbs struct { + state protoimpl.MessageState `protogen:"open.v1"` + Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` // Fixed value "MouseMoveAbs" + X int32 `protobuf:"varint,2,opt,name=x,proto3" json:"x,omitempty"` + Y int32 `protobuf:"varint,3,opt,name=y,proto3" json:"y,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ProtoMouseMoveAbs) Reset() { + *x = ProtoMouseMoveAbs{} + mi := &file_types_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ProtoMouseMoveAbs) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProtoMouseMoveAbs) ProtoMessage() {} + +func (x *ProtoMouseMoveAbs) ProtoReflect() protoreflect.Message { + mi := &file_types_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ProtoMouseMoveAbs.ProtoReflect.Descriptor instead. +func (*ProtoMouseMoveAbs) Descriptor() ([]byte, []int) { + return file_types_proto_rawDescGZIP(), []int{1} +} + +func (x *ProtoMouseMoveAbs) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *ProtoMouseMoveAbs) GetX() int32 { + if x != nil { + return x.X + } + return 0 +} + +func (x *ProtoMouseMoveAbs) GetY() int32 { + if x != nil { + return x.Y + } + return 0 +} + +// MouseWheel message +type ProtoMouseWheel struct { + state protoimpl.MessageState `protogen:"open.v1"` + Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` // Fixed value "MouseWheel" + X int32 `protobuf:"varint,2,opt,name=x,proto3" json:"x,omitempty"` + Y int32 `protobuf:"varint,3,opt,name=y,proto3" json:"y,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ProtoMouseWheel) Reset() { + *x = ProtoMouseWheel{} + mi := &file_types_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ProtoMouseWheel) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProtoMouseWheel) ProtoMessage() {} + +func (x *ProtoMouseWheel) ProtoReflect() protoreflect.Message { + mi := &file_types_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ProtoMouseWheel.ProtoReflect.Descriptor instead. +func (*ProtoMouseWheel) Descriptor() ([]byte, []int) { + return file_types_proto_rawDescGZIP(), []int{2} +} + +func (x *ProtoMouseWheel) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *ProtoMouseWheel) GetX() int32 { + if x != nil { + return x.X + } + return 0 +} + +func (x *ProtoMouseWheel) GetY() int32 { + if x != nil { + return x.Y + } + return 0 +} + +// MouseKeyDown message +type ProtoMouseKeyDown struct { + state protoimpl.MessageState `protogen:"open.v1"` + Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` // Fixed value "MouseKeyDown" + Key int32 `protobuf:"varint,2,opt,name=key,proto3" json:"key,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ProtoMouseKeyDown) Reset() { + *x = ProtoMouseKeyDown{} + mi := &file_types_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ProtoMouseKeyDown) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProtoMouseKeyDown) ProtoMessage() {} + +func (x *ProtoMouseKeyDown) ProtoReflect() protoreflect.Message { + mi := &file_types_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ProtoMouseKeyDown.ProtoReflect.Descriptor instead. +func (*ProtoMouseKeyDown) Descriptor() ([]byte, []int) { + return file_types_proto_rawDescGZIP(), []int{3} +} + +func (x *ProtoMouseKeyDown) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *ProtoMouseKeyDown) GetKey() int32 { + if x != nil { + return x.Key + } + return 0 +} + +// MouseKeyUp message +type ProtoMouseKeyUp struct { + state protoimpl.MessageState `protogen:"open.v1"` + Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` // Fixed value "MouseKeyUp" + Key int32 `protobuf:"varint,2,opt,name=key,proto3" json:"key,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ProtoMouseKeyUp) Reset() { + *x = ProtoMouseKeyUp{} + mi := &file_types_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ProtoMouseKeyUp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProtoMouseKeyUp) ProtoMessage() {} + +func (x *ProtoMouseKeyUp) ProtoReflect() protoreflect.Message { + mi := &file_types_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ProtoMouseKeyUp.ProtoReflect.Descriptor instead. +func (*ProtoMouseKeyUp) Descriptor() ([]byte, []int) { + return file_types_proto_rawDescGZIP(), []int{4} +} + +func (x *ProtoMouseKeyUp) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *ProtoMouseKeyUp) GetKey() int32 { + if x != nil { + return x.Key + } + return 0 +} + +// KeyDown message +type ProtoKeyDown struct { + state protoimpl.MessageState `protogen:"open.v1"` + Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` // Fixed value "KeyDown" + Key int32 `protobuf:"varint,2,opt,name=key,proto3" json:"key,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ProtoKeyDown) Reset() { + *x = ProtoKeyDown{} + mi := &file_types_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ProtoKeyDown) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProtoKeyDown) ProtoMessage() {} + +func (x *ProtoKeyDown) ProtoReflect() protoreflect.Message { + mi := &file_types_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ProtoKeyDown.ProtoReflect.Descriptor instead. +func (*ProtoKeyDown) Descriptor() ([]byte, []int) { + return file_types_proto_rawDescGZIP(), []int{5} +} + +func (x *ProtoKeyDown) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *ProtoKeyDown) GetKey() int32 { + if x != nil { + return x.Key + } + return 0 +} + +// KeyUp message +type ProtoKeyUp struct { + state protoimpl.MessageState `protogen:"open.v1"` + Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` // Fixed value "KeyUp" + Key int32 `protobuf:"varint,2,opt,name=key,proto3" json:"key,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ProtoKeyUp) Reset() { + *x = ProtoKeyUp{} + mi := &file_types_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ProtoKeyUp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProtoKeyUp) ProtoMessage() {} + +func (x *ProtoKeyUp) ProtoReflect() protoreflect.Message { + mi := &file_types_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ProtoKeyUp.ProtoReflect.Descriptor instead. +func (*ProtoKeyUp) Descriptor() ([]byte, []int) { + return file_types_proto_rawDescGZIP(), []int{6} +} + +func (x *ProtoKeyUp) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *ProtoKeyUp) GetKey() int32 { + if x != nil { + return x.Key + } + return 0 +} + +// Union of all Input types +type ProtoInput struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to InputType: + // + // *ProtoInput_MouseMove + // *ProtoInput_MouseMoveAbs + // *ProtoInput_MouseWheel + // *ProtoInput_MouseKeyDown + // *ProtoInput_MouseKeyUp + // *ProtoInput_KeyDown + // *ProtoInput_KeyUp + InputType isProtoInput_InputType `protobuf_oneof:"input_type"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ProtoInput) Reset() { + *x = ProtoInput{} + mi := &file_types_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ProtoInput) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProtoInput) ProtoMessage() {} + +func (x *ProtoInput) ProtoReflect() protoreflect.Message { + mi := &file_types_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ProtoInput.ProtoReflect.Descriptor instead. +func (*ProtoInput) Descriptor() ([]byte, []int) { + return file_types_proto_rawDescGZIP(), []int{7} +} + +func (x *ProtoInput) GetInputType() isProtoInput_InputType { + if x != nil { + return x.InputType + } + return nil +} + +func (x *ProtoInput) GetMouseMove() *ProtoMouseMove { + if x != nil { + if x, ok := x.InputType.(*ProtoInput_MouseMove); ok { + return x.MouseMove + } + } + return nil +} + +func (x *ProtoInput) GetMouseMoveAbs() *ProtoMouseMoveAbs { + if x != nil { + if x, ok := x.InputType.(*ProtoInput_MouseMoveAbs); ok { + return x.MouseMoveAbs + } + } + return nil +} + +func (x *ProtoInput) GetMouseWheel() *ProtoMouseWheel { + if x != nil { + if x, ok := x.InputType.(*ProtoInput_MouseWheel); ok { + return x.MouseWheel + } + } + return nil +} + +func (x *ProtoInput) GetMouseKeyDown() *ProtoMouseKeyDown { + if x != nil { + if x, ok := x.InputType.(*ProtoInput_MouseKeyDown); ok { + return x.MouseKeyDown + } + } + return nil +} + +func (x *ProtoInput) GetMouseKeyUp() *ProtoMouseKeyUp { + if x != nil { + if x, ok := x.InputType.(*ProtoInput_MouseKeyUp); ok { + return x.MouseKeyUp + } + } + return nil +} + +func (x *ProtoInput) GetKeyDown() *ProtoKeyDown { + if x != nil { + if x, ok := x.InputType.(*ProtoInput_KeyDown); ok { + return x.KeyDown + } + } + return nil +} + +func (x *ProtoInput) GetKeyUp() *ProtoKeyUp { + if x != nil { + if x, ok := x.InputType.(*ProtoInput_KeyUp); ok { + return x.KeyUp + } + } + return nil +} + +type isProtoInput_InputType interface { + isProtoInput_InputType() +} + +type ProtoInput_MouseMove struct { + MouseMove *ProtoMouseMove `protobuf:"bytes,1,opt,name=mouse_move,json=mouseMove,proto3,oneof"` +} + +type ProtoInput_MouseMoveAbs struct { + MouseMoveAbs *ProtoMouseMoveAbs `protobuf:"bytes,2,opt,name=mouse_move_abs,json=mouseMoveAbs,proto3,oneof"` +} + +type ProtoInput_MouseWheel struct { + MouseWheel *ProtoMouseWheel `protobuf:"bytes,3,opt,name=mouse_wheel,json=mouseWheel,proto3,oneof"` +} + +type ProtoInput_MouseKeyDown struct { + MouseKeyDown *ProtoMouseKeyDown `protobuf:"bytes,4,opt,name=mouse_key_down,json=mouseKeyDown,proto3,oneof"` +} + +type ProtoInput_MouseKeyUp struct { + MouseKeyUp *ProtoMouseKeyUp `protobuf:"bytes,5,opt,name=mouse_key_up,json=mouseKeyUp,proto3,oneof"` +} + +type ProtoInput_KeyDown struct { + KeyDown *ProtoKeyDown `protobuf:"bytes,6,opt,name=key_down,json=keyDown,proto3,oneof"` +} + +type ProtoInput_KeyUp struct { + KeyUp *ProtoKeyUp `protobuf:"bytes,7,opt,name=key_up,json=keyUp,proto3,oneof"` +} + +func (*ProtoInput_MouseMove) isProtoInput_InputType() {} + +func (*ProtoInput_MouseMoveAbs) isProtoInput_InputType() {} + +func (*ProtoInput_MouseWheel) isProtoInput_InputType() {} + +func (*ProtoInput_MouseKeyDown) isProtoInput_InputType() {} + +func (*ProtoInput_MouseKeyUp) isProtoInput_InputType() {} + +func (*ProtoInput_KeyDown) isProtoInput_InputType() {} + +func (*ProtoInput_KeyUp) isProtoInput_InputType() {} + +var File_types_proto protoreflect.FileDescriptor + +var file_types_proto_rawDesc = string([]byte{ + 0x0a, 0x0b, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x40, 0x0a, 0x0e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4d, 0x6f, 0x75, + 0x73, 0x65, 0x4d, 0x6f, 0x76, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x0c, 0x0a, 0x01, 0x78, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x01, 0x78, 0x12, 0x0c, 0x0a, 0x01, 0x79, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x01, 0x79, 0x22, 0x43, 0x0a, 0x11, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4d, + 0x6f, 0x75, 0x73, 0x65, 0x4d, 0x6f, 0x76, 0x65, 0x41, 0x62, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x74, + 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, + 0x0c, 0x0a, 0x01, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x01, 0x78, 0x12, 0x0c, 0x0a, + 0x01, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x01, 0x79, 0x22, 0x41, 0x0a, 0x0f, 0x50, + 0x72, 0x6f, 0x74, 0x6f, 0x4d, 0x6f, 0x75, 0x73, 0x65, 0x57, 0x68, 0x65, 0x65, 0x6c, 0x12, 0x12, + 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, + 0x70, 0x65, 0x12, 0x0c, 0x0a, 0x01, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x01, 0x78, + 0x12, 0x0c, 0x0a, 0x01, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x01, 0x79, 0x22, 0x39, + 0x0a, 0x11, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4d, 0x6f, 0x75, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x44, + 0x6f, 0x77, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x37, 0x0a, 0x0f, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x4d, 0x6f, 0x75, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x55, 0x70, 0x12, 0x12, 0x0a, 0x04, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, + 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x6b, + 0x65, 0x79, 0x22, 0x34, 0x0a, 0x0c, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4b, 0x65, 0x79, 0x44, 0x6f, + 0x77, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x32, 0x0a, 0x0a, 0x50, 0x72, 0x6f, 0x74, + 0x6f, 0x4b, 0x65, 0x79, 0x55, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, + 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0xab, 0x03, 0x0a, + 0x0a, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x36, 0x0a, 0x0a, 0x6d, + 0x6f, 0x75, 0x73, 0x65, 0x5f, 0x6d, 0x6f, 0x76, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4d, 0x6f, 0x75, + 0x73, 0x65, 0x4d, 0x6f, 0x76, 0x65, 0x48, 0x00, 0x52, 0x09, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x4d, + 0x6f, 0x76, 0x65, 0x12, 0x40, 0x0a, 0x0e, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x5f, 0x6d, 0x6f, 0x76, + 0x65, 0x5f, 0x61, 0x62, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4d, 0x6f, 0x75, 0x73, 0x65, 0x4d, 0x6f, + 0x76, 0x65, 0x41, 0x62, 0x73, 0x48, 0x00, 0x52, 0x0c, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x4d, 0x6f, + 0x76, 0x65, 0x41, 0x62, 0x73, 0x12, 0x39, 0x0a, 0x0b, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x5f, 0x77, + 0x68, 0x65, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4d, 0x6f, 0x75, 0x73, 0x65, 0x57, 0x68, 0x65, + 0x65, 0x6c, 0x48, 0x00, 0x52, 0x0a, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x57, 0x68, 0x65, 0x65, 0x6c, + 0x12, 0x40, 0x0a, 0x0e, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x64, 0x6f, + 0x77, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4d, 0x6f, 0x75, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x44, 0x6f, + 0x77, 0x6e, 0x48, 0x00, 0x52, 0x0c, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x44, 0x6f, + 0x77, 0x6e, 0x12, 0x3a, 0x0a, 0x0c, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x5f, + 0x75, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4d, 0x6f, 0x75, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x55, 0x70, + 0x48, 0x00, 0x52, 0x0a, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x55, 0x70, 0x12, 0x30, + 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4b, 0x65, + 0x79, 0x44, 0x6f, 0x77, 0x6e, 0x48, 0x00, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x44, 0x6f, 0x77, 0x6e, + 0x12, 0x2a, 0x0a, 0x06, 0x6b, 0x65, 0x79, 0x5f, 0x75, 0x70, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x4b, 0x65, + 0x79, 0x55, 0x70, 0x48, 0x00, 0x52, 0x05, 0x6b, 0x65, 0x79, 0x55, 0x70, 0x42, 0x0c, 0x0a, 0x0a, + 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x42, 0x16, 0x5a, 0x14, 0x72, 0x65, + 0x6c, 0x61, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +}) + +var ( + file_types_proto_rawDescOnce sync.Once + file_types_proto_rawDescData []byte +) + +func file_types_proto_rawDescGZIP() []byte { + file_types_proto_rawDescOnce.Do(func() { + file_types_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_types_proto_rawDesc), len(file_types_proto_rawDesc))) + }) + return file_types_proto_rawDescData +} + +var file_types_proto_msgTypes = make([]protoimpl.MessageInfo, 8) +var file_types_proto_goTypes = []any{ + (*ProtoMouseMove)(nil), // 0: proto.ProtoMouseMove + (*ProtoMouseMoveAbs)(nil), // 1: proto.ProtoMouseMoveAbs + (*ProtoMouseWheel)(nil), // 2: proto.ProtoMouseWheel + (*ProtoMouseKeyDown)(nil), // 3: proto.ProtoMouseKeyDown + (*ProtoMouseKeyUp)(nil), // 4: proto.ProtoMouseKeyUp + (*ProtoKeyDown)(nil), // 5: proto.ProtoKeyDown + (*ProtoKeyUp)(nil), // 6: proto.ProtoKeyUp + (*ProtoInput)(nil), // 7: proto.ProtoInput +} +var file_types_proto_depIdxs = []int32{ + 0, // 0: proto.ProtoInput.mouse_move:type_name -> proto.ProtoMouseMove + 1, // 1: proto.ProtoInput.mouse_move_abs:type_name -> proto.ProtoMouseMoveAbs + 2, // 2: proto.ProtoInput.mouse_wheel:type_name -> proto.ProtoMouseWheel + 3, // 3: proto.ProtoInput.mouse_key_down:type_name -> proto.ProtoMouseKeyDown + 4, // 4: proto.ProtoInput.mouse_key_up:type_name -> proto.ProtoMouseKeyUp + 5, // 5: proto.ProtoInput.key_down:type_name -> proto.ProtoKeyDown + 6, // 6: proto.ProtoInput.key_up:type_name -> proto.ProtoKeyUp + 7, // [7:7] is the sub-list for method output_type + 7, // [7:7] is the sub-list for method input_type + 7, // [7:7] is the sub-list for extension type_name + 7, // [7:7] is the sub-list for extension extendee + 0, // [0:7] is the sub-list for field type_name +} + +func init() { file_types_proto_init() } +func file_types_proto_init() { + if File_types_proto != nil { + return + } + file_types_proto_msgTypes[7].OneofWrappers = []any{ + (*ProtoInput_MouseMove)(nil), + (*ProtoInput_MouseMoveAbs)(nil), + (*ProtoInput_MouseWheel)(nil), + (*ProtoInput_MouseKeyDown)(nil), + (*ProtoInput_MouseKeyUp)(nil), + (*ProtoInput_KeyDown)(nil), + (*ProtoInput_KeyUp)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_types_proto_rawDesc), len(file_types_proto_rawDesc)), + NumEnums: 0, + NumMessages: 8, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_types_proto_goTypes, + DependencyIndexes: file_types_proto_depIdxs, + MessageInfos: file_types_proto_msgTypes, + }.Build() + File_types_proto = out.File + file_types_proto_goTypes = nil + file_types_proto_depIdxs = nil +} diff --git a/packages/relay/internal/websocket.go b/packages/relay/internal/websocket.go index 9b8f3bd9..2c85fdbc 100644 --- a/packages/relay/internal/websocket.go +++ b/packages/relay/internal/websocket.go @@ -1,6 +1,7 @@ package relay import ( + "encoding/json" "github.com/gorilla/websocket" "log" "sync" @@ -10,22 +11,22 @@ import ( type SafeWebSocket struct { *websocket.Conn sync.Mutex - closeCallback func() // OnClose callback - binaryCallbacks map[string]OnMessageCallback // MessageBase type -> callback + closeCallback func() // OnClose callback + callbacks map[string]OnMessageCallback // MessageBase type -> callback } // NewSafeWebSocket creates a new SafeWebSocket from *websocket.Conn func NewSafeWebSocket(conn *websocket.Conn) *SafeWebSocket { ws := &SafeWebSocket{ - Conn: conn, - closeCallback: nil, - binaryCallbacks: make(map[string]OnMessageCallback), + Conn: conn, + closeCallback: nil, + callbacks: make(map[string]OnMessageCallback), } - // Launch a goroutine to handle binary messages + // Launch a goroutine to handle messages go func() { for { - // Read binary message + // Read message kind, data, err := ws.Conn.ReadMessage() if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure, websocket.CloseNoStatusReceived) { // If unexpected close error, break @@ -42,22 +43,23 @@ func NewSafeWebSocket(conn *websocket.Conn) *SafeWebSocket { switch kind { case websocket.TextMessage: - // Ignore, we use binary messages - continue - case websocket.BinaryMessage: // Decode message var msg MessageBase - if err = DecodeMessage(data, &msg); err != nil { - log.Printf("Failed to decode binary WebSocket message, reason: %s\n", err) + if err = json.Unmarshal(data, &msg); err != nil { + log.Printf("Failed to decode text WebSocket message, reason: %s\n", err) continue } // Handle message type callback - if callback, ok := ws.binaryCallbacks[msg.PayloadType]; ok { + if callback, ok := ws.callbacks[msg.PayloadType]; ok { callback(data) } // TODO: Log unknown message type? + break + case websocket.BinaryMessage: + break default: log.Printf("Unknown WebSocket message type: %d\n", kind) + break } } @@ -88,18 +90,18 @@ func (ws *SafeWebSocket) SendBinary(data []byte) error { func (ws *SafeWebSocket) RegisterMessageCallback(msgType string, callback OnMessageCallback) { ws.Lock() defer ws.Unlock() - if ws.binaryCallbacks == nil { - ws.binaryCallbacks = make(map[string]OnMessageCallback) + if ws.callbacks == nil { + ws.callbacks = make(map[string]OnMessageCallback) } - ws.binaryCallbacks[msgType] = callback + ws.callbacks[msgType] = callback } // UnregisterMessageCallback removes the callback for binary message of given type func (ws *SafeWebSocket) UnregisterMessageCallback(msgType string) { ws.Lock() defer ws.Unlock() - if ws.binaryCallbacks != nil { - delete(ws.binaryCallbacks, msgType) + if ws.callbacks != nil { + delete(ws.callbacks, msgType) } } @@ -108,7 +110,7 @@ func (ws *SafeWebSocket) RegisterOnClose(callback func()) { ws.closeCallback = func() { // Clear our callbacks ws.Lock() - ws.binaryCallbacks = nil + ws.callbacks = nil ws.Unlock() // Call the callback callback() diff --git a/packages/server/Cargo.toml b/packages/server/Cargo.toml index fc65ba2e..d2eec91a 100644 --- a/packages/server/Cargo.toml +++ b/packages/server/Cargo.toml @@ -15,15 +15,15 @@ serde = {version = "1.0.214", features = ["derive"] } tokio = { version = "1.41.0", features = ["full"] } clap = { version = "4.5.20", features = ["env"] } serde_json = "1.0.132" -webrtc = "0.11.0" +webrtc = "0.12.0" regex = "1.11.1" -rand = "0.8.5" +rand = "0.9.0" rustls = { version = "0.23.17", features = ["ring"] } -tokio-util = "0.7.12" -flate2 = "1.0.35" -tokio-tungstenite = { version = "0.24.0", features = ["native-tls"] } +tokio-tungstenite = { version = "0.26.1", features = ["native-tls"] } log = { version = "0.4.22", features = ["std"] } chrono = "0.4.38" futures-util = "0.3.31" num-derive = "0.4.2" num-traits = "0.2.19" +prost = "0.13.4" +prost-types = "0.13.4" diff --git a/packages/server/src/args/app_args.rs b/packages/server/src/args/app_args.rs index ef937f90..3d94c7e8 100644 --- a/packages/server/src/args/app_args.rs +++ b/packages/server/src/args/app_args.rs @@ -48,7 +48,10 @@ impl AppArgs { .unwrap() .parse::() .unwrap_or(60), - relay_url: matches.get_one::("relay-url").unwrap().clone(), + relay_url: matches + .get_one::("relay-url") + .expect("relay url cannot be empty") + .clone(), // Generate random room name if not provided room: matches .get_one::("room") diff --git a/packages/server/src/latency.rs b/packages/server/src/latency.rs index 659c35d0..8e3f3340 100644 --- a/packages/server/src/latency.rs +++ b/packages/server/src/latency.rs @@ -1,5 +1,5 @@ -use std::collections::HashMap; use serde::{Deserialize, Serialize}; +use std::collections::HashMap; #[derive(Serialize, Deserialize, Debug)] pub struct TimestampEntry { diff --git a/packages/server/src/main.rs b/packages/server/src/main.rs index 99c32860..cf32ecaa 100644 --- a/packages/server/src/main.rs +++ b/packages/server/src/main.rs @@ -5,6 +5,7 @@ mod latency; mod messages; mod nestrisink; mod websocket; +mod proto; use crate::args::encoding_args; use crate::nestrisink::NestriSignaller; diff --git a/packages/server/src/messages.rs b/packages/server/src/messages.rs index 4cd8d346..e1550f8d 100644 --- a/packages/server/src/messages.rs +++ b/packages/server/src/messages.rs @@ -1,50 +1,14 @@ -use std::error::Error; -use std::io::{Read, Write}; -use flate2::Compression; -use flate2::read::GzDecoder; -use flate2::write::GzEncoder; +use crate::latency::LatencyTracker; use num_derive::{FromPrimitive, ToPrimitive}; use num_traits::{FromPrimitive, ToPrimitive}; use serde::{Deserialize, Serialize}; +use std::error::Error; use webrtc::ice_transport::ice_candidate::RTCIceCandidateInit; use webrtc::peer_connection::sdp::session_description::RTCSessionDescription; -use crate::latency::LatencyTracker; - -#[derive(Serialize, Deserialize, Debug)] -#[serde(tag = "type")] -pub enum InputMessage { - #[serde(rename = "mousemove")] - MouseMove { x: i32, y: i32 }, - - #[serde(rename = "mousemoveabs")] - MouseMoveAbs { x: i32, y: i32 }, - - #[serde(rename = "wheel")] - Wheel { x: f64, y: f64 }, - - #[serde(rename = "mousedown")] - MouseDown { key: i32 }, - // Add other variants as needed - #[serde(rename = "mouseup")] - MouseUp { key: i32 }, - - #[serde(rename = "keydown")] - KeyDown { key: i32 }, - - #[serde(rename = "keyup")] - KeyUp { key: i32 }, -} #[derive(Serialize, Deserialize, Debug)] pub struct MessageBase { pub payload_type: String, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct MessageInput { - #[serde(flatten)] - pub base: MessageBase, - pub data: String, pub latency: Option, } @@ -136,34 +100,21 @@ pub struct MessageAnswer { pub answer_type: AnswerType, } -pub fn encode_message(message: &T) -> Result, Box> { +pub fn encode_message(message: &T) -> Result> { // Serialize the message to JSON let json = serde_json::to_string(message)?; - - // Compress the JSON using gzip - let mut encoder = GzEncoder::new(Vec::new(), Compression::default()); - encoder.write_all(json.as_bytes())?; - let compressed_data = encoder.finish()?; - - Ok(compressed_data) + Ok(json) } -pub fn decode_message(data: &[u8]) -> Result> { - let mut decoder = GzDecoder::new(data); - let mut decompressed_data = String::new(); - decoder.read_to_string(&mut decompressed_data)?; - - let base_message: MessageBase = serde_json::from_str(&decompressed_data)?; +pub fn decode_message(data: String) -> Result> { + println!("Data: {}", data); + let base_message: MessageBase = serde_json::from_str(&data)?; Ok(base_message) } pub fn decode_message_as Deserialize<'de>>( - data: Vec, + data: String, ) -> Result> { - let mut decoder = GzDecoder::new(data.as_slice()); - let mut decompressed_data = String::new(); - decoder.read_to_string(&mut decompressed_data)?; - - let message: T = serde_json::from_str(&decompressed_data)?; + let message: T = serde_json::from_str(&data)?; Ok(message) -} \ No newline at end of file +} diff --git a/packages/server/src/nestrisink/imp.rs b/packages/server/src/nestrisink/imp.rs index 4df2e499..71a195e9 100644 --- a/packages/server/src/nestrisink/imp.rs +++ b/packages/server/src/nestrisink/imp.rs @@ -1,13 +1,18 @@ use crate::messages::{ - decode_message_as, encode_message, AnswerType, InputMessage, JoinerType, MessageAnswer, - MessageBase, MessageICE, MessageInput, MessageJoin, MessageSDP, + decode_message_as, encode_message, AnswerType, JoinerType, MessageAnswer, MessageBase, + MessageICE, MessageJoin, MessageSDP, }; +use crate::proto::proto::proto_input::InputType::{ + KeyDown, KeyUp, MouseKeyDown, MouseKeyUp, MouseMove, MouseMoveAbs, MouseWheel, +}; +use crate::proto::proto::{ProtoInput, ProtoMessageInput}; use crate::websocket::NestriWebSocket; use glib::subclass::prelude::*; use gst::glib; use gst::prelude::*; use gst_webrtc::{gst_sdp, WebRTCSDPType, WebRTCSessionDescription}; use gstrswebrtc::signaller::{Signallable, SignallableImpl}; +use prost::Message; use std::collections::HashSet; use std::sync::{Arc, LazyLock}; use std::sync::{Mutex, RwLock}; @@ -200,6 +205,7 @@ impl SignallableImpl for Signaller { let join_msg = MessageJoin { base: MessageBase { payload_type: "join".to_string(), + latency: None, }, joiner_type: JoinerType::JoinerNode, }; @@ -237,6 +243,7 @@ impl SignallableImpl for Signaller { let join_msg = MessageJoin { base: MessageBase { payload_type: "join".to_string(), + latency: None, }, joiner_type: JoinerType::JoinerNode, }; @@ -265,6 +272,7 @@ impl SignallableImpl for Signaller { let sdp_message = MessageSDP { base: MessageBase { payload_type: "sdp".to_string(), + latency: None, }, sdp: RTCSessionDescription::offer(sdp.sdp().as_text().unwrap()).unwrap(), }; @@ -301,6 +309,7 @@ impl SignallableImpl for Signaller { let ice_message = MessageICE { base: MessageBase { payload_type: "ice".to_string(), + latency: None, }, candidate: candidate_init, }; @@ -354,11 +363,9 @@ fn setup_data_channel(data_channel: &gst_webrtc::WebRTCDataChannel, pipeline: &g data_channel.connect_on_message_data(move |_data_channel, data| { if let Some(data) = data { - match decode_message_as::(data.to_vec()) { + match ProtoMessageInput::decode(data.to_vec().as_slice()) { Ok(message_input) => { - // Deserialize the input message data - if let Ok(input_msg) = serde_json::from_str::(&message_input.data) - { + if let Some(input_msg) = message_input.data { // Process the input message and create an event if let Some(event) = handle_input_message(input_msg, &pressed_keys, &pressed_buttons) @@ -379,88 +386,92 @@ fn setup_data_channel(data_channel: &gst_webrtc::WebRTCDataChannel, pipeline: &g } fn handle_input_message( - input_msg: InputMessage, + input_msg: ProtoInput, pressed_keys: &Arc>>, pressed_buttons: &Arc>>, ) -> Option { - match input_msg { - InputMessage::MouseMove { x, y } => { - let structure = gst::Structure::builder("MouseMoveRelative") - .field("pointer_x", x as f64) - .field("pointer_y", y as f64) - .build(); + if let Some(input_type) = input_msg.input_type { + match input_type { + MouseMove(data) => { + let structure = gst::Structure::builder("MouseMoveRelative") + .field("pointer_x", data.x as f64) + .field("pointer_y", data.y as f64) + .build(); - Some(gst::event::CustomUpstream::new(structure)) - } - InputMessage::MouseMoveAbs { x, y } => { - let structure = gst::Structure::builder("MouseMoveAbsolute") - .field("pointer_x", x as f64) - .field("pointer_y", y as f64) - .build(); - - Some(gst::event::CustomUpstream::new(structure)) - } - InputMessage::KeyDown { key } => { - let mut keys = pressed_keys.lock().unwrap(); - // If the key is already pressed, return to prevent key lockup - if keys.contains(&key) { - return None; + Some(gst::event::CustomUpstream::new(structure)) } - keys.insert(key); + MouseMoveAbs(data) => { + let structure = gst::Structure::builder("MouseMoveAbsolute") + .field("pointer_x", data.x as f64) + .field("pointer_y", data.y as f64) + .build(); - let structure = gst::Structure::builder("KeyboardKey") - .field("key", key as u32) - .field("pressed", true) - .build(); - - Some(gst::event::CustomUpstream::new(structure)) - } - InputMessage::KeyUp { key } => { - let mut keys = pressed_keys.lock().unwrap(); - // Remove the key from the pressed state when released - keys.remove(&key); - - let structure = gst::Structure::builder("KeyboardKey") - .field("key", key as u32) - .field("pressed", false) - .build(); - - Some(gst::event::CustomUpstream::new(structure)) - } - InputMessage::Wheel { x, y } => { - let structure = gst::Structure::builder("MouseAxis") - .field("x", x as f64) - .field("y", y as f64) - .build(); - - Some(gst::event::CustomUpstream::new(structure)) - } - InputMessage::MouseDown { key } => { - let mut buttons = pressed_buttons.lock().unwrap(); - // If the button is already pressed, return to prevent button lockup - if buttons.contains(&key) { - return None; + Some(gst::event::CustomUpstream::new(structure)) } - buttons.insert(key); + KeyDown(data) => { + let mut keys = pressed_keys.lock().unwrap(); + // If the key is already pressed, return to prevent key lockup + if keys.contains(&data.key) { + return None; + } + keys.insert(data.key); - let structure = gst::Structure::builder("MouseButton") - .field("button", key as u32) - .field("pressed", true) - .build(); + let structure = gst::Structure::builder("KeyboardKey") + .field("key", data.key as u32) + .field("pressed", true) + .build(); - Some(gst::event::CustomUpstream::new(structure)) - } - InputMessage::MouseUp { key } => { - let mut buttons = pressed_buttons.lock().unwrap(); - // Remove the button from the pressed state when released - buttons.remove(&key); - - let structure = gst::Structure::builder("MouseButton") - .field("button", key as u32) - .field("pressed", false) - .build(); - - Some(gst::event::CustomUpstream::new(structure)) + Some(gst::event::CustomUpstream::new(structure)) + } + KeyUp(data) => { + let mut keys = pressed_keys.lock().unwrap(); + // Remove the key from the pressed state when released + keys.remove(&data.key); + + let structure = gst::Structure::builder("KeyboardKey") + .field("key", data.key as u32) + .field("pressed", false) + .build(); + + Some(gst::event::CustomUpstream::new(structure)) + } + MouseWheel(data) => { + let structure = gst::Structure::builder("MouseAxis") + .field("x", data.x as f64) + .field("y", data.y as f64) + .build(); + + Some(gst::event::CustomUpstream::new(structure)) + } + MouseKeyDown(data) => { + let mut buttons = pressed_buttons.lock().unwrap(); + // If the button is already pressed, return to prevent button lockup + if buttons.contains(&data.key) { + return None; + } + buttons.insert(data.key); + + let structure = gst::Structure::builder("MouseButton") + .field("button", data.key as u32) + .field("pressed", true) + .build(); + + Some(gst::event::CustomUpstream::new(structure)) + } + MouseKeyUp(data) => { + let mut buttons = pressed_buttons.lock().unwrap(); + // Remove the button from the pressed state when released + buttons.remove(&data.key); + + let structure = gst::Structure::builder("MouseButton") + .field("button", data.key as u32) + .field("pressed", false) + .build(); + + Some(gst::event::CustomUpstream::new(structure)) + } } + } else { + None } } diff --git a/packages/server/src/proto.rs b/packages/server/src/proto.rs new file mode 100644 index 00000000..3e1772e2 --- /dev/null +++ b/packages/server/src/proto.rs @@ -0,0 +1 @@ +pub mod proto; \ No newline at end of file diff --git a/packages/server/src/proto/proto.rs b/packages/server/src/proto/proto.rs new file mode 100644 index 00000000..3c1e3d56 --- /dev/null +++ b/packages/server/src/proto/proto.rs @@ -0,0 +1,139 @@ +// @generated +// This file is @generated by prost-build. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ProtoTimestampEntry { + #[prost(string, tag="1")] + pub stage: ::prost::alloc::string::String, + #[prost(message, optional, tag="2")] + pub time: ::core::option::Option<::prost_types::Timestamp>, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ProtoLatencyTracker { + #[prost(string, tag="1")] + pub sequence_id: ::prost::alloc::string::String, + #[prost(message, repeated, tag="2")] + pub timestamps: ::prost::alloc::vec::Vec, +} +/// MouseMove message +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ProtoMouseMove { + /// Fixed value "MouseMove" + #[prost(string, tag="1")] + pub r#type: ::prost::alloc::string::String, + #[prost(int32, tag="2")] + pub x: i32, + #[prost(int32, tag="3")] + pub y: i32, +} +/// MouseMoveAbs message +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ProtoMouseMoveAbs { + /// Fixed value "MouseMoveAbs" + #[prost(string, tag="1")] + pub r#type: ::prost::alloc::string::String, + #[prost(int32, tag="2")] + pub x: i32, + #[prost(int32, tag="3")] + pub y: i32, +} +/// MouseWheel message +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ProtoMouseWheel { + /// Fixed value "MouseWheel" + #[prost(string, tag="1")] + pub r#type: ::prost::alloc::string::String, + #[prost(int32, tag="2")] + pub x: i32, + #[prost(int32, tag="3")] + pub y: i32, +} +/// MouseKeyDown message +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ProtoMouseKeyDown { + /// Fixed value "MouseKeyDown" + #[prost(string, tag="1")] + pub r#type: ::prost::alloc::string::String, + #[prost(int32, tag="2")] + pub key: i32, +} +/// MouseKeyUp message +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ProtoMouseKeyUp { + /// Fixed value "MouseKeyUp" + #[prost(string, tag="1")] + pub r#type: ::prost::alloc::string::String, + #[prost(int32, tag="2")] + pub key: i32, +} +/// KeyDown message +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ProtoKeyDown { + /// Fixed value "KeyDown" + #[prost(string, tag="1")] + pub r#type: ::prost::alloc::string::String, + #[prost(int32, tag="2")] + pub key: i32, +} +/// KeyUp message +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ProtoKeyUp { + /// Fixed value "KeyUp" + #[prost(string, tag="1")] + pub r#type: ::prost::alloc::string::String, + #[prost(int32, tag="2")] + pub key: i32, +} +/// Union of all Input types +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ProtoInput { + #[prost(oneof="proto_input::InputType", tags="1, 2, 3, 4, 5, 6, 7")] + pub input_type: ::core::option::Option, +} +/// Nested message and enum types in `ProtoInput`. +pub mod proto_input { + #[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum InputType { + #[prost(message, tag="1")] + MouseMove(super::ProtoMouseMove), + #[prost(message, tag="2")] + MouseMoveAbs(super::ProtoMouseMoveAbs), + #[prost(message, tag="3")] + MouseWheel(super::ProtoMouseWheel), + #[prost(message, tag="4")] + MouseKeyDown(super::ProtoMouseKeyDown), + #[prost(message, tag="5")] + MouseKeyUp(super::ProtoMouseKeyUp), + #[prost(message, tag="6")] + KeyDown(super::ProtoKeyDown), + #[prost(message, tag="7")] + KeyUp(super::ProtoKeyUp), + } +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ProtoMessageBase { + #[prost(string, tag="1")] + pub payload_type: ::prost::alloc::string::String, + #[prost(message, optional, tag="2")] + pub latency: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ProtoMessageInput { + #[prost(message, optional, tag="1")] + pub message_base: ::core::option::Option, + #[prost(message, optional, tag="2")] + pub data: ::core::option::Option, +} +// @@protoc_insertion_point(module) diff --git a/packages/server/src/websocket.rs b/packages/server/src/websocket.rs index b850aaab..e98d47a4 100644 --- a/packages/server/src/websocket.rs +++ b/packages/server/src/websocket.rs @@ -10,10 +10,10 @@ use std::time::Duration; use tokio::net::TcpStream; use tokio::sync::{mpsc, Mutex, Notify}; use tokio::time::sleep; -use tokio_tungstenite::tungstenite::Message; +use tokio_tungstenite::tungstenite::{Message, Utf8Bytes}; use tokio_tungstenite::{connect_async, MaybeTlsStream, WebSocketStream}; -type Callback = Box) + Send + Sync>; +type Callback = Box; type WSRead = SplitStream>>; type WSWrite = SplitSink>, Message>; @@ -23,7 +23,7 @@ pub struct NestriWebSocket { reader: Arc>>, writer: Arc>>, callbacks: Arc>>, - message_tx: mpsc::UnboundedSender>, + message_tx: mpsc::UnboundedSender, reconnected_notify: Arc, } impl NestriWebSocket { @@ -95,8 +95,8 @@ impl NestriWebSocket { while let Some(message_result) = ws_read.next().await { match message_result { Ok(message) => { - let data = message.into_data(); - let base_message = match decode_message(&data) { + let data = message.into_text().expect("failed to turn message into text"); + let base_message = match decode_message(data.to_string()) { Ok(base_message) => base_message, Err(e) => { eprintln!("Failed to decode message: {:?}", e); @@ -107,11 +107,14 @@ impl NestriWebSocket { let callbacks_lock = callbacks.read().unwrap(); if let Some(callback) = callbacks_lock.get(&base_message.payload_type) { let data = data.clone(); - callback(data); + callback(data.to_string()); } } Err(e) => { - eprintln!("Error receiving message: {:?}, reconnecting in 3 seconds...", e); + eprintln!( + "Error receiving message: {:?}, reconnecting in 3 seconds...", + e + ); sleep(Duration::from_secs(3)).await; self_clone.reconnect().await.unwrap(); break; // Break the inner loop to get a new ws_read @@ -123,7 +126,7 @@ impl NestriWebSocket { }); } - fn spawn_write_loop(&self, mut message_rx: mpsc::UnboundedReceiver>) { + fn spawn_write_loop(&self, mut message_rx: mpsc::UnboundedReceiver) { let writer = self.writer.clone(); let self_clone = self.clone(); @@ -136,7 +139,10 @@ impl NestriWebSocket { let mut writer_lock = writer.lock().await; if let Some(writer) = writer_lock.as_mut() { // Try to send the message over the WebSocket - match writer.send(Message::Binary(message.clone())).await { + match writer + .send(Message::Text(Utf8Bytes::from(message.clone()))) + .await + { Ok(_) => { // Message sent successfully break; @@ -196,7 +202,7 @@ impl NestriWebSocket { } /// Send a message through the WebSocket - pub fn send_message(&self, message: Vec) -> Result<(), Box> { + pub fn send_message(&self, message: String) -> Result<(), Box> { self.message_tx .send(message) .map_err(|e| format!("Failed to send message: {:?}", e).into()) @@ -205,7 +211,7 @@ impl NestriWebSocket { /// Register a callback for a specific response type pub fn register_callback(&self, response_type: &str, callback: F) where - F: Fn(Vec) + Send + Sync + 'static, + F: Fn(String) + Send + Sync + 'static, { let mut callbacks_lock = self.callbacks.write().unwrap(); callbacks_lock.insert(response_type.to_string(), Box::new(callback)); @@ -234,6 +240,7 @@ impl Log for NestriWebSocket { let log_message = MessageLog { base: MessageBase { payload_type: "log".to_string(), + latency: None, }, level, message, diff --git a/protobufs/buf.yaml b/protobufs/buf.yaml new file mode 100644 index 00000000..534fcc92 --- /dev/null +++ b/protobufs/buf.yaml @@ -0,0 +1,7 @@ +version: v2 +breaking: + use: + - FILE +lint: + use: + - STANDARD diff --git a/protobufs/latency_tracker.proto b/protobufs/latency_tracker.proto new file mode 100644 index 00000000..6e56b573 --- /dev/null +++ b/protobufs/latency_tracker.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; + +import "google/protobuf/timestamp.proto"; + +option go_package = "relay/internal/proto"; + +package proto; + +message ProtoTimestampEntry { + string stage = 1; + google.protobuf.Timestamp time = 2; +}; + +message ProtoLatencyTracker { + string sequence_id = 1; + repeated ProtoTimestampEntry timestamps = 2; +} \ No newline at end of file diff --git a/protobufs/messages.proto b/protobufs/messages.proto new file mode 100644 index 00000000..7617ccc0 --- /dev/null +++ b/protobufs/messages.proto @@ -0,0 +1,18 @@ +syntax = "proto3"; + +option go_package = "relay/internal/proto"; + +import "types.proto"; +import "latency_tracker.proto"; + +package proto; + +message ProtoMessageBase { + string payload_type = 1; + ProtoLatencyTracker latency = 2; +} + +message ProtoMessageInput { + ProtoMessageBase message_base = 1; + ProtoInput data = 2; +} diff --git a/protobufs/types.proto b/protobufs/types.proto new file mode 100644 index 00000000..c5a73a37 --- /dev/null +++ b/protobufs/types.proto @@ -0,0 +1,63 @@ +syntax = "proto3"; + +option go_package = "relay/internal/proto"; + +package proto; + +// MouseMove message +message ProtoMouseMove { + string type = 1; // Fixed value "MouseMove" + int32 x = 2; + int32 y = 3; +} + +// MouseMoveAbs message +message ProtoMouseMoveAbs { + string type = 1; // Fixed value "MouseMoveAbs" + int32 x = 2; + int32 y = 3; +} + +// MouseWheel message +message ProtoMouseWheel { + string type = 1; // Fixed value "MouseWheel" + int32 x = 2; + int32 y = 3; +} + +// MouseKeyDown message +message ProtoMouseKeyDown { + string type = 1; // Fixed value "MouseKeyDown" + int32 key = 2; +} + +// MouseKeyUp message +message ProtoMouseKeyUp { + string type = 1; // Fixed value "MouseKeyUp" + int32 key = 2; +} + +// KeyDown message +message ProtoKeyDown { + string type = 1; // Fixed value "KeyDown" + int32 key = 2; +} + +// KeyUp message +message ProtoKeyUp { + string type = 1; // Fixed value "KeyUp" + int32 key = 2; +} + +// Union of all Input types +message ProtoInput { + oneof input_type { + ProtoMouseMove mouse_move = 1; + ProtoMouseMoveAbs mouse_move_abs = 2; + ProtoMouseWheel mouse_wheel = 3; + ProtoMouseKeyDown mouse_key_down = 4; + ProtoMouseKeyUp mouse_key_up = 5; + ProtoKeyDown key_down = 6; + ProtoKeyUp key_up = 7; + } +} \ No newline at end of file