From 6a525fa38410931d7cae46a650c169befa58be39 Mon Sep 17 00:00:00 2001 From: "NGnius (Graham)" Date: Sun, 23 Apr 2023 23:03:10 -0400 Subject: [PATCH] Add barebones nRPC over websocket adapters and functionality --- Cargo.lock | 537 ++++++++++++++---------------- usdpl-back/Cargo.toml | 12 +- usdpl-back/src/callable.rs | 87 ----- usdpl-back/src/instance.rs | 262 --------------- usdpl-back/src/lib.rs | 11 +- usdpl-back/src/rpc/mod.rs | 2 + usdpl-back/src/rpc/registry.rs | 42 +++ usdpl-back/src/websockets.rs | 108 ++++++ usdpl-build/Cargo.toml | 2 +- usdpl-front/Cargo.toml | 2 +- usdpl-front/src/client_handler.rs | 4 +- 11 files changed, 417 insertions(+), 652 deletions(-) delete mode 100644 usdpl-back/src/callable.rs delete mode 100644 usdpl-back/src/instance.rs create mode 100644 usdpl-back/src/rpc/registry.rs create mode 100644 usdpl-back/src/websockets.rs diff --git a/Cargo.lock b/Cargo.lock index 8af7fe1..00f5318 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "aead" version = "0.4.3" @@ -55,6 +61,15 @@ dependencies = [ "futures-core", ] +[[package]] +name = "async-lock" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa24f727524730b077666307f2734b4a1a1c57acb79193127dcc8914d5242dd7" +dependencies = [ + "event-listener", +] + [[package]] name = "async-recursion" version = "1.0.4" @@ -89,12 +104,6 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" -[[package]] -name = "base64" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" - [[package]] name = "beef" version = "0.5.2" @@ -109,9 +118,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "block-buffer" -version = "0.10.4" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ "generic-array", ] @@ -174,6 +183,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + [[package]] name = "cpufeatures" version = "0.2.6" @@ -183,6 +198,15 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + [[package]] name = "crossbeam-utils" version = "0.8.15" @@ -192,16 +216,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - [[package]] name = "ctr" version = "0.8.0" @@ -212,13 +226,25 @@ dependencies = [ ] [[package]] -name = "digest" -version = "0.10.6" +name = "derive_more" +version = "0.99.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ - "block-buffer", - "crypto-common", + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", ] [[package]] @@ -333,6 +359,17 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" +[[package]] +name = "flate2" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" +dependencies = [ + "crc32fast", + "libz-sys", + "miniz_oxide", +] + [[package]] name = "fnv" version = "1.0.7" @@ -501,56 +538,12 @@ dependencies = [ "web-sys", ] -[[package]] -name = "h2" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66b91535aa35fea1523ad1b86cb6b53c28e0ae566ba4a460f4457e936cad7c6f" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - [[package]] name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -[[package]] -name = "headers" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3e372db8e5c0d213e0cd0b9be18be2aca3d44cf2fe30a9d46a65581cd454584" -dependencies = [ - "base64 0.13.1", - "bitflags", - "bytes", - "headers-core", - "http", - "httpdate", - "mime", - "sha1", -] - -[[package]] -name = "headers-core" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" -dependencies = [ - "http", -] - [[package]] name = "heck" version = "0.4.1" @@ -595,53 +588,12 @@ dependencies = [ "itoa", ] -[[package]] -name = "http-body" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" -dependencies = [ - "bytes", - "http", - "pin-project-lite", -] - [[package]] name = "httparse" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" -[[package]] -name = "httpdate" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" - -[[package]] -name = "hyper" -version = "0.14.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", -] - [[package]] name = "idna" version = "0.3.0" @@ -718,12 +670,33 @@ version = "0.2.141" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" +[[package]] +name = "libz-sys" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + [[package]] name = "linux-raw-sys" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" +[[package]] +name = "lock_api" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "log" version = "0.4.17" @@ -795,19 +768,12 @@ dependencies = [ ] [[package]] -name = "mime" -version = "0.3.17" +name = "miniz_oxide" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "mime_guess" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" dependencies = [ - "mime", - "unicase", + "adler", ] [[package]] @@ -828,25 +794,11 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" -[[package]] -name = "multiparty" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed1ec6589a6d4a1e0b33b4c0a3f6ee96dfba88ebdb3da51403fd7cf0a24a4b04" -dependencies = [ - "bytes", - "futures-core", - "httparse", - "memchr", - "pin-project-lite", - "try-lock", -] - [[package]] name = "nrpc" -version = "0.2.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8770a9a12e53035a536e41b7899d72bc423b2b8c17402c8f0dbe44d6bb255ac6" +checksum = "6f41caeb65399490c6f68ab2527a833d6f2e9b0d7d5ffc4b062f1484b3fa61cd" dependencies = [ "async-trait", "bytes", @@ -855,9 +807,9 @@ dependencies = [ [[package]] name = "nrpc-build" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5914c2bfd187a4bdfa7a69330e1ef4d8dea4060d8a08bf146f622aa7f176680" +checksum = "5b598ecce0e6d4b2cb367143696174ae24bff5eb4aeb1d8eccffbfeef75fc68e" dependencies = [ "nrpc", "prettyplease 0.2.4", @@ -897,6 +849,29 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "windows-sys 0.45.0", +] + [[package]] name = "percent-encoding" version = "2.2.0" @@ -945,6 +920,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkg-config" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" + [[package]] name = "polyval" version = "0.5.3" @@ -1125,6 +1106,75 @@ dependencies = [ "getrandom", ] +[[package]] +name = "ratchet_core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854bf6632d9f5c7fa7f77cbc332f2b0a8dfb2acc36c3f351fc36bf40f2759728" +dependencies = [ + "base64", + "bitflags", + "bytes", + "derive_more", + "either", + "fnv", + "http", + "httparse", + "log", + "rand", + "ratchet_ext", + "sha-1", + "thiserror", + "tokio", + "tokio-util", + "url", +] + +[[package]] +name = "ratchet_deflate" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0b144cb23a76d810b25737f4b87943fdfd7772b423bdc15c2b3820849207adc" +dependencies = [ + "bytes", + "flate2", + "http", + "log", + "ratchet_ext", + "thiserror", +] + +[[package]] +name = "ratchet_ext" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67f97bb0776d195720319a1e9f08fa343fe3f9f0b7ebf9d97d5926ce50b8e1ad" +dependencies = [ + "bytes", + "http", + "httparse", +] + +[[package]] +name = "ratchet_rs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7dba456fc23026b46ce0936d109ce3e73b4a592baf0dda0f83d49886c5e5f83" +dependencies = [ + "ratchet_core", + "ratchet_deflate", + "ratchet_ext", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + [[package]] name = "redox_syscall" version = "0.3.5" @@ -1149,6 +1199,15 @@ version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "0.37.11" @@ -1163,15 +1222,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "rustls-pemfile" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" -dependencies = [ - "base64 0.21.0", -] - [[package]] name = "ryu" version = "1.0.13" @@ -1184,6 +1234,18 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "semver" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" + [[package]] name = "serde" version = "1.0.160" @@ -1202,26 +1264,25 @@ dependencies = [ ] [[package]] -name = "serde_urlencoded" -version = "0.7.1" +name = "sha-1" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha1" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" dependencies = [ + "block-buffer", "cfg-if", "cpufeatures", "digest", + "opaque-debug", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", ] [[package]] @@ -1233,6 +1294,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + [[package]] name = "socket2" version = "0.4.9" @@ -1279,7 +1346,7 @@ checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" dependencies = [ "cfg-if", "fastrand", - "redox_syscall", + "redox_syscall 0.3.5", "rustix", "windows-sys 0.45.0", ] @@ -1330,98 +1397,37 @@ dependencies = [ "libc", "mio", "num_cpus", + "parking_lot", "pin-project-lite", + "signal-hook-registry", "socket2", + "tokio-macros", "windows-sys 0.45.0", ] [[package]] -name = "tokio-stream" -version = "0.1.12" +name = "tokio-macros" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fb52b74f05dbf495a8fba459fdc331812b96aa086d9eb78101fa0d4569c3313" +checksum = "61a573bdc87985e9d6ddeed1b3d864e8a302c847e40d647746df2f1de209d1ce" dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-tungstenite" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54319c93411147bced34cb5609a80e0a8e44c5999c93903a81cd866630ec0bfd" -dependencies = [ - "futures-util", - "log", - "tokio", - "tungstenite", + "proc-macro2", + "quote", + "syn 2.0.15", ] [[package]] name = "tokio-util" -version = "0.7.7" +version = "0.6.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" +checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507" dependencies = [ "bytes", "futures-core", "futures-sink", + "log", "pin-project-lite", "tokio", - "tracing", -] - -[[package]] -name = "tower-service" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" - -[[package]] -name = "tracing" -version = "0.1.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" -dependencies = [ - "cfg-if", - "log", - "pin-project-lite", - "tracing-core", -] - -[[package]] -name = "tracing-core" -version = "0.1.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" -dependencies = [ - "once_cell", -] - -[[package]] -name = "try-lock" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" - -[[package]] -name = "tungstenite" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ee6ab729cd4cf0fd55218530c4522ed30b7b6081752839b68fcec8d0960788" -dependencies = [ - "base64 0.13.1", - "byteorder", - "bytes", - "http", - "httparse", - "log", - "rand", - "sha1", - "thiserror", - "url", - "utf-8", ] [[package]] @@ -1430,15 +1436,6 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" -[[package]] -name = "unicase" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" -dependencies = [ - "version_check", -] - [[package]] name = "unicode-bidi" version = "0.3.13" @@ -1491,6 +1488,7 @@ dependencies = [ name = "usdpl-back" version = "0.11.0" dependencies = [ + "async-lock", "async-recursion", "async-trait", "bytes", @@ -1499,10 +1497,10 @@ dependencies = [ "log", "nrpc", "obfstr", + "ratchet_rs", "tokio", "usdpl-build", "usdpl-core", - "warp", ] [[package]] @@ -1523,7 +1521,7 @@ name = "usdpl-core" version = "0.11.0" dependencies = [ "aes-gcm-siv", - "base64 0.13.1", + "base64", "hex-literal", ] @@ -1549,10 +1547,10 @@ dependencies = [ ] [[package]] -name = "utf-8" -version = "0.7.6" +name = "vcpkg" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" @@ -1560,47 +1558,6 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" -[[package]] -name = "want" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" -dependencies = [ - "log", - "try-lock", -] - -[[package]] -name = "warp" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27e1a710288f0f91a98dd8a74f05b76a10768db245ce183edf64dc1afdc3016c" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "headers", - "http", - "hyper", - "log", - "mime", - "mime_guess", - "multiparty", - "percent-encoding", - "pin-project", - "rustls-pemfile", - "scoped-tls", - "serde", - "serde_json", - "serde_urlencoded", - "tokio", - "tokio-stream", - "tokio-tungstenite", - "tokio-util", - "tower-service", - "tracing", -] - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" diff --git a/usdpl-back/Cargo.toml b/usdpl-back/Cargo.toml index 4941d35..26ba550 100644 --- a/usdpl-back/Cargo.toml +++ b/usdpl-back/Cargo.toml @@ -10,7 +10,7 @@ description = "Universal Steam Deck Plugin Library back-end" [features] default = ["blocking"] decky = ["usdpl-core/decky"] -blocking = ["tokio", "tokio/rt", "tokio/rt-multi-thread"] # synchronous API for async functionality, using tokio +blocking = [] # synchronous API for async functionality, using tokio encrypt = ["usdpl-core/encrypt", "obfstr", "hex"] [dependencies] @@ -19,12 +19,16 @@ usdpl-core = { version = "0.11", path = "../usdpl-core"} log = "0.4" # gRPC/protobuf -nrpc = "0.2" +nrpc = "0.6" +async-lock = "2.7" + +# websocket framework +ratchet_rs = { version = "0.3", features = [ "deflate" ] } # HTTP web framework -warp = { version = "0.3" } +#warp = { version = "0.3" } bytes = { version = "1.1" } -tokio = { version = "1", optional = true } +tokio = { version = "1", features = [ "full" ]} # this is why people don't like async async-trait = "0.1.57" diff --git a/usdpl-back/src/callable.rs b/usdpl-back/src/callable.rs deleted file mode 100644 index 2a954c2..0000000 --- a/usdpl-back/src/callable.rs +++ /dev/null @@ -1,87 +0,0 @@ -use std::sync::{Arc, Mutex}; - -use usdpl_core::serdes::Primitive; - -/// A mutable function which can be called from the front-end (remotely) -pub trait MutCallable: Send + Sync { - /// Invoke the function - fn call(&mut self, params: Vec) -> Vec; -} - -impl) -> Vec) + Send + Sync> MutCallable for F { - fn call(&mut self, params: Vec) -> Vec { - (self)(params) - } -} - -/// A function which can be called from the front-end (remotely) -pub trait Callable: Send + Sync { - /// Invoke the function - fn call(&self, params: Vec) -> Vec; -} - -impl) -> Vec) + Send + Sync> Callable for F { - fn call(&self, params: Vec) -> Vec { - (self)(params) - } -} - -/// An async function which can be called from the front-end (remotely) -#[async_trait::async_trait] -pub trait AsyncCallable: Send + Sync { - /// Invoke the function - async fn call(&self, params: Vec) -> Vec; -} - -#[async_trait::async_trait] -impl) -> A) + Send + Sync, A: core::future::Future> + Send> AsyncCallable for F { - async fn call(&self, params: Vec) -> Vec { - (self)(params).await - } -} - -pub enum WrappedCallable { - Blocking(Arc>>), - Ref(Arc>), - Async(Arc>), -} - -impl WrappedCallable { - pub fn new_ref(callable: T) -> Self { - Self::Ref(Arc::new(Box::new(callable))) - } - - pub fn new_locking(callable: T) -> Self { - Self::Blocking(Arc::new(Mutex::new(Box::new(callable)))) - } - - pub fn new_async(callable: T) -> Self { - Self::Async(Arc::new(Box::new(callable))) - } -} - -impl Clone for WrappedCallable { - fn clone(&self) -> Self { - match self { - Self::Blocking(x) => Self::Blocking(x.clone()), - Self::Ref(x) => Self::Ref(x.clone()), - Self::Async(x) => Self::Async(x.clone()), - } - } -} - -#[async_trait::async_trait] -impl AsyncCallable for WrappedCallable { - async fn call(&self, params: Vec) -> Vec { - match self { - Self::Blocking(mut_callable) => { - mut_callable - .lock() - .expect("Failed to acquire mut_callable lock") - .call(params) - }, - Self::Ref(callable) => callable.call(params), - Self::Async(async_callable) => async_callable.call(params).await, - } - } -} diff --git a/usdpl-back/src/instance.rs b/usdpl-back/src/instance.rs deleted file mode 100644 index 7dd842e..0000000 --- a/usdpl-back/src/instance.rs +++ /dev/null @@ -1,262 +0,0 @@ -use std::collections::HashMap; -use std::sync::atomic::{AtomicU64, Ordering}; - -use warp::Filter; - -use usdpl_core::serdes::{Dumpable, Loadable}; -use usdpl_core::{socket, RemoteCallResponse}; - -use super::{Callable, MutCallable, AsyncCallable, WrappedCallable}; - -static LAST_ID: AtomicU64 = AtomicU64::new(0); -const MAX_ID_DIFFERENCE: u64 = 32; - -//type WrappedCallable = Arc>>; // thread-safe, cloneable Callable - -#[cfg(feature = "encrypt")] -const NONCE: [u8; socket::NONCE_SIZE] = [0u8; socket::NONCE_SIZE]; - -/// Back-end instance for interacting with the front-end -pub struct Instance { - calls: HashMap, - port: u16, - #[cfg(feature = "encrypt")] - encryption_key: Vec, -} - -impl Instance { - /// Initialise an instance of the back-end - #[inline] - pub fn new(port_usdpl: u16) -> Self { - Instance { - calls: HashMap::new(), - port: port_usdpl, - #[cfg(feature = "encrypt")] - encryption_key: hex::decode(obfstr::obfstr!(env!("USDPL_ENCRYPTION_KEY"))).unwrap(), - } - } - - /// Register a thread-safe function which can be invoked by the front-end - pub fn register, F: Callable + 'static>( - mut self, - name: S, - f: F, - ) -> Self { - self.calls - .insert(name.into(), WrappedCallable::new_ref(f)); - self - } - - /// Register a thread-unsafe function which can be invoked by the front-end - pub fn register_blocking, F: MutCallable + 'static>( - mut self, - name: S, - f: F, - ) -> Self { - self.calls - .insert(name.into(), WrappedCallable::new_locking(f)); - self - } - - /// Register a thread-unsafe function which can be invoked by the front-end - pub fn register_async, F: AsyncCallable + 'static>( - mut self, - name: S, - f: F, - ) -> Self { - self.calls - .insert(name.into(), WrappedCallable::new_async(f)); - self - } - - /// Run the web server instance forever, blocking this thread - #[cfg(feature = "blocking")] - pub fn run_blocking(&self) -> Result<(), ()> { - let result = self.serve_internal(); - tokio::runtime::Builder::new_multi_thread() - .enable_all() - .build() - .unwrap() - .block_on(result) - } - - /// Run the web server forever, asynchronously - pub async fn run(&self) -> Result<(), ()> { - self.serve_internal().await - } - - #[async_recursion::async_recursion] - async fn handle_call( - packet: socket::Packet, - handlers: &HashMap, - ) -> socket::Packet { - match packet { - socket::Packet::Call(call) => { - log::debug!("Got USDPL call {} (`{}`, params: {})", call.id, call.function, call.parameters.len()); - let last_id = LAST_ID.load(Ordering::SeqCst); - if last_id == 0 { - log::info!("Last id is 0, assuming resumed connection (overriding last id)"); - LAST_ID.store(call.id, Ordering::SeqCst); - } else if call.id < MAX_ID_DIFFERENCE { - log::info!("Call ID is low, assuming new connection (resetting last id)"); - LAST_ID.store(call.id, Ordering::SeqCst); - } else if call.id > last_id && call.id - last_id < MAX_ID_DIFFERENCE { - LAST_ID.store(call.id, Ordering::SeqCst); - } else if call.id < last_id && last_id - call.id < MAX_ID_DIFFERENCE { - // Allowed, but don't store new (lower) LAST_ID - } else { - #[cfg(not(debug_assertions))] - { - log::error!("Got USDPL call with strange ID! got:{} last id:{} (rejecting packet)", call.id, last_id); - return socket::Packet::Invalid - } - #[cfg(debug_assertions)] - log::warn!("Got USDPL call with strange ID! got:{} last id:{} (in release mode this packet will be rejected)", call.id, last_id); - } - //let handlers = CALLS.lock().expect("Failed to acquire CALLS lock"); - if let Some(target) = handlers.get(&call.function) { - let result = target.call(call.parameters).await; - socket::Packet::CallResponse(RemoteCallResponse { - id: call.id, - response: result, - }) - } else { - socket::Packet::Invalid - } - }, - socket::Packet::Many(packets) => { - let mut result = Vec::with_capacity(packets.len()); - for packet in packets { - result.push(Self::handle_call(packet, handlers).await); - } - socket::Packet::Many(result) - }, - #[cfg(feature = "translate")] - socket::Packet::Language(lang) => socket::Packet::Translations(get_all_translations(lang)), - _ => socket::Packet::Invalid, - } - } - - #[cfg(not(feature = "encrypt"))] - async fn process_body((data, handlers): (bytes::Bytes, HashMap)) -> impl warp::Reply { - let (packet, _) = match socket::Packet::load_base64(&data) { - Ok(x) => x, - Err(e) => { - return warp::reply::with_status( - warp::http::Response::builder() - .body(format!("Failed to load packet: {}", e)), - warp::http::StatusCode::from_u16(400).unwrap(), - ) - } - }; - //let mut buffer = [0u8; socket::PACKET_BUFFER_SIZE]; - let mut buffer = String::with_capacity(socket::PACKET_BUFFER_SIZE); - let response = Self::handle_call(packet, &handlers).await; - let _len = match response.dump_base64(&mut buffer) { - Ok(x) => x, - Err(e) => { - return warp::reply::with_status( - warp::http::Response::builder() - .body(format!("Failed to dump response packet: {}", e)), - warp::http::StatusCode::from_u16(500).unwrap(), - ) - } - }; - warp::reply::with_status( - warp::http::Response::builder().body(buffer), - warp::http::StatusCode::from_u16(200).unwrap(), - ) - } - - #[cfg(feature = "encrypt")] - async fn process_body((data, handlers, key): (bytes::Bytes, HashMap, Vec)) -> impl warp::Reply { - let (packet, _) = match socket::Packet::load_encrypted(&data, &key, &NONCE) { - Ok(x) => x, - Err(_) => { - return warp::reply::with_status( - warp::http::Response::builder() - .body("Failed to load packet".to_string()), - warp::http::StatusCode::from_u16(400).unwrap(), - ) - } - }; - let mut buffer = Vec::with_capacity(socket::PACKET_BUFFER_SIZE); - //buffer.extend(&[0u8; socket::PACKET_BUFFER_SIZE]); - let response = Self::handle_call(packet, &handlers).await; - let len = match response.dump_encrypted(&mut buffer, &key, &NONCE) { - Ok(x) => x, - Err(_) => { - return warp::reply::with_status( - warp::http::Response::builder() - .body("Failed to dump response packet".to_string()), - warp::http::StatusCode::from_u16(500).unwrap(), - ) - } - }; - buffer.truncate(len); - let string: String = String::from_utf8(buffer).unwrap().into(); - warp::reply::with_status( - warp::http::Response::builder().body(string), - warp::http::StatusCode::from_u16(200).unwrap(), - ) - } - - /// Receive and execute callbacks forever - async fn serve_internal(&self) -> Result<(), ()> { - let handlers = self.calls.clone(); - #[cfg(not(feature = "encrypt"))] - let input_mapper = move |data: bytes::Bytes| { (data, handlers.clone()) }; - #[cfg(feature = "encrypt")] - let key = self.encryption_key.clone(); - #[cfg(feature = "encrypt")] - let input_mapper = move |data: bytes::Bytes| { (data, handlers.clone(), key.clone()) }; - //self.calls = HashMap::new(); - let calls = warp::post() - .and(warp::path!("usdpl" / "call")) - .and(warp::body::content_length_limit( - (socket::PACKET_BUFFER_SIZE * 2) as _, - )) - .and(warp::body::bytes()) - .map(input_mapper) - .then(Self::process_body) - .map(|reply| warp::reply::with_header(reply, "Access-Control-Allow-Origin", "*")); - #[cfg(debug_assertions)] - warp::serve(calls).run(([0, 0, 0, 0], self.port)).await; - #[cfg(not(debug_assertions))] - warp::serve(calls).run(([127, 0, 0, 1], self.port)).await; - Ok(()) - } -} - -#[cfg(feature = "translate")] -fn get_all_translations(language: String) -> Vec<(String, Vec)> { - log::debug!("Loading translations for language `{}`...", language); - let result = load_locale(&language); - match result { - Ok(catalog) => { - let map = catalog.nalltext(); - let mut result = Vec::with_capacity(map.len()); - for (key, val) in map.iter() { - result.push((key.to_owned().into(), val.iter().map(|x| x.into()).collect())); - } - result - }, - Err(e) => { - log::error!("Failed to load translations for language `{}`: {}", language, e); - vec![] - } - } -} - -#[cfg(feature = "translate")] -fn load_locale(lang: &str) -> Result { - let path = crate::api::dirs::plugin().unwrap_or_else(|| "".into()).join("translations").join(format!("{}.mo", lang)); - let file = std::fs::File::open(path).map_err(|e| gettext_ng::Error::Io(e))?; - gettext_ng::Catalog::parse(file) -} - -#[cfg(test)] -mod tests { - #[allow(unused_imports)] - use super::*; -} diff --git a/usdpl-back/src/lib.rs b/usdpl-back/src/lib.rs index 2771cf7..fc4c052 100644 --- a/usdpl-back/src/lib.rs +++ b/usdpl-back/src/lib.rs @@ -13,13 +13,12 @@ mod api_crankshaft; #[cfg(all(feature = "decky", not(any(feature = "crankshaft"))))] mod api_decky; -mod callable; -//mod errors; -mod instance; +mod rpc; -pub use callable::{Callable, MutCallable, AsyncCallable}; -pub(crate) use callable::WrappedCallable; -pub use instance::Instance; +//mod errors; +mod websockets; + +pub use websockets::WebsocketServer as Server; //pub use errors::{ServerError, ServerResult}; /// USDPL backend API. diff --git a/usdpl-back/src/rpc/mod.rs b/usdpl-back/src/rpc/mod.rs index e69de29..6dddc35 100644 --- a/usdpl-back/src/rpc/mod.rs +++ b/usdpl-back/src/rpc/mod.rs @@ -0,0 +1,2 @@ +mod registry; +pub use registry::ServiceRegistry; diff --git a/usdpl-back/src/rpc/registry.rs b/usdpl-back/src/rpc/registry.rs new file mode 100644 index 0000000..6ae165d --- /dev/null +++ b/usdpl-back/src/rpc/registry.rs @@ -0,0 +1,42 @@ +use std::collections::HashMap; +use std::sync::Arc; +use async_lock::Mutex; + +use nrpc::{ServerService, ServiceError}; + +#[derive(Default, Clone)] +pub struct ServiceRegistry<'a> { + entries: HashMap>>>, +} + +impl<'a> ServiceRegistry<'a> { + /*pub async fn call(&self, package: &str, service: &str, method: &str, data: bytes::Bytes) -> Result { + let key = Self::descriptor(package, service); + self.call_descriptor(&key, method, data).await + } + + fn descriptor(package: &str, service: &str) -> String { + format!("{}.{}", package, service) + }*/ + + pub async fn call_descriptor(&self, descriptor: &str, method: &str, data: bytes::Bytes) -> Result { + if let Some(service) = self.entries.get(descriptor) { + let mut output = bytes::BytesMut::new(); + let mut service_lock = service.lock_arc().await; + service_lock.call(method, data, &mut output).await?; + Ok(output.into()) + } else { + Err(ServiceError::ServiceNotFound) + } + } + + pub fn register(&mut self, service: S) -> &mut Self { + let key = service.descriptor().to_owned(); + self.entries.insert(key, Arc::new(Mutex::new(Box::new(service)))); + self + } + + pub fn new() -> Self { + Self::default() + } +} diff --git a/usdpl-back/src/websockets.rs b/usdpl-back/src/websockets.rs new file mode 100644 index 0000000..9ad4fc0 --- /dev/null +++ b/usdpl-back/src/websockets.rs @@ -0,0 +1,108 @@ +use bytes::BytesMut; +use ratchet_rs::deflate::DeflateExtProvider; +use ratchet_rs::{Error as RatchetError, Message, ProtocolRegistry, WebSocketConfig}; +use tokio::net::{TcpListener, TcpStream}; + +use crate::rpc::ServiceRegistry; + +struct MethodDescriptor<'a> { + service: &'a str, + method: &'a str, +} + +/// Handler for communication to and from the front-end +pub struct WebsocketServer { + services: ServiceRegistry<'static>, + port: u16, +} + +impl WebsocketServer { + /// Initialise an instance of the back-end websocket server + pub fn new(port_usdpl: u16) -> Self { + Self { + services: ServiceRegistry::new(), + port: port_usdpl, + } + } + + /// Get the service registry that the server handles + pub fn registry(&mut self) -> &'_ mut ServiceRegistry<'static> { + &mut self.services + } + + /// Run the web server forever, asynchronously + pub async fn run(&self) -> std::io::Result<()> { + #[cfg(debug_assertions)] + let addr = (std::net::Ipv4Addr::UNSPECIFIED, self.port); + #[cfg(not(debug_assertions))] + let addr = (std::net::Ipv4Addr::LOCALHOST, self.port); + + let tcp = TcpListener::bind(addr).await?; + + while let Ok((stream, _addr_do_not_use)) = tcp.accept().await { + tokio::spawn(Self::connection_handler(self.services.clone(), stream)); + } + + Ok(()) + } + + async fn connection_handler(services: ServiceRegistry<'static>, stream: TcpStream) -> Result<(), RatchetError> { + let upgraded = ratchet_rs::accept_with( + stream, + WebSocketConfig::default(), + DeflateExtProvider::default(), + ProtocolRegistry::new(["usdpl-nrpc"])?, + ) + .await? + .upgrade() + .await?; + + let request_path = upgraded.request.uri().path(); + + let mut websocket = upgraded.websocket; + + let descriptor = Self::parse_uri_path(request_path) + .map_err(|e| RatchetError::with_cause(ratchet_rs::ErrorKind::Protocol, e))?; + + let mut buf = BytesMut::new(); + loop { + match websocket.read(&mut buf).await? { + Message::Text => return Err(RatchetError::with_cause(ratchet_rs::ErrorKind::Protocol, "Websocket text messages are not accepted")), + Message::Binary => { + let response = services.call_descriptor( + descriptor.service, + descriptor.method, + buf.clone().freeze() + ) + .await + .map_err(|e| RatchetError::with_cause(ratchet_rs::ErrorKind::Protocol, e.to_string()))?; + websocket.write_binary(response).await?; + }, + Message::Ping(x) => websocket.write_pong(x).await?, + Message::Pong(_) => {}, + Message::Close(_) => break, + } + } + Ok(()) + } + + fn parse_uri_path<'a>(path: &'a str) -> Result, &'static str> { + let mut iter = path.split('/'); + if let Some(service) = iter.next() { + if let Some(method) = iter.next() { + if iter.next().is_none() { + return Ok(MethodDescriptor { + service, + method + }); + } else { + Err("URL path has too many separators") + } + } else { + Err("URL path has no method") + } + } else { + Err("URL path has no service") + } + } +} diff --git a/usdpl-build/Cargo.toml b/usdpl-build/Cargo.toml index f2f4ab7..ff252ba 100644 --- a/usdpl-build/Cargo.toml +++ b/usdpl-build/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -nrpc-build = "0.5" +nrpc-build = "0.6" prost-build = "0.11" prost-types = "0.11" diff --git a/usdpl-front/Cargo.toml b/usdpl-front/Cargo.toml index eaea0ef..afffe0c 100644 --- a/usdpl-front/Cargo.toml +++ b/usdpl-front/Cargo.toml @@ -44,7 +44,7 @@ async-channel = "1.8" obfstr = { version = "0.3", optional = true } hex = { version = "0.4", optional = true } -nrpc = "0.2" +nrpc = "0.6" usdpl-core = { version = "0.11", path = "../usdpl-core" } prost = "0.11" diff --git a/usdpl-front/src/client_handler.rs b/usdpl-front/src/client_handler.rs index d123128..b592370 100644 --- a/usdpl-front/src/client_handler.rs +++ b/usdpl-front/src/client_handler.rs @@ -51,15 +51,17 @@ impl WebSocketHandler { #[async_trait::async_trait] impl ClientHandler for WebSocketHandler { async fn call(&mut self, + package: &str, service: &str, method: &str, input: bytes::Bytes, output: &mut bytes::BytesMut) -> Result<(), ServiceError> { let id = LAST_ID.fetch_add(1, Ordering::SeqCst); let url = format!( - "ws://usdpl-ws-{}.localhost:{}/{}/{}", + "ws://usdpl-ws-{}.localhost:{}/{}.{}/{}", id, self.port, + package, service, method, );