Add barebones nRPC over websocket adapters and functionality

This commit is contained in:
NGnius (Graham) 2023-04-23 23:03:10 -04:00
parent 570c194e82
commit 6a525fa384
11 changed files with 417 additions and 652 deletions

537
Cargo.lock generated
View file

@ -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"

View file

@ -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"

View file

@ -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<Primitive>) -> Vec<Primitive>;
}
impl<F: (FnMut(Vec<Primitive>) -> Vec<Primitive>) + Send + Sync> MutCallable for F {
fn call(&mut self, params: Vec<Primitive>) -> Vec<Primitive> {
(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<Primitive>) -> Vec<Primitive>;
}
impl<F: (Fn(Vec<Primitive>) -> Vec<Primitive>) + Send + Sync> Callable for F {
fn call(&self, params: Vec<Primitive>) -> Vec<Primitive> {
(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<Primitive>) -> Vec<Primitive>;
}
#[async_trait::async_trait]
impl<F: (Fn(Vec<Primitive>) -> A) + Send + Sync, A: core::future::Future<Output=Vec<Primitive>> + Send> AsyncCallable for F {
async fn call(&self, params: Vec<Primitive>) -> Vec<Primitive> {
(self)(params).await
}
}
pub enum WrappedCallable {
Blocking(Arc<Mutex<Box<dyn MutCallable>>>),
Ref(Arc<Box<dyn Callable>>),
Async(Arc<Box<dyn AsyncCallable>>),
}
impl WrappedCallable {
pub fn new_ref<T: Callable + 'static>(callable: T) -> Self {
Self::Ref(Arc::new(Box::new(callable)))
}
pub fn new_locking<T: MutCallable + 'static>(callable: T) -> Self {
Self::Blocking(Arc::new(Mutex::new(Box::new(callable))))
}
pub fn new_async<T: AsyncCallable + 'static>(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<Primitive>) -> Vec<Primitive> {
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,
}
}
}

View file

@ -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<Mutex<Box<dyn Callable>>>; // 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<String, WrappedCallable>,
port: u16,
#[cfg(feature = "encrypt")]
encryption_key: Vec<u8>,
}
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<S: std::convert::Into<String>, 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<S: std::convert::Into<String>, 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<S: std::convert::Into<String>, 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<String, WrappedCallable>,
) -> 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<String, WrappedCallable>)) -> 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<String, WrappedCallable>, Vec<u8>)) -> 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<String>)> {
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<gettext_ng::Catalog, gettext_ng::Error> {
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::*;
}

View file

@ -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.

View file

@ -0,0 +1,2 @@
mod registry;
pub use registry::ServiceRegistry;

View file

@ -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<String, Arc<Mutex<Box<dyn ServerService + Send + 'a>>>>,
}
impl<'a> ServiceRegistry<'a> {
/*pub async fn call(&self, package: &str, service: &str, method: &str, data: bytes::Bytes) -> Result<bytes::Bytes, ServiceError> {
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<bytes::Bytes, ServiceError> {
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<S: ServerService + Send + 'a>(&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()
}
}

View file

@ -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<MethodDescriptor<'a>, &'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")
}
}
}

View file

@ -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"

View file

@ -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"

View file

@ -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,
);