mirror of
https://github.com/uqbar-dao/nectar.git
synced 2024-12-02 08:02:23 +03:00
Merge branch 'v0.4.0' into jf/qns-v2
This commit is contained in:
commit
0d56046a3a
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,4 +1,6 @@
|
||||
target/
|
||||
wit/
|
||||
uqbar
|
||||
.vscode
|
||||
.app-signing
|
||||
.DS_Store
|
||||
|
1124
Cargo.lock
generated
1124
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
18
Cargo.toml
18
Cargo.toml
@ -10,18 +10,17 @@ repository = "https://github.com/uqbar-dao/uqbar"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[build-dependencies]
|
||||
reqwest = { version = "0.11.22", features = ["blocking"] }
|
||||
sha2 = "0.10"
|
||||
walkdir = "2.4"
|
||||
zip = "0.6"
|
||||
|
||||
[features]
|
||||
llm = []
|
||||
simulation-mode = []
|
||||
|
||||
[dependencies]
|
||||
aes-gcm = "0.10.2"
|
||||
anyhow = "1.0.71"
|
||||
async-recursion = "1.0.4"
|
||||
async-trait = "0.1.71"
|
||||
base64 = "0.13"
|
||||
bincode = "1.3.3"
|
||||
@ -34,7 +33,6 @@ clap = { version = "4.4", features = ["derive"] }
|
||||
crossterm = { version = "0.26.1", features = ["event-stream", "bracketed-paste"] }
|
||||
dashmap = "5.5.3"
|
||||
digest = "0.10"
|
||||
dotenv = "0.15.0"
|
||||
elliptic-curve = { version = "0.13.5", features = ["ecdh"] }
|
||||
ethers = "2.0"
|
||||
ethers-providers = "2.0.9"
|
||||
@ -49,7 +47,6 @@ http = "0.2.9"
|
||||
jwt = "0.16"
|
||||
lazy_static = "1.4.0"
|
||||
log = "*"
|
||||
lru-mem = "0.3.0"
|
||||
nohash-hasher = "0.2.0"
|
||||
num-traits = "0.2"
|
||||
open = "5.0.0"
|
||||
@ -59,11 +56,7 @@ reqwest = "0.11.18"
|
||||
ring = "0.16.20"
|
||||
rmp-serde = "1.1.2"
|
||||
route-recognizer = "0.3.1"
|
||||
rsa = "0.9"
|
||||
rusoto_core = "0.48.0"
|
||||
rusoto_s3 = "0.48.0"
|
||||
rusoto_credential = "0.48.0"
|
||||
serde = {version = "1.0", features = ["derive"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
serde_urlencoded = "0.7"
|
||||
sha2 = "0.10"
|
||||
@ -72,9 +65,10 @@ thiserror = "1.0"
|
||||
tokio = { version = "1.28", features = ["fs", "macros", "rt-multi-thread", "sync"] }
|
||||
tokio-tungstenite = "0.20.1"
|
||||
url = "2.4.1"
|
||||
uqbar_process_lib = { git = "ssh://git@github.com/uqbar-dao/process_lib.git", rev = "5e1b94a" }
|
||||
uuid = { version = "1.1.2", features = ["serde", "v4"] }
|
||||
warp = "0.3.5"
|
||||
wasmtime = "14.0.4"
|
||||
wasmtime-wasi = "14.0.4"
|
||||
wasmtime = "15.0.1"
|
||||
wasmtime-wasi = "15.0.1"
|
||||
zip = "0.6"
|
||||
rocksdb = { version = "0.21.0", features = ["multi-threaded-cf"] }
|
||||
rusqlite = { version = "0.30.0", features = ["bundled"] }
|
||||
|
@ -31,7 +31,7 @@ Get an eth-sepolia-rpc API key and pass that as an argument. You can get one for
|
||||
|
||||
Make sure not to use the same home directory for two nodes at once! You can use any name for the home directory: here we just use `home`. The `--` here separates cargo arguments from binary arguments.
|
||||
|
||||
TODO: document feature flags here, `--llm` and `--simulation-mode`
|
||||
TODO: document feature flags `--simulation-mode`
|
||||
```bash
|
||||
cargo +nightly run --release -- home --rpc wss://eth-sepolia.g.alchemy.com/v2/<your-api-key>
|
||||
```
|
||||
@ -73,6 +73,6 @@ On boot you will be prompted to navigate to `localhost:8080`. Make sure your ETH
|
||||
|
||||
Download and install an app:
|
||||
```
|
||||
!m our@main:app_store:uqbar {"Download": {"package": {"package_name": "<pkg>", "publisher_node": "<node>"}, "install_from": "<node>"}}
|
||||
!m our@main:app_store:uqbar {"Install": {"package_name": "<pkg>", "publisher_node": "<node>"}}
|
||||
/m our@main:app_store:uqbar {"Download": {"package": {"package_name": "<pkg>", "publisher_node": "<node>"}, "install_from": "<node>"}}
|
||||
/m our@main:app_store:uqbar {"Install": {"package_name": "<pkg>", "publisher_node": "<node>"}}
|
||||
```
|
||||
|
42
build-release.py
Executable file
42
build-release.py
Executable file
@ -0,0 +1,42 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
|
||||
def build_and_move(feature, tmp_dir):
|
||||
print("\n" + "=" * 50)
|
||||
print(f"BUILDING {feature if feature else 'default'}")
|
||||
print("=" * 50 + "\n")
|
||||
|
||||
if feature:
|
||||
subprocess.run(["cargo", "+nightly", "build", "--release", "--features", feature], check=True)
|
||||
binary_name = f"uqbar-{feature}"
|
||||
else:
|
||||
subprocess.run(["cargo", "+nightly", "build", "--release"], check=True)
|
||||
binary_name = "uqbar"
|
||||
|
||||
# Move and rename the binary
|
||||
source_path = "target/release/uqbar"
|
||||
dest_path = os.path.join(tmp_dir, binary_name)
|
||||
shutil.move(source_path, dest_path)
|
||||
|
||||
def main():
|
||||
# Features to compile with
|
||||
features = ["", "simulation-mode"] # Add more features as needed
|
||||
|
||||
# Ensure the tmp directory is clean
|
||||
tmp_dir = "/tmp/uqbar-release"
|
||||
if os.path.exists(tmp_dir):
|
||||
shutil.rmtree(tmp_dir)
|
||||
os.makedirs(tmp_dir)
|
||||
|
||||
# Loop through the features and build
|
||||
for feature in features:
|
||||
build_and_move(feature, tmp_dir)
|
||||
|
||||
print("Build and move process completed.\nFind release in {tmp_dir}.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
11
build.rs
11
build.rs
@ -135,6 +135,17 @@ fn main() {
|
||||
|
||||
let pwd = std::env::current_dir().unwrap();
|
||||
|
||||
// Pull wit from git repo
|
||||
let wit_dir = pwd.join("wit");
|
||||
fs::create_dir_all(&wit_dir).unwrap();
|
||||
let wit_file = wit_dir.join("uqbar.wit");
|
||||
if !wit_file.exists() {
|
||||
let mut wit_file = std::fs::File::create(&wit_file).unwrap();
|
||||
let uqbar_wit_url = "https://raw.githubusercontent.com/uqbar-dao/uqwit/master/uqbar.wit";
|
||||
let mut response = reqwest::blocking::get(uqbar_wit_url).unwrap();
|
||||
io::copy(&mut response, &mut wit_file).unwrap();
|
||||
}
|
||||
|
||||
// Create target.wasm (compiled .wit) & world
|
||||
run_command(Command::new("wasm-tools").args([
|
||||
"component",
|
||||
|
84
modules/app_store/app_store/Cargo.lock
generated
84
modules/app_store/app_store/Cargo.lock
generated
@ -120,9 +120,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.10"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
|
||||
checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
@ -131,9 +131,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.2"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156"
|
||||
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
@ -184,9 +184,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.9"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
|
||||
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
|
||||
|
||||
[[package]]
|
||||
name = "leb128"
|
||||
@ -196,9 +196,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.150"
|
||||
version = "0.2.151"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
|
||||
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
@ -220,9 +220,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.69"
|
||||
version = "1.0.70"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
|
||||
checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@ -268,9 +268,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.15"
|
||||
version = "1.0.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
|
||||
checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
@ -280,18 +280,18 @@ checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.191"
|
||||
version = "1.0.193"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a834c4821019838224821468552240d4d95d14e751986442c816572d39a080c9"
|
||||
checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.191"
|
||||
version = "1.0.193"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46fa52d5646bce91b680189fe5b1c049d2ea38dabb4e2e7c8d00ca12cfbfbcfd"
|
||||
checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -322,9 +322,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.11.1"
|
||||
version = "1.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a"
|
||||
checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
|
||||
|
||||
[[package]]
|
||||
name = "spdx"
|
||||
@ -337,9 +337,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.39"
|
||||
version = "2.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
|
||||
checksum = "13fa70a4ee923979ffb522cacce59d34421ebdea5625e1073c4326ef9d2dd42e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -389,9 +389,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.13"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
|
||||
checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
@ -422,8 +422,8 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
||||
|
||||
[[package]]
|
||||
name = "uqbar_process_lib"
|
||||
version = "0.3.0"
|
||||
source = "git+ssh://git@github.com/uqbar-dao/process_lib.git?rev=5e1b94a#5e1b94ae2f85c66da33ec52117a72b90d53c4d22"
|
||||
version = "0.4.0"
|
||||
source = "git+ssh://git@github.com/uqbar-dao/process_lib.git?rev=8342b1a#8342b1a131401fb5d141dab8c90e79aa6d2bc909"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
@ -461,18 +461,18 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-encoder"
|
||||
version = "0.36.2"
|
||||
version = "0.38.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "822b645bf4f2446b949776ffca47e2af60b167209ffb70814ef8779d299cd421"
|
||||
checksum = "0ad2b51884de9c7f4fe2fd1043fccb8dcad4b1e29558146ee57a144d15779f3f"
|
||||
dependencies = [
|
||||
"leb128",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-metadata"
|
||||
version = "0.10.11"
|
||||
version = "0.10.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2167ce53b2faa16a92c6cafd4942cff16c9a4fa0c5a5a0a41131ee4e49fc055f"
|
||||
checksum = "d835d67708f6374937c550ad8dd1d17c616ae009e3f00d7a0ac9f7825e78c36a"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"indexmap",
|
||||
@ -486,9 +486,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.116.1"
|
||||
version = "0.118.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a58e28b80dd8340cb07b8242ae654756161f6fc8d0038123d679b7b99964fa50"
|
||||
checksum = "95ee9723b928e735d53000dec9eae7b07a60e490c85ab54abb66659fc61bfcd9"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"semver",
|
||||
@ -496,8 +496,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.13.1"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=efcc759#efcc7592cf3277bcb9be1034e48569c6d822b322"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"wit-bindgen-rust-macro",
|
||||
@ -505,8 +505,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-core"
|
||||
version = "0.13.1"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=efcc759#efcc7592cf3277bcb9be1034e48569c6d822b322"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"wit-component",
|
||||
@ -515,8 +515,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust"
|
||||
version = "0.13.2"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=efcc759#efcc7592cf3277bcb9be1034e48569c6d822b322"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"heck",
|
||||
@ -527,8 +527,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust-macro"
|
||||
version = "0.13.1"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=efcc759#efcc7592cf3277bcb9be1034e48569c6d822b322"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"proc-macro2",
|
||||
@ -541,9 +541,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-component"
|
||||
version = "0.17.0"
|
||||
version = "0.18.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "480cc1a078b305c1b8510f7c455c76cbd008ee49935f3a6c5fd5e937d8d95b1e"
|
||||
checksum = "5b8a35a2a9992898c9d27f1664001860595a4bc99d32dd3599d547412e17d7e2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags",
|
||||
@ -560,9 +560,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-parser"
|
||||
version = "0.12.2"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43771ee863a16ec4ecf9da0fc65c3bbd4a1235c8e3da5f094b562894843dfa76"
|
||||
checksum = "15df6b7b28ce94b8be39d8df5cb21a08a4f3b9f33b631aedb4aa5776f785ead3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"id-arena",
|
||||
|
@ -14,11 +14,11 @@ lto = true
|
||||
anyhow = "1.0"
|
||||
bincode = "1.3.3"
|
||||
rand = "0.8"
|
||||
serde = {version = "1.0", features = ["derive"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
sha2 = "0.10.8"
|
||||
uqbar_process_lib = { git = "ssh://git@github.com/uqbar-dao/process_lib.git", rev = "5e1b94a" }
|
||||
wit-bindgen = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "5390bab780733f1660d14c254ec985df2816bf1d" }
|
||||
uqbar_process_lib = { git = "ssh://git@github.com/uqbar-dao/process_lib.git", rev = "8342b1a" }
|
||||
wit-bindgen = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "efcc759" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
@ -2,10 +2,9 @@ use serde::{Deserialize, Serialize};
|
||||
use sha2::Digest;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use uqbar_process_lib::kernel_types as kt;
|
||||
use uqbar_process_lib::uqbar::process::standard as wit;
|
||||
use uqbar_process_lib::{
|
||||
get_capability, get_payload, get_typed_state, grant_messaging, println, receive, set_state,
|
||||
share_capability, Address, Message, NodeId, PackageId, ProcessId, Request, Response,
|
||||
await_message, get_capability, get_payload, get_typed_state, grant_messaging, println,
|
||||
set_state, share_capability, Address, Message, NodeId, PackageId, ProcessId, Request, Response,
|
||||
};
|
||||
|
||||
wit_bindgen::generate!({
|
||||
@ -182,36 +181,34 @@ impl Guest for Component {
|
||||
|
||||
// active the main messaging loop: handle requests and responses
|
||||
loop {
|
||||
let (source, message) = match receive() {
|
||||
Ok((source, message)) => (source, message),
|
||||
Err((error, _context)) => {
|
||||
// TODO handle net errors more usefully based on their context
|
||||
println!("net error: {:?}", error.kind);
|
||||
match await_message() {
|
||||
Err(send_error) => {
|
||||
println!("{our}: got network error: {send_error:?}");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
match handle_message(&our, &source, &mut state, &message) {
|
||||
Ok(()) => {}
|
||||
Err(e) => println!("app-store: error handling message: {:?}", e),
|
||||
Ok(message) => match handle_message(&our, &mut state, &message) {
|
||||
Ok(()) => {}
|
||||
Err(e) => println!("app-store: error handling message: {:?}", e),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_message(
|
||||
our: &Address,
|
||||
source: &Address,
|
||||
mut state: &mut State,
|
||||
message: &Message,
|
||||
) -> anyhow::Result<()> {
|
||||
fn handle_message(our: &Address, mut state: &mut State, message: &Message) -> anyhow::Result<()> {
|
||||
match message {
|
||||
Message::Request(req) => {
|
||||
match &serde_json::from_slice::<Req>(&req.ipc) {
|
||||
Message::Request {
|
||||
source,
|
||||
expects_response,
|
||||
ipc,
|
||||
..
|
||||
} => {
|
||||
match &serde_json::from_slice::<Req>(&ipc) {
|
||||
Ok(Req::LocalRequest(local_request)) => {
|
||||
match handle_local_request(&our, &source, local_request, &mut state) {
|
||||
Ok(None) => return Ok(()),
|
||||
Ok(Some(resp)) => {
|
||||
if req.expects_response.is_some() {
|
||||
if expects_response.is_some() {
|
||||
Response::new().ipc(serde_json::to_vec(&resp)?).send()?;
|
||||
}
|
||||
}
|
||||
@ -224,7 +221,7 @@ fn handle_message(
|
||||
match handle_remote_request(&our, &source, remote_request, &mut state) {
|
||||
Ok(None) => return Ok(()),
|
||||
Ok(Some(resp)) => {
|
||||
if req.expects_response.is_some() {
|
||||
if expects_response.is_some() {
|
||||
Response::new().ipc(serde_json::to_vec(&resp)?).send()?;
|
||||
}
|
||||
}
|
||||
@ -259,50 +256,48 @@ fn handle_message(
|
||||
}
|
||||
}
|
||||
Ok(Req::FTWorkerCommand(_)) => {
|
||||
spawn_receive_transfer(&our, &req.ipc);
|
||||
spawn_receive_transfer(&our, &ipc);
|
||||
}
|
||||
e => {
|
||||
return Err(anyhow::anyhow!(
|
||||
"app store bad request: {:?}, error {:?}",
|
||||
req.ipc,
|
||||
ipc,
|
||||
e
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
Message::Response((response, context)) => {
|
||||
match &serde_json::from_slice::<Resp>(&response.ipc) {
|
||||
Ok(Resp::RemoteResponse(remote_response)) => match remote_response {
|
||||
RemoteResponse::DownloadApproved => {
|
||||
println!("app store: download approved, should be starting");
|
||||
}
|
||||
RemoteResponse::DownloadDenied => {
|
||||
println!("app store: could not download package from that node!");
|
||||
}
|
||||
},
|
||||
Ok(Resp::FTWorkerResult(ft_worker_result)) => {
|
||||
let Ok(context) =
|
||||
serde_json::from_slice::<FileTransferContext>(&context.as_ref().unwrap())
|
||||
else {
|
||||
return Err(anyhow::anyhow!("file_transfer: got weird local request"));
|
||||
};
|
||||
match ft_worker_result {
|
||||
FTWorkerResult::SendSuccess => {
|
||||
println!(
|
||||
"file_transfer: successfully shared app {} in {:.4}s",
|
||||
context.file_name,
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(context.start_time)
|
||||
.unwrap()
|
||||
.as_secs_f64(),
|
||||
);
|
||||
}
|
||||
e => return Err(anyhow::anyhow!("file_transfer: {:?}", e)),
|
||||
}
|
||||
Message::Response { ipc, context, .. } => match &serde_json::from_slice::<Resp>(&ipc) {
|
||||
Ok(Resp::RemoteResponse(remote_response)) => match remote_response {
|
||||
RemoteResponse::DownloadApproved => {
|
||||
println!("app store: download approved, should be starting");
|
||||
}
|
||||
RemoteResponse::DownloadDenied => {
|
||||
println!("app store: could not download package from that node!");
|
||||
}
|
||||
},
|
||||
Ok(Resp::FTWorkerResult(ft_worker_result)) => {
|
||||
let Ok(context) =
|
||||
serde_json::from_slice::<FileTransferContext>(&context.as_ref().unwrap())
|
||||
else {
|
||||
return Err(anyhow::anyhow!("file_transfer: got weird local request"));
|
||||
};
|
||||
match ft_worker_result {
|
||||
FTWorkerResult::SendSuccess => {
|
||||
println!(
|
||||
"file_transfer: successfully shared app {} in {:.4}s",
|
||||
context.file_name,
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(context.start_time)
|
||||
.unwrap()
|
||||
.as_secs_f64(),
|
||||
);
|
||||
}
|
||||
e => return Err(anyhow::anyhow!("file_transfer: {:?}", e)),
|
||||
}
|
||||
_ => return Err(anyhow::anyhow!("bad response from file transfer worker")),
|
||||
}
|
||||
}
|
||||
_ => return Err(anyhow::anyhow!("bad response from file transfer worker")),
|
||||
},
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -321,14 +316,16 @@ fn handle_local_request(
|
||||
let Some(mut payload) = get_payload() else {
|
||||
return Err(anyhow::anyhow!("no payload"));
|
||||
};
|
||||
let drive = format!("/{}/pkg", package);
|
||||
|
||||
Request::new()
|
||||
.target(Address::from_str("our@vfs:sys:uqbar")?)
|
||||
.ipc(serde_json::to_vec(&kt::VfsRequest {
|
||||
drive: package.to_string(),
|
||||
action: kt::VfsAction::New,
|
||||
path: drive.clone(),
|
||||
action: kt::VfsAction::CreateDrive,
|
||||
})?)
|
||||
.send_and_await_response(5)??;
|
||||
.send_and_await_response(5)?
|
||||
.unwrap();
|
||||
|
||||
// produce the version hash for this new package
|
||||
let mut hasher = sha2::Sha256::new();
|
||||
@ -337,42 +334,49 @@ fn handle_local_request(
|
||||
|
||||
// add zip bytes
|
||||
payload.mime = Some("application/zip".to_string());
|
||||
Request::new()
|
||||
let response = Request::new()
|
||||
.target(Address::from_str("our@vfs:sys:uqbar")?)
|
||||
.ipc(serde_json::to_vec(&kt::VfsRequest {
|
||||
drive: package.to_string(),
|
||||
action: kt::VfsAction::Add {
|
||||
full_path: package.to_string(),
|
||||
entry_type: kt::AddEntryType::ZipArchive,
|
||||
},
|
||||
path: drive.clone(),
|
||||
action: kt::VfsAction::AddZip,
|
||||
})?)
|
||||
.payload(payload.clone())
|
||||
.send_and_await_response(5)??;
|
||||
.send_and_await_response(5)?.unwrap();
|
||||
let Message::Response { ipc: ref vfs_ipc, .. } = response else {
|
||||
panic!("app_store: send_and_await_response must return Response");
|
||||
};
|
||||
let vfs_ipc = serde_json::from_slice::<serde_json::Value>(vfs_ipc)?;
|
||||
if vfs_ipc == serde_json::json!({"Err": "NoCap"}) {
|
||||
return Err(anyhow::anyhow!("cannot add NewPackage: do not have capability to access vfs"));
|
||||
}
|
||||
|
||||
// save the zip file itself in VFS for sharing with other nodes
|
||||
// call it <package>.zip
|
||||
let zip_path = format!("{}/{}.zip", drive.clone(), package);
|
||||
Request::new()
|
||||
.target(Address::from_str("our@vfs:sys:uqbar")?)
|
||||
.inherit(true)
|
||||
.ipc(serde_json::to_vec(&kt::VfsRequest {
|
||||
drive: package.to_string(),
|
||||
action: kt::VfsAction::Add {
|
||||
full_path: format!("/{}.zip", package.to_string()),
|
||||
entry_type: kt::AddEntryType::NewFile,
|
||||
},
|
||||
path: zip_path,
|
||||
action: kt::VfsAction::ReWrite,
|
||||
})?)
|
||||
.payload(payload)
|
||||
.send_and_await_response(5)??;
|
||||
.send_and_await_response(5)?
|
||||
.unwrap();
|
||||
let metadata_path = format!("{}/metadata.json", drive.clone());
|
||||
|
||||
Request::new()
|
||||
.target(Address::from_str("our@vfs:sys:uqbar")?)
|
||||
.ipc(serde_json::to_vec(&kt::VfsRequest {
|
||||
drive: package.to_string(),
|
||||
action: kt::VfsAction::GetEntry("/metadata.json".into()),
|
||||
path: metadata_path,
|
||||
action: kt::VfsAction::Read,
|
||||
})?)
|
||||
.send_and_await_response(5)??;
|
||||
.send_and_await_response(5)?
|
||||
.unwrap();
|
||||
let Some(payload) = get_payload() else {
|
||||
return Err(anyhow::anyhow!("no metadata found!"));
|
||||
};
|
||||
|
||||
let metadata = String::from_utf8(payload.bytes)?;
|
||||
let metadata = serde_json::from_str::<kt::PackageMetadata>(&metadata)?;
|
||||
|
||||
@ -406,8 +410,8 @@ fn handle_local_request(
|
||||
))?)
|
||||
.send_and_await_response(5)
|
||||
{
|
||||
Ok(Ok((_source, Message::Response((resp, _context))))) => {
|
||||
let resp = serde_json::from_slice::<Resp>(&resp.ipc)?;
|
||||
Ok(Ok(Message::Response { ipc, .. })) => {
|
||||
let resp = serde_json::from_slice::<Resp>(&ipc)?;
|
||||
match resp {
|
||||
Resp::RemoteResponse(RemoteResponse::DownloadApproved) => {
|
||||
state.requested_packages.insert(package.clone());
|
||||
@ -421,13 +425,15 @@ fn handle_local_request(
|
||||
},
|
||||
))),
|
||||
LocalRequest::Install(package) => {
|
||||
let drive_path = format!("/{}/pkg", package);
|
||||
Request::new()
|
||||
.target(Address::from_str("our@vfs:sys:uqbar")?)
|
||||
.ipc(serde_json::to_vec(&kt::VfsRequest {
|
||||
drive: package.to_string(),
|
||||
action: kt::VfsAction::GetEntry("/manifest.json".into()),
|
||||
path: format!("{}/manifest.json", drive_path),
|
||||
action: kt::VfsAction::Read,
|
||||
})?)
|
||||
.send_and_await_response(5)??;
|
||||
.send_and_await_response(5)?
|
||||
.unwrap();
|
||||
let Some(payload) = get_payload() else {
|
||||
return Err(anyhow::anyhow!("no payload"));
|
||||
};
|
||||
@ -438,7 +444,7 @@ fn handle_local_request(
|
||||
&Address::new(&our.node, ("vfs", "sys", "uqbar")),
|
||||
&serde_json::to_string(&serde_json::json!({
|
||||
"kind": "read",
|
||||
"drive": package.to_string(),
|
||||
"drive": drive_path,
|
||||
}))?,
|
||||
) else {
|
||||
return Err(anyhow::anyhow!("app-store: no read cap"));
|
||||
@ -447,7 +453,7 @@ fn handle_local_request(
|
||||
&Address::new(&our.node, ("vfs", "sys", "uqbar")),
|
||||
&serde_json::to_string(&serde_json::json!({
|
||||
"kind": "write",
|
||||
"drive": package.to_string(),
|
||||
"drive": drive_path,
|
||||
}))?,
|
||||
) else {
|
||||
return Err(anyhow::anyhow!("app-store: no write cap"));
|
||||
@ -462,33 +468,21 @@ fn handle_local_request(
|
||||
// then, once all have been initialized, grant them requested caps
|
||||
// and finally start them.
|
||||
for entry in &manifest {
|
||||
let path = if entry.process_wasm_path.starts_with("/") {
|
||||
let wasm_path = if entry.process_wasm_path.starts_with("/") {
|
||||
entry.process_wasm_path.clone()
|
||||
} else {
|
||||
format!("/{}", entry.process_wasm_path)
|
||||
};
|
||||
let (_, hash_response) = Request::new()
|
||||
.target(Address::from_str("our@vfs:sys:uqbar")?)
|
||||
.ipc(serde_json::to_vec(&kt::VfsRequest {
|
||||
drive: package.to_string(),
|
||||
action: kt::VfsAction::GetHash(path.clone()),
|
||||
})?)
|
||||
.send_and_await_response(5)??;
|
||||
|
||||
let Message::Response((wit::Response { ipc, .. }, _)) = hash_response else {
|
||||
return Err(anyhow::anyhow!("bad vfs response"));
|
||||
};
|
||||
let kt::VfsResponse::GetHash(Some(hash)) = serde_json::from_slice(&ipc)? else {
|
||||
return Err(anyhow::anyhow!("no hash in vfs"));
|
||||
};
|
||||
let wasm_path = format!("{}{}", drive_path, wasm_path);
|
||||
// build initial caps
|
||||
let mut initial_capabilities: HashSet<kt::SignedCapability> = HashSet::new();
|
||||
if entry.request_networking {
|
||||
initial_capabilities.insert(kt::de_wit_signed_capability(networking_cap.clone()));
|
||||
initial_capabilities
|
||||
.insert(kt::de_wit_signed_capability(networking_cap.clone()));
|
||||
}
|
||||
initial_capabilities.insert(kt::de_wit_signed_capability(read_cap.clone()));
|
||||
initial_capabilities.insert(kt::de_wit_signed_capability(write_cap.clone()));
|
||||
let process_id = format!("{}:{}", entry.process_name, package.to_string());
|
||||
let process_id = format!("{}:{}", entry.process_name, package);
|
||||
let Ok(parsed_new_process_id) = ProcessId::from_str(&process_id) else {
|
||||
return Err(anyhow::anyhow!("app-store: invalid process id!"));
|
||||
};
|
||||
@ -500,24 +494,26 @@ fn handle_local_request(
|
||||
))?)
|
||||
.send()?;
|
||||
|
||||
let (_, _bytes_response) = Request::new()
|
||||
let _bytes_response = Request::new()
|
||||
.target(Address::from_str("our@vfs:sys:uqbar")?)
|
||||
.ipc(serde_json::to_vec(&kt::VfsRequest {
|
||||
drive: package.to_string(),
|
||||
action: kt::VfsAction::GetEntry(path),
|
||||
path: wasm_path.clone(),
|
||||
action: kt::VfsAction::Read,
|
||||
})?)
|
||||
.send_and_await_response(5)??;
|
||||
.send_and_await_response(5)?
|
||||
.unwrap();
|
||||
Request::new()
|
||||
.target(Address::from_str("our@kernel:sys:uqbar")?)
|
||||
.ipc(serde_json::to_vec(&kt::KernelCommand::InitializeProcess {
|
||||
id: parsed_new_process_id,
|
||||
wasm_bytes_handle: hash,
|
||||
on_panic: entry.on_panic.clone(),
|
||||
wasm_bytes_handle: wasm_path,
|
||||
on_exit: entry.on_exit.clone(),
|
||||
initial_capabilities,
|
||||
public: entry.public,
|
||||
})?)
|
||||
.inherit(true)
|
||||
.send_and_await_response(5)?;
|
||||
.send_and_await_response(5)?
|
||||
.unwrap();
|
||||
}
|
||||
for entry in &manifest {
|
||||
let process_id = ProcessId::new(
|
||||
@ -526,41 +522,93 @@ fn handle_local_request(
|
||||
package.publisher(),
|
||||
);
|
||||
if let Some(to_request) = &entry.request_messaging {
|
||||
for process_name in to_request {
|
||||
let Ok(parsed_process_id) = ProcessId::from_str(&process_name) else {
|
||||
// TODO handle arbitrary caps here
|
||||
continue;
|
||||
};
|
||||
let Some(messaging_cap) = get_capability(
|
||||
&Address {
|
||||
node: our.node.clone(),
|
||||
process: parsed_process_id.clone(),
|
||||
},
|
||||
&"\"messaging\"".into(),
|
||||
) else {
|
||||
println!("app-store: no cap for {} to give away!", process_name);
|
||||
continue;
|
||||
};
|
||||
share_capability(&process_id, &messaging_cap);
|
||||
for value in to_request {
|
||||
let mut capability = None;
|
||||
match value {
|
||||
serde_json::Value::String(process_name) => {
|
||||
if let Ok(parsed_process_id) = ProcessId::from_str(process_name) {
|
||||
capability = get_capability(
|
||||
&Address {
|
||||
node: our.node.clone(),
|
||||
process: parsed_process_id.clone(),
|
||||
},
|
||||
&"\"messaging\"".into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
serde_json::Value::Object(map) => {
|
||||
if let Some(process_name) = map.get("process") {
|
||||
if let Ok(parsed_process_id) =
|
||||
ProcessId::from_str(&process_name.to_string())
|
||||
{
|
||||
if let Some(params) = map.get("params") {
|
||||
capability = get_capability(
|
||||
&Address {
|
||||
node: our.node.clone(),
|
||||
process: parsed_process_id.clone(),
|
||||
},
|
||||
¶ms.to_string(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if let Some(cap) = capability {
|
||||
share_capability(&process_id, &cap);
|
||||
} else {
|
||||
println!("app-store: no cap: {}, for {} to request!", value.to_string(), process_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(to_grant) = &entry.grant_messaging {
|
||||
let Some(messaging_cap) = get_capability(
|
||||
&Address {
|
||||
node: our.node.clone(),
|
||||
process: process_id.clone(),
|
||||
},
|
||||
&"\"messaging\"".into(),
|
||||
) else {
|
||||
println!("app-store: no cap for {} to give away!", process_id);
|
||||
continue;
|
||||
};
|
||||
for process_name in to_grant {
|
||||
let Ok(parsed_process_id) = ProcessId::from_str(&process_name) else {
|
||||
// TODO handle arbitrary caps here
|
||||
continue;
|
||||
};
|
||||
share_capability(&parsed_process_id, &messaging_cap);
|
||||
for value in to_grant {
|
||||
let mut capability = None;
|
||||
let mut to_process = None;
|
||||
match value {
|
||||
serde_json::Value::String(process_name) => {
|
||||
if let Ok(parsed_process_id) = ProcessId::from_str(process_name) {
|
||||
capability = get_capability(
|
||||
&Address {
|
||||
node: our.node.clone(),
|
||||
process: process_id.clone(),
|
||||
},
|
||||
&"\"messaging\"".into(),
|
||||
);
|
||||
to_process = Some(parsed_process_id);
|
||||
}
|
||||
}
|
||||
serde_json::Value::Object(map) => {
|
||||
if let Some(process_name) = map.get("process") {
|
||||
if let Ok(parsed_process_id) =
|
||||
ProcessId::from_str(&process_name.to_string())
|
||||
{
|
||||
if let Some(params) = map.get("params") {
|
||||
capability = get_capability(
|
||||
&Address {
|
||||
node: our.node.clone(),
|
||||
process: process_id.clone(),
|
||||
},
|
||||
¶ms.to_string(),
|
||||
);
|
||||
to_process = Some(parsed_process_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(cap) = capability {
|
||||
share_capability(&to_process.unwrap(), &cap);
|
||||
} else {
|
||||
println!("app-store: no cap: {}, for {} to grant!", value.to_string(), process_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
Request::new()
|
||||
@ -568,7 +616,8 @@ fn handle_local_request(
|
||||
.ipc(serde_json::to_vec(&kt::KernelCommand::RunProcess(
|
||||
process_id,
|
||||
))?)
|
||||
.send_and_await_response(5)?;
|
||||
.send_and_await_response(5)?
|
||||
.unwrap();
|
||||
}
|
||||
Ok(Some(Resp::InstallResponse(InstallResponse::Success)))
|
||||
}
|
||||
@ -598,15 +647,18 @@ fn handle_remote_request(
|
||||
return Ok(Some(Resp::RemoteResponse(RemoteResponse::DownloadDenied)));
|
||||
}
|
||||
// get the .zip from VFS and attach as payload to response
|
||||
let file_name = format!("/{}.zip", package.to_string());
|
||||
let drive_name = format!("/{}/pkg", package);
|
||||
let file_path = format!("/{}.zip", drive_name);
|
||||
Request::new()
|
||||
.target(Address::from_str("our@vfs:sys:uqbar")?)
|
||||
.ipc(serde_json::to_vec(&kt::VfsRequest {
|
||||
drive: package.to_string(),
|
||||
action: kt::VfsAction::GetEntry(file_name.clone()),
|
||||
path: file_path,
|
||||
action: kt::VfsAction::Read,
|
||||
})?)
|
||||
.send_and_await_response(5)?;
|
||||
.send_and_await_response(5)?
|
||||
.unwrap();
|
||||
// transfer will inherit the payload bytes we receive from VFS
|
||||
let file_name = format!("/{}.zip", package);
|
||||
spawn_transfer(&our, &file_name, None, &source);
|
||||
Ok(Some(Resp::RemoteResponse(RemoteResponse::DownloadApproved)))
|
||||
}
|
||||
|
84
modules/app_store/ft_worker/Cargo.lock
generated
84
modules/app_store/ft_worker/Cargo.lock
generated
@ -71,9 +71,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.10"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
|
||||
checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
@ -82,9 +82,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.2"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156"
|
||||
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
@ -135,9 +135,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.9"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
|
||||
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
|
||||
|
||||
[[package]]
|
||||
name = "leb128"
|
||||
@ -147,9 +147,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.150"
|
||||
version = "0.2.151"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
|
||||
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
@ -171,9 +171,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.69"
|
||||
version = "1.0.70"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
|
||||
checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@ -219,9 +219,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.15"
|
||||
version = "1.0.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
|
||||
checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
@ -231,18 +231,18 @@ checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.191"
|
||||
version = "1.0.193"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a834c4821019838224821468552240d4d95d14e751986442c816572d39a080c9"
|
||||
checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.191"
|
||||
version = "1.0.193"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46fa52d5646bce91b680189fe5b1c049d2ea38dabb4e2e7c8d00ca12cfbfbcfd"
|
||||
checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -262,9 +262,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.11.1"
|
||||
version = "1.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a"
|
||||
checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
|
||||
|
||||
[[package]]
|
||||
name = "spdx"
|
||||
@ -277,9 +277,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.39"
|
||||
version = "2.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
|
||||
checksum = "13fa70a4ee923979ffb522cacce59d34421ebdea5625e1073c4326ef9d2dd42e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -323,9 +323,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.13"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
|
||||
checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
@ -356,8 +356,8 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
||||
|
||||
[[package]]
|
||||
name = "uqbar_process_lib"
|
||||
version = "0.3.0"
|
||||
source = "git+ssh://git@github.com/uqbar-dao/process_lib.git?rev=5e1b94a#5e1b94ae2f85c66da33ec52117a72b90d53c4d22"
|
||||
version = "0.4.0"
|
||||
source = "git+ssh://git@github.com/uqbar-dao/process_lib.git?rev=b09d987#b09d9875edce1a230549cf56cf088f95e38d4abd"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
@ -389,18 +389,18 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-encoder"
|
||||
version = "0.36.2"
|
||||
version = "0.38.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "822b645bf4f2446b949776ffca47e2af60b167209ffb70814ef8779d299cd421"
|
||||
checksum = "0ad2b51884de9c7f4fe2fd1043fccb8dcad4b1e29558146ee57a144d15779f3f"
|
||||
dependencies = [
|
||||
"leb128",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-metadata"
|
||||
version = "0.10.11"
|
||||
version = "0.10.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2167ce53b2faa16a92c6cafd4942cff16c9a4fa0c5a5a0a41131ee4e49fc055f"
|
||||
checksum = "d835d67708f6374937c550ad8dd1d17c616ae009e3f00d7a0ac9f7825e78c36a"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"indexmap",
|
||||
@ -414,9 +414,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.116.1"
|
||||
version = "0.118.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a58e28b80dd8340cb07b8242ae654756161f6fc8d0038123d679b7b99964fa50"
|
||||
checksum = "95ee9723b928e735d53000dec9eae7b07a60e490c85ab54abb66659fc61bfcd9"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"semver",
|
||||
@ -424,8 +424,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.13.1"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=efcc759#efcc7592cf3277bcb9be1034e48569c6d822b322"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"wit-bindgen-rust-macro",
|
||||
@ -433,8 +433,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-core"
|
||||
version = "0.13.1"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=efcc759#efcc7592cf3277bcb9be1034e48569c6d822b322"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"wit-component",
|
||||
@ -443,8 +443,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust"
|
||||
version = "0.13.2"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=efcc759#efcc7592cf3277bcb9be1034e48569c6d822b322"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"heck",
|
||||
@ -455,8 +455,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust-macro"
|
||||
version = "0.13.1"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=efcc759#efcc7592cf3277bcb9be1034e48569c6d822b322"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"proc-macro2",
|
||||
@ -469,9 +469,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-component"
|
||||
version = "0.17.0"
|
||||
version = "0.18.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "480cc1a078b305c1b8510f7c455c76cbd008ee49935f3a6c5fd5e937d8d95b1e"
|
||||
checksum = "5b8a35a2a9992898c9d27f1664001860595a4bc99d32dd3599d547412e17d7e2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags",
|
||||
@ -488,9 +488,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-parser"
|
||||
version = "0.12.2"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43771ee863a16ec4ecf9da0fc65c3bbd4a1235c8e3da5f094b562894843dfa76"
|
||||
checksum = "15df6b7b28ce94b8be39d8df5cb21a08a4f3b9f33b631aedb4aa5776f785ead3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"id-arena",
|
||||
|
@ -14,10 +14,10 @@ lto = true
|
||||
anyhow = "1.0"
|
||||
bincode = "1.3.3"
|
||||
rand = "0.8"
|
||||
serde = {version = "1.0", features = ["derive"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
uqbar_process_lib = { git = "ssh://git@github.com/uqbar-dao/process_lib.git", rev = "5e1b94a" }
|
||||
wit-bindgen = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "5390bab780733f1660d14c254ec985df2816bf1d" }
|
||||
uqbar_process_lib = { git = "ssh://git@github.com/uqbar-dao/process_lib.git", rev = "b09d987" }
|
||||
wit-bindgen = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "efcc759" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
@ -55,7 +55,7 @@ pub fn spawn_transfer(
|
||||
let Ok(worker_process_id) = spawn(
|
||||
Some(&transfer_id.to_string()),
|
||||
"/ft_worker.wasm".into(),
|
||||
&OnPanic::None, // can set message-on-panic here
|
||||
&OnExit::None, // can set message-on-panic here
|
||||
&Capabilities::All,
|
||||
false, // not public
|
||||
) else {
|
||||
@ -106,7 +106,7 @@ pub fn spawn_receive_transfer(our: &Address, ipc: &[u8]) {
|
||||
let Ok(worker_process_id) = spawn(
|
||||
Some(&transfer_id.to_string()),
|
||||
"/ft_worker.wasm".into(),
|
||||
&OnPanic::None, // can set message-on-panic here
|
||||
&OnExit::None, // can set message-on-panic here
|
||||
&Capabilities::All,
|
||||
false, // not public
|
||||
) else {
|
||||
|
@ -1,5 +1,8 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uqbar_process_lib::uqbar::process::standard::*;
|
||||
//use uqbar_process_lib::uqbar::process::standard::*;
|
||||
|
||||
use uqbar_process_lib::uqbar::process::standard::{Message as StdMessage, Request as StdRequest, Response as StdResponse, SendErrorKind};
|
||||
use uqbar_process_lib::{await_message, get_payload, print_to_terminal, send_and_await_response, send_request, send_response, Address, Message, Payload};
|
||||
|
||||
mod ft_worker_lib;
|
||||
use ft_worker_lib::*;
|
||||
@ -25,11 +28,11 @@ impl Guest for Component {
|
||||
let our = Address::from_str(&our).unwrap();
|
||||
print_to_terminal(1, &format!("{}: start", our.process));
|
||||
|
||||
let Ok((parent_process, Message::Request(req))) = receive() else {
|
||||
let Ok(Message::Request { source: parent_process, ipc, .. }) = await_message() else {
|
||||
panic!("ft_worker: got bad init message");
|
||||
};
|
||||
|
||||
let command = serde_json::from_slice::<FTWorkerCommand>(&req.ipc)
|
||||
let command = serde_json::from_slice::<FTWorkerCommand>(&ipc)
|
||||
.expect("ft_worker: got unparseable init message");
|
||||
|
||||
match command {
|
||||
@ -55,7 +58,7 @@ impl Guest for Component {
|
||||
// acknowledgement.
|
||||
match send_and_await_response(
|
||||
&Address::from_str(&target).unwrap(),
|
||||
&Request {
|
||||
&StdRequest {
|
||||
inherit: false,
|
||||
expects_response: Some(timeout),
|
||||
ipc: serde_json::to_vec(&FTWorkerCommand::Receive {
|
||||
@ -76,7 +79,7 @@ impl Guest for Component {
|
||||
SendErrorKind::Timeout => TransferError::TargetTimeout,
|
||||
}))
|
||||
}
|
||||
Ok((opp_worker, Message::Response((response, _)))) => {
|
||||
Ok((opp_worker, StdMessage::Response((response, _)))) => {
|
||||
let Ok(FTWorkerProtocol::Ready) = serde_json::from_slice(&response.ipc) else {
|
||||
respond_to_parent(FTWorkerResult::Err(TransferError::TargetRejected));
|
||||
return;
|
||||
@ -94,7 +97,7 @@ impl Guest for Component {
|
||||
};
|
||||
send_request(
|
||||
&opp_worker,
|
||||
&Request {
|
||||
&StdRequest {
|
||||
inherit: false,
|
||||
expects_response: Some(timeout),
|
||||
ipc: vec![],
|
||||
@ -113,7 +116,7 @@ impl Guest for Component {
|
||||
};
|
||||
send_request(
|
||||
&opp_worker,
|
||||
&Request {
|
||||
&StdRequest {
|
||||
inherit: false,
|
||||
expects_response: None,
|
||||
ipc: vec![],
|
||||
@ -126,11 +129,11 @@ impl Guest for Component {
|
||||
offset += chunk_size;
|
||||
}
|
||||
// now wait for Finished response
|
||||
let Ok((receiving_worker, Message::Response((resp, _)))) = receive() else {
|
||||
let Ok(Message::Response { ipc, .. }) = await_message() else {
|
||||
respond_to_parent(FTWorkerResult::Err(TransferError::TargetRejected));
|
||||
return;
|
||||
};
|
||||
let Ok(FTWorkerProtocol::Finished) = serde_json::from_slice(&resp.ipc) else {
|
||||
let Ok(FTWorkerProtocol::Finished) = serde_json::from_slice(&ipc) else {
|
||||
respond_to_parent(FTWorkerResult::Err(TransferError::TargetRejected));
|
||||
return;
|
||||
};
|
||||
@ -141,15 +144,14 @@ impl Guest for Component {
|
||||
}
|
||||
}
|
||||
FTWorkerCommand::Receive {
|
||||
transfer_id,
|
||||
file_name,
|
||||
file_size,
|
||||
total_chunks,
|
||||
timeout,
|
||||
..
|
||||
} => {
|
||||
// send Ready response to counterparty
|
||||
send_response(
|
||||
&Response {
|
||||
&StdResponse {
|
||||
inherit: false,
|
||||
ipc: serde_json::to_vec(&FTWorkerProtocol::Ready).unwrap(),
|
||||
metadata: None,
|
||||
@ -163,7 +165,7 @@ impl Guest for Component {
|
||||
let mut chunks_received = 0;
|
||||
let start_time = std::time::Instant::now();
|
||||
loop {
|
||||
let Ok((source, Message::Request(req))) = receive() else {
|
||||
let Ok(Message::Request { .. }) = await_message() else {
|
||||
respond_to_parent(FTWorkerResult::Err(TransferError::SourceFailed));
|
||||
return;
|
||||
};
|
||||
@ -183,7 +185,7 @@ impl Guest for Component {
|
||||
}
|
||||
// send Finished message to sender
|
||||
send_response(
|
||||
&Response {
|
||||
&StdResponse {
|
||||
inherit: false,
|
||||
ipc: serde_json::to_vec(&FTWorkerProtocol::Finished).unwrap(),
|
||||
metadata: None,
|
||||
@ -193,7 +195,7 @@ impl Guest for Component {
|
||||
// send Success message to parent
|
||||
send_request(
|
||||
&parent_process,
|
||||
&Request {
|
||||
&StdRequest {
|
||||
inherit: false,
|
||||
expects_response: None,
|
||||
ipc: serde_json::to_vec(&FTWorkerResult::ReceiveSuccess(file_name))
|
||||
@ -213,7 +215,7 @@ impl Guest for Component {
|
||||
|
||||
fn respond_to_parent(result: FTWorkerResult) {
|
||||
send_response(
|
||||
&Response {
|
||||
&StdResponse {
|
||||
inherit: false,
|
||||
ipc: serde_json::to_vec(&result).unwrap(),
|
||||
metadata: None,
|
||||
|
@ -2,7 +2,7 @@
|
||||
{
|
||||
"process_name": "main",
|
||||
"process_wasm_path": "/app_store.wasm",
|
||||
"on_panic": "Restart",
|
||||
"on_exit": "Restart",
|
||||
"request_networking": true,
|
||||
"request_messaging": [
|
||||
"terminal:terminal:uqbar",
|
||||
@ -13,7 +13,13 @@
|
||||
"net:sys:uqbar",
|
||||
"vfs:sys:uqbar",
|
||||
"kernel:sys:uqbar",
|
||||
"eth_rpc:sys:uqbar"
|
||||
"eth_rpc:sys:uqbar",
|
||||
{
|
||||
"process": "vfs:sys:uqbar",
|
||||
"params": {
|
||||
"root": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"public": false
|
||||
}
|
||||
|
103
modules/chess/Cargo.lock
generated
103
modules/chess/Cargo.lock
generated
@ -64,7 +64,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "chess"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64",
|
||||
@ -73,6 +73,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"uqbar_process_lib",
|
||||
"url",
|
||||
"wit-bindgen",
|
||||
]
|
||||
|
||||
@ -138,9 +139,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.2.0"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652"
|
||||
checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
@ -153,9 +154,9 @@ checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.10"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
|
||||
checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
@ -164,9 +165,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.2"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156"
|
||||
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
@ -202,9 +203,9 @@ checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005"
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.4.0"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
|
||||
checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
|
||||
dependencies = [
|
||||
"unicode-bidi",
|
||||
"unicode-normalization",
|
||||
@ -223,9 +224,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.9"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
|
||||
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
@ -241,9 +242,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.150"
|
||||
version = "0.2.151"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
|
||||
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
@ -278,9 +279,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.0"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
|
||||
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||
|
||||
[[package]]
|
||||
name = "pleco"
|
||||
@ -304,9 +305,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.69"
|
||||
version = "1.0.70"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
|
||||
checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@ -487,9 +488,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.15"
|
||||
version = "1.0.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
|
||||
checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
@ -505,18 +506,18 @@ checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.191"
|
||||
version = "1.0.193"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a834c4821019838224821468552240d4d95d14e751986442c816572d39a080c9"
|
||||
checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.191"
|
||||
version = "1.0.193"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46fa52d5646bce91b680189fe5b1c049d2ea38dabb4e2e7c8d00ca12cfbfbcfd"
|
||||
checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -536,9 +537,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.11.1"
|
||||
version = "1.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a"
|
||||
checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
|
||||
|
||||
[[package]]
|
||||
name = "spdx"
|
||||
@ -551,9 +552,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.39"
|
||||
version = "2.0.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
|
||||
checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -597,9 +598,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.13"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
|
||||
checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
@ -630,8 +631,8 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
||||
|
||||
[[package]]
|
||||
name = "uqbar_process_lib"
|
||||
version = "0.3.0"
|
||||
source = "git+ssh://git@github.com/uqbar-dao/process_lib.git?rev=5e1b94a#5e1b94ae2f85c66da33ec52117a72b90d53c4d22"
|
||||
version = "0.4.0"
|
||||
source = "git+ssh://git@github.com/uqbar-dao/process_lib.git?rev=65e07e4#65e07e49553a5fa3340ff7c3d9cf3340a53610c8"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
@ -646,9 +647,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.4.1"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5"
|
||||
checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna",
|
||||
@ -663,18 +664,18 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-encoder"
|
||||
version = "0.36.2"
|
||||
version = "0.38.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "822b645bf4f2446b949776ffca47e2af60b167209ffb70814ef8779d299cd421"
|
||||
checksum = "0ad2b51884de9c7f4fe2fd1043fccb8dcad4b1e29558146ee57a144d15779f3f"
|
||||
dependencies = [
|
||||
"leb128",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-metadata"
|
||||
version = "0.10.11"
|
||||
version = "0.10.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2167ce53b2faa16a92c6cafd4942cff16c9a4fa0c5a5a0a41131ee4e49fc055f"
|
||||
checksum = "d835d67708f6374937c550ad8dd1d17c616ae009e3f00d7a0ac9f7825e78c36a"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"indexmap",
|
||||
@ -688,9 +689,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.116.1"
|
||||
version = "0.118.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a58e28b80dd8340cb07b8242ae654756161f6fc8d0038123d679b7b99964fa50"
|
||||
checksum = "95ee9723b928e735d53000dec9eae7b07a60e490c85ab54abb66659fc61bfcd9"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"semver",
|
||||
@ -720,8 +721,8 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.13.1"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=efcc759#efcc7592cf3277bcb9be1034e48569c6d822b322"
|
||||
dependencies = [
|
||||
"bitflags 2.4.1",
|
||||
"wit-bindgen-rust-macro",
|
||||
@ -729,8 +730,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-core"
|
||||
version = "0.13.1"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=efcc759#efcc7592cf3277bcb9be1034e48569c6d822b322"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"wit-component",
|
||||
@ -739,8 +740,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust"
|
||||
version = "0.13.2"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=efcc759#efcc7592cf3277bcb9be1034e48569c6d822b322"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"heck",
|
||||
@ -751,8 +752,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust-macro"
|
||||
version = "0.13.1"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=efcc759#efcc7592cf3277bcb9be1034e48569c6d822b322"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"proc-macro2",
|
||||
@ -765,9 +766,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-component"
|
||||
version = "0.17.0"
|
||||
version = "0.18.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "480cc1a078b305c1b8510f7c455c76cbd008ee49935f3a6c5fd5e937d8d95b1e"
|
||||
checksum = "5b8a35a2a9992898c9d27f1664001860595a4bc99d32dd3599d547412e17d7e2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags 2.4.1",
|
||||
@ -784,9 +785,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-parser"
|
||||
version = "0.12.2"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43771ee863a16ec4ecf9da0fc65c3bbd4a1235c8e3da5f094b562894843dfa76"
|
||||
checksum = "15df6b7b28ce94b8be39d8df5cb21a08a4f3b9f33b631aedb4aa5776f785ead3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"id-arena",
|
||||
|
@ -1,10 +1,8 @@
|
||||
[package]
|
||||
name = "chess"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
opt-level = "s"
|
||||
@ -15,10 +13,11 @@ anyhow = "1.0"
|
||||
base64 = "0.13"
|
||||
bincode = "1.3.3"
|
||||
pleco = "0.5"
|
||||
serde = {version = "1.0", features = ["derive"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
uqbar_process_lib = { git = "ssh://git@github.com/uqbar-dao/process_lib.git", rev = "5e1b94a" }
|
||||
wit-bindgen = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "5390bab780733f1660d14c254ec985df2816bf1d" }
|
||||
url = "*"
|
||||
uqbar_process_lib = { git = "ssh://git@github.com/uqbar-dao/process_lib.git", rev = "65e07e4" }
|
||||
wit-bindgen = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "efcc759" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -2,11 +2,14 @@
|
||||
{
|
||||
"process_name": "chess",
|
||||
"process_wasm_path": "/chess.wasm",
|
||||
"on_panic": "Restart",
|
||||
"on_exit": "Restart",
|
||||
"request_networking": true,
|
||||
"request_messaging": [
|
||||
"net:sys:uqbar"
|
||||
],
|
||||
"grant_messaging": [
|
||||
"http_server:sys:uqbar"
|
||||
],
|
||||
"public": false
|
||||
"public": true
|
||||
}
|
||||
]
|
||||
|
@ -1,39 +1,45 @@
|
||||
#![feature(let_chains)]
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
extern crate base64;
|
||||
extern crate pleco;
|
||||
use pleco::Board;
|
||||
use uqbar_process_lib::uqbar::process::standard as wit;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use uqbar_process_lib::{
|
||||
get_payload, get_typed_state, grant_messaging, http, println, receive, set_state, Address,
|
||||
Message, Payload, ProcessId, Request, Response,
|
||||
await_message, call_init, get_payload, get_typed_state, http, println, set_state, Address,
|
||||
Message, NodeId, Payload, Request, Response,
|
||||
};
|
||||
extern crate base64;
|
||||
|
||||
mod utils;
|
||||
// Lazy way to include our static files in the binary. We'll use these to serve
|
||||
// our chess app's frontend.
|
||||
const CHESS_HTML: &str = include_str!("../pkg/chess.html");
|
||||
const CHESS_JS: &str = include_str!("../pkg/index.js");
|
||||
const CHESS_CSS: &str = include_str!("../pkg/index.css");
|
||||
|
||||
wit_bindgen::generate!({
|
||||
path: "../../wit",
|
||||
world: "process",
|
||||
exports: {
|
||||
world: Component,
|
||||
},
|
||||
});
|
||||
//
|
||||
// Our "chess protocol" request/response format. We'll always serialize these
|
||||
// to a byte vector and send them over IPC.
|
||||
//
|
||||
|
||||
struct Component;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Game {
|
||||
pub id: String, // the node with whom we are playing
|
||||
pub turns: u64,
|
||||
pub board: Board,
|
||||
pub white: String,
|
||||
pub black: String,
|
||||
pub ended: bool,
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
enum ChessRequest {
|
||||
NewGame { white: String, black: String },
|
||||
Move { game_id: String, move_str: String },
|
||||
Resign(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
enum ChessResponse {
|
||||
NewGameAccepted,
|
||||
NewGameRejected,
|
||||
MoveAccepted,
|
||||
MoveRejected,
|
||||
}
|
||||
|
||||
//
|
||||
// Our serializable state format.
|
||||
//
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct StoredGame {
|
||||
struct Game {
|
||||
pub id: String, // the node with whom we are playing
|
||||
pub turns: u64,
|
||||
pub board: String,
|
||||
@ -42,280 +48,408 @@ pub struct StoredGame {
|
||||
pub ended: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ChessState {
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct ChessState {
|
||||
pub games: HashMap<String, Game>, // game is by opposing player id
|
||||
pub records: HashMap<String, (u64, u64, u64)>, // wins, losses, draws
|
||||
pub clients: HashSet<u32>, // doesn't get persisted
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct StoredChessState {
|
||||
pub games: HashMap<String, StoredGame>, // game is by opposing player id
|
||||
pub records: HashMap<String, (u64, u64, u64)>, // wins, losses, draws
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct StoredChessState {
|
||||
pub games: HashMap<String, Game>, // game is by opposing player id
|
||||
}
|
||||
|
||||
const CHESS_PAGE: &str = include_str!("../pkg/chess.html");
|
||||
const CHESS_JS: &str = include_str!("../pkg/index.js");
|
||||
const CHESS_CSS: &str = include_str!("../pkg/index.css");
|
||||
fn save_chess_state(state: &ChessState) {
|
||||
set_state(&bincode::serialize(&state.games).unwrap());
|
||||
}
|
||||
|
||||
impl Guest for Component {
|
||||
fn init(our: String) {
|
||||
let our = Address::from_str(&our).unwrap();
|
||||
println!("{our}: start");
|
||||
fn load_chess_state() -> ChessState {
|
||||
match get_typed_state(|bytes| Ok(bincode::deserialize::<HashMap<String, Game>>(bytes)?)) {
|
||||
Some(games) => ChessState {
|
||||
games,
|
||||
clients: HashSet::new(),
|
||||
},
|
||||
None => ChessState {
|
||||
games: HashMap::new(),
|
||||
clients: HashSet::new(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
grant_messaging(
|
||||
&our,
|
||||
vec![ProcessId::new(Some("http_server"), "sys", "uqbar")],
|
||||
);
|
||||
fn send_ws_update(our: &Address, game: &Game, open_channels: &HashSet<u32>) -> anyhow::Result<()> {
|
||||
for channel in open_channels {
|
||||
Request::new()
|
||||
.target((&our.node, "http_server", "sys", "uqbar"))
|
||||
.ipc(serde_json::to_vec(
|
||||
&http::HttpServerAction::WebSocketPush {
|
||||
channel_id: *channel,
|
||||
message_type: http::WsMessageType::Binary,
|
||||
},
|
||||
)?)
|
||||
.payload(Payload {
|
||||
mime: Some("application/json".to_string()),
|
||||
bytes: serde_json::json!({
|
||||
"kind": "game_update",
|
||||
"data": game,
|
||||
})
|
||||
.to_string()
|
||||
.into_bytes(),
|
||||
})
|
||||
.send()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// serve static page at /
|
||||
// dynamically handle requests to /games
|
||||
http::bind_http_static_path(
|
||||
"/",
|
||||
true,
|
||||
false,
|
||||
Some("text/html".to_string()),
|
||||
CHESS_PAGE
|
||||
.replace("${node}", &our.node)
|
||||
.replace("${process}", &our.process.to_string())
|
||||
// TODO serve these independently on paths..
|
||||
// also build utils for just serving a vfs dir
|
||||
.replace("${js}", CHESS_JS)
|
||||
.replace("${css}", CHESS_CSS)
|
||||
.as_bytes()
|
||||
.to_vec(),
|
||||
)
|
||||
.unwrap();
|
||||
http::bind_http_path("/games", true, false).unwrap();
|
||||
// Boilerplate: generate the wasm bindings for an Uqbar app
|
||||
wit_bindgen::generate!({
|
||||
path: "../../wit",
|
||||
world: "process",
|
||||
exports: {
|
||||
world: Component,
|
||||
},
|
||||
});
|
||||
// After generating bindings, use this macro to define the Component struct
|
||||
// and its init() function, which the kernel will look for on startup.
|
||||
call_init!(initialize);
|
||||
|
||||
let mut state: ChessState = match get_typed_state(|bytes| {
|
||||
Ok(bincode::deserialize::<StoredChessState>(bytes)?)
|
||||
}) {
|
||||
Some(mut state) => ChessState {
|
||||
games: state
|
||||
.games
|
||||
.iter_mut()
|
||||
.map(|(id, game)| {
|
||||
(
|
||||
id.clone(),
|
||||
Game {
|
||||
id: id.to_owned(),
|
||||
turns: game.turns,
|
||||
board: Board::from_fen(&game.board).unwrap_or(Board::start_pos()),
|
||||
white: game.white.to_owned(),
|
||||
black: game.black.to_owned(),
|
||||
ended: game.ended,
|
||||
},
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
records: state.records,
|
||||
},
|
||||
None => ChessState {
|
||||
games: HashMap::new(),
|
||||
records: HashMap::new(),
|
||||
},
|
||||
};
|
||||
fn initialize(our: Address) {
|
||||
// A little printout to show in terminal that the process has started.
|
||||
println!("{} by {}: start", our.process(), our.publisher());
|
||||
|
||||
loop {
|
||||
let Ok((source, message)) = receive() else {
|
||||
println!("chess: got network error");
|
||||
// serve static page at /index.html, /index.js, /index.css
|
||||
// dynamically handle requests to /games
|
||||
http::bind_http_static_path(
|
||||
"/",
|
||||
true, // only serve for ourselves
|
||||
false, // can access remotely
|
||||
Some("text/html".to_string()),
|
||||
CHESS_HTML
|
||||
.replace("${node}", &our.node)
|
||||
.replace("${process}", &our.process.to_string())
|
||||
.as_bytes()
|
||||
.to_vec(),
|
||||
)
|
||||
.unwrap();
|
||||
http::bind_http_static_path(
|
||||
"/index.js",
|
||||
true,
|
||||
false,
|
||||
Some("text/javascript".to_string()),
|
||||
CHESS_JS.as_bytes().to_vec(),
|
||||
)
|
||||
.unwrap();
|
||||
http::bind_http_static_path(
|
||||
"/index.css",
|
||||
true,
|
||||
false,
|
||||
Some("text/css".to_string()),
|
||||
CHESS_CSS.as_bytes().to_vec(),
|
||||
)
|
||||
.unwrap();
|
||||
http::bind_http_path("/games", true, false).unwrap();
|
||||
// Allow websockets to be opened at / (our process ID will be prepended).
|
||||
http::bind_ws_path("/", true, false).unwrap();
|
||||
|
||||
// Grab our state, then enter the main event loop.
|
||||
let mut state: ChessState = load_chess_state();
|
||||
main_loop(&our, &mut state);
|
||||
}
|
||||
|
||||
fn main_loop(our: &Address, state: &mut ChessState) {
|
||||
loop {
|
||||
// Call await_message() to wait for any incoming messages.
|
||||
// If we get a network error, make a print and throw it away.
|
||||
// In a high-quality consumer-grade app, we'd want to explicitly handle
|
||||
// this and surface it to the user.
|
||||
match await_message() {
|
||||
Err(send_error) => {
|
||||
println!("{our}: got network error: {send_error:?}");
|
||||
continue;
|
||||
};
|
||||
let Message::Request(request) = message else {
|
||||
println!("chess: got unexpected Response");
|
||||
continue;
|
||||
};
|
||||
match handle_request(&our, &source, &request, &mut state) {
|
||||
Ok(()) => continue,
|
||||
Err(e) => println!("chess: error handling request: {:?}", e),
|
||||
}
|
||||
Ok(message) => match handle_request(&our, &message, state) {
|
||||
Ok(()) => continue,
|
||||
Err(e) => println!("{our}: error handling request: {:?}", e),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_request(
|
||||
our: &Address,
|
||||
source: &Address,
|
||||
request: &wit::Request,
|
||||
state: &mut ChessState,
|
||||
) -> anyhow::Result<()> {
|
||||
if source.process == "chess:chess:uqbar" {
|
||||
let message_json = serde_json::from_slice::<serde_json::Value>(&request.ipc)?;
|
||||
handle_chess_request(our, source, message_json, state)
|
||||
} else if source.process.to_string() == "http_server:sys:uqbar" {
|
||||
let http_request = serde_json::from_slice::<http::IncomingHttpRequest>(&request.ipc)?;
|
||||
handle_http_request(our, http_request, state)
|
||||
/// Handle chess protocol messages from ourself *or* other nodes.
|
||||
fn handle_request(our: &Address, message: &Message, state: &mut ChessState) -> anyhow::Result<()> {
|
||||
// Throw away responses. We never expect any responses *here*, because for every
|
||||
// chess protocol request, we *await* its response in-place. This is appropriate
|
||||
// for direct node<>node comms, less appropriate for other circumstances...
|
||||
if !message.is_request() {
|
||||
return Ok(());
|
||||
}
|
||||
// If the request is from another node, handle it as an incoming request.
|
||||
// Note that we can enforce the ProcessId as well, but it shouldn't be a trusted
|
||||
// piece of information, since another node can easily spoof any ProcessId on a request.
|
||||
// It can still be useful simply as a protocol-level switch to handle different kinds of
|
||||
// requests from the same node, with the knowledge that the remote node can finagle with
|
||||
// which ProcessId a given message can be from. It's their code, after all.
|
||||
if message.source().node != our.node {
|
||||
// Deserialize the request IPC to our format, and throw it away if it
|
||||
// doesn't fit.
|
||||
let Ok(chess_request) = serde_json::from_slice::<ChessRequest>(message.ipc()) else {
|
||||
return Err(anyhow::anyhow!("invalid chess request"));
|
||||
};
|
||||
handle_chess_request(our, &message.source().node, state, &chess_request)
|
||||
// ...and if the request is from ourselves, handle it as our own!
|
||||
// Note that since this is a local request, we *can* trust the ProcessId.
|
||||
// Here, we'll accept messages from the local terminal so as to make this a "CLI" app.
|
||||
} else if message.source().node == our.node
|
||||
&& message.source().process == "terminal:terminal:uqbar"
|
||||
{
|
||||
let Ok(chess_request) = serde_json::from_slice::<ChessRequest>(message.ipc()) else {
|
||||
return Err(anyhow::anyhow!("invalid chess request"));
|
||||
};
|
||||
handle_local_request(our, state, &chess_request)
|
||||
} else if message.source().node == our.node
|
||||
&& message.source().process == "http_server:sys:uqbar"
|
||||
{
|
||||
// receive HTTP requests and websocket connection messages from our server
|
||||
match serde_json::from_slice::<http::HttpServerRequest>(message.ipc())? {
|
||||
http::HttpServerRequest::Http(ref incoming) => {
|
||||
match handle_http_request(our, state, incoming) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(e) => {
|
||||
println!("chess: error handling http request: {:?}", e);
|
||||
http::send_response(
|
||||
http::StatusCode::SERVICE_UNAVAILABLE,
|
||||
None,
|
||||
"Service Unavailable".to_string().as_bytes().to_vec(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
http::HttpServerRequest::WebSocketOpen { path, channel_id } => {
|
||||
// We know this is authenticated and unencrypted because we only
|
||||
// bound one path, the root path. So we know that client
|
||||
// frontend opened a websocket and can send updates
|
||||
state.clients.insert(channel_id);
|
||||
Ok(())
|
||||
}
|
||||
http::HttpServerRequest::WebSocketClose(channel_id) => {
|
||||
// client frontend closed a websocket
|
||||
state.clients.remove(&channel_id);
|
||||
Ok(())
|
||||
}
|
||||
http::HttpServerRequest::WebSocketPush { .. } => {
|
||||
// client frontend sent a websocket message
|
||||
// we don't expect this! we only use websockets to push updates
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(anyhow::anyhow!("chess: got request from unexpected source"));
|
||||
// If we get a request from ourselves that isn't from the terminal, we'll just
|
||||
// throw it away. This is a good place to put a printout to show that we've
|
||||
// received a request from ourselves that we don't know how to handle.
|
||||
return Err(anyhow::anyhow!(
|
||||
"got request from not-the-terminal, ignoring"
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle chess protocol messages from other nodes.
|
||||
fn handle_chess_request(
|
||||
our: &Address,
|
||||
source: &Address,
|
||||
message_json: serde_json::Value,
|
||||
source_node: &NodeId,
|
||||
state: &mut ChessState,
|
||||
action: &ChessRequest,
|
||||
) -> anyhow::Result<()> {
|
||||
let action = message_json["action"].as_str().unwrap_or("");
|
||||
let game_id = &source.node;
|
||||
println!("chess: handling action from {source_node}: {action:?}");
|
||||
|
||||
// For simplicity's sake, we'll just use the node we're playing with as the game id.
|
||||
// This limits us to one active game per partner.
|
||||
let game_id = source_node;
|
||||
|
||||
match action {
|
||||
"new_game" => {
|
||||
// make a new game with source.node if the current game has ended
|
||||
if let Some(game) = state.games.get(game_id) {
|
||||
if !game.ended {
|
||||
return Response::new()
|
||||
.ipc(vec![])
|
||||
.payload(Payload {
|
||||
mime: Some("application/octet-stream".to_string()),
|
||||
bytes: "conflict".as_bytes().to_vec(),
|
||||
})
|
||||
.send();
|
||||
}
|
||||
ChessRequest::NewGame { white, black } => {
|
||||
// Make a new game with source.node
|
||||
// This will replace any existing game with source.node!
|
||||
if state.games.contains_key(game_id) {
|
||||
println!("chess: resetting game with {game_id} on their request!");
|
||||
}
|
||||
let game = Game {
|
||||
id: game_id.to_string(),
|
||||
turns: 0,
|
||||
board: Board::start_pos(),
|
||||
white: message_json["white"]
|
||||
.as_str()
|
||||
.unwrap_or(game_id)
|
||||
.to_string(),
|
||||
black: message_json["black"]
|
||||
.as_str()
|
||||
.unwrap_or(&our.node)
|
||||
.to_string(),
|
||||
board: Board::start_pos().fen(),
|
||||
white: white.to_string(),
|
||||
black: black.to_string(),
|
||||
ended: false,
|
||||
};
|
||||
state.games.insert(game_id.to_string(), game.clone());
|
||||
|
||||
utils::send_ws_update(&our, &game)?;
|
||||
utils::save_chess_state(&state);
|
||||
|
||||
// Use our helper function to persist state after every action.
|
||||
// The simplest and most trivial way to keep state. You'll want to
|
||||
// use a database or something in a real app, and consider performance
|
||||
// when doing intensive data-based operations.
|
||||
send_ws_update(&our, &game, &state.clients)?;
|
||||
state.games.insert(game_id.to_string(), game);
|
||||
save_chess_state(&state);
|
||||
// Send a response to tell them we've accepted the game.
|
||||
// Remember, the other player is waiting for this.
|
||||
Response::new()
|
||||
.ipc(vec![])
|
||||
.payload(Payload {
|
||||
mime: Some("application/octet-stream".to_string()),
|
||||
bytes: "success".as_bytes().to_vec(),
|
||||
})
|
||||
.ipc(serde_json::to_vec(&ChessResponse::NewGameAccepted)?)
|
||||
.send()
|
||||
}
|
||||
"make_move" => {
|
||||
// check the move and then update if correct and send WS update
|
||||
ChessRequest::Move { ref move_str, .. } => {
|
||||
// Get the associated game, and respond with an error if
|
||||
// we don't have it in our state.
|
||||
let Some(game) = state.games.get_mut(game_id) else {
|
||||
// If we don't have a game with them, reject the move.
|
||||
return Response::new()
|
||||
.ipc(vec![])
|
||||
.payload(Payload {
|
||||
mime: Some("application/octet-stream".to_string()),
|
||||
bytes: "not found".as_bytes().to_vec(),
|
||||
})
|
||||
.ipc(serde_json::to_vec(&ChessResponse::MoveRejected)?)
|
||||
.send();
|
||||
};
|
||||
let valid_move = game
|
||||
.board
|
||||
.apply_uci_move(message_json["move"].as_str().unwrap_or(""));
|
||||
if valid_move {
|
||||
game.turns += 1;
|
||||
let checkmate = game.board.checkmate();
|
||||
let draw = game.board.stalemate();
|
||||
|
||||
if checkmate || draw {
|
||||
// Convert the saved board to one we can manipulate.
|
||||
let mut board = Board::from_fen(&game.board).unwrap();
|
||||
if !board.apply_uci_move(move_str) {
|
||||
// Reject invalid moves!
|
||||
return Response::new()
|
||||
.ipc(serde_json::to_vec(&ChessResponse::MoveRejected)?)
|
||||
.send();
|
||||
}
|
||||
game.turns += 1;
|
||||
if board.checkmate() || board.stalemate() {
|
||||
game.ended = true;
|
||||
}
|
||||
// Persist state.
|
||||
game.board = board.fen();
|
||||
send_ws_update(&our, &game, &state.clients)?;
|
||||
save_chess_state(&state);
|
||||
// Send a response to tell them we've accepted the move.
|
||||
Response::new()
|
||||
.ipc(serde_json::to_vec(&ChessResponse::MoveAccepted)?)
|
||||
.send()
|
||||
}
|
||||
ChessRequest::Resign(_) => {
|
||||
// They've resigned. The sender isn't waiting for a response to this,
|
||||
// so we don't need to send one.
|
||||
match state.games.get_mut(game_id) {
|
||||
Some(game) => {
|
||||
game.ended = true;
|
||||
let winner = if checkmate {
|
||||
if game.turns % 2 == 1 {
|
||||
game.white.clone()
|
||||
} else {
|
||||
game.black.clone()
|
||||
}
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
|
||||
// update the records
|
||||
if draw {
|
||||
if let Some(record) = state.records.get_mut(&game.id) {
|
||||
record.2 += 1;
|
||||
} else {
|
||||
state.records.insert(game.id.clone(), (0, 0, 1));
|
||||
}
|
||||
} else {
|
||||
if let Some(record) = state.records.get_mut(&game.id) {
|
||||
if winner == our.node {
|
||||
record.0 += 1;
|
||||
} else {
|
||||
record.1 += 1;
|
||||
}
|
||||
} else {
|
||||
if winner == our.node {
|
||||
state.records.insert(game.id.clone(), (1, 0, 0));
|
||||
} else {
|
||||
state.records.insert(game.id.clone(), (0, 1, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
send_ws_update(&our, &game, &state.clients)?;
|
||||
save_chess_state(&state);
|
||||
}
|
||||
|
||||
utils::send_ws_update(&our, &game)?;
|
||||
utils::save_chess_state(&state);
|
||||
|
||||
Response::new()
|
||||
.ipc(vec![])
|
||||
.payload(Payload {
|
||||
mime: Some("application/octet-stream".to_string()),
|
||||
bytes: "success".as_bytes().to_vec(),
|
||||
})
|
||||
.send()
|
||||
} else {
|
||||
Response::new()
|
||||
.ipc(vec![])
|
||||
.payload(Payload {
|
||||
mime: Some("application/octet-stream".to_string()),
|
||||
bytes: "invalid move".as_bytes().to_vec(),
|
||||
})
|
||||
.send()
|
||||
None => {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
"end_game" => {
|
||||
// end the game and send WS update, update the standings
|
||||
let Some(game) = state.games.get_mut(game_id) else {
|
||||
return Response::new()
|
||||
.ipc(vec![])
|
||||
.payload(Payload {
|
||||
mime: Some("application/octet-stream".to_string()),
|
||||
bytes: "not found".as_bytes().to_vec(),
|
||||
})
|
||||
.send();
|
||||
};
|
||||
|
||||
game.ended = true;
|
||||
|
||||
if let Some(record) = state.records.get_mut(&game.id) {
|
||||
record.0 += 1;
|
||||
} else {
|
||||
state.records.insert(game.id.clone(), (1, 0, 0));
|
||||
}
|
||||
|
||||
utils::send_ws_update(&our, &game)?;
|
||||
utils::save_chess_state(&state);
|
||||
|
||||
Response::new()
|
||||
.ipc(vec![])
|
||||
.payload(Payload {
|
||||
mime: Some("application/octet-stream".to_string()),
|
||||
bytes: "success".as_bytes().to_vec(),
|
||||
})
|
||||
.send()
|
||||
}
|
||||
_ => return Err(anyhow::anyhow!("chess: got unexpected action")),
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle actions we are performing. Here's where we'll send_and_await various requests.
|
||||
fn handle_local_request(
|
||||
our: &Address,
|
||||
state: &mut ChessState,
|
||||
action: &ChessRequest,
|
||||
) -> anyhow::Result<()> {
|
||||
match action {
|
||||
ChessRequest::NewGame { white, black } => {
|
||||
// Create a new game. We'll enforce that one of the two players is us.
|
||||
if white != &our.node && black != &our.node {
|
||||
return Err(anyhow::anyhow!("cannot start a game without us!"));
|
||||
}
|
||||
let game_id = if white == &our.node { black } else { white };
|
||||
// If we already have a game with this player, throw an error.
|
||||
if let Some(game) = state.games.get(game_id)
|
||||
&& !game.ended
|
||||
{
|
||||
return Err(anyhow::anyhow!("already have a game with {game_id}"));
|
||||
};
|
||||
// Send the other player a NewGame request
|
||||
// The request is exactly the same as what we got from terminal.
|
||||
// We'll give them 5 seconds to respond...
|
||||
let Ok(Message::Response { ref ipc, .. }) = Request::new()
|
||||
.target((game_id.as_ref(), our.process.clone()))
|
||||
.ipc(serde_json::to_vec(&action)?)
|
||||
.send_and_await_response(5)?
|
||||
else {
|
||||
return Err(anyhow::anyhow!(
|
||||
"other player did not respond properly to new game request"
|
||||
));
|
||||
};
|
||||
// If they accept, create a new game -- otherwise, error out.
|
||||
if serde_json::from_slice::<ChessResponse>(ipc)? != ChessResponse::NewGameAccepted {
|
||||
return Err(anyhow::anyhow!("other player rejected new game request!"));
|
||||
}
|
||||
// New game with default board.
|
||||
let game = Game {
|
||||
id: game_id.to_string(),
|
||||
turns: 0,
|
||||
board: Board::start_pos().fen(),
|
||||
white: white.to_string(),
|
||||
black: black.to_string(),
|
||||
ended: false,
|
||||
};
|
||||
state.games.insert(game_id.to_string(), game);
|
||||
save_chess_state(&state);
|
||||
Ok(())
|
||||
}
|
||||
ChessRequest::Move { game_id, move_str } => {
|
||||
// Make a move. We'll enforce that it's our turn. The game_id is the
|
||||
// person we're playing with.
|
||||
let Some(game) = state.games.get_mut(game_id) else {
|
||||
return Err(anyhow::anyhow!("no game with {game_id}"));
|
||||
};
|
||||
if (game.turns % 2 == 0 && game.white != our.node)
|
||||
|| (game.turns % 2 == 1 && game.black != our.node)
|
||||
{
|
||||
return Err(anyhow::anyhow!("not our turn!"));
|
||||
} else if game.ended {
|
||||
return Err(anyhow::anyhow!("that game is over!"));
|
||||
}
|
||||
let mut board = Board::from_fen(&game.board).unwrap();
|
||||
if !board.apply_uci_move(move_str) {
|
||||
return Err(anyhow::anyhow!("illegal move!"));
|
||||
}
|
||||
// Send the move to the other player, then check if the game is over.
|
||||
// The request is exactly the same as what we got from terminal.
|
||||
// We'll give them 5 seconds to respond...
|
||||
let Ok(Message::Response { ref ipc, .. }) = Request::new()
|
||||
.target((game_id.as_ref(), our.process.clone()))
|
||||
.ipc(serde_json::to_vec(&action)?)
|
||||
.send_and_await_response(5)?
|
||||
else {
|
||||
return Err(anyhow::anyhow!(
|
||||
"other player did not respond properly to our move"
|
||||
));
|
||||
};
|
||||
if serde_json::from_slice::<ChessResponse>(ipc)? != ChessResponse::MoveAccepted {
|
||||
return Err(anyhow::anyhow!("other player rejected our move"));
|
||||
}
|
||||
game.turns += 1;
|
||||
if board.checkmate() || board.stalemate() {
|
||||
game.ended = true;
|
||||
}
|
||||
game.board = board.fen();
|
||||
save_chess_state(&state);
|
||||
Ok(())
|
||||
}
|
||||
ChessRequest::Resign(ref with_who) => {
|
||||
// Resign from a game with a given player.
|
||||
let Some(game) = state.games.get_mut(with_who) else {
|
||||
return Err(anyhow::anyhow!("no game with {with_who}"));
|
||||
};
|
||||
// send the other player an end game request -- no response expected
|
||||
Request::new()
|
||||
.target((with_who.as_ref(), our.process.clone()))
|
||||
.ipc(serde_json::to_vec(&action)?)
|
||||
.send()?;
|
||||
game.ended = true;
|
||||
save_chess_state(&state);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle HTTP requests from our own frontend.
|
||||
fn handle_http_request(
|
||||
our: &Address,
|
||||
http_request: http::IncomingHttpRequest,
|
||||
state: &mut ChessState,
|
||||
http_request: &http::IncomingHttpRequest,
|
||||
) -> anyhow::Result<()> {
|
||||
if http_request.path()? != "/games" {
|
||||
if http_request.path()? != "games" {
|
||||
return http::send_response(
|
||||
http::StatusCode::NOT_FOUND,
|
||||
None,
|
||||
@ -323,20 +457,17 @@ fn handle_http_request(
|
||||
);
|
||||
}
|
||||
match http_request.method.as_str() {
|
||||
// on GET: give the frontend all of our active games
|
||||
"GET" => http::send_response(
|
||||
http::StatusCode::OK,
|
||||
Some(HashMap::from([(
|
||||
String::from("Content-Type"),
|
||||
String::from("application/json"),
|
||||
)])),
|
||||
serde_json::to_vec(&serde_json::json!(state
|
||||
.games
|
||||
.iter()
|
||||
.map(|(id, game)| (id.to_string(), utils::json_game(game)))
|
||||
.collect::<HashMap<String, serde_json::Value>>()))?,
|
||||
serde_json::to_vec(&state.games)?,
|
||||
),
|
||||
// on POST: create a new game
|
||||
"POST" => {
|
||||
// create a new game
|
||||
let Some(payload) = get_payload() else {
|
||||
return http::send_response(http::StatusCode::BAD_REQUEST, None, vec![]);
|
||||
};
|
||||
@ -360,38 +491,36 @@ fn handle_http_request(
|
||||
.to_string();
|
||||
|
||||
// send the other player a new game request
|
||||
let response = Request::new()
|
||||
.target((game_id, "chess", "chess", "uqbar"))
|
||||
.ipc(serde_json::to_vec(&serde_json::json!({
|
||||
"action": "new_game",
|
||||
"white": player_white.clone(),
|
||||
"black": player_black.clone(),
|
||||
}))?)
|
||||
.send_and_await_response(30)?;
|
||||
let Ok(msg) = Request::new()
|
||||
.target((game_id, our.process.clone()))
|
||||
.ipc(serde_json::to_vec(&ChessRequest::NewGame {
|
||||
white: player_white.clone(),
|
||||
black: player_black.clone(),
|
||||
})?)
|
||||
.send_and_await_response(5)?
|
||||
else {
|
||||
return Err(anyhow::anyhow!(
|
||||
"other player did not respond properly to new game request"
|
||||
));
|
||||
};
|
||||
// if they accept, create a new game
|
||||
// otherwise, should surface error to FE...
|
||||
let Ok((_source, Message::Response((resp, _context)))) = response else {
|
||||
return http::send_response(
|
||||
http::StatusCode::SERVICE_UNAVAILABLE,
|
||||
None,
|
||||
"Service Unavailable".to_string().as_bytes().to_vec(),
|
||||
);
|
||||
};
|
||||
if resp.ipc != "success".as_bytes() {
|
||||
return http::send_response(http::StatusCode::SERVICE_UNAVAILABLE, None, vec![]);
|
||||
if serde_json::from_slice::<ChessResponse>(msg.ipc())? != ChessResponse::NewGameAccepted
|
||||
{
|
||||
return Err(anyhow::anyhow!("other player rejected new game request"));
|
||||
}
|
||||
// create a new game
|
||||
let game = Game {
|
||||
id: game_id.to_string(),
|
||||
turns: 0,
|
||||
board: Board::start_pos(),
|
||||
board: Board::start_pos().fen(),
|
||||
white: player_white,
|
||||
black: player_black,
|
||||
ended: false,
|
||||
};
|
||||
let body = serde_json::to_vec(&utils::json_game(&game))?;
|
||||
let body = serde_json::to_vec(&game)?;
|
||||
state.games.insert(game_id.to_string(), game);
|
||||
utils::save_chess_state(&state);
|
||||
save_chess_state(&state);
|
||||
http::send_response(
|
||||
http::StatusCode::OK,
|
||||
Some(HashMap::from([(
|
||||
@ -401,8 +530,8 @@ fn handle_http_request(
|
||||
body,
|
||||
)
|
||||
}
|
||||
// on PUT: make a move
|
||||
"PUT" => {
|
||||
// make a move
|
||||
let Some(payload) = get_payload() else {
|
||||
return http::send_response(http::StatusCode::BAD_REQUEST, None, vec![]);
|
||||
};
|
||||
@ -420,71 +549,41 @@ fn handle_http_request(
|
||||
} else if game.ended {
|
||||
return http::send_response(http::StatusCode::CONFLICT, None, vec![]);
|
||||
}
|
||||
let move_str = payload_json["move"].as_str().unwrap_or("");
|
||||
if !game.board.apply_uci_move(move_str) {
|
||||
let Some(move_str) = payload_json["move"].as_str() else {
|
||||
return http::send_response(http::StatusCode::BAD_REQUEST, None, vec![]);
|
||||
};
|
||||
let mut board = Board::from_fen(&game.board).unwrap();
|
||||
if !board.apply_uci_move(move_str) {
|
||||
// TODO surface illegal move to player or something here
|
||||
return http::send_response(http::StatusCode::BAD_REQUEST, None, vec![]);
|
||||
}
|
||||
// send the move to the other player
|
||||
// check if the game is over
|
||||
// if so, update the records
|
||||
let response = Request::new()
|
||||
.target((game_id, "chess", "chess", "uqbar"))
|
||||
.ipc(serde_json::to_vec(&serde_json::json!({
|
||||
"action": "make_move",
|
||||
"move": move_str,
|
||||
}))?)
|
||||
.send_and_await_response(30)?;
|
||||
let Ok((_source, Message::Response((resp, _context)))) = response else {
|
||||
// TODO surface error to player, let them know other player is
|
||||
// offline or whatever they respond here was invalid
|
||||
return http::send_response(http::StatusCode::BAD_REQUEST, None, vec![]);
|
||||
let Ok(msg) = Request::new()
|
||||
.target((game_id, our.process.clone()))
|
||||
.ipc(serde_json::to_vec(&ChessRequest::Move {
|
||||
game_id: game_id.to_string(),
|
||||
move_str: move_str.to_string(),
|
||||
})?)
|
||||
.send_and_await_response(5)?
|
||||
else {
|
||||
return Err(anyhow::anyhow!(
|
||||
"other player did not respond properly to our move"
|
||||
));
|
||||
};
|
||||
if resp.ipc != "success".as_bytes() {
|
||||
return http::send_response(http::StatusCode::SERVICE_UNAVAILABLE, None, vec![]);
|
||||
if serde_json::from_slice::<ChessResponse>(msg.ipc())? != ChessResponse::MoveAccepted {
|
||||
return Err(anyhow::anyhow!("other player rejected our move"));
|
||||
}
|
||||
// update the game
|
||||
game.turns += 1;
|
||||
let checkmate = game.board.checkmate();
|
||||
let draw = game.board.stalemate();
|
||||
|
||||
if checkmate || draw {
|
||||
if board.checkmate() || board.stalemate() {
|
||||
game.ended = true;
|
||||
let winner = if checkmate {
|
||||
if game.turns % 2 == 1 {
|
||||
&game.white
|
||||
} else {
|
||||
&game.black
|
||||
}
|
||||
} else {
|
||||
""
|
||||
};
|
||||
// update the records
|
||||
if draw {
|
||||
if let Some(record) = state.records.get_mut(&game.id) {
|
||||
record.2 += 1;
|
||||
} else {
|
||||
state.records.insert(game.id.clone(), (0, 0, 1));
|
||||
}
|
||||
} else {
|
||||
if let Some(record) = state.records.get_mut(&game.id) {
|
||||
if winner == our.node {
|
||||
record.0 += 1;
|
||||
} else {
|
||||
record.1 += 1;
|
||||
}
|
||||
} else {
|
||||
if winner == our.node {
|
||||
state.records.insert(game.id.clone(), (1, 0, 0));
|
||||
} else {
|
||||
state.records.insert(game.id.clone(), (0, 1, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// game is not over, update state and return to FE
|
||||
let body = serde_json::to_vec(&utils::json_game(&game))?;
|
||||
utils::save_chess_state(&state);
|
||||
game.board = board.fen();
|
||||
// update state and return to FE
|
||||
let body = serde_json::to_vec(&game)?;
|
||||
save_chess_state(&state);
|
||||
// return the game
|
||||
http::send_response(
|
||||
http::StatusCode::OK,
|
||||
@ -495,41 +594,22 @@ fn handle_http_request(
|
||||
body,
|
||||
)
|
||||
}
|
||||
// on DELETE: end the game
|
||||
"DELETE" => {
|
||||
// "end the game"?
|
||||
let query_params = http_request.query_params()?;
|
||||
let Some(game_id) = query_params.get("id") else {
|
||||
let Some(game_id) = http_request.query_params.get("id") else {
|
||||
return http::send_response(http::StatusCode::BAD_REQUEST, None, vec![]);
|
||||
};
|
||||
let Some(game) = state.games.get_mut(game_id) else {
|
||||
return http::send_response(http::StatusCode::BAD_REQUEST, None, vec![]);
|
||||
};
|
||||
// send the other player an end game request
|
||||
let response = Request::new()
|
||||
.target((game_id, "chess", "chess", "uqbar"))
|
||||
.ipc(serde_json::to_vec(&serde_json::json!({
|
||||
"action": "end_game",
|
||||
}))?)
|
||||
.send_and_await_response(30)?;
|
||||
let Ok((_source, Message::Response((resp, _context)))) = response else {
|
||||
// TODO surface error to player, let them know other player is
|
||||
// offline or whatever they respond here was invalid
|
||||
return http::send_response(http::StatusCode::SERVICE_UNAVAILABLE, None, vec![]);
|
||||
};
|
||||
if resp.ipc != "success".as_bytes() {
|
||||
return http::send_response(http::StatusCode::SERVICE_UNAVAILABLE, None, vec![]);
|
||||
}
|
||||
|
||||
Request::new()
|
||||
.target((game_id.as_str(), our.process.clone()))
|
||||
.ipc(serde_json::to_vec(&ChessRequest::Resign(our.node.clone()))?)
|
||||
.send()?;
|
||||
game.ended = true;
|
||||
if let Some(record) = state.records.get_mut(&game.id) {
|
||||
record.1 += 1;
|
||||
} else {
|
||||
state.records.insert(game.id.clone(), (0, 1, 0));
|
||||
}
|
||||
// return the game
|
||||
let body = serde_json::to_vec(&utils::json_game(&game))?;
|
||||
utils::save_chess_state(&state);
|
||||
|
||||
let body = serde_json::to_vec(&game)?;
|
||||
save_chess_state(&state);
|
||||
http::send_response(
|
||||
http::StatusCode::OK,
|
||||
Some(HashMap::from([(
|
||||
@ -539,11 +619,7 @@ fn handle_http_request(
|
||||
body,
|
||||
)
|
||||
}
|
||||
_ => Response::new()
|
||||
.ipc(serde_json::to_vec(&http::HttpResponse {
|
||||
status: 405,
|
||||
headers: HashMap::new(),
|
||||
})?)
|
||||
.send(),
|
||||
// Any other method will be rejected.
|
||||
_ => http::send_response(http::StatusCode::METHOD_NOT_ALLOWED, None, vec![]),
|
||||
}
|
||||
}
|
||||
|
@ -1,82 +0,0 @@
|
||||
use crate::*;
|
||||
|
||||
pub fn save_chess_state(state: &ChessState) {
|
||||
let stored_state = convert_state(&state);
|
||||
set_state(&bincode::serialize(&stored_state).unwrap());
|
||||
}
|
||||
|
||||
fn convert_game(game: Game) -> StoredGame {
|
||||
StoredGame {
|
||||
id: game.id,
|
||||
turns: game.turns,
|
||||
board: game.board.fen(),
|
||||
white: game.white,
|
||||
black: game.black,
|
||||
ended: game.ended,
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_state(state: &ChessState) -> StoredChessState {
|
||||
StoredChessState {
|
||||
games: state
|
||||
.games
|
||||
.iter()
|
||||
.map(|(id, game)| (id.to_string(), convert_game(game.clone())))
|
||||
.collect(),
|
||||
records: state.records.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn json_game(game: &Game) -> serde_json::Value {
|
||||
serde_json::json!({
|
||||
"id": game.id,
|
||||
"turns": game.turns,
|
||||
"board": game.board.fen(),
|
||||
"white": game.white,
|
||||
"black": game.black,
|
||||
"ended": game.ended,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn send_ws_update(our: &Address, game: &Game) -> anyhow::Result<()> {
|
||||
Request::new()
|
||||
.target((&our.node, "http_server", "sys", "uqbar"))
|
||||
.ipc(
|
||||
serde_json::json!({
|
||||
"EncryptAndForward": {
|
||||
"channel_id": our.process.to_string(),
|
||||
"forward_to": {
|
||||
"node": our.node.clone(),
|
||||
"process": {
|
||||
"process_name": "http_server",
|
||||
"package_name": "sys",
|
||||
"publisher_node": "uqbar"
|
||||
}
|
||||
}, // node, process
|
||||
"json": Some(serde_json::json!({ // this is the JSON to forward
|
||||
"WebSocketPush": {
|
||||
"target": {
|
||||
"node": our.node.clone(),
|
||||
"id": "chess", // If the message passed in an ID then we could send to just that ID
|
||||
}
|
||||
}
|
||||
})),
|
||||
}
|
||||
|
||||
})
|
||||
.to_string()
|
||||
.as_bytes()
|
||||
.to_vec(),
|
||||
)
|
||||
.payload(Payload {
|
||||
mime: Some("application/json".to_string()),
|
||||
bytes: serde_json::json!({
|
||||
"kind": "game_update",
|
||||
"data": json_game(game),
|
||||
})
|
||||
.to_string()
|
||||
.as_bytes()
|
||||
.to_vec(),
|
||||
})
|
||||
.send()
|
||||
}
|
84
modules/homepage/Cargo.lock
generated
84
modules/homepage/Cargo.lock
generated
@ -58,9 +58,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.10"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
|
||||
checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
@ -69,9 +69,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.2"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156"
|
||||
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
@ -134,9 +134,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.9"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
|
||||
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
|
||||
|
||||
[[package]]
|
||||
name = "leb128"
|
||||
@ -146,9 +146,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.150"
|
||||
version = "0.2.151"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
|
||||
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
@ -170,9 +170,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.69"
|
||||
version = "1.0.70"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
|
||||
checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@ -218,9 +218,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.15"
|
||||
version = "1.0.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
|
||||
checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
@ -230,18 +230,18 @@ checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.191"
|
||||
version = "1.0.193"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a834c4821019838224821468552240d4d95d14e751986442c816572d39a080c9"
|
||||
checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.191"
|
||||
version = "1.0.193"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46fa52d5646bce91b680189fe5b1c049d2ea38dabb4e2e7c8d00ca12cfbfbcfd"
|
||||
checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -261,9 +261,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.11.1"
|
||||
version = "1.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a"
|
||||
checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
|
||||
|
||||
[[package]]
|
||||
name = "spdx"
|
||||
@ -276,9 +276,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.39"
|
||||
version = "2.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
|
||||
checksum = "13fa70a4ee923979ffb522cacce59d34421ebdea5625e1073c4326ef9d2dd42e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -322,9 +322,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.13"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
|
||||
checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
@ -355,8 +355,8 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
||||
|
||||
[[package]]
|
||||
name = "uqbar_process_lib"
|
||||
version = "0.3.0"
|
||||
source = "git+ssh://git@github.com/uqbar-dao/process_lib.git?rev=5e1b94a#5e1b94ae2f85c66da33ec52117a72b90d53c4d22"
|
||||
version = "0.4.0"
|
||||
source = "git+ssh://git@github.com/uqbar-dao/process_lib.git?rev=1ce0d41#1ce0d412169e795c2a99464563b42ae2a2628d77"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
@ -388,18 +388,18 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-encoder"
|
||||
version = "0.36.2"
|
||||
version = "0.38.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "822b645bf4f2446b949776ffca47e2af60b167209ffb70814ef8779d299cd421"
|
||||
checksum = "0ad2b51884de9c7f4fe2fd1043fccb8dcad4b1e29558146ee57a144d15779f3f"
|
||||
dependencies = [
|
||||
"leb128",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-metadata"
|
||||
version = "0.10.11"
|
||||
version = "0.10.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2167ce53b2faa16a92c6cafd4942cff16c9a4fa0c5a5a0a41131ee4e49fc055f"
|
||||
checksum = "d835d67708f6374937c550ad8dd1d17c616ae009e3f00d7a0ac9f7825e78c36a"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"indexmap",
|
||||
@ -413,9 +413,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.116.1"
|
||||
version = "0.118.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a58e28b80dd8340cb07b8242ae654756161f6fc8d0038123d679b7b99964fa50"
|
||||
checksum = "95ee9723b928e735d53000dec9eae7b07a60e490c85ab54abb66659fc61bfcd9"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"semver",
|
||||
@ -423,8 +423,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.13.1"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=efcc759#efcc7592cf3277bcb9be1034e48569c6d822b322"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"wit-bindgen-rust-macro",
|
||||
@ -432,8 +432,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-core"
|
||||
version = "0.13.1"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=efcc759#efcc7592cf3277bcb9be1034e48569c6d822b322"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"wit-component",
|
||||
@ -442,8 +442,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust"
|
||||
version = "0.13.2"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=efcc759#efcc7592cf3277bcb9be1034e48569c6d822b322"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"heck",
|
||||
@ -454,8 +454,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust-macro"
|
||||
version = "0.13.1"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=efcc759#efcc7592cf3277bcb9be1034e48569c6d822b322"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"proc-macro2",
|
||||
@ -468,9 +468,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-component"
|
||||
version = "0.17.0"
|
||||
version = "0.18.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "480cc1a078b305c1b8510f7c455c76cbd008ee49935f3a6c5fd5e937d8d95b1e"
|
||||
checksum = "5b8a35a2a9992898c9d27f1664001860595a4bc99d32dd3599d547412e17d7e2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags",
|
||||
@ -487,9 +487,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-parser"
|
||||
version = "0.12.2"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43771ee863a16ec4ecf9da0fc65c3bbd4a1235c8e3da5f094b562894843dfa76"
|
||||
checksum = "15df6b7b28ce94b8be39d8df5cb21a08a4f3b9f33b631aedb4aa5776f785ead3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"id-arena",
|
||||
|
@ -13,10 +13,10 @@ lto = true
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
bincode = "1.3.3"
|
||||
serde = {version = "1.0", features = ["derive"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
uqbar_process_lib = { git = "ssh://git@github.com/uqbar-dao/process_lib.git", rev = "5e1b94a" }
|
||||
wit-bindgen = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "5390bab780733f1660d14c254ec985df2816bf1d" }
|
||||
uqbar_process_lib = { git = "ssh://git@github.com/uqbar-dao/process_lib.git", rev = "1ce0d41" }
|
||||
wit-bindgen = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "efcc759" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
@ -2,7 +2,7 @@
|
||||
{
|
||||
"process_name": "homepage",
|
||||
"process_wasm_path": "/homepage.wasm",
|
||||
"on_panic": "Restart",
|
||||
"on_exit": "Restart",
|
||||
"request_networking": false,
|
||||
"request_messaging": [
|
||||
"http_bindings:http_bindings:uqbar",
|
||||
|
@ -196,7 +196,7 @@
|
||||
|
||||
<h4>Apps:</h4>
|
||||
<!-- <a id="file-transfer" href="/file-transfer">File Transfer</a> -->
|
||||
<a id="chess" href="/chess:chess:uqbar/">Chess [NOT WORKING]</a>
|
||||
<a id="chess" href="/chess:chess:uqbar/">Chess</a>
|
||||
</div>
|
||||
<script>window.ourName = window.our = '${our}'</script>
|
||||
<script>
|
||||
|
@ -1,7 +1,7 @@
|
||||
#![feature(let_chains)]
|
||||
use uqbar_process_lib::{
|
||||
grant_messaging, http::bind_http_static_path, http::HttpServerError, println, receive, Address,
|
||||
Message, ProcessId, Response,
|
||||
await_message, grant_messaging, http::bind_http_static_path, http::HttpServerError, println, Address,
|
||||
Message, ProcessId,
|
||||
};
|
||||
|
||||
wit_bindgen::generate!({
|
||||
@ -43,21 +43,38 @@ fn main(our: Address) -> anyhow::Result<()> {
|
||||
.to_vec(),
|
||||
)?;
|
||||
|
||||
bind_http_static_path(
|
||||
"/our",
|
||||
false,
|
||||
false,
|
||||
Some("text/html".to_string()),
|
||||
our.node.clone().as_bytes().to_vec(),
|
||||
)?;
|
||||
|
||||
bind_http_static_path(
|
||||
"/our.js",
|
||||
false,
|
||||
false,
|
||||
Some("application/javascript".to_string()),
|
||||
format!("window.our = {{}}; window.our.node = '{}';", &our.node).as_bytes().to_vec(),
|
||||
)?;
|
||||
|
||||
loop {
|
||||
let Ok((ref source, ref message)) = receive() else {
|
||||
let Ok(ref message) = await_message() else {
|
||||
println!("homepage: got network error??");
|
||||
continue;
|
||||
};
|
||||
if let Message::Response((ref msg, _)) = message
|
||||
if let Message::Response { source, ipc, ..} = message
|
||||
&& source.process == "http_server:sys:uqbar"
|
||||
{
|
||||
match serde_json::from_slice::<Result<(), HttpServerError>>(&msg.ipc) {
|
||||
match serde_json::from_slice::<Result<(), HttpServerError>>(&ipc) {
|
||||
Ok(Ok(())) => continue,
|
||||
Ok(Err(e)) => println!("homepage: got error from http_server: {e}"),
|
||||
Err(_e) => println!("homepage: got malformed message from http_server!"),
|
||||
}
|
||||
} else {
|
||||
println!("homepage: got message from {source:?}: {message:?}");
|
||||
println!("homepage: got message: {message:?}");
|
||||
//println!("homepage: got message from {source:?}: {message:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
504
modules/key_value/key_value/Cargo.lock
generated
504
modules/key_value/key_value/Cargo.lock
generated
@ -1,504 +0,0 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.75"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "id-arena"
|
||||
version = "2.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005"
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
|
||||
dependencies = [
|
||||
"unicode-bidi",
|
||||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
|
||||
|
||||
[[package]]
|
||||
name = "key_value"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"uqbar_process_lib",
|
||||
"wit-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "leb128"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.150"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.188"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.188"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.105"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
|
||||
|
||||
[[package]]
|
||||
name = "spdx"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b19b32ed6d899ab23174302ff105c1577e45a06b08d4fe0a9dd13ce804bbbf71"
|
||||
dependencies = [
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.49"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.49"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
|
||||
dependencies = [
|
||||
"tinyvec_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec_macros"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
|
||||
dependencies = [
|
||||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
||||
|
||||
[[package]]
|
||||
name = "uqbar_process_lib"
|
||||
version = "0.3.0"
|
||||
source = "git+ssh://git@github.com/uqbar-dao/process_lib.git?rev=5e1b94a#5e1b94ae2f85c66da33ec52117a72b90d53c4d22"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
"http",
|
||||
"rand",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"url",
|
||||
"wit-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna",
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-encoder"
|
||||
version = "0.36.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "822b645bf4f2446b949776ffca47e2af60b167209ffb70814ef8779d299cd421"
|
||||
dependencies = [
|
||||
"leb128",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-metadata"
|
||||
version = "0.10.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2167ce53b2faa16a92c6cafd4942cff16c9a4fa0c5a5a0a41131ee4e49fc055f"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"spdx",
|
||||
"wasm-encoder",
|
||||
"wasmparser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.116.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a58e28b80dd8340cb07b8242ae654756161f6fc8d0038123d679b7b99964fa50"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.13.1"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"wit-bindgen-rust-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-core"
|
||||
version = "0.13.1"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"wit-component",
|
||||
"wit-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust"
|
||||
version = "0.13.2"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"heck",
|
||||
"wasm-metadata",
|
||||
"wit-bindgen-core",
|
||||
"wit-component",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust-macro"
|
||||
version = "0.13.1"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wit-bindgen-core",
|
||||
"wit-bindgen-rust",
|
||||
"wit-component",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-component"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "480cc1a078b305c1b8510f7c455c76cbd008ee49935f3a6c5fd5e937d8d95b1e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags",
|
||||
"indexmap",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"wasm-encoder",
|
||||
"wasm-metadata",
|
||||
"wasmparser",
|
||||
"wit-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-parser"
|
||||
version = "0.12.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43771ee863a16ec4ecf9da0fc65c3bbd4a1235c8e3da5f094b562894843dfa76"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"id-arena",
|
||||
"indexmap",
|
||||
"log",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"unicode-xid",
|
||||
]
|
@ -1,31 +0,0 @@
|
||||
[package]
|
||||
name = "key_value"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
opt-level = "s"
|
||||
lto = true
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
bincode = "1.3.3"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
thiserror = "1.0"
|
||||
uqbar_process_lib = { git = "ssh://git@github.com/uqbar-dao/process_lib.git", rev = "5e1b94a" }
|
||||
wit-bindgen = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "5390bab780733f1660d14c254ec985df2816bf1d" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[package.metadata.component]
|
||||
package = "uqbar:process"
|
||||
|
||||
[package.metadata.component.target]
|
||||
path = "wit"
|
||||
|
||||
[package.metadata.component.dependencies]
|
@ -1 +0,0 @@
|
||||
../../key_value_types.rs
|
@ -1,191 +0,0 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
// use serde::{Deserialize, Serialize};
|
||||
|
||||
use uqbar_process_lib::{Address, ProcessId, Request, Response};
|
||||
use uqbar_process_lib::kernel_types as kt;
|
||||
use uqbar_process_lib::uqbar::process::standard as wit;
|
||||
|
||||
wit_bindgen::generate!({
|
||||
path: "../../../wit",
|
||||
world: "process",
|
||||
exports: {
|
||||
world: Component,
|
||||
},
|
||||
});
|
||||
|
||||
mod key_value_types;
|
||||
use key_value_types as kv;
|
||||
|
||||
const PREFIX: &str = "key_value-";
|
||||
|
||||
type DbToProcess = HashMap<String, ProcessId>;
|
||||
|
||||
fn make_vfs_cap(kind: &str, drive: &str) -> String {
|
||||
serde_json::to_string(&serde_json::json!({
|
||||
"kind": kind,
|
||||
"drive": drive,
|
||||
}))
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn make_db_cap(kind: &str, db: &str) -> String {
|
||||
serde_json::to_string(&serde_json::json!({
|
||||
"kind": kind,
|
||||
"db": db,
|
||||
}))
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn forward_if_have_cap(
|
||||
our: &Address,
|
||||
operation_type: &str,
|
||||
db: &str,
|
||||
ipc: Vec<u8>,
|
||||
db_to_process: &mut DbToProcess,
|
||||
) -> anyhow::Result<()> {
|
||||
if wit::has_capability(&make_db_cap(operation_type, db)) {
|
||||
// forward
|
||||
let Some(process_id) = db_to_process.get(db) else {
|
||||
return Err(kv::KeyValueError::DbDoesNotExist.into());
|
||||
};
|
||||
Request::new()
|
||||
.target(wit::Address {
|
||||
node: our.node.clone(),
|
||||
process: process_id.clone(),
|
||||
})
|
||||
// .target(Address::new(our.node.clone(), process_id.clone()))?
|
||||
.inherit(true)
|
||||
.ipc(ipc)
|
||||
.send()?;
|
||||
return Ok(());
|
||||
} else {
|
||||
// reject
|
||||
return Err(kv::KeyValueError::NoCap.into());
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_message(our: &Address, db_to_process: &mut DbToProcess) -> anyhow::Result<()> {
|
||||
let (source, message) = wit::receive().unwrap();
|
||||
|
||||
if our.node != source.node {
|
||||
return Err(kv::KeyValueError::RejectForeign.into());
|
||||
}
|
||||
|
||||
match message {
|
||||
wit::Message::Response(_) => {
|
||||
return Err(kv::KeyValueError::UnexpectedResponse.into());
|
||||
}
|
||||
wit::Message::Request(wit::Request { ipc, .. }) => {
|
||||
match serde_json::from_slice(&ipc)? {
|
||||
kv::KeyValueMessage::New { ref db } => {
|
||||
// TODO: make atomic
|
||||
// (1): create vfs drive
|
||||
// (2): spin up worker, granting vfs caps
|
||||
// (3): issue new caps
|
||||
// (4): persist
|
||||
|
||||
if db_to_process.contains_key(db) {
|
||||
return Err(kv::KeyValueError::DbAlreadyExists.into());
|
||||
}
|
||||
|
||||
// (1)
|
||||
let vfs_address = Address {
|
||||
node: our.node.clone(),
|
||||
process: ProcessId::new(Some("vfs"), "sys", "uqbar"),
|
||||
};
|
||||
let vfs_drive = format!("{}{}", PREFIX, db);
|
||||
let _ = Request::new()
|
||||
.target(vfs_address.clone())
|
||||
.ipc(serde_json::to_vec(&kt::VfsRequest {
|
||||
drive: vfs_drive.clone(),
|
||||
action: kt::VfsAction::New,
|
||||
})?)
|
||||
.send_and_await_response(15)??;
|
||||
|
||||
// (2)
|
||||
let vfs_read = wit::get_capability(
|
||||
&vfs_address,
|
||||
&make_vfs_cap("read", &vfs_drive)
|
||||
).ok_or(anyhow::anyhow!("New failed: no vfs 'read' capability found"))?;
|
||||
let vfs_write = wit::get_capability(
|
||||
&vfs_address,
|
||||
&make_vfs_cap("write", &vfs_drive)
|
||||
).ok_or(anyhow::anyhow!("New failed: no vfs 'write' capability found"))?;
|
||||
let messaging = wit::get_capability(
|
||||
&source,
|
||||
&"\"messaging\"".into(),
|
||||
).ok_or(anyhow::anyhow!("New failed: no source 'messaging' capability found"))?;
|
||||
let spawned_process_id = match wit::spawn(
|
||||
None,
|
||||
"/key_value_worker.wasm",
|
||||
&wit::OnPanic::None, // TODO: notify us
|
||||
&wit::Capabilities::Some(vec![vfs_read, vfs_write, messaging]),
|
||||
false, // not public
|
||||
) {
|
||||
Ok(spawned_process_id) => spawned_process_id,
|
||||
Err(e) => {
|
||||
wit::print_to_terminal(0, &format!("couldn't spawn: {}", e));
|
||||
panic!("couldn't spawn"); // TODO
|
||||
}
|
||||
};
|
||||
// grant caps
|
||||
wit::create_capability(&source.process, &make_db_cap("read", db));
|
||||
wit::create_capability(&source.process, &make_db_cap("write", db));
|
||||
// initialize worker
|
||||
Request::new()
|
||||
.target(wit::Address {
|
||||
node: our.node.clone(),
|
||||
process: spawned_process_id.clone(),
|
||||
})
|
||||
.ipc(ipc.clone())
|
||||
.send()?;
|
||||
|
||||
// (4)
|
||||
db_to_process.insert(db.into(), spawned_process_id);
|
||||
// TODO: persistence?
|
||||
|
||||
Response::new()
|
||||
.ipc(ipc)
|
||||
.send()?;
|
||||
}
|
||||
kv::KeyValueMessage::Write { ref db, .. } => {
|
||||
forward_if_have_cap(our, "write", db, ipc, db_to_process)?;
|
||||
}
|
||||
kv::KeyValueMessage::Read { ref db, .. } => {
|
||||
forward_if_have_cap(our, "read", db, ipc, db_to_process)?;
|
||||
}
|
||||
kv::KeyValueMessage::Err { error } => {
|
||||
return Err(error.into());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Component;
|
||||
impl Guest for Component {
|
||||
fn init(our: String) {
|
||||
wit::print_to_terminal(0, "key_value: begin");
|
||||
|
||||
let our = Address::from_str(&our).unwrap();
|
||||
let mut db_to_process: DbToProcess = HashMap::new();
|
||||
|
||||
loop {
|
||||
match handle_message(&our, &mut db_to_process) {
|
||||
Ok(()) => {}
|
||||
Err(e) => {
|
||||
wit::print_to_terminal(0, format!("key_value: error: {:?}", e,).as_str());
|
||||
if let Some(e) = e.downcast_ref::<kv::KeyValueError>() {
|
||||
Response::new()
|
||||
.ipc(serde_json::to_vec(&e).unwrap())
|
||||
.send()
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum KeyValueMessage {
|
||||
New { db: String },
|
||||
Write { db: String, key: Vec<u8> },
|
||||
Read { db: String, key: Vec<u8> },
|
||||
Err { error: KeyValueError },
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, thiserror::Error)]
|
||||
pub enum KeyValueError {
|
||||
#[error("DbDoesNotExist")]
|
||||
DbDoesNotExist,
|
||||
#[error("DbAlreadyExists")]
|
||||
DbAlreadyExists,
|
||||
#[error("NoCap")]
|
||||
NoCap,
|
||||
#[error("RejectForeign")]
|
||||
RejectForeign,
|
||||
#[error("UnexpectedResponse")]
|
||||
UnexpectedResponse,
|
||||
}
|
644
modules/key_value/key_value_worker/Cargo.lock
generated
644
modules/key_value/key_value_worker/Cargo.lock
generated
@ -1,644 +0,0 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.75"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.83"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.28.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "id-arena"
|
||||
version = "2.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005"
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
|
||||
dependencies = [
|
||||
"unicode-bidi",
|
||||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
|
||||
|
||||
[[package]]
|
||||
name = "key_value_worker"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
"redb",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"uqbar_process_lib",
|
||||
"wit-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "leb128"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.147"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
|
||||
dependencies = [
|
||||
"adler",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.32.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyo3-build-config"
|
||||
version = "0.19.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "076c73d0bc438f7a4ef6fdd0c3bb4732149136abd952b110ac93e4edb13a6ba5"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"target-lexicon",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redb"
|
||||
version = "1.2.0"
|
||||
source = "git+https://github.com/uqbar-dao/redb?rev=8e192d9#8e192d945295e1ddd331003bae215cd8d1564c4b"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"pyo3-build-config",
|
||||
"rand",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.188"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.188"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.105"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
|
||||
|
||||
[[package]]
|
||||
name = "spdx"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b19b32ed6d899ab23174302ff105c1577e45a06b08d4fe0a9dd13ce804bbbf71"
|
||||
dependencies = [
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "target-lexicon"
|
||||
version = "0.12.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d0e916b1148c8e263850e1ebcbd046f333e0683c724876bb0da63ea4373dc8a"
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.49"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.49"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
|
||||
dependencies = [
|
||||
"tinyvec_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec_macros"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.32.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"pin-project-lite",
|
||||
"tokio-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
|
||||
dependencies = [
|
||||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
||||
|
||||
[[package]]
|
||||
name = "uqbar_process_lib"
|
||||
version = "0.3.0"
|
||||
source = "git+ssh://git@github.com/uqbar-dao/process_lib.git?rev=5e1b94a#5e1b94ae2f85c66da33ec52117a72b90d53c4d22"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
"http",
|
||||
"rand",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"url",
|
||||
"wit-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna",
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-encoder"
|
||||
version = "0.36.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "822b645bf4f2446b949776ffca47e2af60b167209ffb70814ef8779d299cd421"
|
||||
dependencies = [
|
||||
"leb128",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-metadata"
|
||||
version = "0.10.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2167ce53b2faa16a92c6cafd4942cff16c9a4fa0c5a5a0a41131ee4e49fc055f"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"spdx",
|
||||
"wasm-encoder",
|
||||
"wasmparser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.116.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a58e28b80dd8340cb07b8242ae654756161f6fc8d0038123d679b7b99964fa50"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.13.1"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"wit-bindgen-rust-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-core"
|
||||
version = "0.13.1"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"wit-component",
|
||||
"wit-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust"
|
||||
version = "0.13.2"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"heck",
|
||||
"wasm-metadata",
|
||||
"wit-bindgen-core",
|
||||
"wit-component",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust-macro"
|
||||
version = "0.13.1"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wit-bindgen-core",
|
||||
"wit-bindgen-rust",
|
||||
"wit-component",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-component"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "480cc1a078b305c1b8510f7c455c76cbd008ee49935f3a6c5fd5e937d8d95b1e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags",
|
||||
"indexmap",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"wasm-encoder",
|
||||
"wasm-metadata",
|
||||
"wasmparser",
|
||||
"wit-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-parser"
|
||||
version = "0.12.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43771ee863a16ec4ecf9da0fc65c3bbd4a1235c8e3da5f094b562894843dfa76"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"id-arena",
|
||||
"indexmap",
|
||||
"log",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"unicode-xid",
|
||||
]
|
@ -1,32 +0,0 @@
|
||||
[package]
|
||||
name = "key_value_worker"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
opt-level = "s"
|
||||
lto = true
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
bincode = "1.3.3"
|
||||
redb = { git = "https://github.com/uqbar-dao/redb", rev = "8e192d9" }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
thiserror = "1.0"
|
||||
uqbar_process_lib = { git = "ssh://git@github.com/uqbar-dao/process_lib.git", rev = "5e1b94a" }
|
||||
wit-bindgen = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "5390bab780733f1660d14c254ec985df2816bf1d" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[package.metadata.component]
|
||||
package = "uqbar:process"
|
||||
|
||||
[package.metadata.component.target]
|
||||
path = "wit"
|
||||
|
||||
[package.metadata.component.dependencies]
|
@ -1 +0,0 @@
|
||||
../key_value_types.rs
|
@ -1 +0,0 @@
|
||||
../../key_value_types.rs
|
@ -1,206 +0,0 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use redb::ReadableTable;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use uqbar_process_lib::{Address, create_capability, ProcessId, Response};
|
||||
use uqbar_process_lib::uqbar::process::standard as wit;
|
||||
|
||||
wit_bindgen::generate!({
|
||||
path: "../../../wit",
|
||||
world: "process",
|
||||
exports: {
|
||||
world: Component,
|
||||
},
|
||||
});
|
||||
|
||||
mod key_value_types;
|
||||
use key_value_types as kv;
|
||||
|
||||
const PREFIX: &str = "key_value-";
|
||||
const TABLE: redb::TableDefinition<&[u8], &[u8]> = redb::TableDefinition::new("process");
|
||||
|
||||
fn get_payload_wrapped() -> Option<(Option<String>, Vec<u8>)> {
|
||||
match wit::get_payload() {
|
||||
None => None,
|
||||
Some(wit::Payload { mime, bytes }) => Some((mime, bytes)),
|
||||
}
|
||||
}
|
||||
|
||||
fn send_and_await_response_wrapped(
|
||||
target_node: String,
|
||||
target_process: String,
|
||||
target_package: String,
|
||||
target_publisher: String,
|
||||
request_ipc: Vec<u8>,
|
||||
request_metadata: Option<String>,
|
||||
payload: Option<(Option<String>, Vec<u8>)>,
|
||||
timeout: u64,
|
||||
) -> (Vec<u8>, Option<String>) {
|
||||
let payload = match payload {
|
||||
None => None,
|
||||
Some((mime, bytes)) => Some(wit::Payload { mime, bytes }),
|
||||
};
|
||||
let (
|
||||
_,
|
||||
wit::Message::Response((wit::Response { ipc, metadata, .. }, _)),
|
||||
) = wit::send_and_await_response(
|
||||
&wit::Address {
|
||||
node: target_node,
|
||||
process: ProcessId::new(
|
||||
Some(&target_process),
|
||||
&target_package,
|
||||
&target_publisher,
|
||||
),
|
||||
},
|
||||
&wit::Request {
|
||||
inherit: false,
|
||||
expects_response: Some(timeout),
|
||||
ipc: request_ipc,
|
||||
metadata: request_metadata,
|
||||
},
|
||||
match payload {
|
||||
None => None,
|
||||
Some(ref p) => Some(p),
|
||||
},
|
||||
).unwrap() else {
|
||||
panic!("");
|
||||
};
|
||||
(ipc, metadata)
|
||||
}
|
||||
|
||||
fn handle_message (
|
||||
our: &wit::Address,
|
||||
db_handle: &mut Option<redb::Database>,
|
||||
) -> anyhow::Result<()> {
|
||||
let (source, message) = wit::receive().unwrap();
|
||||
|
||||
if our.node != source.node {
|
||||
return Err(kv::KeyValueError::RejectForeign.into());
|
||||
}
|
||||
|
||||
match message {
|
||||
wit::Message::Response(_) => { unimplemented!() },
|
||||
wit::Message::Request(wit::Request { ipc, .. }) => {
|
||||
match serde_json::from_slice(&ipc)? {
|
||||
kv::KeyValueMessage::New { db } => {
|
||||
let vfs_drive = format!("{}{}", PREFIX, db);
|
||||
match db_handle {
|
||||
Some(_) => {
|
||||
return Err(kv::KeyValueError::DbAlreadyExists.into());
|
||||
},
|
||||
None => {
|
||||
wit::print_to_terminal(1, "key_value_worker: Create");
|
||||
*db_handle = Some(redb::Database::create(
|
||||
format!("/{}.redb", db),
|
||||
our.node.clone(),
|
||||
vfs_drive,
|
||||
get_payload_wrapped,
|
||||
send_and_await_response_wrapped,
|
||||
)?);
|
||||
wit::print_to_terminal(1, "key_value_worker: Create done");
|
||||
},
|
||||
}
|
||||
},
|
||||
kv::KeyValueMessage::Write { ref key, .. } => {
|
||||
let Some(db_handle) = db_handle else {
|
||||
return Err(kv::KeyValueError::DbDoesNotExist.into());
|
||||
};
|
||||
|
||||
let wit::Payload { ref bytes, .. } = wit::get_payload()
|
||||
.ok_or(anyhow::anyhow!("couldnt get bytes for Write"))?;
|
||||
|
||||
let write_txn = db_handle.begin_write()?;
|
||||
{
|
||||
let mut table = write_txn.open_table(TABLE)?;
|
||||
table.insert(&key[..], &bytes[..])?;
|
||||
}
|
||||
write_txn.commit()?;
|
||||
|
||||
Response::new()
|
||||
.ipc(ipc)
|
||||
.send()?;
|
||||
},
|
||||
kv::KeyValueMessage::Read { ref key, .. } => {
|
||||
let Some(db_handle) = db_handle else {
|
||||
return Err(kv::KeyValueError::DbDoesNotExist.into());
|
||||
};
|
||||
|
||||
let read_txn = db_handle.begin_read()?;
|
||||
|
||||
let table = read_txn.open_table(TABLE)?;
|
||||
|
||||
match table.get(&key[..])? {
|
||||
None => {
|
||||
Response::new()
|
||||
.ipc(ipc)
|
||||
.send()?;
|
||||
},
|
||||
Some(v) => {
|
||||
let bytes = v.value().to_vec();
|
||||
wit::print_to_terminal(
|
||||
1,
|
||||
&format!(
|
||||
"key_value_worker: key, val: {:?}, {}",
|
||||
key,
|
||||
if bytes.len() < 100 {
|
||||
format!("{:?}", bytes)
|
||||
} else {
|
||||
"<elided>".into()
|
||||
},
|
||||
),
|
||||
);
|
||||
Response::new()
|
||||
.ipc(ipc)
|
||||
.payload(wit::Payload {
|
||||
mime: None,
|
||||
bytes,
|
||||
})
|
||||
.send()?;
|
||||
},
|
||||
};
|
||||
},
|
||||
kv::KeyValueMessage::Err { error } => {
|
||||
return Err(error.into());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
struct Component;
|
||||
impl Guest for Component {
|
||||
fn init(our: String) {
|
||||
wit::print_to_terminal(1, "key_value_worker: begin");
|
||||
|
||||
let our = Address::from_str(&our).unwrap();
|
||||
let mut db_handle: Option<redb::Database> = None;
|
||||
|
||||
let vfs_address = ProcessId::from_str("vfs:sys:uqbar").unwrap();
|
||||
create_capability(
|
||||
&vfs_address,
|
||||
&"\"messaging\"".into(),
|
||||
);
|
||||
|
||||
loop {
|
||||
match handle_message(&our, &mut db_handle) {
|
||||
Ok(()) => {},
|
||||
Err(e) => {
|
||||
wit::print_to_terminal(0, format!(
|
||||
"key_value_worker: error: {:?}",
|
||||
e,
|
||||
).as_str());
|
||||
if let Some(e) = e.downcast_ref::<kv::KeyValueError>() {
|
||||
Response::new()
|
||||
.ipc(serde_json::to_vec(&e).unwrap())
|
||||
.send()
|
||||
.unwrap();
|
||||
}
|
||||
panic!("");
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
[
|
||||
{
|
||||
"process_name": "key_value",
|
||||
"process_wasm_path": "/key_value.wasm",
|
||||
"on_panic": "Restart",
|
||||
"request_networking": false,
|
||||
"request_messaging": [
|
||||
"vfs:sys:uqbar"
|
||||
],
|
||||
"public": true
|
||||
}
|
||||
]
|
@ -1,5 +0,0 @@
|
||||
{
|
||||
"package": "key_value",
|
||||
"publisher": "uqbar",
|
||||
"version": [0, 1, 0]
|
||||
}
|
210
modules/qns_indexer/Cargo.lock
generated
210
modules/qns_indexer/Cargo.lock
generated
@ -42,7 +42,7 @@ dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.39",
|
||||
"syn 2.0.40",
|
||||
"syn-solidity",
|
||||
"tiny-keccak",
|
||||
]
|
||||
@ -192,12 +192,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.5"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860"
|
||||
checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -223,9 +223,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.10"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
|
||||
checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
@ -234,9 +234,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.2"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156"
|
||||
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
@ -299,9 +299,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.9"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
|
||||
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
@ -317,9 +317,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.150"
|
||||
version = "0.2.151"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
|
||||
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
@ -329,9 +329,9 @@ checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.10"
|
||||
version = "0.4.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f"
|
||||
checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
@ -369,18 +369,18 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.69"
|
||||
version = "1.0.70"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
|
||||
checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proptest"
|
||||
version = "1.3.1"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c003ac8c77cb07bb74f5f198bce836a689bcd5a42574612bf14d17bfd08c20e"
|
||||
checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf"
|
||||
dependencies = [
|
||||
"bit-set",
|
||||
"bit-vec",
|
||||
@ -477,9 +477,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.7.5"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da"
|
||||
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||
|
||||
[[package]]
|
||||
name = "rmp"
|
||||
@ -505,9 +505,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruint"
|
||||
version = "1.11.0"
|
||||
version = "1.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "724fd11728a3804e9944b14cab63825024c40bf42f8af87c8b5d97c4bbacf426"
|
||||
checksum = "608a5726529f2f0ef81b8fde9873c4bb829d6b5b5ca6be4d97345ddf0749c825"
|
||||
dependencies = [
|
||||
"proptest",
|
||||
"rand",
|
||||
@ -534,15 +534,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.21"
|
||||
version = "0.38.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3"
|
||||
checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316"
|
||||
dependencies = [
|
||||
"bitflags 2.4.1",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -559,9 +559,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.15"
|
||||
version = "1.0.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
|
||||
checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
@ -571,22 +571,22 @@ checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.192"
|
||||
version = "1.0.193"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001"
|
||||
checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.192"
|
||||
version = "1.0.193"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1"
|
||||
checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.39",
|
||||
"syn 2.0.40",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -602,9 +602,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.11.1"
|
||||
version = "1.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a"
|
||||
checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
|
||||
|
||||
[[package]]
|
||||
name = "smol_str"
|
||||
@ -637,9 +637,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.39"
|
||||
version = "2.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
|
||||
checksum = "13fa70a4ee923979ffb522cacce59d34421ebdea5625e1073c4326ef9d2dd42e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -655,7 +655,7 @@ dependencies = [
|
||||
"paste",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.39",
|
||||
"syn 2.0.40",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -668,7 +668,7 @@ dependencies = [
|
||||
"fastrand",
|
||||
"redox_syscall",
|
||||
"rustix",
|
||||
"windows-sys",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -688,7 +688,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.39",
|
||||
"syn 2.0.40",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -723,9 +723,9 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.13"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
|
||||
checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
@ -756,8 +756,8 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
||||
|
||||
[[package]]
|
||||
name = "uqbar_process_lib"
|
||||
version = "0.3.0"
|
||||
source = "git+ssh://git@github.com/uqbar-dao/process_lib.git?rev=5e1b94a#5e1b94ae2f85c66da33ec52117a72b90d53c4d22"
|
||||
version = "0.4.0"
|
||||
source = "git+ssh://git@github.com/uqbar-dao/process_lib.git?rev=1ce0d41#1ce0d412169e795c2a99464563b42ae2a2628d77"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
@ -804,18 +804,18 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-encoder"
|
||||
version = "0.36.2"
|
||||
version = "0.38.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "822b645bf4f2446b949776ffca47e2af60b167209ffb70814ef8779d299cd421"
|
||||
checksum = "0ad2b51884de9c7f4fe2fd1043fccb8dcad4b1e29558146ee57a144d15779f3f"
|
||||
dependencies = [
|
||||
"leb128",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-metadata"
|
||||
version = "0.10.11"
|
||||
version = "0.10.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2167ce53b2faa16a92c6cafd4942cff16c9a4fa0c5a5a0a41131ee4e49fc055f"
|
||||
checksum = "d835d67708f6374937c550ad8dd1d17c616ae009e3f00d7a0ac9f7825e78c36a"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"indexmap",
|
||||
@ -829,9 +829,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.116.1"
|
||||
version = "0.118.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a58e28b80dd8340cb07b8242ae654756161f6fc8d0038123d679b7b99964fa50"
|
||||
checksum = "95ee9723b928e735d53000dec9eae7b07a60e490c85ab54abb66659fc61bfcd9"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"semver",
|
||||
@ -843,7 +843,16 @@ version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -852,13 +861,28 @@ version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
"windows_aarch64_gnullvm 0.48.5",
|
||||
"windows_aarch64_msvc 0.48.5",
|
||||
"windows_i686_gnu 0.48.5",
|
||||
"windows_i686_msvc 0.48.5",
|
||||
"windows_x86_64_gnu 0.48.5",
|
||||
"windows_x86_64_gnullvm 0.48.5",
|
||||
"windows_x86_64_msvc 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.52.0",
|
||||
"windows_aarch64_msvc 0.52.0",
|
||||
"windows_i686_gnu 0.52.0",
|
||||
"windows_i686_msvc 0.52.0",
|
||||
"windows_x86_64_gnu 0.52.0",
|
||||
"windows_x86_64_gnullvm 0.52.0",
|
||||
"windows_x86_64_msvc 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -867,46 +891,88 @@ version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.13.1"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=efcc759#efcc7592cf3277bcb9be1034e48569c6d822b322"
|
||||
dependencies = [
|
||||
"bitflags 2.4.1",
|
||||
"wit-bindgen-rust-macro",
|
||||
@ -914,8 +980,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-core"
|
||||
version = "0.13.1"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=efcc759#efcc7592cf3277bcb9be1034e48569c6d822b322"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"wit-component",
|
||||
@ -924,8 +990,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust"
|
||||
version = "0.13.2"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=efcc759#efcc7592cf3277bcb9be1034e48569c6d822b322"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"heck",
|
||||
@ -936,13 +1002,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust-macro"
|
||||
version = "0.13.1"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=efcc759#efcc7592cf3277bcb9be1034e48569c6d822b322"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.39",
|
||||
"syn 2.0.40",
|
||||
"wit-bindgen-core",
|
||||
"wit-bindgen-rust",
|
||||
"wit-component",
|
||||
@ -950,9 +1016,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-component"
|
||||
version = "0.17.0"
|
||||
version = "0.18.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "480cc1a078b305c1b8510f7c455c76cbd008ee49935f3a6c5fd5e937d8d95b1e"
|
||||
checksum = "5b8a35a2a9992898c9d27f1664001860595a4bc99d32dd3599d547412e17d7e2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags 2.4.1",
|
||||
@ -969,9 +1035,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-parser"
|
||||
version = "0.12.2"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43771ee863a16ec4ecf9da0fc65c3bbd4a1235c8e3da5f094b562894843dfa76"
|
||||
checksum = "15df6b7b28ce94b8be39d8df5cb21a08a4f3b9f33b631aedb4aa5776f785ead3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"id-arena",
|
||||
@ -986,6 +1052,6 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.6.0"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9"
|
||||
checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d"
|
||||
|
@ -17,10 +17,10 @@ alloy-sol-types = "0.3.2"
|
||||
bincode = "1.3.3"
|
||||
hex = "0.4.3"
|
||||
rmp-serde = "1.1.2"
|
||||
serde = {version = "1.0", features = ["derive"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
uqbar_process_lib = { git = "ssh://git@github.com/uqbar-dao/process_lib.git", rev = "5e1b94a" }
|
||||
wit-bindgen = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "5390bab780733f1660d14c254ec985df2816bf1d" }
|
||||
uqbar_process_lib = { git = "ssh://git@github.com/uqbar-dao/process_lib.git", rev = "1ce0d41" }
|
||||
wit-bindgen = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "efcc759" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
@ -2,7 +2,7 @@
|
||||
{
|
||||
"process_name": "qns_indexer",
|
||||
"process_wasm_path": "/qns_indexer.wasm",
|
||||
"on_panic": "Restart",
|
||||
"on_exit": "Restart",
|
||||
"request_networking": true,
|
||||
"request_messaging": [
|
||||
"net:sys:uqbar",
|
||||
|
@ -6,8 +6,8 @@ use serde_json::json;
|
||||
use std::collections::HashMap;
|
||||
use std::string::FromUtf8Error;
|
||||
use uqbar_process_lib::{
|
||||
get_typed_state, http, println, receive, set_state,
|
||||
Address, Message, Payload, Request, Response,
|
||||
await_message, get_typed_state, http, println, receive, set_state, Address, Message, Payload,
|
||||
Request, Response,
|
||||
};
|
||||
|
||||
wit_bindgen::generate!({
|
||||
@ -147,7 +147,6 @@ impl Guest for Component {
|
||||
}
|
||||
|
||||
fn main(our: Address, mut state: State) -> anyhow::Result<()> {
|
||||
|
||||
// shove all state into net::net
|
||||
Request::new()
|
||||
.target((&our.node, "net", "sys", "uqbar"))
|
||||
@ -165,18 +164,18 @@ fn main(our: Address, mut state: State) -> anyhow::Result<()> {
|
||||
http::bind_http_path("/node/:name", false, false)?;
|
||||
|
||||
loop {
|
||||
let Ok((source, message)) = receive() else {
|
||||
let Ok(message) = await_message() else {
|
||||
println!("qns_indexer: got network error");
|
||||
continue;
|
||||
};
|
||||
let Message::Request(request) = message else {
|
||||
let Message::Request { source, ipc, .. } = message else {
|
||||
// TODO we should store the subscription ID for eth_rpc
|
||||
// incase we want to cancel/reset it
|
||||
continue;
|
||||
};
|
||||
|
||||
if source.process == "http_server:sys:uqbar" {
|
||||
if let Ok(ipc_json) = serde_json::from_slice::<serde_json::Value>(&request.ipc) {
|
||||
if let Ok(ipc_json) = serde_json::from_slice::<serde_json::Value>(&ipc) {
|
||||
if ipc_json["path"].as_str().unwrap_or_default() == "/node/:name" {
|
||||
if let Some(name) = ipc_json["url_params"]["name"].as_str() {
|
||||
if let Some(node) = state.nodes.get(name) {
|
||||
@ -219,12 +218,11 @@ fn main(our: Address, mut state: State) -> anyhow::Result<()> {
|
||||
continue;
|
||||
}
|
||||
|
||||
let Ok(msg) = serde_json::from_slice::<AllActions>(&request.ipc) else {
|
||||
let Ok(msg) = serde_json::from_slice::<AllActions>(&ipc) else {
|
||||
println!("qns_indexer: got invalid message");
|
||||
continue;
|
||||
};
|
||||
|
||||
|
||||
match msg {
|
||||
// Probably more message types later...maybe not...
|
||||
AllActions::EventSubscription(e) => {
|
||||
@ -232,10 +230,15 @@ fn main(our: Address, mut state: State) -> anyhow::Result<()> {
|
||||
let nodeId = &e.topics[1];
|
||||
|
||||
let name = if decode_hex(&e.topics[0].clone()) == NodeRegistered::SIGNATURE_HASH {
|
||||
let decoded = NodeRegistered::decode_data(&decode_hex_to_vec(&e.data), true).unwrap();
|
||||
let decoded =
|
||||
NodeRegistered::decode_data(&decode_hex_to_vec(&e.data), true).unwrap();
|
||||
match dnswire_decode(decoded.0.clone()) {
|
||||
Ok(name) => { state.names.insert(nodeId.to_string(), name.clone()); }
|
||||
Err(_) => { println!("qns_indexer: failed to decode name: {:?}", decoded.0); }
|
||||
Ok(name) => {
|
||||
state.names.insert(nodeId.to_string(), name.clone());
|
||||
}
|
||||
Err(_) => {
|
||||
println!("qns_indexer: failed to decode name: {:?}", decoded.0);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
} else if let Some(name) = state.names.get(nodeId) {
|
||||
@ -245,7 +248,10 @@ fn main(our: Address, mut state: State) -> anyhow::Result<()> {
|
||||
continue;
|
||||
};
|
||||
|
||||
let node = state.nodes.entry(name.clone()).or_insert_with(QnsUpdate::default);
|
||||
let node = state
|
||||
.nodes
|
||||
.entry(name.clone())
|
||||
.or_insert_with(QnsUpdate::default);
|
||||
|
||||
if node.name == "" {
|
||||
node.name = name.clone();
|
||||
@ -260,12 +266,14 @@ fn main(our: Address, mut state: State) -> anyhow::Result<()> {
|
||||
match decode_hex(&e.topics[0].clone()) {
|
||||
NodeRegistered::SIGNATURE_HASH => {}
|
||||
KeyUpdate::SIGNATURE_HASH => {
|
||||
let decoded = KeyUpdate::decode_data(&decode_hex_to_vec(&e.data), true).unwrap();
|
||||
let decoded =
|
||||
KeyUpdate::decode_data(&decode_hex_to_vec(&e.data), true).unwrap();
|
||||
node.public_key = format!("0x{}", hex::encode(decoded.0));
|
||||
send = true;
|
||||
}
|
||||
IpUpdate::SIGNATURE_HASH => {
|
||||
let decoded = IpUpdate::decode_data(&decode_hex_to_vec(&e.data), true).unwrap();
|
||||
let decoded =
|
||||
IpUpdate::decode_data(&decode_hex_to_vec(&e.data), true).unwrap();
|
||||
let ip = decoded.0;
|
||||
node.ip = format!(
|
||||
"{}.{}.{}.{}",
|
||||
@ -277,23 +285,28 @@ fn main(our: Address, mut state: State) -> anyhow::Result<()> {
|
||||
send = true;
|
||||
}
|
||||
WsUpdate::SIGNATURE_HASH => {
|
||||
let decoded = WsUpdate::decode_data(&decode_hex_to_vec(&e.data), true).unwrap();
|
||||
let decoded =
|
||||
WsUpdate::decode_data(&decode_hex_to_vec(&e.data), true).unwrap();
|
||||
node.port = decoded.0;
|
||||
send = true;
|
||||
}
|
||||
WtUpdate::SIGNATURE_HASH => {
|
||||
let decoded = WtUpdate::decode_data(&decode_hex_to_vec(&e.data), true).unwrap();
|
||||
let decoded =
|
||||
WtUpdate::decode_data(&decode_hex_to_vec(&e.data), true).unwrap();
|
||||
}
|
||||
TcpUpdate::SIGNATURE_HASH => {
|
||||
let decoded = TcpUpdate::decode_data(&decode_hex_to_vec(&e.data), true).unwrap();
|
||||
let decoded =
|
||||
TcpUpdate::decode_data(&decode_hex_to_vec(&e.data), true).unwrap();
|
||||
}
|
||||
UdpUpdate::SIGNATURE_HASH => {
|
||||
let decoded = UdpUpdate::decode_data(&decode_hex_to_vec(&e.data), true).unwrap();
|
||||
UdpUpdate::SIGNATURE_HASH => {
|
||||
let decoded =
|
||||
UdpUpdate::decode_data(&decode_hex_to_vec(&e.data), true).unwrap();
|
||||
}
|
||||
RoutingUpdate::SIGNATURE_HASH => {
|
||||
let decoded = RoutingUpdate::decode_data(&decode_hex_to_vec(&e.data), true).unwrap();
|
||||
let decoded =
|
||||
RoutingUpdate::decode_data(&decode_hex_to_vec(&e.data), true).unwrap();
|
||||
let routers_raw = decoded.0;
|
||||
node.routers = routers_raw
|
||||
node.routers = routers_raw
|
||||
.iter()
|
||||
.map(|r| {
|
||||
let key = format!("0x{}", hex::encode(r));
|
||||
@ -311,14 +324,11 @@ fn main(our: Address, mut state: State) -> anyhow::Result<()> {
|
||||
}
|
||||
|
||||
if send {
|
||||
|
||||
Request::new()
|
||||
.target((&our.node, "net", "sys", "uqbar"))
|
||||
.try_ipc(NetActions::QnsUpdate(node.clone()))?
|
||||
.send()?;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
set_state(&bincode::serialize(&state)?);
|
||||
|
@ -1,12 +0,0 @@
|
||||
[
|
||||
{
|
||||
"process_name": "sqlite",
|
||||
"process_wasm_path": "/sqlite.wasm",
|
||||
"on_panic": "Restart",
|
||||
"request_networking": false,
|
||||
"request_messaging": [
|
||||
"vfs:sys:uqbar"
|
||||
],
|
||||
"public": true
|
||||
}
|
||||
]
|
@ -1,4 +0,0 @@
|
||||
{
|
||||
"package": "sqlite",
|
||||
"publisher": "uqbar"
|
||||
}
|
504
modules/sqlite/sqlite/Cargo.lock
generated
504
modules/sqlite/sqlite/Cargo.lock
generated
@ -1,504 +0,0 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.75"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "id-arena"
|
||||
version = "2.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005"
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
|
||||
dependencies = [
|
||||
"unicode-bidi",
|
||||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
|
||||
|
||||
[[package]]
|
||||
name = "leb128"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.150"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.188"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.188"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.105"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
|
||||
|
||||
[[package]]
|
||||
name = "spdx"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b19b32ed6d899ab23174302ff105c1577e45a06b08d4fe0a9dd13ce804bbbf71"
|
||||
dependencies = [
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sqlite"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"uqbar_process_lib",
|
||||
"wit-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
|
||||
dependencies = [
|
||||
"tinyvec_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec_macros"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
|
||||
dependencies = [
|
||||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
||||
|
||||
[[package]]
|
||||
name = "uqbar_process_lib"
|
||||
version = "0.3.0"
|
||||
source = "git+ssh://git@github.com/uqbar-dao/process_lib.git?rev=5e1b94a#5e1b94ae2f85c66da33ec52117a72b90d53c4d22"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
"http",
|
||||
"rand",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"url",
|
||||
"wit-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna",
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-encoder"
|
||||
version = "0.36.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "822b645bf4f2446b949776ffca47e2af60b167209ffb70814ef8779d299cd421"
|
||||
dependencies = [
|
||||
"leb128",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-metadata"
|
||||
version = "0.10.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2167ce53b2faa16a92c6cafd4942cff16c9a4fa0c5a5a0a41131ee4e49fc055f"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"spdx",
|
||||
"wasm-encoder",
|
||||
"wasmparser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.116.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a58e28b80dd8340cb07b8242ae654756161f6fc8d0038123d679b7b99964fa50"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.13.1"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"wit-bindgen-rust-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-core"
|
||||
version = "0.13.1"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"wit-component",
|
||||
"wit-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust"
|
||||
version = "0.13.2"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"heck",
|
||||
"wasm-metadata",
|
||||
"wit-bindgen-core",
|
||||
"wit-component",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust-macro"
|
||||
version = "0.13.1"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wit-bindgen-core",
|
||||
"wit-bindgen-rust",
|
||||
"wit-component",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-component"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "480cc1a078b305c1b8510f7c455c76cbd008ee49935f3a6c5fd5e937d8d95b1e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags",
|
||||
"indexmap",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"wasm-encoder",
|
||||
"wasm-metadata",
|
||||
"wasmparser",
|
||||
"wit-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-parser"
|
||||
version = "0.12.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43771ee863a16ec4ecf9da0fc65c3bbd4a1235c8e3da5f094b562894843dfa76"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"id-arena",
|
||||
"indexmap",
|
||||
"log",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"unicode-xid",
|
||||
]
|
@ -1,31 +0,0 @@
|
||||
[package]
|
||||
name = "sqlite"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
opt-level = "s"
|
||||
lto = true
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
bincode = "1.3.3"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
thiserror = "1.0"
|
||||
uqbar_process_lib = { git = "ssh://git@github.com/uqbar-dao/process_lib.git", rev = "5e1b94a" }
|
||||
wit-bindgen = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "5390bab780733f1660d14c254ec985df2816bf1d" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[package.metadata.component]
|
||||
package = "uqbar:process"
|
||||
|
||||
[package.metadata.component.target]
|
||||
path = "wit"
|
||||
|
||||
[package.metadata.component.dependencies]
|
@ -1,250 +0,0 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use uqbar_process_lib::{Address, ProcessId, Request, Response};
|
||||
use uqbar_process_lib::kernel_types as kt;
|
||||
use uqbar_process_lib::uqbar::process::standard as wit;
|
||||
|
||||
wit_bindgen::generate!({
|
||||
path: "../../../wit",
|
||||
world: "process",
|
||||
exports: {
|
||||
world: Component,
|
||||
},
|
||||
});
|
||||
|
||||
mod sqlite_types;
|
||||
use sqlite_types as sq;
|
||||
|
||||
const PREFIX: &str = "sqlite-";
|
||||
|
||||
type DbToProcess = HashMap<String, ProcessId>;
|
||||
|
||||
fn make_vfs_cap(kind: &str, drive: &str) -> String {
|
||||
serde_json::to_string(&serde_json::json!({
|
||||
"kind": kind,
|
||||
"drive": drive,
|
||||
})).unwrap()
|
||||
}
|
||||
|
||||
fn make_db_cap(kind: &str, db: &str) -> String {
|
||||
serde_json::to_string(&serde_json::json!({
|
||||
"kind": kind,
|
||||
"db": db,
|
||||
})).unwrap()
|
||||
}
|
||||
|
||||
fn forward_if_have_cap(
|
||||
our: &Address,
|
||||
operation_type: &str,
|
||||
// operation_type: OperationType,
|
||||
db: &str,
|
||||
ipc: Vec<u8>,
|
||||
db_to_process: &mut DbToProcess,
|
||||
) -> anyhow::Result<()> {
|
||||
if wit::has_capability(&make_db_cap(operation_type, db)) {
|
||||
// forward
|
||||
let Some(process_id) = db_to_process.get(db) else {
|
||||
return Err(sq::SqliteError::DbDoesNotExist.into());
|
||||
};
|
||||
Request::new()
|
||||
.target(wit::Address {
|
||||
node: our.node.clone(),
|
||||
process: process_id.clone(),
|
||||
})
|
||||
// .target(Address::new(our.node.clone(), process_id.clone()))?
|
||||
.inherit(true)
|
||||
.ipc(ipc)
|
||||
.send()?;
|
||||
return Ok(());
|
||||
} else {
|
||||
// reject
|
||||
return Err(sq::SqliteError::NoCap.into());
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_message (
|
||||
our: &Address,
|
||||
db_to_process: &mut DbToProcess,
|
||||
read_keywords: &HashSet<String>,
|
||||
write_keywords: &HashSet<String>,
|
||||
) -> anyhow::Result<()> {
|
||||
let (source, message) = wit::receive().unwrap();
|
||||
|
||||
if our.node != source.node {
|
||||
return Err(sq::SqliteError::RejectForeign.into());
|
||||
}
|
||||
|
||||
match message {
|
||||
wit::Message::Response(_) => {
|
||||
return Err(sq::SqliteError::UnexpectedResponse.into());
|
||||
},
|
||||
wit::Message::Request(wit::Request { ipc, .. }) => {
|
||||
match serde_json::from_slice(&ipc)? {
|
||||
sq::SqliteMessage::New { ref db } => {
|
||||
// TODO: make atomic
|
||||
// (1): create vfs drive
|
||||
// (2): spin up worker, granting vfs caps & msg_cap
|
||||
// (3): issue new caps
|
||||
|
||||
if db_to_process.contains_key(db) {
|
||||
return Err(sq::SqliteError::DbAlreadyExists.into());
|
||||
}
|
||||
|
||||
// (1)
|
||||
let vfs_address = Address {
|
||||
node: our.node.clone(),
|
||||
process: ProcessId::new(Some("vfs"), "sys", "uqbar"),
|
||||
};
|
||||
|
||||
let vfs_drive = format!("{}{}", PREFIX, db);
|
||||
let _ = Request::new()
|
||||
.target(vfs_address.clone())
|
||||
.ipc(serde_json::to_vec(&kt::VfsRequest {
|
||||
drive: vfs_drive.clone(),
|
||||
action: kt::VfsAction::New,
|
||||
})?)
|
||||
.send_and_await_response(15)??;
|
||||
|
||||
// (2)
|
||||
let vfs_read = wit::get_capability(
|
||||
&vfs_address,
|
||||
&make_vfs_cap("read", &vfs_drive),
|
||||
).ok_or(anyhow::anyhow!("New failed: no vfs 'read' capability found"))?;
|
||||
|
||||
let vfs_write = wit::get_capability(
|
||||
&vfs_address,
|
||||
&make_vfs_cap("write", &vfs_drive),
|
||||
).ok_or(anyhow::anyhow!("New failed: no vfs 'write' capability found"))?;
|
||||
|
||||
let msg_cap = wit::get_capability(
|
||||
&source,
|
||||
&"\"messaging\"".into(),
|
||||
).ok_or(anyhow::anyhow!("New failed: no msg capability passed"))?;
|
||||
|
||||
let spawned_process_id = match wit::spawn(
|
||||
None,
|
||||
"/sqlite_worker.wasm",
|
||||
&wit::OnPanic::None,
|
||||
&wit::Capabilities::Some(vec![vfs_read, vfs_write, msg_cap]),
|
||||
false, // not public
|
||||
) {
|
||||
Ok(spawned_process_id) => spawned_process_id,
|
||||
Err(e) => {
|
||||
wit::print_to_terminal(0, &format!("couldn't spawn: {}", e));
|
||||
panic!("couldn't spawn"); // TODO
|
||||
},
|
||||
};
|
||||
// grant caps
|
||||
wit::create_capability(&source.process, &make_db_cap("read", db));
|
||||
wit::create_capability(&source.process, &make_db_cap("write", db));
|
||||
// initialize worker
|
||||
Request::new()
|
||||
.target(wit::Address {
|
||||
node: our.node.clone(),
|
||||
process: spawned_process_id.clone(),
|
||||
})
|
||||
.ipc(ipc.clone())
|
||||
.send()?;
|
||||
|
||||
db_to_process.insert(db.into(), spawned_process_id);
|
||||
|
||||
Response::new()
|
||||
.ipc(ipc)
|
||||
.send()?;
|
||||
},
|
||||
sq::SqliteMessage::Write { ref db, ref statement, .. } => {
|
||||
let first_word = statement
|
||||
.split_whitespace()
|
||||
.next()
|
||||
.map(|word| word.to_uppercase())
|
||||
.unwrap_or("".to_string());
|
||||
if !write_keywords.contains(&first_word) {
|
||||
return Err(sq::SqliteError::NotAWriteKeyword.into())
|
||||
}
|
||||
forward_if_have_cap(our, "write", db, ipc, db_to_process)?;
|
||||
},
|
||||
sq::SqliteMessage::Read { ref db, ref query } => {
|
||||
let first_word = query
|
||||
.split_whitespace()
|
||||
.next()
|
||||
.map(|word| word.to_uppercase())
|
||||
.unwrap_or("".to_string());
|
||||
if !read_keywords.contains(&first_word) {
|
||||
return Err(sq::SqliteError::NotAReadKeyword.into())
|
||||
}
|
||||
forward_if_have_cap(our, "read", db, ipc, db_to_process)?;
|
||||
},
|
||||
sq::SqliteMessage::Commit { ref db, .. } => {
|
||||
forward_if_have_cap(our, "write", db, ipc, db_to_process)?;
|
||||
},
|
||||
}
|
||||
|
||||
Ok(())
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
struct Component;
|
||||
impl Guest for Component {
|
||||
fn init(our: String) {
|
||||
wit::print_to_terminal(0, "sqlite: begin");
|
||||
|
||||
let our = Address::from_str(&our).unwrap();
|
||||
|
||||
let mut db_to_process: DbToProcess = HashMap::new();
|
||||
|
||||
let read_keywords: HashSet<String> = [
|
||||
"ANALYZE",
|
||||
"ATTACH",
|
||||
"BEGIN",
|
||||
"EXPLAIN",
|
||||
"PRAGMA",
|
||||
"SELECT",
|
||||
"VALUES",
|
||||
"WITH",
|
||||
]
|
||||
.iter()
|
||||
.map(|x| x.to_string())
|
||||
.collect();
|
||||
let write_keywords: HashSet<String> = [
|
||||
"ALTER",
|
||||
"ANALYZE",
|
||||
"COMMIT",
|
||||
"CREATE",
|
||||
"DELETE",
|
||||
"DETACH",
|
||||
"DROP",
|
||||
"END",
|
||||
"INSERT",
|
||||
"REINDEX",
|
||||
"RELEASE",
|
||||
"RENAME",
|
||||
"REPLACE",
|
||||
"ROLLBACK",
|
||||
"SAVEPOINT",
|
||||
"UPDATE",
|
||||
"VACUUM",
|
||||
]
|
||||
.iter()
|
||||
.map(|x| x.to_string())
|
||||
.collect();
|
||||
|
||||
loop {
|
||||
match handle_message(&our, &mut db_to_process, &read_keywords, &write_keywords) {
|
||||
Ok(()) => {},
|
||||
Err(e) => {
|
||||
wit::print_to_terminal(0, format!(
|
||||
"sqlite: error: {:?}",
|
||||
e,
|
||||
).as_str());
|
||||
if let Some(e) = e.downcast_ref::<sq::SqliteError>() {
|
||||
Response::new()
|
||||
.ipc(serde_json::to_vec(&e).unwrap())
|
||||
.send()
|
||||
.unwrap();
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -1 +0,0 @@
|
||||
../../sqlite_types.rs
|
@ -1,41 +0,0 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum SqliteMessage {
|
||||
New { db: String },
|
||||
Write { db: String, statement: String, tx_id: Option<u64> },
|
||||
Read { db: String, query: String },
|
||||
Commit { db: String, tx_id: u64 },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum SqlValue {
|
||||
Integer(i64),
|
||||
Real(f64),
|
||||
Text(String),
|
||||
Blob(Vec<u8>),
|
||||
Boolean(bool),
|
||||
Null,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, thiserror::Error)]
|
||||
pub enum SqliteError {
|
||||
#[error("DbDoesNotExist")]
|
||||
DbDoesNotExist,
|
||||
#[error("DbAlreadyExists")]
|
||||
DbAlreadyExists,
|
||||
#[error("NoTx")]
|
||||
NoTx,
|
||||
#[error("NoCap")]
|
||||
NoCap,
|
||||
#[error("RejectForeign")]
|
||||
RejectForeign,
|
||||
#[error("UnexpectedResponse")]
|
||||
UnexpectedResponse,
|
||||
#[error("NotAWriteKeyword")]
|
||||
NotAWriteKeyword,
|
||||
#[error("NotAReadKeyword")]
|
||||
NotAReadKeyword,
|
||||
#[error("Invalid Parameters")]
|
||||
InvalidParameters,
|
||||
}
|
610
modules/sqlite/sqlite_worker/Cargo.lock
generated
610
modules/sqlite/sqlite_worker/Cargo.lock
generated
@ -1,610 +0,0 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.75"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.83"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "fallible-iterator"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
|
||||
|
||||
[[package]]
|
||||
name = "fallible-streaming-iterator"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"allocator-api2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashlink"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "id-arena"
|
||||
version = "2.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005"
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
|
||||
dependencies = [
|
||||
"unicode-bidi",
|
||||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
|
||||
|
||||
[[package]]
|
||||
name = "leb128"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.147"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
|
||||
|
||||
[[package]]
|
||||
name = "libsqlite3-sys"
|
||||
version = "0.26.0"
|
||||
source = "git+https://github.com/uqbar-dao/rusqlite?rev=8fb20a9#8fb20a9dedf4bea626036af8b43c92b050a24d9f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rusqlite"
|
||||
version = "0.29.0"
|
||||
source = "git+https://github.com/uqbar-dao/rusqlite?rev=8fb20a9#8fb20a9dedf4bea626036af8b43c92b050a24d9f"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"fallible-iterator",
|
||||
"fallible-streaming-iterator",
|
||||
"hashlink",
|
||||
"libsqlite3-sys",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.188"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.188"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.105"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
|
||||
|
||||
[[package]]
|
||||
name = "spdx"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b19b32ed6d899ab23174302ff105c1577e45a06b08d4fe0a9dd13ce804bbbf71"
|
||||
dependencies = [
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sqlite_worker"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64",
|
||||
"bincode",
|
||||
"rusqlite",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"uqbar_process_lib",
|
||||
"wit-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
|
||||
dependencies = [
|
||||
"tinyvec_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec_macros"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
|
||||
dependencies = [
|
||||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
||||
|
||||
[[package]]
|
||||
name = "uqbar_process_lib"
|
||||
version = "0.3.0"
|
||||
source = "git+ssh://git@github.com/uqbar-dao/process_lib.git?rev=5e1b94a#5e1b94ae2f85c66da33ec52117a72b90d53c4d22"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
"http",
|
||||
"rand",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"url",
|
||||
"wit-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna",
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-encoder"
|
||||
version = "0.36.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "822b645bf4f2446b949776ffca47e2af60b167209ffb70814ef8779d299cd421"
|
||||
dependencies = [
|
||||
"leb128",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-metadata"
|
||||
version = "0.10.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2167ce53b2faa16a92c6cafd4942cff16c9a4fa0c5a5a0a41131ee4e49fc055f"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"spdx",
|
||||
"wasm-encoder",
|
||||
"wasmparser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.116.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a58e28b80dd8340cb07b8242ae654756161f6fc8d0038123d679b7b99964fa50"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.13.1"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"wit-bindgen-rust-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-core"
|
||||
version = "0.13.1"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"wit-component",
|
||||
"wit-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust"
|
||||
version = "0.13.2"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"heck",
|
||||
"wasm-metadata",
|
||||
"wit-bindgen-core",
|
||||
"wit-component",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust-macro"
|
||||
version = "0.13.1"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wit-bindgen-core",
|
||||
"wit-bindgen-rust",
|
||||
"wit-component",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-component"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "480cc1a078b305c1b8510f7c455c76cbd008ee49935f3a6c5fd5e937d8d95b1e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags",
|
||||
"indexmap",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"wasm-encoder",
|
||||
"wasm-metadata",
|
||||
"wasmparser",
|
||||
"wit-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-parser"
|
||||
version = "0.12.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43771ee863a16ec4ecf9da0fc65c3bbd4a1235c8e3da5f094b562894843dfa76"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"id-arena",
|
||||
"indexmap",
|
||||
"log",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"unicode-xid",
|
||||
]
|
@ -1,33 +0,0 @@
|
||||
[package]
|
||||
name = "sqlite_worker"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
opt-level = "s"
|
||||
lto = true
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
base64 = "0.13"
|
||||
bincode = "1.3.3"
|
||||
rusqlite = { git = "https://github.com/uqbar-dao/rusqlite", rev = "8fb20a9", features = ["bundled", "wasm32-wasi-vfs"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
thiserror = "1.0"
|
||||
uqbar_process_lib = { git = "ssh://git@github.com/uqbar-dao/process_lib.git", rev = "5e1b94a" }
|
||||
wit-bindgen = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "5390bab780733f1660d14c254ec985df2816bf1d" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[package.metadata.component]
|
||||
package = "uqbar:process"
|
||||
|
||||
[package.metadata.component.target]
|
||||
path = "wit"
|
||||
|
||||
[package.metadata.component.dependencies]
|
@ -1,66 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
crossplatform_wget() {
|
||||
curl -L "${1}" -o $(basename "${1}")
|
||||
}
|
||||
|
||||
crossplatform_realpath_inner() {
|
||||
python3 -c "import os; print(os.path.realpath('$1'))"
|
||||
}
|
||||
|
||||
crossplatform_realpath() {
|
||||
if [ -e "$1" ] || [ -L "$1" ]; then
|
||||
crossplatform_realpath_inner "$1"
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# cd sqlite
|
||||
# cargo build --release --no-default-features --target wasm32-wasi
|
||||
#
|
||||
# cd ../sqlite_worker
|
||||
|
||||
# Get special clang compiler required to build & link sqlite3 C lib.
|
||||
mkdir -p target
|
||||
cd target
|
||||
|
||||
WASI_VERSION=20
|
||||
WASI_VERSION_FULL=${WASI_VERSION}.0
|
||||
CC_PATH=$(crossplatform_realpath ./wasi-sdk-${WASI_VERSION_FULL}/bin/clang)
|
||||
|
||||
# Determine operating system
|
||||
OS_TYPE="$(uname)"
|
||||
if [ "$OS_TYPE" = "Darwin" ]; then
|
||||
WASI_PLATFORM="macos"
|
||||
elif [ "$OS_TYPE" = "Linux" ]; then
|
||||
WASI_PLATFORM="linux"
|
||||
else
|
||||
echo "sqlite_worker build failed: Unsupported OS: $OS_TYPE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -e "$CC_PATH" ]; then
|
||||
$(crossplatform_wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_VERSION}/wasi-sdk-${WASI_VERSION_FULL}-${WASI_PLATFORM}.tar.gz)
|
||||
tar xvf wasi-sdk-${WASI_VERSION_FULL}-${WASI_PLATFORM}.tar.gz
|
||||
fi
|
||||
|
||||
CC_PATH=$(crossplatform_realpath ./wasi-sdk-${WASI_VERSION_FULL}/bin/clang)
|
||||
|
||||
cd ..
|
||||
|
||||
# We write env vars to `.cargo/config.toml` here because:
|
||||
# 1. Doing `export foo=/path && export bar=/path2 && RUSTFLAGS=baz cargo build ...`
|
||||
# does not properly pass the RUSTFLAGS (cargo bug?).
|
||||
# 2. Specifying `~/path` inside `.cargo/config.toml` doesn't expand.
|
||||
mkdir -p .cargo
|
||||
|
||||
# Write to the .cargo/config.toml file
|
||||
cat <<EOF > .cargo/config.toml
|
||||
[env]
|
||||
CC_wasm32_wasi = "$CC_PATH"
|
||||
CARGO_TARGET_WASM32_WASI_LINKER = "$CC_PATH"
|
||||
EOF
|
||||
|
||||
RUSTFLAGS="-C target-feature=-crt-static -C link-arg=-Wl,--no-entry,--export=init,--export=cabi_realloc" cargo build --release --no-default-features --target wasm32-wasi
|
||||
|
@ -1,575 +0,0 @@
|
||||
use core::ffi::{c_char, c_int, c_ulonglong, CStr};
|
||||
use std::ffi::CString;
|
||||
|
||||
use rusqlite::{types::FromSql, types::FromSqlError, types::ToSql, types::ValueRef};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use uqbar_process_lib::{Address, create_capability, ProcessId, Response};
|
||||
use uqbar_process_lib::uqbar::process::standard as wit;
|
||||
|
||||
|
||||
wit_bindgen::generate!({
|
||||
path: "../../../wit",
|
||||
world: "process",
|
||||
exports: {
|
||||
world: Component,
|
||||
},
|
||||
});
|
||||
|
||||
mod sqlite_types;
|
||||
use sqlite_types as sq;
|
||||
|
||||
const PREFIX: &str = "sqlite-";
|
||||
|
||||
impl ToSql for sq::SqlValue {
|
||||
fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput> {
|
||||
match self {
|
||||
sq::SqlValue::Integer(i) => i.to_sql(),
|
||||
sq::SqlValue::Real(f) => f.to_sql(),
|
||||
sq::SqlValue::Text(ref s) => s.to_sql(),
|
||||
sq::SqlValue::Blob(ref b) => b.to_sql(),
|
||||
sq::SqlValue::Boolean(b) => b.to_sql(),
|
||||
sq::SqlValue::Null => Ok(rusqlite::types::ToSqlOutput::Owned(rusqlite::types::Value::Null)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromSql for sq::SqlValue {
|
||||
fn column_result(value: ValueRef<'_>) -> Result<Self, FromSqlError> {
|
||||
match value {
|
||||
ValueRef::Integer(i) => Ok(sq::SqlValue::Integer(i)),
|
||||
ValueRef::Real(f) => Ok(sq::SqlValue::Real(f)),
|
||||
ValueRef::Text(t) => {
|
||||
let text_str = std::str::from_utf8(t).map_err(|_| FromSqlError::InvalidType)?;
|
||||
Ok(sq::SqlValue::Text(text_str.to_string()))
|
||||
},
|
||||
ValueRef::Blob(b) => Ok(sq::SqlValue::Blob(b.to_vec())),
|
||||
_ => Err(FromSqlError::InvalidType),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct CPreOptionStr {
|
||||
is_empty: c_int, // 0 -> string is empty
|
||||
string: CString,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct COptionStr {
|
||||
is_empty: c_int, // 0 -> string is empty
|
||||
string: *mut c_char,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct CBytes {
|
||||
data: *mut u8,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct CPayload {
|
||||
is_empty: c_int, // 0 -> payload is empty
|
||||
mime: *mut COptionStr,
|
||||
bytes: *mut CBytes,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct CPrePayload {
|
||||
is_empty: c_int, // 0 -> payload is empty
|
||||
mime: COptionStr,
|
||||
bytes: CBytes,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct CProcessId {
|
||||
process_name: *const c_char,
|
||||
package_name: *const c_char,
|
||||
publisher_node: *const c_char,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct CIpcMetadata {
|
||||
ipc: *mut COptionStr,
|
||||
metadata: *mut COptionStr,
|
||||
}
|
||||
|
||||
impl CPreOptionStr {
|
||||
fn new(s: Option<Vec<u8>>) -> Self {
|
||||
let (is_empty, string) = match s {
|
||||
None => (0, CString::new("").unwrap()),
|
||||
Some(s) => (1, CString::new(s).unwrap()),
|
||||
};
|
||||
CPreOptionStr {
|
||||
is_empty,
|
||||
string,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl COptionStr {
|
||||
fn new(s: Option<Vec<u8>>) -> Self {
|
||||
let (is_empty, string) = match s {
|
||||
None => (0, CString::new("").unwrap()),
|
||||
Some(s) => (1, CString::new(s).unwrap()),
|
||||
};
|
||||
COptionStr {
|
||||
is_empty,
|
||||
string: string.as_ptr() as *mut c_char,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn from_coptionstr_to_bytes(s: *const COptionStr) -> Vec<u8> {
|
||||
if unsafe { (*s).is_empty == 0 } {
|
||||
vec![]
|
||||
} else {
|
||||
from_cstr_to_string(unsafe { (*s).string }).as_bytes().to_vec()
|
||||
}
|
||||
}
|
||||
|
||||
fn from_coptionstr_to_option_string(s: *const COptionStr) -> Option<String> {
|
||||
if unsafe { (*s).is_empty == 0 } {
|
||||
None
|
||||
} else {
|
||||
Some(from_cstr_to_string(unsafe { (*s).string }))
|
||||
}
|
||||
}
|
||||
|
||||
impl CBytes {
|
||||
fn new(mut bytes: Vec<u8>) -> Self {
|
||||
CBytes {
|
||||
data: bytes.as_mut_ptr(),
|
||||
len: bytes.len(),
|
||||
}
|
||||
}
|
||||
|
||||
fn new_empty() -> Self {
|
||||
CBytes::new(Vec::with_capacity(0))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<u8>> for CBytes {
|
||||
fn from(bytes: Vec<u8>) -> Self {
|
||||
CBytes::new(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CBytes> for Vec<u8> {
|
||||
fn from(bytes: CBytes) -> Self {
|
||||
let bytes = unsafe { Vec::from_raw_parts(bytes.data, bytes.len, bytes.len) };
|
||||
bytes
|
||||
}
|
||||
}
|
||||
|
||||
fn from_cbytes_to_vec_u8(bytes: *mut CBytes) -> Vec<u8> {
|
||||
// let bytes = unsafe { Vec::from_raw_parts((*bytes).data, (*bytes).len, (*bytes).len) };
|
||||
let bytes = unsafe { std::slice::from_raw_parts((*bytes).data, (*bytes).len) };
|
||||
let bytes = bytes.to_vec();
|
||||
bytes
|
||||
}
|
||||
|
||||
impl From<Option<wit::Payload>> for CPrePayload {
|
||||
fn from(p: Option<wit::Payload>) -> Self {
|
||||
let (is_empty, mime, bytes) = match p {
|
||||
None => (0, COptionStr::new(None), CBytes::new_empty()),
|
||||
Some(wit::Payload { mime, bytes }) => {
|
||||
let mime = match mime {
|
||||
Some(s) => Some(s.as_bytes().to_vec()),
|
||||
None => None,
|
||||
};
|
||||
(1, COptionStr::new(mime), CBytes::new(bytes))
|
||||
}
|
||||
};
|
||||
CPrePayload {
|
||||
is_empty,
|
||||
mime,
|
||||
bytes,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CPayload> for Option<wit::Payload> {
|
||||
fn from(p: CPayload) -> Self {
|
||||
if p.is_empty == 0 {
|
||||
None
|
||||
} else {
|
||||
let mime = from_coptionstr_to_option_string(p.mime);
|
||||
let bytes = from_cbytes_to_vec_u8(p.bytes);
|
||||
Some(wit::Payload {
|
||||
mime,
|
||||
bytes,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn from_cpayload_to_option_payload(p: *const CPayload) -> Option<wit::Payload> {
|
||||
if unsafe { (*p).is_empty == 0 } {
|
||||
None
|
||||
} else {
|
||||
let mime = unsafe { from_coptionstr_to_option_string((*p).mime) };
|
||||
let bytes = unsafe { from_cbytes_to_vec_u8((*p).bytes) };
|
||||
Some(wit::Payload {
|
||||
mime,
|
||||
bytes,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn from_cprocessid_to_processid(pid: *const CProcessId) -> ProcessId {
|
||||
ProcessId {
|
||||
process_name: from_cstr_to_string(unsafe { (*pid).process_name }),
|
||||
package_name: from_cstr_to_string(unsafe { (*pid).package_name }),
|
||||
publisher_node: from_cstr_to_string(unsafe { (*pid).publisher_node }),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_cstr_to_string(s: *const c_char) -> String {
|
||||
let cstr = unsafe { CStr::from_ptr(s) };
|
||||
cstr.to_str().unwrap().into()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn get_payload_wrapped(return_val: *mut CPayload) {
|
||||
// TODO: remove this logic; just here to avoid writing to invalid places
|
||||
// in memory due to an fs bug where chunk size may be bigger than requested
|
||||
let max_len = unsafe { (*(*return_val).bytes).len.clone() };
|
||||
|
||||
let payload = wit::get_payload();
|
||||
let mime_len = {
|
||||
match payload {
|
||||
None => None,
|
||||
Some(ref payload) => {
|
||||
match payload.mime {
|
||||
None => None,
|
||||
Some(ref mime) => {
|
||||
Some(mime.len())
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
unsafe {
|
||||
match payload {
|
||||
None => {},
|
||||
Some(payload) => {
|
||||
(*return_val).is_empty = 1;
|
||||
match payload.mime {
|
||||
None => {},
|
||||
Some(mime) => {
|
||||
(*(*return_val).mime).is_empty = 1;
|
||||
let Some(mime_len) = mime_len else { panic!("") };
|
||||
let mime = CString::new(mime).unwrap();
|
||||
std::ptr::copy_nonoverlapping(
|
||||
mime.as_ptr(),
|
||||
(*(*return_val).mime).string,
|
||||
mime_len + 1,
|
||||
);
|
||||
},
|
||||
}
|
||||
(*(*return_val).bytes).len = std::cmp::min(max_len, payload.bytes.len());
|
||||
std::ptr::copy_nonoverlapping(
|
||||
payload.bytes.as_ptr(),
|
||||
(*(*return_val).bytes).data,
|
||||
std::cmp::min(max_len, payload.bytes.len()),
|
||||
);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CIpcMetadata {
|
||||
fn copy_to_ptr(ptr: *mut CIpcMetadata, ipc: CPreOptionStr, metadata: CPreOptionStr) {
|
||||
unsafe {
|
||||
(*(*ptr).ipc).is_empty = ipc.is_empty;
|
||||
if ipc.is_empty == 1 {
|
||||
std::ptr::copy_nonoverlapping(
|
||||
ipc.string.as_ptr(),
|
||||
(*(*ptr).ipc).string,
|
||||
ipc.string.as_bytes_with_nul().len(),
|
||||
);
|
||||
}
|
||||
(*(*ptr).metadata).is_empty = metadata.is_empty;
|
||||
if metadata.is_empty == 1 {
|
||||
std::ptr::copy_nonoverlapping(
|
||||
metadata.string.as_ptr(),
|
||||
(*(*ptr).metadata).string,
|
||||
metadata.string.as_bytes_with_nul().len(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn send_and_await_response_wrapped(
|
||||
target_node: *const c_char,
|
||||
target_process: *const CProcessId,
|
||||
request_ipc: *const COptionStr,
|
||||
request_metadata: *const COptionStr,
|
||||
payload: *const CPayload,
|
||||
timeout: c_ulonglong,
|
||||
return_val: *mut CIpcMetadata,
|
||||
) {
|
||||
let target_node = from_cstr_to_string(target_node);
|
||||
let target_process = from_cprocessid_to_processid(target_process);
|
||||
let payload = from_cpayload_to_option_payload(payload);
|
||||
let request_ipc = from_coptionstr_to_bytes(request_ipc);
|
||||
let request_metadata = from_coptionstr_to_option_string(request_metadata);
|
||||
let (
|
||||
_,
|
||||
wit::Message::Response((wit::Response { ipc, metadata, .. }, _)),
|
||||
) = wit::send_and_await_response(
|
||||
&wit::Address {
|
||||
node: target_node,
|
||||
process: target_process,
|
||||
},
|
||||
&wit::Request {
|
||||
inherit: false,
|
||||
expects_response: Some(timeout),
|
||||
ipc: request_ipc,
|
||||
metadata: request_metadata,
|
||||
},
|
||||
match payload {
|
||||
None => None,
|
||||
Some(ref p) => Some(p),
|
||||
},
|
||||
).unwrap() else {
|
||||
panic!("");
|
||||
};
|
||||
let ipc = CPreOptionStr::new(Some(ipc));
|
||||
let metadata = CPreOptionStr::new(match metadata {
|
||||
None => None,
|
||||
Some(s) => Some(s.as_bytes().to_vec())
|
||||
});
|
||||
|
||||
CIpcMetadata::copy_to_ptr(return_val, ipc, metadata);
|
||||
}
|
||||
|
||||
fn json_to_sqlite(value: &serde_json::Value) -> Result<sq::SqlValue, sq::SqliteError> {
|
||||
match value {
|
||||
serde_json::Value::Number(n) => {
|
||||
if let Some(int_val) = n.as_i64() {
|
||||
Ok(sq::SqlValue::Integer(int_val))
|
||||
} else if let Some(float_val) = n.as_f64() {
|
||||
Ok(sq::SqlValue::Real(float_val))
|
||||
} else {
|
||||
Err(sq::SqliteError::InvalidParameters)
|
||||
}
|
||||
},
|
||||
serde_json::Value::String(s) => {
|
||||
match base64::decode(&s) {
|
||||
Ok(decoded_bytes) => {
|
||||
// Convert to SQLite Blob if it's a valid base64 string
|
||||
Ok(sq::SqlValue::Blob(decoded_bytes))
|
||||
},
|
||||
Err(_) => {
|
||||
// If it's not base64, just use the string itself
|
||||
Ok(sq::SqlValue::Text(s.clone()))
|
||||
}
|
||||
}
|
||||
},
|
||||
serde_json::Value::Bool(b) => {
|
||||
Ok(sq::SqlValue::Boolean(*b))
|
||||
},
|
||||
serde_json::Value::Null => {
|
||||
Ok(sq::SqlValue::Null)
|
||||
},
|
||||
_ => {
|
||||
Err(sq::SqliteError::InvalidParameters)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_message(
|
||||
our: &wit::Address,
|
||||
conn: &mut Option<rusqlite::Connection>,
|
||||
txs: &mut HashMap<u64, Vec<(String, Vec<sq::SqlValue>)>>,
|
||||
) -> anyhow::Result<()> {
|
||||
let (source, message) = wit::receive().unwrap();
|
||||
|
||||
if our.node != source.node {
|
||||
return Err(sq::SqliteError::RejectForeign.into());
|
||||
}
|
||||
|
||||
match message {
|
||||
wit::Message::Response(_) => { unimplemented!() },
|
||||
wit::Message::Request(wit::Request { ipc, .. }) => {
|
||||
match serde_json::from_slice(&ipc)? {
|
||||
sq::SqliteMessage::New { db } => {
|
||||
let vfs_drive = format!("{}{}", PREFIX, db);
|
||||
|
||||
match conn {
|
||||
Some(_) => {
|
||||
return Err(sq::SqliteError::DbAlreadyExists.into());
|
||||
},
|
||||
None => {
|
||||
let flags = rusqlite::OpenFlags::default();
|
||||
*conn = Some(rusqlite::Connection::open_with_flags_and_vfs(
|
||||
format!(
|
||||
"{}:{}:/{}.sql",
|
||||
our.node,
|
||||
vfs_drive,
|
||||
db,
|
||||
),
|
||||
flags,
|
||||
"uqbar",
|
||||
)?);
|
||||
},
|
||||
}
|
||||
},
|
||||
sq::SqliteMessage::Write { ref statement, tx_id, .. } => {
|
||||
let Some(ref conn) = conn else {
|
||||
return Err(sq::SqliteError::DbDoesNotExist.into());
|
||||
};
|
||||
|
||||
let parameters: Vec<sq::SqlValue> = match wit::get_payload() {
|
||||
None => vec![],
|
||||
Some(wit::Payload { mime: _, ref bytes }) => {
|
||||
let json_params = serde_json::from_slice::<serde_json::Value>(bytes)?;
|
||||
match json_params {
|
||||
serde_json::Value::Array(vec) => {
|
||||
vec.iter().map(|value| json_to_sqlite(value)).collect::<Result<Vec<_>, _>>()?
|
||||
},
|
||||
_ => {
|
||||
return Err(sq::SqliteError::InvalidParameters.into());
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
match tx_id {
|
||||
Some(tx_id) => {
|
||||
txs.entry(tx_id)
|
||||
.or_insert_with(Vec::new)
|
||||
.push((statement.clone(), parameters));
|
||||
},
|
||||
None => {
|
||||
let mut stmt = conn.prepare(statement)?;
|
||||
stmt.execute(rusqlite::params_from_iter(parameters.iter()))?;
|
||||
},
|
||||
};
|
||||
|
||||
Response::new()
|
||||
.ipc(ipc)
|
||||
.send()?;
|
||||
},
|
||||
sq::SqliteMessage::Commit { ref tx_id, .. } => {
|
||||
let Some(queries) = txs.remove(tx_id) else {
|
||||
return Err(sq::SqliteError::NoTx.into());
|
||||
};
|
||||
|
||||
let Some(ref mut conn) = conn else {
|
||||
return Err(sq::SqliteError::DbDoesNotExist.into());
|
||||
};
|
||||
|
||||
let tx = conn.transaction()?;
|
||||
for (query, params) in queries {
|
||||
tx.execute(&query, rusqlite::params_from_iter(params.iter()))?;
|
||||
}
|
||||
|
||||
tx.commit()?;
|
||||
|
||||
Response::new()
|
||||
.ipc(ipc)
|
||||
.send()?;
|
||||
},
|
||||
sq::SqliteMessage::Read { ref query, .. } => {
|
||||
let Some(ref db_handle) = conn else {
|
||||
return Err(sq::SqliteError::DbDoesNotExist.into());
|
||||
};
|
||||
|
||||
let parameters: Vec<sq::SqlValue> = match wit::get_payload() {
|
||||
None => vec![],
|
||||
Some(wit::Payload { mime: _, ref bytes }) => {
|
||||
let json_params = serde_json::from_slice::<serde_json::Value>(bytes)?;
|
||||
match json_params {
|
||||
serde_json::Value::Array(vec) => {
|
||||
vec.iter().map(|value| json_to_sqlite(value)).collect::<Result<Vec<_>, _>>()?
|
||||
},
|
||||
_ => {
|
||||
return Err(sq::SqliteError::InvalidParameters.into());
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
let mut statement = db_handle.prepare(query)?;
|
||||
let column_names: Vec<String> = statement
|
||||
.column_names()
|
||||
.iter()
|
||||
.map(|c| c.to_string())
|
||||
.collect();
|
||||
|
||||
let results: Vec<HashMap<String, serde_json::Value>> = statement
|
||||
.query_map(rusqlite::params_from_iter(parameters.iter()), |row| {
|
||||
let mut map = HashMap::new();
|
||||
for (i, column_name) in column_names.iter().enumerate() {
|
||||
let value: sq::SqlValue = row.get(i)?;
|
||||
let value_json = match value {
|
||||
sq::SqlValue::Integer(int) => serde_json::Value::Number(int.into()),
|
||||
sq::SqlValue::Real(real) => serde_json::Value::Number(serde_json::Number::from_f64(real).unwrap()),
|
||||
sq::SqlValue::Text(text) => serde_json::Value::String(text),
|
||||
sq::SqlValue::Blob(blob) => serde_json::Value::String(base64::encode(blob)), // or another representation if you prefer
|
||||
_ => serde_json::Value::Null,
|
||||
};
|
||||
map.insert(column_name.clone(), value_json);
|
||||
}
|
||||
Ok(map)
|
||||
})?
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
let results = serde_json::json!(results).to_string();
|
||||
let results_bytes = results.as_bytes().to_vec();
|
||||
|
||||
Response::new()
|
||||
.ipc(ipc)
|
||||
.payload(wit::Payload {
|
||||
mime: None,
|
||||
bytes: results_bytes,
|
||||
})
|
||||
.send()?;
|
||||
},
|
||||
}
|
||||
|
||||
Ok(())
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
struct Component;
|
||||
impl Guest for Component {
|
||||
fn init(our: String) {
|
||||
wit::print_to_terminal(1, "sqlite_worker: begin");
|
||||
let our = Address::from_str(&our).unwrap();
|
||||
|
||||
let mut conn: Option<rusqlite::Connection> = None;
|
||||
let mut txs: HashMap<u64, Vec<(String, Vec<sq::SqlValue>)>> = HashMap::new();
|
||||
|
||||
let vfs_address = ProcessId::from_str("vfs:sys:uqbar").unwrap();
|
||||
create_capability(
|
||||
&vfs_address,
|
||||
&"\"messaging\"".into(),
|
||||
);
|
||||
|
||||
loop {
|
||||
match handle_message(&our, &mut conn, &mut txs) {
|
||||
Ok(()) => {},
|
||||
Err(e) => {
|
||||
// TODO: should we send an error on failure?
|
||||
wit::print_to_terminal(0, format!(
|
||||
"sqlite_worker: error: {:?}",
|
||||
e,
|
||||
).as_str());
|
||||
if let Some(e) = e.downcast_ref::<sq::SqliteError>() {
|
||||
Response::new()
|
||||
.ipc(serde_json::to_vec(&e).unwrap())
|
||||
.send()
|
||||
.unwrap();
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -1 +0,0 @@
|
||||
../../sqlite_types.rs
|
84
modules/terminal/Cargo.lock
generated
84
modules/terminal/Cargo.lock
generated
@ -58,9 +58,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.10"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
|
||||
checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
@ -69,9 +69,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.2"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156"
|
||||
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
@ -122,9 +122,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.9"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
|
||||
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
|
||||
|
||||
[[package]]
|
||||
name = "leb128"
|
||||
@ -134,9 +134,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.149"
|
||||
version = "0.2.151"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b"
|
||||
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
@ -158,9 +158,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.69"
|
||||
version = "1.0.70"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
|
||||
checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@ -206,9 +206,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.15"
|
||||
version = "1.0.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
|
||||
checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
@ -218,18 +218,18 @@ checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.190"
|
||||
version = "1.0.193"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7"
|
||||
checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.190"
|
||||
version = "1.0.193"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3"
|
||||
checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -249,9 +249,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.11.1"
|
||||
version = "1.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a"
|
||||
checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
|
||||
|
||||
[[package]]
|
||||
name = "spdx"
|
||||
@ -264,9 +264,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.38"
|
||||
version = "2.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b"
|
||||
checksum = "13fa70a4ee923979ffb522cacce59d34421ebdea5625e1073c4326ef9d2dd42e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -322,9 +322,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.13"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
|
||||
checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
@ -355,8 +355,8 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
||||
|
||||
[[package]]
|
||||
name = "uqbar_process_lib"
|
||||
version = "0.3.0"
|
||||
source = "git+ssh://git@github.com/uqbar-dao/process_lib.git?rev=5e1b94a#5e1b94ae2f85c66da33ec52117a72b90d53c4d22"
|
||||
version = "0.4.0"
|
||||
source = "git+ssh://git@github.com/uqbar-dao/process_lib.git?rev=1ce0d41#1ce0d412169e795c2a99464563b42ae2a2628d77"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
@ -388,18 +388,18 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-encoder"
|
||||
version = "0.36.1"
|
||||
version = "0.38.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53ae0be20bf87918df4fa831bfbbd0b491d24aee407ed86360eae4c2c5608d38"
|
||||
checksum = "0ad2b51884de9c7f4fe2fd1043fccb8dcad4b1e29558146ee57a144d15779f3f"
|
||||
dependencies = [
|
||||
"leb128",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-metadata"
|
||||
version = "0.10.10"
|
||||
version = "0.10.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5621910462c61a8efc3248fdfb1739bf649bb335b0df935c27b340418105f9d8"
|
||||
checksum = "d835d67708f6374937c550ad8dd1d17c616ae009e3f00d7a0ac9f7825e78c36a"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"indexmap",
|
||||
@ -413,9 +413,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.116.0"
|
||||
version = "0.118.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53290b1276c5c2d47d694fb1a920538c01f51690e7e261acbe1d10c5fc306ea1"
|
||||
checksum = "95ee9723b928e735d53000dec9eae7b07a60e490c85ab54abb66659fc61bfcd9"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"semver",
|
||||
@ -423,8 +423,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.13.1"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=efcc759#efcc7592cf3277bcb9be1034e48569c6d822b322"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"wit-bindgen-rust-macro",
|
||||
@ -432,8 +432,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-core"
|
||||
version = "0.13.1"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=efcc759#efcc7592cf3277bcb9be1034e48569c6d822b322"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"wit-component",
|
||||
@ -442,8 +442,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust"
|
||||
version = "0.13.2"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=efcc759#efcc7592cf3277bcb9be1034e48569c6d822b322"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"heck",
|
||||
@ -454,8 +454,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust-macro"
|
||||
version = "0.13.1"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=efcc759#efcc7592cf3277bcb9be1034e48569c6d822b322"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"proc-macro2",
|
||||
@ -468,9 +468,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-component"
|
||||
version = "0.17.0"
|
||||
version = "0.18.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "480cc1a078b305c1b8510f7c455c76cbd008ee49935f3a6c5fd5e937d8d95b1e"
|
||||
checksum = "5b8a35a2a9992898c9d27f1664001860595a4bc99d32dd3599d547412e17d7e2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags",
|
||||
@ -487,9 +487,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-parser"
|
||||
version = "0.12.2"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43771ee863a16ec4ecf9da0fc65c3bbd4a1235c8e3da5f094b562894843dfa76"
|
||||
checksum = "15df6b7b28ce94b8be39d8df5cb21a08a4f3b9f33b631aedb4aa5776f785ead3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"id-arena",
|
||||
|
@ -13,10 +13,10 @@ lto = true
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
bincode = "1.3.3"
|
||||
serde = {version = "1.0", features = ["derive"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
uqbar_process_lib = { git = "ssh://git@github.com/uqbar-dao/process_lib.git", rev = "5e1b94a" }
|
||||
wit-bindgen = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "5390bab780733f1660d14c254ec985df2816bf1d" }
|
||||
uqbar_process_lib = { git = "ssh://git@github.com/uqbar-dao/process_lib.git", rev = "1ce0d41" }
|
||||
wit-bindgen = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "efcc759" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
@ -2,7 +2,7 @@
|
||||
{
|
||||
"process_name": "terminal",
|
||||
"process_wasm_path": "/terminal.wasm",
|
||||
"on_panic": "Restart",
|
||||
"on_exit": "Restart",
|
||||
"request_networking": true,
|
||||
"request_messaging": [
|
||||
"net:sys:uqbar",
|
||||
|
@ -2,7 +2,7 @@
|
||||
{
|
||||
"process_name": "tester",
|
||||
"process_wasm_path": "/tester.wasm",
|
||||
"on_panic": "Restart",
|
||||
"on_exit": "Restart",
|
||||
"request_networking": true,
|
||||
"request_messaging": [
|
||||
"net:sys:uqbar"
|
||||
|
104
modules/tester/test_runner/Cargo.lock
generated
104
modules/tester/test_runner/Cargo.lock
generated
@ -19,9 +19,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.4.0"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
|
||||
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
@ -58,9 +58,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.10"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
|
||||
checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
@ -69,9 +69,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.0"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
|
||||
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
@ -111,9 +111,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.0.0"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
|
||||
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
@ -122,9 +122,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.9"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
|
||||
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
|
||||
|
||||
[[package]]
|
||||
name = "leb128"
|
||||
@ -134,9 +134,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.150"
|
||||
version = "0.2.151"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
|
||||
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
@ -158,9 +158,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.66"
|
||||
version = "1.0.70"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
|
||||
checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@ -206,30 +206,30 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.15"
|
||||
version = "1.0.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
|
||||
checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.18"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918"
|
||||
checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.188"
|
||||
version = "1.0.193"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e"
|
||||
checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.188"
|
||||
version = "1.0.193"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
|
||||
checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -238,9 +238,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.105"
|
||||
version = "1.0.108"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360"
|
||||
checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
@ -249,9 +249,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.11.0"
|
||||
version = "1.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
|
||||
checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
|
||||
|
||||
[[package]]
|
||||
name = "spdx"
|
||||
@ -264,9 +264,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.31"
|
||||
version = "2.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398"
|
||||
checksum = "13fa70a4ee923979ffb522cacce59d34421ebdea5625e1073c4326ef9d2dd42e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -323,15 +323,15 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.13"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
|
||||
checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.11"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
@ -356,8 +356,8 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
||||
|
||||
[[package]]
|
||||
name = "uqbar_process_lib"
|
||||
version = "0.3.0"
|
||||
source = "git+ssh://git@github.com/uqbar-dao/process_lib.git?rev=5e1b94a#5e1b94ae2f85c66da33ec52117a72b90d53c4d22"
|
||||
version = "0.4.0"
|
||||
source = "git+ssh://git@github.com/uqbar-dao/process_lib.git?rev=8342b1a#8342b1a131401fb5d141dab8c90e79aa6d2bc909"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
@ -389,18 +389,18 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-encoder"
|
||||
version = "0.36.2"
|
||||
version = "0.38.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "822b645bf4f2446b949776ffca47e2af60b167209ffb70814ef8779d299cd421"
|
||||
checksum = "0ad2b51884de9c7f4fe2fd1043fccb8dcad4b1e29558146ee57a144d15779f3f"
|
||||
dependencies = [
|
||||
"leb128",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-metadata"
|
||||
version = "0.10.11"
|
||||
version = "0.10.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2167ce53b2faa16a92c6cafd4942cff16c9a4fa0c5a5a0a41131ee4e49fc055f"
|
||||
checksum = "d835d67708f6374937c550ad8dd1d17c616ae009e3f00d7a0ac9f7825e78c36a"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"indexmap",
|
||||
@ -414,9 +414,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.116.1"
|
||||
version = "0.118.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a58e28b80dd8340cb07b8242ae654756161f6fc8d0038123d679b7b99964fa50"
|
||||
checksum = "95ee9723b928e735d53000dec9eae7b07a60e490c85ab54abb66659fc61bfcd9"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"semver",
|
||||
@ -424,8 +424,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.13.1"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=efcc759#efcc7592cf3277bcb9be1034e48569c6d822b322"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"wit-bindgen-rust-macro",
|
||||
@ -433,8 +433,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-core"
|
||||
version = "0.13.1"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=efcc759#efcc7592cf3277bcb9be1034e48569c6d822b322"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"wit-component",
|
||||
@ -443,8 +443,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust"
|
||||
version = "0.13.2"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=efcc759#efcc7592cf3277bcb9be1034e48569c6d822b322"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"heck",
|
||||
@ -455,8 +455,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust-macro"
|
||||
version = "0.13.1"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=efcc759#efcc7592cf3277bcb9be1034e48569c6d822b322"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"proc-macro2",
|
||||
@ -469,9 +469,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-component"
|
||||
version = "0.17.0"
|
||||
version = "0.18.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "480cc1a078b305c1b8510f7c455c76cbd008ee49935f3a6c5fd5e937d8d95b1e"
|
||||
checksum = "5b8a35a2a9992898c9d27f1664001860595a4bc99d32dd3599d547412e17d7e2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags",
|
||||
@ -488,9 +488,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-parser"
|
||||
version = "0.12.2"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43771ee863a16ec4ecf9da0fc65c3bbd4a1235c8e3da5f094b562894843dfa76"
|
||||
checksum = "15df6b7b28ce94b8be39d8df5cb21a08a4f3b9f33b631aedb4aa5776f785ead3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"id-arena",
|
||||
|
@ -13,19 +13,14 @@ lto = true
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
bincode = "1.3.3"
|
||||
serde = {version = "1.0", features = ["derive"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
thiserror = "1.0"
|
||||
uqbar_process_lib = { git = "ssh://git@github.com/uqbar-dao/process_lib.git", rev = "5e1b94a" }
|
||||
wit-bindgen = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "5390bab780733f1660d14c254ec985df2816bf1d" }
|
||||
uqbar_process_lib = { git = "ssh://git@github.com/uqbar-dao/process_lib.git", rev = "8342b1a" }
|
||||
wit-bindgen = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "efcc759" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[package.metadata.component]
|
||||
package = "uqbar:process"
|
||||
|
||||
[package.metadata.component.target]
|
||||
path = "wit"
|
||||
|
||||
[package.metadata.component.dependencies]
|
||||
|
@ -1,9 +1,9 @@
|
||||
use serde::{Serialize, Deserialize};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use uqbar_process_lib::{Address, ProcessId, Request, Response};
|
||||
use uqbar_process_lib::kernel_types as kt;
|
||||
use uqbar_process_lib::uqbar::process::standard as wit;
|
||||
use uqbar_process_lib::{spawn, Address, Message, OnExit, ProcessId, Request, Response};
|
||||
|
||||
mod tester_types;
|
||||
use tester_types as tt;
|
||||
@ -33,23 +33,29 @@ fn handle_message(our: &Address) -> anyhow::Result<()> {
|
||||
match message {
|
||||
wit::Message::Response(_) => {
|
||||
return Err(tt::TesterError::UnexpectedResponse.into());
|
||||
},
|
||||
}
|
||||
wit::Message::Request(wit::Request { ref ipc, .. }) => {
|
||||
match serde_json::from_slice(ipc)? {
|
||||
tt::TesterRequest::Run(_) => {
|
||||
tt::TesterRequest::Run { test_timeout, .. } => {
|
||||
wit::print_to_terminal(0, "test_runner: got Run");
|
||||
|
||||
let (_, response) = Request::new()
|
||||
let response = Request::new()
|
||||
.target(make_vfs_address(&our)?)
|
||||
.ipc(serde_json::to_vec(&kt::VfsRequest {
|
||||
drive: "tester:uqbar".into(),
|
||||
action: kt::VfsAction::GetEntry("/".into()),
|
||||
path: "/tester:uqbar/pkg".into(),
|
||||
action: kt::VfsAction::ReadDir,
|
||||
})?)
|
||||
.send_and_await_response(5)??;
|
||||
.send_and_await_response(test_timeout)?
|
||||
.unwrap();
|
||||
|
||||
let wit::Message::Response((response, _)) = response else { panic!("") };
|
||||
let kt::VfsResponse::GetEntry { children, .. } =
|
||||
serde_json::from_slice(&response.ipc)? else { panic!("") };
|
||||
let Message::Response { ipc: vfs_ipc, .. } = response else {
|
||||
panic!("")
|
||||
};
|
||||
let kt::VfsResponse::ReadDir(children) =
|
||||
serde_json::from_slice(&vfs_ipc)?
|
||||
else {
|
||||
panic!("")
|
||||
};
|
||||
let mut children: HashSet<_> = children.into_iter().collect();
|
||||
children.remove("/manifest.json");
|
||||
children.remove("/metadata.json");
|
||||
@ -58,36 +64,49 @@ fn handle_message(our: &Address) -> anyhow::Result<()> {
|
||||
|
||||
wit::print_to_terminal(0, &format!("test_runner: running {:?}...", children));
|
||||
|
||||
// todo: are children returned as absolute paths.
|
||||
|
||||
for child in &children {
|
||||
let child_process_id = match wit::spawn(
|
||||
let child_process_id = match spawn(
|
||||
None,
|
||||
child,
|
||||
&wit::OnPanic::None, // TODO: notify us
|
||||
OnExit::None, // TODO: notify us
|
||||
&wit::Capabilities::All,
|
||||
false, // not public
|
||||
) {
|
||||
Ok(child_process_id) => child_process_id,
|
||||
Err(e) => {
|
||||
wit::print_to_terminal(0, &format!("couldn't spawn {}: {}", child, e));
|
||||
wit::print_to_terminal(
|
||||
0,
|
||||
&format!("couldn't spawn {}: {}", child, e),
|
||||
);
|
||||
panic!("couldn't spawn"); // TODO
|
||||
}
|
||||
};
|
||||
|
||||
let (_, response) = Request::new()
|
||||
let response = Request::new()
|
||||
.target(Address {
|
||||
node: our.node.clone(),
|
||||
process: child_process_id,
|
||||
})
|
||||
.ipc(ipc.clone())
|
||||
.send_and_await_response(5)??;
|
||||
.send_and_await_response(test_timeout)?
|
||||
.unwrap();
|
||||
|
||||
let wit::Message::Response((response, _)) = response else { panic!("") };
|
||||
match serde_json::from_slice(&response.ipc)? {
|
||||
tt::TesterResponse::Pass => {},
|
||||
tt::TesterResponse::GetFullMessage(_) => {},
|
||||
tt::TesterResponse::Fail { test, file, line, column } => {
|
||||
let Message::Response { ipc, .. } = response else {
|
||||
panic!("")
|
||||
};
|
||||
match serde_json::from_slice(&ipc)? {
|
||||
tt::TesterResponse::Pass => {}
|
||||
tt::TesterResponse::GetFullMessage(_) => {}
|
||||
tt::TesterResponse::Fail {
|
||||
test,
|
||||
file,
|
||||
line,
|
||||
column,
|
||||
} => {
|
||||
fail!(test, file, line, column);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -97,11 +116,13 @@ fn handle_message(our: &Address) -> anyhow::Result<()> {
|
||||
.ipc(serde_json::to_vec(&tt::TesterResponse::Pass).unwrap())
|
||||
.send()
|
||||
.unwrap();
|
||||
},
|
||||
tt::TesterRequest::KernelMessage(_) | tt::TesterRequest::GetFullMessage(_) => { unimplemented!() },
|
||||
}
|
||||
tt::TesterRequest::KernelMessage(_) | tt::TesterRequest::GetFullMessage(_) => {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,14 +140,11 @@ impl Guest for Component {
|
||||
|
||||
loop {
|
||||
match handle_message(&our) {
|
||||
Ok(()) => {},
|
||||
Ok(()) => {}
|
||||
Err(e) => {
|
||||
wit::print_to_terminal(0, format!(
|
||||
"test_runner: error: {:?}",
|
||||
e,
|
||||
).as_str());
|
||||
wit::print_to_terminal(0, format!("test_runner: error: {:?}", e,).as_str());
|
||||
fail!("test_runner");
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
100
modules/tester/tester/Cargo.lock
generated
100
modules/tester/tester/Cargo.lock
generated
@ -19,9 +19,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.4.0"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
|
||||
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
@ -58,9 +58,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.10"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
|
||||
checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
@ -69,9 +69,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.2"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156"
|
||||
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
@ -122,9 +122,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.9"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
|
||||
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
|
||||
|
||||
[[package]]
|
||||
name = "leb128"
|
||||
@ -134,9 +134,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.150"
|
||||
version = "0.2.151"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
|
||||
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
@ -158,9 +158,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.66"
|
||||
version = "1.0.70"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
|
||||
checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@ -206,30 +206,30 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.15"
|
||||
version = "1.0.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
|
||||
checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.18"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918"
|
||||
checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.188"
|
||||
version = "1.0.193"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e"
|
||||
checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.188"
|
||||
version = "1.0.193"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
|
||||
checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -238,9 +238,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.105"
|
||||
version = "1.0.108"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360"
|
||||
checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
@ -249,9 +249,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.11.0"
|
||||
version = "1.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
|
||||
checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
|
||||
|
||||
[[package]]
|
||||
name = "spdx"
|
||||
@ -264,9 +264,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.31"
|
||||
version = "2.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398"
|
||||
checksum = "13fa70a4ee923979ffb522cacce59d34421ebdea5625e1073c4326ef9d2dd42e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -324,15 +324,15 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.13"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
|
||||
checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.11"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
@ -357,8 +357,8 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
||||
|
||||
[[package]]
|
||||
name = "uqbar_process_lib"
|
||||
version = "0.3.0"
|
||||
source = "git+ssh://git@github.com/uqbar-dao/process_lib.git?rev=5e1b94a#5e1b94ae2f85c66da33ec52117a72b90d53c4d22"
|
||||
version = "0.4.0"
|
||||
source = "git+ssh://git@github.com/uqbar-dao/process_lib.git?rev=a1dd690#a1dd690b2372ca9f249d96d0c46c97c7333a8b8b"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
@ -390,18 +390,18 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-encoder"
|
||||
version = "0.36.2"
|
||||
version = "0.38.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "822b645bf4f2446b949776ffca47e2af60b167209ffb70814ef8779d299cd421"
|
||||
checksum = "0ad2b51884de9c7f4fe2fd1043fccb8dcad4b1e29558146ee57a144d15779f3f"
|
||||
dependencies = [
|
||||
"leb128",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-metadata"
|
||||
version = "0.10.11"
|
||||
version = "0.10.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2167ce53b2faa16a92c6cafd4942cff16c9a4fa0c5a5a0a41131ee4e49fc055f"
|
||||
checksum = "d835d67708f6374937c550ad8dd1d17c616ae009e3f00d7a0ac9f7825e78c36a"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"indexmap",
|
||||
@ -415,9 +415,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.116.1"
|
||||
version = "0.118.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a58e28b80dd8340cb07b8242ae654756161f6fc8d0038123d679b7b99964fa50"
|
||||
checksum = "95ee9723b928e735d53000dec9eae7b07a60e490c85ab54abb66659fc61bfcd9"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"semver",
|
||||
@ -425,8 +425,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.13.1"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=efcc759#efcc7592cf3277bcb9be1034e48569c6d822b322"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"wit-bindgen-rust-macro",
|
||||
@ -434,8 +434,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-core"
|
||||
version = "0.13.1"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=efcc759#efcc7592cf3277bcb9be1034e48569c6d822b322"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"wit-component",
|
||||
@ -444,8 +444,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust"
|
||||
version = "0.13.2"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=efcc759#efcc7592cf3277bcb9be1034e48569c6d822b322"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"heck",
|
||||
@ -456,8 +456,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust-macro"
|
||||
version = "0.13.1"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=5390bab780733f1660d14c254ec985df2816bf1d#5390bab780733f1660d14c254ec985df2816bf1d"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/bytecodealliance/wit-bindgen?rev=efcc759#efcc7592cf3277bcb9be1034e48569c6d822b322"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"proc-macro2",
|
||||
@ -470,9 +470,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-component"
|
||||
version = "0.17.0"
|
||||
version = "0.18.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "480cc1a078b305c1b8510f7c455c76cbd008ee49935f3a6c5fd5e937d8d95b1e"
|
||||
checksum = "5b8a35a2a9992898c9d27f1664001860595a4bc99d32dd3599d547412e17d7e2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags",
|
||||
@ -489,9 +489,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-parser"
|
||||
version = "0.12.2"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43771ee863a16ec4ecf9da0fc65c3bbd4a1235c8e3da5f094b562894843dfa76"
|
||||
checksum = "15df6b7b28ce94b8be39d8df5cb21a08a4f3b9f33b631aedb4aa5776f785ead3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"id-arena",
|
||||
|
@ -14,19 +14,14 @@ lto = true
|
||||
anyhow = "1.0"
|
||||
bincode = "1.3.3"
|
||||
indexmap = "2.1"
|
||||
serde = {version = "1.0", features = ["derive"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
thiserror = "1.0"
|
||||
uqbar_process_lib = { git = "ssh://git@github.com/uqbar-dao/process_lib.git", rev = "5e1b94a" }
|
||||
wit-bindgen = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "5390bab780733f1660d14c254ec985df2816bf1d" }
|
||||
uqbar_process_lib = { git = "ssh://git@github.com/uqbar-dao/process_lib.git", rev = "a1dd690" }
|
||||
wit-bindgen = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "efcc759" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[package.metadata.component]
|
||||
package = "uqbar:process"
|
||||
|
||||
[package.metadata.component.target]
|
||||
path = "wit"
|
||||
|
||||
[package.metadata.component.dependencies]
|
||||
|
@ -1,8 +1,10 @@
|
||||
use indexmap::map::IndexMap;
|
||||
|
||||
use uqbar_process_lib::{Address, ProcessId, Request, Response};
|
||||
use uqbar_process_lib::kernel_types as kt;
|
||||
use uqbar_process_lib::uqbar::process::standard as wit;
|
||||
use uqbar_process_lib::{
|
||||
await_message, call_init, get_capability, println, share_capability, spawn, Address,
|
||||
Capabilities, Message, OnExit, ProcessId, Request, Response,
|
||||
};
|
||||
|
||||
mod tester_types;
|
||||
use tester_types as tt;
|
||||
@ -17,8 +19,8 @@ wit_bindgen::generate!({
|
||||
|
||||
type Messages = IndexMap<kt::Message, tt::KernelMessage>;
|
||||
|
||||
fn make_vfs_address(our: &wit::Address) -> anyhow::Result<Address> {
|
||||
Ok(wit::Address {
|
||||
fn make_vfs_address(our: &Address) -> anyhow::Result<Address> {
|
||||
Ok(Address {
|
||||
node: our.node.clone(),
|
||||
process: ProcessId::from_str("vfs:sys:uqbar")?,
|
||||
})
|
||||
@ -29,29 +31,35 @@ fn handle_message(
|
||||
_messages: &mut Messages,
|
||||
node_names: &mut Vec<String>,
|
||||
) -> anyhow::Result<()> {
|
||||
let (source, message) = wit::receive().unwrap();
|
||||
println!("handle_message");
|
||||
let Ok(message) = await_message() else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
match message {
|
||||
wit::Message::Response((wit::Response { ipc, .. }, _)) => {
|
||||
Message::Response { source, ipc, .. } => {
|
||||
match serde_json::from_slice(&ipc)? {
|
||||
tt::TesterResponse::Pass | tt::TesterResponse::Fail { .. } => {
|
||||
if (source.process.package_name != "tester")
|
||||
| (source.process.publisher_node != "uqbar") {
|
||||
| (source.process.publisher_node != "uqbar")
|
||||
{
|
||||
return Err(tt::TesterError::UnexpectedResponse.into());
|
||||
}
|
||||
Response::new()
|
||||
.ipc(ipc)
|
||||
.send()
|
||||
.unwrap();
|
||||
},
|
||||
tt::TesterResponse::GetFullMessage(_) => { unimplemented!() }
|
||||
Response::new().ipc(ipc).send().unwrap();
|
||||
}
|
||||
tt::TesterResponse::GetFullMessage(_) => {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
wit::Message::Request(wit::Request { ipc, .. }) => {
|
||||
}
|
||||
Message::Request { source, ipc, .. } => {
|
||||
match serde_json::from_slice(&ipc)? {
|
||||
tt::TesterRequest::Run(input_node_names) => {
|
||||
wit::print_to_terminal(0, "tester: got Run");
|
||||
tt::TesterRequest::Run {
|
||||
input_node_names,
|
||||
test_timeout,
|
||||
} => {
|
||||
println!("tester: got Run");
|
||||
|
||||
assert!(input_node_names.len() >= 1);
|
||||
*node_names = input_node_names.clone();
|
||||
@ -63,17 +71,17 @@ fn handle_message(
|
||||
.unwrap();
|
||||
} else {
|
||||
// we are master node
|
||||
let child = "/test_runner.wasm";
|
||||
let child_process_id = match wit::spawn(
|
||||
let child = "/tester:uqbar/pkg/test_runner.wasm";
|
||||
let child_process_id = match spawn(
|
||||
None,
|
||||
child,
|
||||
&wit::OnPanic::None, // TODO: notify us
|
||||
&wit::Capabilities::All,
|
||||
OnExit::None, // TODO: notify us
|
||||
&Capabilities::All,
|
||||
false, // not public
|
||||
) {
|
||||
Ok(child_process_id) => child_process_id,
|
||||
Err(e) => {
|
||||
wit::print_to_terminal(0, &format!("couldn't spawn {}: {}", child, e));
|
||||
println!("couldn't spawn {}: {}", child, e);
|
||||
panic!("couldn't spawn"); // TODO
|
||||
}
|
||||
};
|
||||
@ -83,48 +91,48 @@ fn handle_message(
|
||||
process: child_process_id,
|
||||
})
|
||||
.ipc(ipc)
|
||||
.expects_response(15)
|
||||
.expects_response(test_timeout)
|
||||
.send()?;
|
||||
}
|
||||
},
|
||||
tt::TesterRequest::KernelMessage(_) | tt::TesterRequest::GetFullMessage(_) => { unimplemented!() },
|
||||
}
|
||||
tt::TesterRequest::KernelMessage(_) | tt::TesterRequest::GetFullMessage(_) => {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
struct Component;
|
||||
impl Guest for Component {
|
||||
fn init(our: String) {
|
||||
wit::print_to_terminal(0, "tester: begin");
|
||||
|
||||
let our = Address::from_str(&our).unwrap();
|
||||
let mut messages: Messages = IndexMap::new();
|
||||
let mut node_names: Vec<String> = Vec::new();
|
||||
|
||||
// orchestrate tests using external scripts
|
||||
// -> must give drive cap to rpc
|
||||
let drive_cap = wit::get_capability(
|
||||
&make_vfs_address(&our).unwrap(),
|
||||
&serde_json::to_string(&serde_json::json!({
|
||||
"kind": "write",
|
||||
"drive": "tester:uqbar",
|
||||
})).unwrap()
|
||||
).unwrap();
|
||||
wit::share_capability(&ProcessId::from_str("http_server:sys:uqbar").unwrap(), &drive_cap);
|
||||
|
||||
loop {
|
||||
match handle_message(&our, &mut messages, &mut node_names) {
|
||||
Ok(()) => {},
|
||||
Err(e) => {
|
||||
wit::print_to_terminal(0, format!(
|
||||
"tester: error: {:?}",
|
||||
e,
|
||||
).as_str());
|
||||
fail!("tester");
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
call_init!(init);
|
||||
fn init(our: Address) {
|
||||
println!("tester: begin");
|
||||
|
||||
let mut messages: Messages = IndexMap::new();
|
||||
let mut node_names: Vec<String> = Vec::new();
|
||||
|
||||
// orchestrate tests using external scripts
|
||||
// -> must give drive cap to rpc
|
||||
let drive_cap = get_capability(
|
||||
&make_vfs_address(&our).unwrap(),
|
||||
&serde_json::to_string(&serde_json::json!({
|
||||
"kind": "write",
|
||||
"drive": "/tester:uqbar/pkg",
|
||||
}))
|
||||
.expect("couldn't serialize"),
|
||||
)
|
||||
.expect("couldn't get drive cap");
|
||||
share_capability(
|
||||
&ProcessId::from_str("http_server:sys:uqbar").expect("couldn't make pid"),
|
||||
&drive_cap,
|
||||
);
|
||||
|
||||
loop {
|
||||
match handle_message(&our, &mut messages, &mut node_names) {
|
||||
Ok(()) => {}
|
||||
Err(e) => {
|
||||
println!("tester: error: {:?}", e,);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ pub struct KernelMessage {
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum TesterRequest {
|
||||
Run(Vec<String>),
|
||||
Run { input_node_names: Vec<String>, test_timeout: u64 },
|
||||
KernelMessage(KernelMessage),
|
||||
GetFullMessage(kt::Message),
|
||||
}
|
||||
@ -61,6 +61,7 @@ macro_rules! fail {
|
||||
}).unwrap())
|
||||
.send()
|
||||
.unwrap();
|
||||
panic!("")
|
||||
};
|
||||
($test:expr, $file:expr, $line:expr, $column:expr) => {
|
||||
Response::new()
|
||||
@ -72,6 +73,6 @@ macro_rules! fail {
|
||||
}).unwrap())
|
||||
.send()
|
||||
.unwrap();
|
||||
panic!("");
|
||||
panic!("")
|
||||
};
|
||||
}
|
||||
|
@ -280,7 +280,7 @@ fn make_error_message(our_name: String, km: &KernelMessage, error: EthRpcError)
|
||||
id: km.id,
|
||||
source: Address {
|
||||
node: our_name.clone(),
|
||||
process: FILESYSTEM_PROCESS_ID.clone(),
|
||||
process: ETH_RPC_PROCESS_ID.clone(),
|
||||
},
|
||||
target: match &km.rsvp {
|
||||
None => km.source.clone(),
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,820 +0,0 @@
|
||||
use crate::filesystem::manifest::{FileIdentifier, Manifest};
|
||||
use crate::types::*;
|
||||
/// log structured filesystem
|
||||
use anyhow::Result;
|
||||
use std::collections::{HashMap, HashSet, VecDeque};
|
||||
use std::io::Read;
|
||||
use std::sync::Arc;
|
||||
use tokio::fs;
|
||||
use tokio::sync::oneshot::{Receiver, Sender};
|
||||
use tokio::sync::Mutex;
|
||||
use tokio::time::{interval, Duration};
|
||||
mod manifest;
|
||||
|
||||
pub async fn load_fs(
|
||||
our_name: String,
|
||||
home_directory_path: String,
|
||||
file_key: Vec<u8>,
|
||||
fs_config: FsConfig,
|
||||
runtime_extensions: Vec<(ProcessId, MessageSender, bool)>,
|
||||
) -> Result<(ProcessMap, Manifest, Vec<KernelMessage>), FsError> {
|
||||
// load/create fs directory, manifest + log if none.
|
||||
let fs_directory_path_str = format!("{}/fs", &home_directory_path);
|
||||
|
||||
if let Err(e) = fs::create_dir_all(&fs_directory_path_str).await {
|
||||
panic!("failed creating fs dir! {:?}", e);
|
||||
}
|
||||
|
||||
let fs_directory_path: std::path::PathBuf =
|
||||
fs::canonicalize(fs_directory_path_str).await.unwrap();
|
||||
|
||||
// open and load manifest+log
|
||||
|
||||
let manifest_path = fs_directory_path.join("manifest.bin");
|
||||
|
||||
let manifest_file = fs::OpenOptions::new()
|
||||
.append(true)
|
||||
.read(true)
|
||||
.create(true)
|
||||
.open(&manifest_path)
|
||||
.await
|
||||
.expect("fs: failed to open manifest file");
|
||||
|
||||
let wal_path = fs_directory_path.join("wal.bin");
|
||||
|
||||
let wal_file = fs::OpenOptions::new()
|
||||
.append(true)
|
||||
.read(true)
|
||||
.create(true)
|
||||
.open(&wal_path)
|
||||
.await
|
||||
.expect("fs: failed to open WAL file");
|
||||
|
||||
// in memory details about files.
|
||||
let mut manifest = Manifest::load(
|
||||
manifest_file,
|
||||
wal_file,
|
||||
&fs_directory_path,
|
||||
file_key,
|
||||
fs_config,
|
||||
)
|
||||
.await
|
||||
.expect("manifest load failed!");
|
||||
|
||||
// get kernel state for booting up
|
||||
let kernel_process_id = FileIdentifier::Process(KERNEL_PROCESS_ID.clone());
|
||||
let mut process_map: ProcessMap = HashMap::new();
|
||||
|
||||
// get current processes' wasm_bytes handles. GetState(kernel)
|
||||
let vfs_messages = match manifest.read(&kernel_process_id, None, None).await {
|
||||
Err(_) => {
|
||||
// bootstrap filesystem
|
||||
bootstrap(
|
||||
&our_name,
|
||||
&kernel_process_id,
|
||||
runtime_extensions,
|
||||
&mut process_map,
|
||||
&mut manifest,
|
||||
)
|
||||
.await
|
||||
.expect("fresh bootstrap failed!")
|
||||
}
|
||||
Ok(bytes) => {
|
||||
process_map = bincode::deserialize(&bytes).expect("state map deserialization error!");
|
||||
vec![]
|
||||
}
|
||||
};
|
||||
|
||||
Ok((process_map, manifest, vfs_messages))
|
||||
}
|
||||
|
||||
/// function run only upon fresh boot.
|
||||
///
|
||||
/// for each folder in /modules, looks for a package.zip file, extracts the contents,
|
||||
/// sends the contents to VFS, and reads the manifest.json.
|
||||
///
|
||||
/// the manifest.json contains instructions for which processes to boot and what
|
||||
/// capabilities to give them. since we are inside runtime, can spawn those out of
|
||||
/// thin air.
|
||||
async fn bootstrap(
|
||||
our_name: &str,
|
||||
kernel_process_id: &FileIdentifier,
|
||||
runtime_extensions: Vec<(ProcessId, MessageSender, bool)>,
|
||||
process_map: &mut ProcessMap,
|
||||
manifest: &mut Manifest,
|
||||
) -> Result<Vec<KernelMessage>> {
|
||||
println!("bootstrapping node...\r");
|
||||
|
||||
let mut runtime_caps: HashSet<Capability> = HashSet::new();
|
||||
// kernel is a special case
|
||||
runtime_caps.insert(Capability {
|
||||
issuer: Address {
|
||||
node: our_name.to_string(),
|
||||
process: ProcessId::from_str("kernel:sys:uqbar").unwrap(),
|
||||
},
|
||||
params: "\"messaging\"".into(),
|
||||
});
|
||||
// net is a special case
|
||||
runtime_caps.insert(Capability {
|
||||
issuer: Address {
|
||||
node: our_name.to_string(),
|
||||
process: ProcessId::from_str("net:sys:uqbar").unwrap(),
|
||||
},
|
||||
params: "\"messaging\"".into(),
|
||||
});
|
||||
for runtime_module in runtime_extensions.clone() {
|
||||
runtime_caps.insert(Capability {
|
||||
issuer: Address {
|
||||
node: our_name.to_string(),
|
||||
process: runtime_module.0,
|
||||
},
|
||||
params: "\"messaging\"".into(),
|
||||
});
|
||||
}
|
||||
// give all runtime processes the ability to send messages across the network
|
||||
runtime_caps.insert(Capability {
|
||||
issuer: Address {
|
||||
node: our_name.to_string(),
|
||||
process: KERNEL_PROCESS_ID.clone(),
|
||||
},
|
||||
params: "\"network\"".into(),
|
||||
});
|
||||
|
||||
// finally, save runtime modules in state map as well, somewhat fakely
|
||||
// special cases for kernel and net
|
||||
process_map
|
||||
.entry(ProcessId::from_str("kernel:sys:uqbar").unwrap())
|
||||
.or_insert(PersistedProcess {
|
||||
wasm_bytes_handle: 0,
|
||||
on_panic: OnPanic::Restart,
|
||||
capabilities: runtime_caps.clone(),
|
||||
public: false,
|
||||
});
|
||||
process_map
|
||||
.entry(ProcessId::from_str("net:sys:uqbar").unwrap())
|
||||
.or_insert(PersistedProcess {
|
||||
wasm_bytes_handle: 0,
|
||||
on_panic: OnPanic::Restart,
|
||||
capabilities: runtime_caps.clone(),
|
||||
public: false,
|
||||
});
|
||||
for runtime_module in runtime_extensions {
|
||||
process_map
|
||||
.entry(runtime_module.0)
|
||||
.or_insert(PersistedProcess {
|
||||
wasm_bytes_handle: 0,
|
||||
on_panic: OnPanic::Restart,
|
||||
capabilities: runtime_caps.clone(),
|
||||
public: runtime_module.2,
|
||||
});
|
||||
}
|
||||
|
||||
let packages: Vec<(String, zip::ZipArchive<std::io::Cursor<Vec<u8>>>)> =
|
||||
get_zipped_packages().await;
|
||||
|
||||
let mut vfs_messages = Vec::new();
|
||||
|
||||
for (package_name, mut package) in packages {
|
||||
// special case tester: only load it in if in simulation mode
|
||||
if package_name == "tester" {
|
||||
#[cfg(not(feature = "simulation-mode"))]
|
||||
continue;
|
||||
#[cfg(feature = "simulation-mode")]
|
||||
{}
|
||||
}
|
||||
|
||||
println!("fs: handling package {package_name}...\r");
|
||||
// get and read metadata.json
|
||||
let Ok(mut package_metadata_zip) = package.by_name("metadata.json") else {
|
||||
println!(
|
||||
"fs: missing metadata for package {}, skipping",
|
||||
package_name
|
||||
);
|
||||
continue;
|
||||
};
|
||||
let mut metadata_content = Vec::new();
|
||||
package_metadata_zip
|
||||
.read_to_end(&mut metadata_content)
|
||||
.unwrap();
|
||||
drop(package_metadata_zip);
|
||||
let package_metadata: serde_json::Value =
|
||||
serde_json::from_slice(&metadata_content).expect("fs: metadata parse error");
|
||||
|
||||
println!("fs: found package metadata: {:?}\r", package_metadata);
|
||||
|
||||
let package_name = package_metadata["package"]
|
||||
.as_str()
|
||||
.expect("fs: metadata parse error: bad package name");
|
||||
|
||||
let package_publisher = package_metadata["publisher"]
|
||||
.as_str()
|
||||
.expect("fs: metadata parse error: bad publisher name");
|
||||
|
||||
// create a new package in VFS
|
||||
let our_drive_name = [package_name, package_publisher].join(":");
|
||||
vfs_messages.push(KernelMessage {
|
||||
id: rand::random(),
|
||||
source: Address {
|
||||
node: our_name.to_string(),
|
||||
process: FILESYSTEM_PROCESS_ID.clone(),
|
||||
},
|
||||
target: Address {
|
||||
node: our_name.to_string(),
|
||||
process: VFS_PROCESS_ID.clone(),
|
||||
},
|
||||
rsvp: None,
|
||||
message: Message::Request(Request {
|
||||
inherit: false,
|
||||
expects_response: None,
|
||||
ipc: serde_json::to_vec::<VfsRequest>(&VfsRequest {
|
||||
drive: our_drive_name.clone(),
|
||||
action: VfsAction::New,
|
||||
})
|
||||
.unwrap(),
|
||||
metadata: None,
|
||||
}),
|
||||
payload: None,
|
||||
signed_capabilities: None,
|
||||
});
|
||||
// for each file in package.zip, recursively through all dirs, send a newfile KM to VFS
|
||||
for i in 0..package.len() {
|
||||
let mut file = package.by_index(i).unwrap();
|
||||
if file.is_file() {
|
||||
let file_path = file
|
||||
.enclosed_name()
|
||||
.expect("fs: name error reading package.zip")
|
||||
.to_owned();
|
||||
let mut file_path = file_path.to_string_lossy().to_string();
|
||||
if !file_path.starts_with('/') {
|
||||
file_path = format!("/{}", file_path);
|
||||
}
|
||||
println!("fs: found file {}...\r", file_path);
|
||||
let mut file_content = Vec::new();
|
||||
file.read_to_end(&mut file_content).unwrap();
|
||||
vfs_messages.push(KernelMessage {
|
||||
id: rand::random(),
|
||||
source: Address {
|
||||
node: our_name.to_string(),
|
||||
process: FILESYSTEM_PROCESS_ID.clone(),
|
||||
},
|
||||
target: Address {
|
||||
node: our_name.to_string(),
|
||||
process: VFS_PROCESS_ID.clone(),
|
||||
},
|
||||
rsvp: None,
|
||||
message: Message::Request(Request {
|
||||
inherit: false,
|
||||
expects_response: None,
|
||||
ipc: serde_json::to_vec::<VfsRequest>(&VfsRequest {
|
||||
drive: our_drive_name.clone(),
|
||||
action: VfsAction::Add {
|
||||
full_path: file_path,
|
||||
entry_type: AddEntryType::NewFile,
|
||||
},
|
||||
})
|
||||
.unwrap(),
|
||||
metadata: None,
|
||||
}),
|
||||
payload: Some(Payload {
|
||||
mime: None,
|
||||
bytes: file_content,
|
||||
}),
|
||||
signed_capabilities: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// get and read manifest.json
|
||||
let Ok(mut package_manifest_zip) = package.by_name("manifest.json") else {
|
||||
println!(
|
||||
"fs: missing manifest for package {}, skipping",
|
||||
package_name
|
||||
);
|
||||
continue;
|
||||
};
|
||||
let mut manifest_content = Vec::new();
|
||||
package_manifest_zip
|
||||
.read_to_end(&mut manifest_content)
|
||||
.unwrap();
|
||||
drop(package_manifest_zip);
|
||||
let package_manifest = String::from_utf8(manifest_content)?;
|
||||
let package_manifest = serde_json::from_str::<Vec<PackageManifestEntry>>(&package_manifest)
|
||||
.expect("fs: manifest parse error");
|
||||
|
||||
// for each process-entry in manifest.json:
|
||||
for mut entry in package_manifest {
|
||||
let wasm_bytes = &mut Vec::new();
|
||||
let mut file_path = entry.process_wasm_path.to_string();
|
||||
if file_path.starts_with('/') {
|
||||
file_path = file_path[1..].to_string();
|
||||
}
|
||||
package
|
||||
.by_name(&file_path)
|
||||
.expect("fs: no wasm found in package!")
|
||||
.read_to_end(wasm_bytes)
|
||||
.unwrap();
|
||||
|
||||
// spawn the requested capabilities
|
||||
// remember: out of thin air, because this is the root distro
|
||||
let mut requested_caps = HashSet::new();
|
||||
let our_process_id = format!(
|
||||
"{}:{}:{}",
|
||||
entry.process_name, package_name, package_publisher
|
||||
);
|
||||
entry.request_messaging = Some(entry.request_messaging.unwrap_or_default());
|
||||
if let Some(ref mut request_messaging) = entry.request_messaging {
|
||||
request_messaging.push(our_process_id.clone());
|
||||
for process_name in request_messaging {
|
||||
requested_caps.insert(Capability {
|
||||
issuer: Address {
|
||||
node: our_name.to_string(),
|
||||
process: ProcessId::from_str(process_name).unwrap(),
|
||||
},
|
||||
params: "\"messaging\"".into(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if entry.request_networking {
|
||||
requested_caps.insert(Capability {
|
||||
issuer: Address {
|
||||
node: our_name.to_string(),
|
||||
process: KERNEL_PROCESS_ID.clone(),
|
||||
},
|
||||
params: "\"network\"".into(),
|
||||
});
|
||||
}
|
||||
|
||||
// give access to package_name vfs
|
||||
requested_caps.insert(Capability {
|
||||
issuer: Address {
|
||||
node: our_name.into(),
|
||||
process: VFS_PROCESS_ID.clone(),
|
||||
},
|
||||
params: serde_json::to_string(&serde_json::json!({
|
||||
"kind": "read",
|
||||
"drive": our_drive_name,
|
||||
}))
|
||||
.unwrap(),
|
||||
});
|
||||
requested_caps.insert(Capability {
|
||||
issuer: Address {
|
||||
node: our_name.into(),
|
||||
process: VFS_PROCESS_ID.clone(),
|
||||
},
|
||||
params: serde_json::to_string(&serde_json::json!({
|
||||
"kind": "write",
|
||||
"drive": our_drive_name,
|
||||
}))
|
||||
.unwrap(),
|
||||
});
|
||||
|
||||
let public_process = entry.public;
|
||||
|
||||
// save in process map
|
||||
let file = FileIdentifier::new_uuid();
|
||||
manifest.write(&file, wasm_bytes).await.unwrap();
|
||||
let wasm_bytes_handle = file.to_uuid().unwrap();
|
||||
|
||||
process_map.insert(
|
||||
ProcessId::new(Some(&entry.process_name), package_name, package_publisher),
|
||||
PersistedProcess {
|
||||
wasm_bytes_handle,
|
||||
on_panic: entry.on_panic,
|
||||
capabilities: requested_caps,
|
||||
public: public_process,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// save kernel process state. FsAction::SetState(kernel)
|
||||
let serialized_process_map =
|
||||
bincode::serialize(&process_map).expect("state map serialization error!");
|
||||
let process_map_hash: [u8; 32] = hash_bytes(&serialized_process_map);
|
||||
|
||||
if manifest.get_by_hash(&process_map_hash).await.is_none() {
|
||||
let _ = manifest
|
||||
.write(kernel_process_id, &serialized_process_map)
|
||||
.await;
|
||||
}
|
||||
|
||||
Ok(vfs_messages)
|
||||
}
|
||||
|
||||
/// go into /target folder and get all .zip package files
|
||||
async fn get_zipped_packages() -> Vec<(String, zip::ZipArchive<std::io::Cursor<Vec<u8>>>)> {
|
||||
println!("fs: reading distro packages...\r");
|
||||
let target_path = std::path::Path::new("target");
|
||||
|
||||
let mut packages = Vec::new();
|
||||
|
||||
if let Ok(mut entries) = fs::read_dir(target_path).await {
|
||||
while let Ok(Some(entry)) = entries.next_entry().await {
|
||||
if entry.file_name().to_string_lossy().ends_with(".zip") {
|
||||
let package_name = entry
|
||||
.file_name()
|
||||
.to_string_lossy()
|
||||
.trim_end_matches(".zip")
|
||||
.to_string();
|
||||
if let Ok(bytes) = fs::read(entry.path()).await {
|
||||
if let Ok(zip) = zip::ZipArchive::new(std::io::Cursor::new(bytes)) {
|
||||
// add to list of packages
|
||||
println!("fs: found package: {}\r", package_name);
|
||||
packages.push((package_name, zip));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
packages
|
||||
}
|
||||
|
||||
pub async fn fs_sender(
|
||||
our_name: String,
|
||||
manifest: Manifest,
|
||||
send_to_loop: MessageSender,
|
||||
send_to_terminal: PrintSender,
|
||||
mut recv_in_fs: MessageReceiver,
|
||||
mut recv_kill: Receiver<()>,
|
||||
send_kill_confirm: Sender<()>,
|
||||
) -> Result<()> {
|
||||
// process queues for consistency
|
||||
// todo: use file_drive for moar concurrency!
|
||||
let process_queues = Arc::new(Mutex::new(
|
||||
HashMap::<ProcessId, VecDeque<KernelMessage>>::new(),
|
||||
));
|
||||
|
||||
// interval for deleting/(flushing), don't want to run immediately upon bootup.
|
||||
// -> separate wal_flush and cold_flush
|
||||
let mut interval = interval(Duration::from_secs(manifest.flush_cold_freq as u64));
|
||||
let mut first_open = true;
|
||||
|
||||
// into main loop
|
||||
loop {
|
||||
tokio::select! {
|
||||
Some(kernel_message) = recv_in_fs.recv() => {
|
||||
if our_name != kernel_message.source.node {
|
||||
println!(
|
||||
"fs: request must come from our_name={}, got: {}",
|
||||
our_name, &kernel_message,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
// internal structures have Arc::clone setup.
|
||||
let manifest_clone = manifest.clone();
|
||||
|
||||
let our_name = our_name.clone();
|
||||
let mut source = kernel_message.source.clone();
|
||||
let send_to_loop = send_to_loop.clone();
|
||||
let send_to_terminal = send_to_terminal.clone();
|
||||
|
||||
let mut process_lock = process_queues.lock().await;
|
||||
|
||||
// optimization for get/set_state queues.
|
||||
update_src_from_kernel_metadata(&mut source, &kernel_message);
|
||||
|
||||
if let Some(queue) = process_lock.get_mut(&source.process) {
|
||||
queue.push_back(kernel_message.clone());
|
||||
} else {
|
||||
let mut new_queue = VecDeque::new();
|
||||
new_queue.push_back(kernel_message.clone());
|
||||
process_lock.insert(source.process.clone(), new_queue);
|
||||
|
||||
// clone Arc for thread
|
||||
let process_lock_clone = process_queues.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
let mut process_lock = process_lock_clone.lock().await;
|
||||
|
||||
while let Some(km) = process_lock.get_mut(&source.process).and_then(|q| q.pop_front()) {
|
||||
if let Err(e) = handle_request(
|
||||
our_name.clone(),
|
||||
km.clone(),
|
||||
manifest_clone.clone(),
|
||||
send_to_loop.clone(),
|
||||
send_to_terminal.clone(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
let _ = send_to_loop
|
||||
.send(make_error_message(our_name.clone(), &km, e))
|
||||
.await;
|
||||
}
|
||||
}
|
||||
// Remove the process entry if no more tasks are left
|
||||
if let Some(queue) = process_lock.get(&source.process) {
|
||||
if queue.is_empty() {
|
||||
process_lock.remove(&source.process);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
_ = interval.tick() => {
|
||||
if !first_open {
|
||||
let manifest_clone = manifest.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
let _ = manifest_clone.flush_to_cold().await;
|
||||
// let _ = manifest_clone.cleanup().await;
|
||||
});
|
||||
}
|
||||
first_open = false;
|
||||
}
|
||||
_ = &mut recv_kill => {
|
||||
let manifest_clone = manifest.clone();
|
||||
let _ = manifest_clone.flush_to_wal_main().await;
|
||||
|
||||
let _ = send_kill_confirm.send(());
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_request(
|
||||
our_name: String,
|
||||
kernel_message: KernelMessage,
|
||||
manifest: Manifest,
|
||||
send_to_loop: MessageSender,
|
||||
_send_to_terminal: PrintSender,
|
||||
) -> Result<(), FsError> {
|
||||
let KernelMessage {
|
||||
id,
|
||||
source,
|
||||
rsvp,
|
||||
message,
|
||||
payload,
|
||||
..
|
||||
} = kernel_message;
|
||||
let Message::Request(Request {
|
||||
expects_response,
|
||||
ipc,
|
||||
metadata, // for kernel
|
||||
..
|
||||
}) = message
|
||||
else {
|
||||
return Err(FsError::NoJson);
|
||||
};
|
||||
|
||||
let action: FsAction = match serde_json::from_slice(&ipc) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Err(FsError::BadJson {
|
||||
json: String::from_utf8(ipc).unwrap_or_default(),
|
||||
error: format!("parse failed: {:?}", e),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
// println!("got action! {:?}", action);
|
||||
|
||||
let (ipc, bytes) = match action {
|
||||
FsAction::Write(maybe_file_id) => {
|
||||
let Some(ref payload) = payload else {
|
||||
return Err(FsError::BadBytes {
|
||||
action: "Write".into(),
|
||||
});
|
||||
};
|
||||
let file_uuid = match maybe_file_id {
|
||||
Some(id) => FileIdentifier::Uuid(id),
|
||||
None => FileIdentifier::new_uuid(),
|
||||
};
|
||||
|
||||
match manifest.write(&file_uuid, &payload.bytes).await {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
return Err(FsError::WriteFailed {
|
||||
file: file_uuid.to_uuid().unwrap_or_default(),
|
||||
error: e.to_string(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
(FsResponse::Write(file_uuid.to_uuid().unwrap()), None)
|
||||
}
|
||||
FsAction::WriteOffset((file_uuid, offset)) => {
|
||||
let Some(ref payload) = payload else {
|
||||
return Err(FsError::BadBytes {
|
||||
action: "Write".into(),
|
||||
});
|
||||
};
|
||||
|
||||
let file_uuid = FileIdentifier::Uuid(file_uuid);
|
||||
|
||||
match manifest.write_at(&file_uuid, offset, &payload.bytes).await {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
return Err(FsError::WriteFailed {
|
||||
file: file_uuid.to_uuid().unwrap_or_default(),
|
||||
error: format!("write_offset error: {}", e),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
(FsResponse::Write(file_uuid.to_uuid().unwrap()), None)
|
||||
}
|
||||
FsAction::Read(file_uuid) => {
|
||||
let file = FileIdentifier::Uuid(file_uuid);
|
||||
|
||||
match manifest.read(&file, None, None).await {
|
||||
Err(e) => {
|
||||
return Err(FsError::ReadFailed {
|
||||
file: file.to_uuid().unwrap_or_default(),
|
||||
error: e.to_string(),
|
||||
})
|
||||
}
|
||||
Ok(bytes) => (FsResponse::Read(file_uuid), Some(bytes)),
|
||||
}
|
||||
}
|
||||
FsAction::ReadChunk(req) => {
|
||||
let file = FileIdentifier::Uuid(req.file);
|
||||
|
||||
match manifest
|
||||
.read(&file, Some(req.start), Some(req.length))
|
||||
.await
|
||||
{
|
||||
Err(e) => {
|
||||
return Err(FsError::ReadFailed {
|
||||
file: file.to_uuid().unwrap_or_default(),
|
||||
error: e.to_string(),
|
||||
})
|
||||
}
|
||||
Ok(bytes) => (FsResponse::Read(req.file), Some(bytes)),
|
||||
}
|
||||
}
|
||||
FsAction::Delete(del) => {
|
||||
let file = FileIdentifier::Uuid(del);
|
||||
manifest.delete(&file).await?;
|
||||
|
||||
(FsResponse::Delete(del), None)
|
||||
}
|
||||
FsAction::Append(maybe_file_uuid) => {
|
||||
let Some(ref payload) = payload else {
|
||||
return Err(FsError::BadBytes {
|
||||
action: "Append".into(),
|
||||
});
|
||||
};
|
||||
|
||||
let file_uuid = match maybe_file_uuid {
|
||||
Some(uuid) => FileIdentifier::Uuid(uuid),
|
||||
None => FileIdentifier::new_uuid(),
|
||||
};
|
||||
|
||||
match manifest.append(&file_uuid, &payload.bytes).await {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
return Err(FsError::WriteFailed {
|
||||
file: file_uuid.to_uuid().unwrap_or_default(),
|
||||
error: format!("append error: {}", e),
|
||||
})
|
||||
}
|
||||
};
|
||||
// note expecting file_uuid here, if we want process state to access append, we would change this.
|
||||
(FsResponse::Append(file_uuid.to_uuid().unwrap()), None)
|
||||
}
|
||||
FsAction::Length(file_uuid) => {
|
||||
let file = FileIdentifier::Uuid(file_uuid);
|
||||
let length = manifest.get_length(&file).await;
|
||||
match length {
|
||||
Some(len) => (FsResponse::Length(len), None),
|
||||
None => {
|
||||
return Err(FsError::LengthError {
|
||||
error: format!("file not found: {:?}", file_uuid),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
FsAction::SetLength((file_uuid, length)) => {
|
||||
let file = FileIdentifier::Uuid(file_uuid);
|
||||
manifest.set_length(&file, length).await?;
|
||||
|
||||
// doublecheck if this is the type of return statement we want.
|
||||
(FsResponse::Length(length), None)
|
||||
}
|
||||
// process state handlers
|
||||
FsAction::SetState(process_id) => {
|
||||
let Some(ref payload) = payload else {
|
||||
return Err(FsError::BadBytes {
|
||||
action: "SetState".into(),
|
||||
});
|
||||
};
|
||||
|
||||
// println!("setting state for process {:?} with len {:?}", process_id, &payload.bytes.len());
|
||||
let file = FileIdentifier::Process(process_id);
|
||||
match manifest.write(&file, &payload.bytes).await {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
return Err(FsError::WriteFailed {
|
||||
file: file.to_uuid().unwrap_or_default(),
|
||||
error: format!("SetState error: {}", e),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
(FsResponse::SetState, None)
|
||||
}
|
||||
FsAction::DeleteState(process_id) => {
|
||||
let file = FileIdentifier::Process(process_id);
|
||||
manifest.delete(&file).await?;
|
||||
|
||||
(FsResponse::Delete(0), None)
|
||||
}
|
||||
FsAction::GetState(process_id) => {
|
||||
let file = FileIdentifier::Process(process_id);
|
||||
|
||||
match manifest.read(&file, None, None).await {
|
||||
Err(e) => return Err(e),
|
||||
Ok(bytes) => (FsResponse::GetState, Some(bytes)),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if expects_response.is_some() {
|
||||
let response = KernelMessage {
|
||||
id,
|
||||
source: Address {
|
||||
node: our_name.clone(),
|
||||
process: FILESYSTEM_PROCESS_ID.clone(),
|
||||
},
|
||||
target: match rsvp {
|
||||
None => source,
|
||||
Some(rsvp) => rsvp,
|
||||
},
|
||||
rsvp: None,
|
||||
message: Message::Response((
|
||||
Response {
|
||||
inherit: false,
|
||||
ipc: serde_json::to_vec::<Result<FsResponse, FsError>>(&Ok(ipc)).unwrap(),
|
||||
metadata, // for kernel
|
||||
},
|
||||
None,
|
||||
)),
|
||||
payload: bytes.map(|bytes| Payload { mime: None, bytes }),
|
||||
signed_capabilities: None,
|
||||
};
|
||||
|
||||
let _ = send_to_loop.send(response).await;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// HELPERS
|
||||
|
||||
pub fn hash_bytes(bytes: &[u8]) -> [u8; 32] {
|
||||
let mut hasher = blake3::Hasher::new();
|
||||
let chunk_size: usize = 1024 * 256;
|
||||
|
||||
for chunk in bytes.chunks(chunk_size) {
|
||||
let chunk_hash: [u8; 32] = blake3::hash(chunk).into();
|
||||
hasher.update(&chunk_hash);
|
||||
}
|
||||
hasher.finalize().into()
|
||||
}
|
||||
|
||||
fn update_src_from_kernel_metadata(source: &mut Address, kernel_message: &KernelMessage) {
|
||||
if kernel_message.source.process == *KERNEL_PROCESS_ID {
|
||||
if let Message::Request(request) = &kernel_message.message {
|
||||
if let Some(process_id_str) = &request.metadata {
|
||||
if let Ok(process_id) = ProcessId::from_str(process_id_str) {
|
||||
source.process = process_id;
|
||||
}
|
||||
}
|
||||
} else if let Message::Response((response, _)) = &kernel_message.message {
|
||||
if let Some(process_id_str) = &response.metadata {
|
||||
if let Ok(process_id) = ProcessId::from_str(process_id_str) {
|
||||
source.process = process_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn make_error_message(our_name: String, km: &KernelMessage, error: FsError) -> KernelMessage {
|
||||
KernelMessage {
|
||||
id: km.id,
|
||||
source: Address {
|
||||
node: our_name.clone(),
|
||||
process: FILESYSTEM_PROCESS_ID.clone(),
|
||||
},
|
||||
target: match &km.rsvp {
|
||||
None => km.source.clone(),
|
||||
Some(rsvp) => rsvp.clone(),
|
||||
},
|
||||
rsvp: None,
|
||||
message: Message::Response((
|
||||
Response {
|
||||
inherit: false,
|
||||
ipc: serde_json::to_vec::<Result<FsResponse, FsError>>(&Err(error)).unwrap(),
|
||||
metadata: None,
|
||||
},
|
||||
None,
|
||||
)),
|
||||
payload: None,
|
||||
signed_capabilities: None,
|
||||
}
|
||||
}
|
@ -136,38 +136,36 @@ async fn handle_message(
|
||||
|
||||
match client.execute(request).await {
|
||||
Ok(response) => {
|
||||
if expects_response.is_some() {
|
||||
let _ = send_to_loop
|
||||
.send(KernelMessage {
|
||||
id,
|
||||
source: Address {
|
||||
node: our.to_string(),
|
||||
process: ProcessId::new(Some("http_client"), "sys", "uqbar"),
|
||||
let _ = send_to_loop
|
||||
.send(KernelMessage {
|
||||
id,
|
||||
source: Address {
|
||||
node: our.to_string(),
|
||||
process: ProcessId::new(Some("http_client"), "sys", "uqbar"),
|
||||
},
|
||||
target,
|
||||
rsvp: None,
|
||||
message: Message::Response((
|
||||
Response {
|
||||
inherit: false,
|
||||
ipc: serde_json::to_vec::<Result<HttpResponse, HttpClientError>>(&Ok(
|
||||
HttpResponse {
|
||||
status: response.status().as_u16(),
|
||||
headers: serialize_headers(response.headers()),
|
||||
},
|
||||
))
|
||||
.unwrap(),
|
||||
metadata: None,
|
||||
},
|
||||
target,
|
||||
rsvp: None,
|
||||
message: Message::Response((
|
||||
Response {
|
||||
inherit: false,
|
||||
ipc: serde_json::to_vec::<Result<HttpResponse, HttpClientError>>(
|
||||
&Ok(HttpResponse {
|
||||
status: response.status().as_u16(),
|
||||
headers: serialize_headers(response.headers()),
|
||||
}),
|
||||
)
|
||||
.unwrap(),
|
||||
metadata: None,
|
||||
},
|
||||
None,
|
||||
)),
|
||||
payload: Some(Payload {
|
||||
mime: None,
|
||||
bytes: response.bytes().await.unwrap_or_default().to_vec(),
|
||||
}),
|
||||
signed_capabilities: None,
|
||||
})
|
||||
.await;
|
||||
}
|
||||
None,
|
||||
)),
|
||||
payload: Some(Payload {
|
||||
mime: None,
|
||||
bytes: response.bytes().await.unwrap_or_default().to_vec(),
|
||||
}),
|
||||
signed_capabilities: None,
|
||||
})
|
||||
.await;
|
||||
}
|
||||
Err(e) => {
|
||||
make_error_message(
|
||||
|
298
src/http/login.html
Normal file
298
src/http/login.html
Normal file
File diff suppressed because one or more lines are too long
@ -1,11 +1,13 @@
|
||||
use crate::http::types::*;
|
||||
use crate::http::utils::*;
|
||||
use crate::register;
|
||||
use crate::types::*;
|
||||
use crate::{keygen, register};
|
||||
use anyhow::Result;
|
||||
use dashmap::DashMap;
|
||||
use futures::{SinkExt, StreamExt};
|
||||
use http::uri::Authority;
|
||||
use route_recognizer::Router;
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::collections::HashMap;
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::Arc;
|
||||
@ -14,7 +16,12 @@ use warp::http::{header::HeaderValue, StatusCode};
|
||||
use warp::ws::{WebSocket, Ws};
|
||||
use warp::{Filter, Reply};
|
||||
|
||||
#[cfg(not(feature = "simulation-mode"))]
|
||||
const HTTP_SELF_IMPOSED_TIMEOUT: u64 = 15;
|
||||
#[cfg(feature = "simulation-mode")]
|
||||
const HTTP_SELF_IMPOSED_TIMEOUT: u64 = 600;
|
||||
|
||||
const LOGIN_HTML: &str = include_str!("login.html");
|
||||
|
||||
/// mapping from a given HTTP request (assigned an ID) to the oneshot
|
||||
/// channel that will get a response from the app that handles the request,
|
||||
@ -29,14 +36,23 @@ type WebSocketSenders = Arc<DashMap<u32, (ProcessId, WebSocketSender)>>;
|
||||
type WebSocketSender = tokio::sync::mpsc::Sender<warp::ws::Message>;
|
||||
|
||||
type PathBindings = Arc<RwLock<Router<BoundPath>>>;
|
||||
type WsPathBindings = Arc<RwLock<Router<BoundWsPath>>>;
|
||||
|
||||
struct BoundPath {
|
||||
pub app: ProcessId,
|
||||
pub secure_subdomain: Option<String>,
|
||||
pub authenticated: bool,
|
||||
pub local_only: bool,
|
||||
pub static_content: Option<Payload>, // TODO store in filesystem and cache
|
||||
}
|
||||
|
||||
struct BoundWsPath {
|
||||
pub app: ProcessId,
|
||||
pub secure_subdomain: Option<String>,
|
||||
pub authenticated: bool,
|
||||
pub encrypted: bool, // TODO use
|
||||
}
|
||||
|
||||
/// HTTP server: a runtime module that handles HTTP requests at a given port.
|
||||
/// The server accepts bindings-requests from apps. These can be used in two ways:
|
||||
///
|
||||
@ -55,34 +71,41 @@ struct BoundPath {
|
||||
pub async fn http_server(
|
||||
our_name: String,
|
||||
our_port: u16,
|
||||
encoded_keyfile: Vec<u8>,
|
||||
jwt_secret_bytes: Vec<u8>,
|
||||
mut recv_in_server: MessageReceiver,
|
||||
send_to_loop: MessageSender,
|
||||
print_tx: PrintSender,
|
||||
) -> Result<()> {
|
||||
let our_name = Arc::new(our_name);
|
||||
let encoded_keyfile = Arc::new(encoded_keyfile);
|
||||
let jwt_secret_bytes = Arc::new(jwt_secret_bytes);
|
||||
let http_response_senders: HttpResponseSenders = Arc::new(DashMap::new());
|
||||
let ws_senders: WebSocketSenders = Arc::new(DashMap::new());
|
||||
|
||||
// Add RPC path
|
||||
// add RPC path
|
||||
let mut bindings_map: Router<BoundPath> = Router::new();
|
||||
let rpc_bound_path = BoundPath {
|
||||
app: ProcessId::from_str("rpc:sys:uqbar").unwrap(),
|
||||
secure_subdomain: None, // TODO maybe RPC should have subdomain?
|
||||
authenticated: false,
|
||||
local_only: true,
|
||||
static_content: None,
|
||||
};
|
||||
bindings_map.add("/rpc:sys:uqbar/message", rpc_bound_path);
|
||||
|
||||
let path_bindings: PathBindings = Arc::new(RwLock::new(bindings_map));
|
||||
|
||||
// ws path bindings
|
||||
let ws_path_bindings: WsPathBindings = Arc::new(RwLock::new(Router::new()));
|
||||
|
||||
tokio::spawn(serve(
|
||||
our_name.clone(),
|
||||
our_port,
|
||||
http_response_senders.clone(),
|
||||
path_bindings.clone(),
|
||||
ws_path_bindings.clone(),
|
||||
ws_senders.clone(),
|
||||
encoded_keyfile.clone(),
|
||||
jwt_secret_bytes.clone(),
|
||||
send_to_loop.clone(),
|
||||
print_tx.clone(),
|
||||
@ -94,10 +117,9 @@ pub async fn http_server(
|
||||
km,
|
||||
http_response_senders.clone(),
|
||||
path_bindings.clone(),
|
||||
ws_path_bindings.clone(),
|
||||
ws_senders.clone(),
|
||||
jwt_secret_bytes.clone(),
|
||||
send_to_loop.clone(),
|
||||
print_tx.clone(),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
@ -111,7 +133,9 @@ async fn serve(
|
||||
our_port: u16,
|
||||
http_response_senders: HttpResponseSenders,
|
||||
path_bindings: PathBindings,
|
||||
ws_path_bindings: WsPathBindings,
|
||||
ws_senders: WebSocketSenders,
|
||||
encoded_keyfile: Arc<Vec<u8>>,
|
||||
jwt_secret_bytes: Arc<Vec<u8>>,
|
||||
send_to_loop: MessageSender,
|
||||
print_tx: PrintSender,
|
||||
@ -123,42 +147,42 @@ async fn serve(
|
||||
})
|
||||
.await;
|
||||
|
||||
// Filter to receive websockets
|
||||
// filter to receive websockets
|
||||
let cloned_msg_tx = send_to_loop.clone();
|
||||
let cloned_our = our.clone();
|
||||
let cloned_jwt_secret_bytes = jwt_secret_bytes.clone();
|
||||
let cloned_print_tx = print_tx.clone();
|
||||
let ws_route = warp::path::end()
|
||||
.and(warp::ws())
|
||||
let ws_route = warp::ws()
|
||||
.and(warp::path::full())
|
||||
.and(warp::filters::host::optional())
|
||||
.and(warp::filters::header::headers_cloned())
|
||||
.and(warp::any().map(move || cloned_our.clone()))
|
||||
.and(warp::any().map(move || cloned_jwt_secret_bytes.clone()))
|
||||
.and(warp::any().map(move || ws_senders.clone()))
|
||||
.and(warp::any().map(move || ws_path_bindings.clone()))
|
||||
.and(warp::any().map(move || cloned_msg_tx.clone()))
|
||||
.and(warp::any().map(move || cloned_print_tx.clone()))
|
||||
.map(
|
||||
|ws_connection: Ws,
|
||||
our: Arc<String>,
|
||||
jwt_secret_bytes: Arc<Vec<u8>>,
|
||||
ws_senders: WebSocketSenders,
|
||||
send_to_loop: MessageSender,
|
||||
print_tx: PrintSender| {
|
||||
ws_connection.on_upgrade(move |ws: WebSocket| async move {
|
||||
maintain_websocket(
|
||||
ws,
|
||||
our,
|
||||
jwt_secret_bytes,
|
||||
ws_senders,
|
||||
send_to_loop,
|
||||
print_tx,
|
||||
)
|
||||
.await
|
||||
})
|
||||
},
|
||||
);
|
||||
// Filter to receive HTTP requests
|
||||
.and_then(ws_handler);
|
||||
|
||||
// filter to receive and handle login requests
|
||||
let cloned_our = our.clone();
|
||||
let login = warp::path("login").and(warp::path::end()).and(
|
||||
warp::get()
|
||||
.map(|| warp::reply::with_status(warp::reply::html(LOGIN_HTML), StatusCode::OK))
|
||||
.or(warp::post()
|
||||
.and(warp::body::content_length_limit(1024 * 16))
|
||||
.and(warp::body::json())
|
||||
.and(warp::any().map(move || cloned_our.clone()))
|
||||
.and(warp::any().map(move || encoded_keyfile.clone()))
|
||||
.and_then(login_handler)),
|
||||
);
|
||||
|
||||
// filter to receive all other HTTP requests
|
||||
let filter = warp::filters::method::method()
|
||||
.and(warp::addr::remote())
|
||||
.and(warp::filters::host::optional())
|
||||
.and(warp::path::full())
|
||||
.and(warp::query::<HashMap<String, String>>())
|
||||
.and(warp::filters::header::headers_cloned())
|
||||
.and(warp::filters::body::bytes())
|
||||
.and(warp::any().map(move || our.clone()))
|
||||
@ -166,18 +190,148 @@ async fn serve(
|
||||
.and(warp::any().map(move || path_bindings.clone()))
|
||||
.and(warp::any().map(move || jwt_secret_bytes.clone()))
|
||||
.and(warp::any().map(move || send_to_loop.clone()))
|
||||
.and(warp::any().map(move || print_tx.clone()))
|
||||
.and_then(http_handler);
|
||||
|
||||
let filter_with_ws = ws_route.or(filter);
|
||||
let filter_with_ws = ws_route.or(login).or(filter);
|
||||
warp::serve(filter_with_ws)
|
||||
.run(([0, 0, 0, 0], our_port))
|
||||
.await;
|
||||
}
|
||||
|
||||
/// handle non-GET requests on /login. if POST, validate password
|
||||
/// and return auth token, which will be stored in a cookie.
|
||||
/// then redirect to wherever they were trying to go.
|
||||
async fn login_handler(
|
||||
info: LoginInfo,
|
||||
our: Arc<String>,
|
||||
encoded_keyfile: Arc<Vec<u8>>,
|
||||
) -> Result<impl warp::Reply, warp::Rejection> {
|
||||
match keygen::decode_keyfile(&encoded_keyfile, &info.password) {
|
||||
Ok(keyfile) => {
|
||||
let token = match register::generate_jwt(&keyfile.jwt_secret_bytes, our.as_ref()) {
|
||||
Some(token) => token,
|
||||
None => {
|
||||
return Ok(warp::reply::with_status(
|
||||
warp::reply::json(&"Failed to generate JWT"),
|
||||
StatusCode::SERVICE_UNAVAILABLE,
|
||||
)
|
||||
.into_response())
|
||||
}
|
||||
};
|
||||
|
||||
let mut response = warp::reply::with_status(
|
||||
warp::reply::json(&base64::encode(encoded_keyfile.to_vec())),
|
||||
StatusCode::FOUND,
|
||||
)
|
||||
.into_response();
|
||||
|
||||
match HeaderValue::from_str(&format!("uqbar-auth_{}={};", our.as_ref(), &token)) {
|
||||
Ok(v) => {
|
||||
response.headers_mut().append(http::header::SET_COOKIE, v);
|
||||
Ok(response)
|
||||
}
|
||||
Err(_) => {
|
||||
return Ok(warp::reply::with_status(
|
||||
warp::reply::json(&"Failed to generate Auth JWT"),
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
)
|
||||
.into_response())
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => Ok(warp::reply::with_status(
|
||||
warp::reply::json(&"Failed to decode keyfile"),
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
)
|
||||
.into_response()),
|
||||
}
|
||||
}
|
||||
|
||||
async fn ws_handler(
|
||||
ws_connection: Ws,
|
||||
path: warp::path::FullPath,
|
||||
host: Option<Authority>,
|
||||
headers: warp::http::HeaderMap,
|
||||
our: Arc<String>,
|
||||
jwt_secret_bytes: Arc<Vec<u8>>,
|
||||
ws_senders: WebSocketSenders,
|
||||
ws_path_bindings: WsPathBindings,
|
||||
send_to_loop: MessageSender,
|
||||
print_tx: PrintSender,
|
||||
) -> Result<impl warp::Reply, warp::Rejection> {
|
||||
let original_path = normalize_path(path.as_str());
|
||||
let _ = print_tx.send(Printout {
|
||||
verbosity: 1,
|
||||
content: format!("got ws request for {original_path}"),
|
||||
});
|
||||
|
||||
let serialized_headers = serialize_headers(&headers);
|
||||
let ws_path_bindings = ws_path_bindings.read().await;
|
||||
|
||||
let Ok(route) = ws_path_bindings.recognize(&original_path) else {
|
||||
return Err(warp::reject::not_found());
|
||||
};
|
||||
|
||||
let bound_path = route.handler();
|
||||
if let Some(ref subdomain) = bound_path.secure_subdomain {
|
||||
let _ = print_tx
|
||||
.send(Printout {
|
||||
verbosity: 1,
|
||||
content: format!(
|
||||
"got request for path {original_path} bound by subdomain {subdomain}"
|
||||
),
|
||||
})
|
||||
.await;
|
||||
// assert that host matches what this app wants it to be
|
||||
if host.is_none() {
|
||||
return Err(warp::reject::not_found());
|
||||
}
|
||||
let host = host.as_ref().unwrap();
|
||||
// parse out subdomain from host (there can only be one)
|
||||
let request_subdomain = host.host().split('.').next().unwrap_or("");
|
||||
if request_subdomain != subdomain {
|
||||
return Err(warp::reject::not_found());
|
||||
}
|
||||
}
|
||||
|
||||
if bound_path.authenticated {
|
||||
let Some(auth_token) = serialized_headers.get("cookie") else {
|
||||
return Err(warp::reject::not_found());
|
||||
};
|
||||
if !auth_cookie_valid(&our, &auth_token, &jwt_secret_bytes) {
|
||||
return Err(warp::reject::not_found());
|
||||
}
|
||||
}
|
||||
|
||||
let app = bound_path.app.clone();
|
||||
Ok(ws_connection.on_upgrade(move |ws: WebSocket| async move {
|
||||
maintain_websocket(
|
||||
ws,
|
||||
our.clone(),
|
||||
app,
|
||||
// remove process id from beginning of path by splitting into segments
|
||||
// separated by "/" and taking all but the first
|
||||
original_path
|
||||
.split('/')
|
||||
.skip(1)
|
||||
.collect::<Vec<&str>>()
|
||||
.join("/"),
|
||||
jwt_secret_bytes.clone(),
|
||||
ws_senders.clone(),
|
||||
send_to_loop.clone(),
|
||||
print_tx.clone(),
|
||||
)
|
||||
.await;
|
||||
}))
|
||||
}
|
||||
|
||||
async fn http_handler(
|
||||
method: warp::http::Method,
|
||||
socket_addr: Option<SocketAddr>,
|
||||
host: Option<Authority>,
|
||||
path: warp::path::FullPath,
|
||||
query_params: HashMap<String, String>,
|
||||
headers: warp::http::HeaderMap,
|
||||
body: warp::hyper::body::Bytes,
|
||||
our: Arc<String>,
|
||||
@ -185,11 +339,18 @@ async fn http_handler(
|
||||
path_bindings: PathBindings,
|
||||
jwt_secret_bytes: Arc<Vec<u8>>,
|
||||
send_to_loop: MessageSender,
|
||||
print_tx: PrintSender,
|
||||
) -> Result<impl warp::Reply, warp::Rejection> {
|
||||
// TODO this is all so dirty. Figure out what actually matters.
|
||||
|
||||
// trim trailing "/"
|
||||
let original_path = normalize_path(path.as_str());
|
||||
let _ = print_tx
|
||||
.send(Printout {
|
||||
verbosity: 1,
|
||||
content: format!("got request for path {original_path}"),
|
||||
})
|
||||
.await;
|
||||
let id: u64 = rand::random();
|
||||
let serialized_headers = serialize_headers(&headers);
|
||||
let path_bindings = path_bindings.read().await;
|
||||
@ -200,11 +361,55 @@ async fn http_handler(
|
||||
let bound_path = route.handler();
|
||||
|
||||
if bound_path.authenticated {
|
||||
let auth_token = serialized_headers
|
||||
.get("cookie")
|
||||
.cloned()
|
||||
.unwrap_or_default();
|
||||
if !auth_cookie_valid(&our, &auth_token, &jwt_secret_bytes) {
|
||||
match serialized_headers.get("cookie") {
|
||||
Some(auth_token) => {
|
||||
// they have an auth token, validate
|
||||
if !auth_cookie_valid(&our, &auth_token, &jwt_secret_bytes) {
|
||||
return Ok(
|
||||
warp::reply::with_status(vec![], StatusCode::UNAUTHORIZED).into_response()
|
||||
);
|
||||
}
|
||||
}
|
||||
None => {
|
||||
// redirect to login page so they can get an auth token
|
||||
let _ = print_tx
|
||||
.send(Printout {
|
||||
verbosity: 1,
|
||||
content: format!("redirecting request from {socket_addr:?} to login page"),
|
||||
})
|
||||
.await;
|
||||
return Ok(warp::http::Response::builder()
|
||||
.status(StatusCode::TEMPORARY_REDIRECT)
|
||||
.header(
|
||||
"Location",
|
||||
format!(
|
||||
"http://{}/login",
|
||||
host.unwrap_or(Authority::from_static("localhost"))
|
||||
),
|
||||
)
|
||||
.body(vec![])
|
||||
.into_response());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref subdomain) = bound_path.secure_subdomain {
|
||||
let _ = print_tx
|
||||
.send(Printout {
|
||||
verbosity: 1,
|
||||
content: format!(
|
||||
"got request for path {original_path} bound by subdomain {subdomain}"
|
||||
),
|
||||
})
|
||||
.await;
|
||||
// assert that host matches what this app wants it to be
|
||||
if host.is_none() {
|
||||
return Ok(warp::reply::with_status(vec![], StatusCode::UNAUTHORIZED).into_response());
|
||||
}
|
||||
let host = host.as_ref().unwrap();
|
||||
// parse out subdomain from host (there can only be one)
|
||||
let request_subdomain = host.host().split('.').next().unwrap_or("");
|
||||
if request_subdomain != subdomain {
|
||||
return Ok(warp::reply::with_status(vec![], StatusCode::UNAUTHORIZED).into_response());
|
||||
}
|
||||
}
|
||||
@ -258,14 +463,20 @@ async fn http_handler(
|
||||
message: Message::Request(Request {
|
||||
inherit: false,
|
||||
expects_response: Some(HTTP_SELF_IMPOSED_TIMEOUT),
|
||||
ipc: serde_json::to_vec(&IncomingHttpRequest {
|
||||
ipc: serde_json::to_vec(&HttpServerRequest::Http(IncomingHttpRequest {
|
||||
source_socket_addr: socket_addr.map(|addr| addr.to_string()),
|
||||
method: method.to_string(),
|
||||
raw_path: format!("http://localhost{}", original_path),
|
||||
raw_path: format!(
|
||||
"http://{}{}",
|
||||
host.unwrap_or(Authority::from_static("localhost"))
|
||||
.to_string(),
|
||||
original_path
|
||||
),
|
||||
headers: serialized_headers,
|
||||
})
|
||||
query_params,
|
||||
}))
|
||||
.unwrap(),
|
||||
metadata: None,
|
||||
metadata: Some("http".into()),
|
||||
}),
|
||||
payload: Some(Payload {
|
||||
mime: None,
|
||||
@ -387,57 +598,25 @@ async fn handle_rpc_message(
|
||||
async fn maintain_websocket(
|
||||
ws: WebSocket,
|
||||
our: Arc<String>,
|
||||
jwt_secret_bytes: Arc<Vec<u8>>,
|
||||
app: ProcessId,
|
||||
path: String,
|
||||
_jwt_secret_bytes: Arc<Vec<u8>>, // TODO use for encrypted channels
|
||||
ws_senders: WebSocketSenders,
|
||||
send_to_loop: MessageSender,
|
||||
_print_tx: PrintSender,
|
||||
print_tx: PrintSender,
|
||||
) {
|
||||
let (mut write_stream, mut read_stream) = ws.split();
|
||||
let _ = print_tx
|
||||
.send(Printout {
|
||||
verbosity: 1,
|
||||
content: format!("got new client websocket connection"),
|
||||
})
|
||||
.await;
|
||||
|
||||
// first, receive a message from client that contains the target process
|
||||
// and the auth token
|
||||
|
||||
let Some(Ok(register_msg)) = read_stream.next().await else {
|
||||
// stream closed, exit
|
||||
let stream = write_stream.reunite(read_stream).unwrap();
|
||||
let _ = stream.close().await;
|
||||
return;
|
||||
};
|
||||
|
||||
let Ok(ws_register) = serde_json::from_slice::<WsRegister>(register_msg.as_bytes()) else {
|
||||
// stream error, exit
|
||||
let stream = write_stream.reunite(read_stream).unwrap();
|
||||
let _ = stream.close().await;
|
||||
return;
|
||||
};
|
||||
|
||||
let Ok(owner_process) = ProcessId::from_str(&ws_register.target_process) else {
|
||||
// invalid process id, exit
|
||||
let stream = write_stream.reunite(read_stream).unwrap();
|
||||
let _ = stream.close().await;
|
||||
return;
|
||||
};
|
||||
|
||||
let Ok(our_name) = verify_auth_token(&ws_register.auth_token, &jwt_secret_bytes) else {
|
||||
// invalid auth token, exit
|
||||
let stream = write_stream.reunite(read_stream).unwrap();
|
||||
let _ = stream.close().await;
|
||||
return;
|
||||
};
|
||||
|
||||
if our_name != *our {
|
||||
// invalid auth token, exit
|
||||
let stream = write_stream.reunite(read_stream).unwrap();
|
||||
let _ = stream.close().await;
|
||||
return;
|
||||
}
|
||||
|
||||
let ws_channel_id: u32 = rand::random();
|
||||
let channel_id: u32 = rand::random();
|
||||
let (ws_sender, mut ws_receiver) = tokio::sync::mpsc::channel(100);
|
||||
ws_senders.insert(ws_channel_id, (owner_process.clone(), ws_sender));
|
||||
ws_senders.insert(channel_id, (app.clone(), ws_sender));
|
||||
|
||||
// send a message to the process associated with this channel
|
||||
// notifying them that the channel is now open
|
||||
let _ = send_to_loop
|
||||
.send(KernelMessage {
|
||||
id: rand::random(),
|
||||
@ -446,91 +625,69 @@ async fn maintain_websocket(
|
||||
process: HTTP_SERVER_PROCESS_ID.clone(),
|
||||
},
|
||||
target: Address {
|
||||
node: our.to_string(),
|
||||
process: owner_process.clone(),
|
||||
node: our.clone().to_string(),
|
||||
process: app.clone(),
|
||||
},
|
||||
rsvp: None,
|
||||
message: Message::Request(Request {
|
||||
inherit: false,
|
||||
expects_response: None,
|
||||
ipc: serde_json::to_vec(&HttpServerAction::WebSocketOpen(ws_channel_id)).unwrap(),
|
||||
metadata: None,
|
||||
ipc: serde_json::to_vec(&HttpServerRequest::WebSocketOpen { path, channel_id })
|
||||
.unwrap(),
|
||||
metadata: Some("ws".into()),
|
||||
}),
|
||||
payload: None,
|
||||
signed_capabilities: None,
|
||||
})
|
||||
.await;
|
||||
|
||||
// respond to the client notifying them that the channel is now open
|
||||
let Ok(()) = write_stream
|
||||
.send(warp::ws::Message::text(
|
||||
serde_json::to_string(&WsRegisterResponse {
|
||||
channel_id: ws_channel_id,
|
||||
})
|
||||
.unwrap(),
|
||||
))
|
||||
.await
|
||||
else {
|
||||
// stream error, exit
|
||||
let stream = write_stream.reunite(read_stream).unwrap();
|
||||
let _ = stream.close().await;
|
||||
return;
|
||||
};
|
||||
|
||||
let _ = print_tx.send(Printout {
|
||||
verbosity: 1,
|
||||
content: format!("websocket channel {channel_id} opened"),
|
||||
});
|
||||
loop {
|
||||
tokio::select! {
|
||||
read = read_stream.next() => {
|
||||
match read {
|
||||
None => {
|
||||
// stream closed, remove and exit
|
||||
websocket_close(ws_channel_id, owner_process, &ws_senders, &send_to_loop).await;
|
||||
break;
|
||||
}
|
||||
Some(Err(_e)) => {
|
||||
// stream error, remove and exit
|
||||
websocket_close(ws_channel_id, owner_process, &ws_senders, &send_to_loop).await;
|
||||
break;
|
||||
}
|
||||
Some(Ok(msg)) => {
|
||||
// forward message to process associated with this channel
|
||||
let _ = send_to_loop
|
||||
.send(KernelMessage {
|
||||
id: rand::random(),
|
||||
source: Address {
|
||||
node: our.to_string(),
|
||||
process: HTTP_SERVER_PROCESS_ID.clone(),
|
||||
},
|
||||
target: Address {
|
||||
node: our.to_string(),
|
||||
process: owner_process.clone(),
|
||||
},
|
||||
rsvp: None,
|
||||
message: Message::Request(Request {
|
||||
inherit: false,
|
||||
expects_response: None,
|
||||
ipc: serde_json::to_vec(&HttpServerAction::WebSocketPush {
|
||||
channel_id: ws_channel_id,
|
||||
message_type: WsMessageType::Binary,
|
||||
}).unwrap(),
|
||||
metadata: None,
|
||||
}),
|
||||
payload: Some(Payload {
|
||||
mime: None,
|
||||
bytes: msg.into_bytes(),
|
||||
}),
|
||||
signed_capabilities: None,
|
||||
})
|
||||
.await;
|
||||
let _ = send_to_loop.send(KernelMessage {
|
||||
id: rand::random(),
|
||||
source: Address {
|
||||
node: our.to_string(),
|
||||
process: HTTP_SERVER_PROCESS_ID.clone(),
|
||||
},
|
||||
target: Address {
|
||||
node: our.to_string(),
|
||||
process: app.clone(),
|
||||
},
|
||||
rsvp: None,
|
||||
message: Message::Request(Request {
|
||||
inherit: false,
|
||||
expects_response: None,
|
||||
ipc: serde_json::to_vec(&HttpServerRequest::WebSocketPush {
|
||||
channel_id,
|
||||
message_type: WsMessageType::Binary,
|
||||
}).unwrap(),
|
||||
metadata: Some("ws".into()),
|
||||
}),
|
||||
payload: Some(Payload {
|
||||
mime: None,
|
||||
bytes: msg.into_bytes(),
|
||||
}),
|
||||
signed_capabilities: None,
|
||||
});
|
||||
}
|
||||
_ => {
|
||||
websocket_close(channel_id, app.clone(), &ws_senders, &send_to_loop).await;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(outgoing) = ws_receiver.recv() => {
|
||||
// forward message to websocket
|
||||
match write_stream.send(outgoing).await {
|
||||
Ok(()) => continue,
|
||||
Err(_e) => {
|
||||
// stream error, remove and exit
|
||||
websocket_close(ws_channel_id, owner_process, &ws_senders, &send_to_loop).await;
|
||||
Err(_) => {
|
||||
websocket_close(channel_id, app.clone(), &ws_senders, &send_to_loop).await;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -563,8 +720,8 @@ async fn websocket_close(
|
||||
message: Message::Request(Request {
|
||||
inherit: false,
|
||||
expects_response: None,
|
||||
ipc: serde_json::to_vec(&HttpServerAction::WebSocketClose(channel_id)).unwrap(),
|
||||
metadata: None,
|
||||
ipc: serde_json::to_vec(&HttpServerRequest::WebSocketClose(channel_id)).unwrap(),
|
||||
metadata: Some("ws".into()),
|
||||
}),
|
||||
payload: Some(Payload {
|
||||
mime: None,
|
||||
@ -583,10 +740,9 @@ async fn handle_app_message(
|
||||
km: KernelMessage,
|
||||
http_response_senders: HttpResponseSenders,
|
||||
path_bindings: PathBindings,
|
||||
ws_path_bindings: WsPathBindings,
|
||||
ws_senders: WebSocketSenders,
|
||||
jwt_secret_bytes: Arc<Vec<u8>>,
|
||||
send_to_loop: MessageSender,
|
||||
print_tx: PrintSender,
|
||||
) {
|
||||
// when we get a Response, try to match it to an outstanding HTTP
|
||||
// request and send it there.
|
||||
@ -618,60 +774,10 @@ async fn handle_app_message(
|
||||
.unwrap(),
|
||||
));
|
||||
} else {
|
||||
let Ok(mut response) = serde_json::from_slice::<HttpResponse>(&response.ipc) else {
|
||||
let Ok(response) = serde_json::from_slice::<HttpResponse>(&response.ipc) else {
|
||||
// the receiver will automatically trigger a 503 when sender is dropped.
|
||||
return;
|
||||
};
|
||||
// XX REFACTOR THIS:
|
||||
// for the login case, todo refactor out?
|
||||
let segments: Vec<&str> = path
|
||||
.split('/')
|
||||
.filter(|&segment| !segment.is_empty())
|
||||
.collect();
|
||||
// If we're getting back a /login from a proxy (or our own node),
|
||||
// then we should generate a jwt from the secret + the name of the ship,
|
||||
// and then attach it to a header.
|
||||
if response.status < 400
|
||||
&& (segments.len() == 1 || segments.len() == 4)
|
||||
&& matches!(segments.last(), Some(&"login"))
|
||||
{
|
||||
if let Some(auth_cookie) = response.headers.get("set-cookie") {
|
||||
let mut ws_auth_username = km.source.node.clone();
|
||||
|
||||
if segments.len() == 4
|
||||
&& matches!(segments.first(), Some(&"http-proxy"))
|
||||
&& matches!(segments.get(1), Some(&"serve"))
|
||||
{
|
||||
if let Some(segment) = segments.get(2) {
|
||||
ws_auth_username = segment.to_string();
|
||||
}
|
||||
}
|
||||
if let Some(token) = register::generate_jwt(
|
||||
jwt_secret_bytes.to_vec().as_slice(),
|
||||
ws_auth_username.clone(),
|
||||
) {
|
||||
let auth_cookie_with_ws = format!(
|
||||
"{}; uqbar-ws-auth_{}={};",
|
||||
auth_cookie,
|
||||
ws_auth_username.clone(),
|
||||
token
|
||||
);
|
||||
response
|
||||
.headers
|
||||
.insert("set-cookie".to_string(), auth_cookie_with_ws);
|
||||
|
||||
let _ = print_tx
|
||||
.send(Printout {
|
||||
verbosity: 2,
|
||||
content: format!(
|
||||
"SET WS AUTH COOKIE WITH USERNAME: {}",
|
||||
ws_auth_username
|
||||
),
|
||||
})
|
||||
.await;
|
||||
}
|
||||
}
|
||||
}
|
||||
let _ = sender.send((
|
||||
HttpResponse {
|
||||
status: response.status,
|
||||
@ -722,6 +828,7 @@ async fn handle_app_message(
|
||||
&normalize_path(&path),
|
||||
BoundPath {
|
||||
app: km.source.process.clone(),
|
||||
secure_subdomain: None,
|
||||
authenticated,
|
||||
local_only,
|
||||
static_content: None,
|
||||
@ -743,6 +850,7 @@ async fn handle_app_message(
|
||||
&normalize_path(&path),
|
||||
BoundPath {
|
||||
app: km.source.process.clone(),
|
||||
secure_subdomain: None,
|
||||
authenticated,
|
||||
local_only,
|
||||
static_content: Some(payload),
|
||||
@ -751,7 +859,99 @@ async fn handle_app_message(
|
||||
}
|
||||
send_action_response(km.id, km.source, &send_to_loop, Ok(())).await;
|
||||
}
|
||||
HttpServerAction::WebSocketOpen(_) => {
|
||||
HttpServerAction::SecureBind { path, cache } => {
|
||||
// the process ID is hashed to generate a unique subdomain
|
||||
// only the first 32 chars, or 128 bits are used.
|
||||
// we hash because the process ID can contain many more than
|
||||
// simply alphanumeric characters that will cause issues as a subdomain.
|
||||
let process_id_hash =
|
||||
format!("{:x}", Sha256::digest(km.source.process.to_string()));
|
||||
let subdomain = process_id_hash.split_at(32).0.to_owned();
|
||||
let mut path_bindings = path_bindings.write().await;
|
||||
if !cache {
|
||||
// trim trailing "/"
|
||||
path_bindings.add(
|
||||
&normalize_path(&path),
|
||||
BoundPath {
|
||||
app: km.source.process.clone(),
|
||||
secure_subdomain: Some(subdomain),
|
||||
authenticated: true,
|
||||
local_only: false,
|
||||
static_content: None,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
let Some(payload) = km.payload else {
|
||||
send_action_response(
|
||||
km.id,
|
||||
km.source,
|
||||
&send_to_loop,
|
||||
Err(HttpServerError::NoPayload),
|
||||
)
|
||||
.await;
|
||||
return;
|
||||
};
|
||||
// trim trailing "/"
|
||||
path_bindings.add(
|
||||
&normalize_path(&path),
|
||||
BoundPath {
|
||||
app: km.source.process.clone(),
|
||||
secure_subdomain: Some(subdomain),
|
||||
authenticated: true,
|
||||
local_only: false,
|
||||
static_content: Some(payload),
|
||||
},
|
||||
);
|
||||
}
|
||||
send_action_response(km.id, km.source, &send_to_loop, Ok(())).await;
|
||||
}
|
||||
HttpServerAction::WebSocketBind {
|
||||
mut path,
|
||||
authenticated,
|
||||
encrypted,
|
||||
} => {
|
||||
path = if path.starts_with('/') {
|
||||
format!("/{}{}", km.source.process, path)
|
||||
} else {
|
||||
format!("/{}/{}", km.source.process, path)
|
||||
};
|
||||
let mut ws_path_bindings = ws_path_bindings.write().await;
|
||||
ws_path_bindings.add(
|
||||
&normalize_path(&path),
|
||||
BoundWsPath {
|
||||
app: km.source.process.clone(),
|
||||
secure_subdomain: None,
|
||||
authenticated,
|
||||
encrypted,
|
||||
},
|
||||
);
|
||||
send_action_response(km.id, km.source, &send_to_loop, Ok(())).await;
|
||||
}
|
||||
HttpServerAction::WebSocketSecureBind {
|
||||
mut path,
|
||||
encrypted,
|
||||
} => {
|
||||
path = if path.starts_with('/') {
|
||||
format!("/{}{}", km.source.process, path)
|
||||
} else {
|
||||
format!("/{}/{}", km.source.process, path)
|
||||
};
|
||||
let process_id_hash =
|
||||
format!("{:x}", Sha256::digest(km.source.process.to_string()));
|
||||
let subdomain = process_id_hash.split_at(32).0.to_owned();
|
||||
let mut ws_path_bindings = ws_path_bindings.write().await;
|
||||
ws_path_bindings.add(
|
||||
&normalize_path(&path),
|
||||
BoundWsPath {
|
||||
app: km.source.process.clone(),
|
||||
secure_subdomain: Some(subdomain),
|
||||
authenticated: true,
|
||||
encrypted,
|
||||
},
|
||||
);
|
||||
send_action_response(km.id, km.source, &send_to_loop, Ok(())).await;
|
||||
}
|
||||
HttpServerAction::WebSocketOpen { .. } => {
|
||||
// we cannot receive these, only send them to processes
|
||||
send_action_response(
|
||||
km.id,
|
||||
|
@ -5,12 +5,35 @@ use thiserror::Error;
|
||||
|
||||
/// HTTP Request type that can be shared over WASM boundary to apps.
|
||||
/// This is the one you receive from the `http_server:sys:uqbar` service.
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum HttpServerRequest {
|
||||
Http(IncomingHttpRequest),
|
||||
/// Processes will receive this kind of request when a client connects to them.
|
||||
/// If a process does not want this websocket open, they should issue a *request*
|
||||
/// containing a [`type@HttpServerAction::WebSocketClose`] message and this channel ID.
|
||||
WebSocketOpen {
|
||||
path: String,
|
||||
channel_id: u32,
|
||||
},
|
||||
/// Processes can both SEND and RECEIVE this kind of request
|
||||
/// (send as [`type@HttpServerAction::WebSocketPush`]).
|
||||
/// When received, will contain the message bytes as payload.
|
||||
WebSocketPush {
|
||||
channel_id: u32,
|
||||
message_type: WsMessageType,
|
||||
},
|
||||
/// Receiving will indicate that the client closed the socket. Can be sent to close
|
||||
/// from the server-side, as [`type@HttpServerAction::WebSocketClose`].
|
||||
WebSocketClose(u32),
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct IncomingHttpRequest {
|
||||
pub source_socket_addr: Option<String>, // will parse to SocketAddr
|
||||
pub method: String, // will parse to http::Method
|
||||
pub raw_path: String,
|
||||
pub headers: HashMap<String, String>,
|
||||
pub query_params: HashMap<String, String>,
|
||||
// BODY is stored in the payload, as bytes
|
||||
}
|
||||
|
||||
@ -56,8 +79,8 @@ pub enum HttpClientError {
|
||||
}
|
||||
|
||||
/// Request type sent to `http_server:sys:uqbar` in order to configure it.
|
||||
/// You can also send [`WebSocketPush`], which allows you to push messages
|
||||
/// across an existing open WebSocket connection.
|
||||
/// You can also send [`type@HttpServerAction::WebSocketPush`], which
|
||||
/// allows you to push messages across an existing open WebSocket connection.
|
||||
///
|
||||
/// If a response is expected, all HttpServerActions will return a Response
|
||||
/// with the shape Result<(), HttpServerActionError> serialized to JSON.
|
||||
@ -67,23 +90,53 @@ pub enum HttpServerAction {
|
||||
/// be the static file to serve at this path.
|
||||
Bind {
|
||||
path: String,
|
||||
/// Set whether the HTTP request needs a valid login cookie, AKA, whether
|
||||
/// the user needs to be logged in to access this path.
|
||||
authenticated: bool,
|
||||
/// Set whether requests can be fielded from anywhere, or only the loopback address.
|
||||
local_only: bool,
|
||||
/// Set whether to bind the payload statically to this path. That is, take the
|
||||
/// payload bytes and serve them as the response to any request to this path.
|
||||
cache: bool,
|
||||
},
|
||||
/// SecureBind expects a payload if and only if `cache` is TRUE. The payload should
|
||||
/// be the static file to serve at this path.
|
||||
///
|
||||
/// SecureBind is the same as Bind, except that it forces requests to be made from
|
||||
/// the unique subdomain of the process that bound the path. These requests are
|
||||
/// *always* authenticated, and *never* local_only. The purpose of SecureBind is to
|
||||
/// serve elements of an app frontend or API in an exclusive manner, such that other
|
||||
/// apps installed on this node cannot access them. Since the subdomain is unique, it
|
||||
/// will require the user to be logged in separately to the general domain authentication.
|
||||
SecureBind {
|
||||
path: String,
|
||||
/// Set whether to bind the payload statically to this path. That is, take the
|
||||
/// payload bytes and serve them as the response to any request to this path.
|
||||
cache: bool,
|
||||
},
|
||||
/// Bind a path to receive incoming WebSocket connections.
|
||||
/// Doesn't need a cache since does not serve assets.
|
||||
WebSocketBind {
|
||||
path: String,
|
||||
authenticated: bool,
|
||||
encrypted: bool,
|
||||
},
|
||||
/// SecureBind is the same as Bind, except that it forces new connections to be made
|
||||
/// from the unique subdomain of the process that bound the path. These are *always*
|
||||
/// authenticated. Since the subdomain is unique, it will require the user to be
|
||||
/// logged in separately to the general domain authentication.
|
||||
WebSocketSecureBind { path: String, encrypted: bool },
|
||||
/// Processes will RECEIVE this kind of request when a client connects to them.
|
||||
|
||||
/// If a process does not want this websocket open, they should issue a *request*
|
||||
/// containing a [`enum@HttpServerAction::WebSocketClose`] message and this channel ID.
|
||||
WebSocketOpen(u32),
|
||||
/// Processes can both SEND and RECEIVE this kind of request.
|
||||
/// containing a [`type@HttpServerAction::WebSocketClose`] message and this channel ID.
|
||||
WebSocketOpen { path: String, channel_id: u32 },
|
||||
/// When sent, expects a payload containing the WebSocket message bytes to send.
|
||||
WebSocketPush {
|
||||
channel_id: u32,
|
||||
message_type: WsMessageType,
|
||||
},
|
||||
/// Processes can both SEND and RECEIVE this kind of request. Sending will
|
||||
/// close a socket the process controls. Receiving will indicate that the
|
||||
/// client closed the socket.
|
||||
/// Sending will close a socket the process controls.
|
||||
WebSocketClose(u32),
|
||||
}
|
||||
|
||||
|
@ -21,11 +21,13 @@ pub struct RpcMessage {
|
||||
}
|
||||
|
||||
/// Ingest an auth token given from client and return the node name or an error.
|
||||
pub fn verify_auth_token(auth_token: &str, jwt_secret: &[u8]) -> Result<String, jwt::Error> {
|
||||
pub fn _verify_auth_token(auth_token: &str, jwt_secret: &[u8]) -> Result<String, jwt::Error> {
|
||||
let Ok(secret) = Hmac::<Sha256>::new_from_slice(jwt_secret) else {
|
||||
return Err(jwt::Error::Format);
|
||||
};
|
||||
|
||||
println!("hello\r");
|
||||
|
||||
let claims: Result<JwtClaims, jwt::Error> = auth_token.verify_with_key(&secret);
|
||||
|
||||
match claims {
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::types as t;
|
||||
use crate::FILESYSTEM_PROCESS_ID;
|
||||
use crate::types::STATE_PROCESS_ID;
|
||||
use crate::types::{self as t, VFS_PROCESS_ID};
|
||||
use crate::KERNEL_PROCESS_ID;
|
||||
use anyhow::Result;
|
||||
use ring::signature::{self, KeyPair};
|
||||
@ -57,13 +57,14 @@ async fn persist_state(
|
||||
},
|
||||
target: t::Address {
|
||||
node: our_name.to_string(),
|
||||
process: FILESYSTEM_PROCESS_ID.clone(),
|
||||
process: STATE_PROCESS_ID.clone(),
|
||||
},
|
||||
rsvp: None,
|
||||
message: t::Message::Request(t::Request {
|
||||
inherit: true,
|
||||
expects_response: None,
|
||||
ipc: serde_json::to_vec(&t::FsAction::SetState(KERNEL_PROCESS_ID.clone())).unwrap(),
|
||||
ipc: serde_json::to_vec(&t::StateAction::SetState(KERNEL_PROCESS_ID.clone()))
|
||||
.unwrap(),
|
||||
metadata: None,
|
||||
}),
|
||||
payload: Some(t::Payload { mime: None, bytes }),
|
||||
@ -142,7 +143,7 @@ async fn handle_kernel_request(
|
||||
t::KernelCommand::InitializeProcess {
|
||||
id,
|
||||
wasm_bytes_handle,
|
||||
on_panic,
|
||||
on_exit,
|
||||
initial_capabilities,
|
||||
public,
|
||||
} => {
|
||||
@ -248,7 +249,7 @@ async fn handle_kernel_request(
|
||||
process_id: id,
|
||||
persisted: t::PersistedProcess {
|
||||
wasm_bytes_handle,
|
||||
on_panic,
|
||||
on_exit,
|
||||
capabilities: valid_capabilities,
|
||||
public,
|
||||
},
|
||||
@ -453,8 +454,8 @@ async fn handle_kernel_response(
|
||||
.await;
|
||||
return;
|
||||
};
|
||||
// ignore responses that aren't filesystem responses
|
||||
if km.source.process != *FILESYSTEM_PROCESS_ID {
|
||||
// ignore responses that aren't filesystem or state responses
|
||||
if km.source.process != *STATE_PROCESS_ID && km.source.process != *VFS_PROCESS_ID {
|
||||
return;
|
||||
}
|
||||
let Some(ref metadata) = response.metadata else {
|
||||
@ -571,8 +572,8 @@ async fn start_process(
|
||||
node: our_name.clone(),
|
||||
process: id.clone(),
|
||||
},
|
||||
wasm_bytes_handle: process_metadata.persisted.wasm_bytes_handle,
|
||||
on_panic: process_metadata.persisted.on_panic.clone(),
|
||||
wasm_bytes_handle: process_metadata.persisted.wasm_bytes_handle.clone(),
|
||||
on_exit: process_metadata.persisted.on_exit.clone(),
|
||||
public: process_metadata.persisted.public,
|
||||
};
|
||||
process_handles.insert(
|
||||
@ -659,7 +660,7 @@ pub async fn kernel(
|
||||
for (process_id, persisted) in &process_map {
|
||||
// runtime extensions will have a bytes_handle of 0, because they have no
|
||||
// WASM code saved in filesystem.
|
||||
if persisted.on_panic.is_restart() && persisted.wasm_bytes_handle != 0 {
|
||||
if persisted.on_exit.is_restart() && persisted.wasm_bytes_handle != "" {
|
||||
send_to_loop
|
||||
.send(t::KernelMessage {
|
||||
id: rand::random(),
|
||||
@ -669,14 +670,17 @@ pub async fn kernel(
|
||||
},
|
||||
target: t::Address {
|
||||
node: our.name.clone(),
|
||||
process: FILESYSTEM_PROCESS_ID.clone(),
|
||||
process: VFS_PROCESS_ID.clone(),
|
||||
},
|
||||
rsvp: None,
|
||||
message: t::Message::Request(t::Request {
|
||||
inherit: true,
|
||||
expects_response: Some(5), // TODO evaluate
|
||||
ipc: serde_json::to_vec(&t::FsAction::Read(persisted.wasm_bytes_handle))
|
||||
.unwrap(),
|
||||
ipc: serde_json::to_vec(&t::VfsRequest {
|
||||
path: persisted.wasm_bytes_handle.clone(),
|
||||
action: t::VfsAction::Read,
|
||||
})
|
||||
.unwrap(),
|
||||
metadata: Some(
|
||||
serde_json::to_string(&StartProcessMetadata {
|
||||
source: t::Address {
|
||||
@ -696,7 +700,7 @@ pub async fn kernel(
|
||||
.await
|
||||
.expect("event loop: fatal: sender died");
|
||||
}
|
||||
if let t::OnPanic::Requests(requests) = &persisted.on_panic {
|
||||
if let t::OnExit::Requests(requests) = &persisted.on_exit {
|
||||
// if a persisted process had on-death-requests, we should perform them now
|
||||
// even in death, a process can only message processes it has capabilities for
|
||||
for (address, request, payload) in requests {
|
||||
@ -851,7 +855,7 @@ pub async fn kernel(
|
||||
verbosity: 0,
|
||||
content: format!(
|
||||
"event loop: don't have {} amongst registered processes (got message for it from network)",
|
||||
kernel_message.source.process,
|
||||
kernel_message.target.process,
|
||||
)
|
||||
})
|
||||
.await;
|
||||
@ -881,7 +885,7 @@ pub async fn kernel(
|
||||
// enforce that local process has capability to message a target process of this name
|
||||
// kernel and filesystem can ALWAYS message any local process
|
||||
if kernel_message.source.process != *KERNEL_PROCESS_ID
|
||||
&& kernel_message.source.process != *FILESYSTEM_PROCESS_ID
|
||||
&& kernel_message.source.process != *STATE_PROCESS_ID
|
||||
{
|
||||
let Some(persisted_source) = process_map.get(&kernel_message.source.process) else {
|
||||
continue
|
||||
|
@ -534,11 +534,11 @@ pub async fn make_process_loop(
|
||||
.await
|
||||
.expect("event loop: fatal: sender died");
|
||||
|
||||
// fulfill the designated OnPanic behavior
|
||||
match metadata.on_panic {
|
||||
t::OnPanic::None => {}
|
||||
// fulfill the designated OnExit behavior
|
||||
match metadata.on_exit {
|
||||
t::OnExit::None => {}
|
||||
// if restart, tell ourselves to init the app again, with same capabilities
|
||||
t::OnPanic::Restart => {
|
||||
t::OnExit::Restart => {
|
||||
send_to_loop
|
||||
.send(t::KernelMessage {
|
||||
id: rand::random(),
|
||||
@ -551,7 +551,7 @@ pub async fn make_process_loop(
|
||||
ipc: serde_json::to_vec(&t::KernelCommand::InitializeProcess {
|
||||
id: metadata.our.process.clone(),
|
||||
wasm_bytes_handle: metadata.wasm_bytes_handle,
|
||||
on_panic: metadata.on_panic,
|
||||
on_exit: metadata.on_exit,
|
||||
initial_capabilities,
|
||||
public: metadata.public,
|
||||
})
|
||||
@ -569,7 +569,7 @@ pub async fn make_process_loop(
|
||||
}
|
||||
// if requests, fire them
|
||||
// even in death, a process can only message processes it has capabilities for
|
||||
t::OnPanic::Requests(requests) => {
|
||||
t::OnExit::Requests(requests) => {
|
||||
for (address, mut request, payload) in requests {
|
||||
request.expects_response = None;
|
||||
let (tx, rx) = tokio::sync::oneshot::channel();
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::kernel::process;
|
||||
use crate::kernel::process::uqbar::process::standard as wit;
|
||||
use crate::types as t;
|
||||
use crate::FILESYSTEM_PROCESS_ID;
|
||||
use crate::types::STATE_PROCESS_ID;
|
||||
use crate::KERNEL_PROCESS_ID;
|
||||
use crate::VFS_PROCESS_ID;
|
||||
use anyhow::Result;
|
||||
@ -40,11 +40,15 @@ impl StandardHost for process::ProcessWasi {
|
||||
//
|
||||
|
||||
/// TODO critical: move to kernel logic to enable persistence of choice made here
|
||||
async fn set_on_panic(&mut self, on_panic: wit::OnPanic) -> Result<()> {
|
||||
self.process.metadata.on_panic = t::de_wit_on_panic(on_panic);
|
||||
async fn set_on_exit(&mut self, on_exit: wit::OnExit) -> Result<()> {
|
||||
self.process.metadata.on_exit = t::OnExit::de_wit(on_exit);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_on_exit(&mut self) -> Result<wit::OnExit> {
|
||||
Ok(self.process.metadata.on_exit.en_wit())
|
||||
}
|
||||
|
||||
/// create a message from the *kernel* to the filesystem,
|
||||
/// asking it to fetch the current state saved under this process
|
||||
async fn get_state(&mut self) -> Result<Option<Vec<u8>>> {
|
||||
@ -57,12 +61,12 @@ impl StandardHost for process::ProcessWasi {
|
||||
}),
|
||||
wit::Address {
|
||||
node: self.process.metadata.our.node.clone(),
|
||||
process: FILESYSTEM_PROCESS_ID.en_wit(),
|
||||
process: STATE_PROCESS_ID.en_wit(),
|
||||
},
|
||||
wit::Request {
|
||||
inherit: false,
|
||||
expects_response: Some(5),
|
||||
ipc: serde_json::to_vec(&t::FsAction::GetState(
|
||||
ipc: serde_json::to_vec(&t::StateAction::GetState(
|
||||
self.process.metadata.our.process.clone(),
|
||||
))
|
||||
.unwrap(),
|
||||
@ -98,12 +102,12 @@ impl StandardHost for process::ProcessWasi {
|
||||
}),
|
||||
wit::Address {
|
||||
node: self.process.metadata.our.node.clone(),
|
||||
process: FILESYSTEM_PROCESS_ID.en_wit(),
|
||||
process: STATE_PROCESS_ID.en_wit(),
|
||||
},
|
||||
wit::Request {
|
||||
inherit: false,
|
||||
expects_response: Some(5),
|
||||
ipc: serde_json::to_vec(&t::FsAction::SetState(
|
||||
ipc: serde_json::to_vec(&t::StateAction::SetState(
|
||||
self.process.metadata.our.process.clone(),
|
||||
))
|
||||
.unwrap(),
|
||||
@ -137,12 +141,12 @@ impl StandardHost for process::ProcessWasi {
|
||||
}),
|
||||
wit::Address {
|
||||
node: self.process.metadata.our.node.clone(),
|
||||
process: FILESYSTEM_PROCESS_ID.en_wit(),
|
||||
process: STATE_PROCESS_ID.en_wit(),
|
||||
},
|
||||
wit::Request {
|
||||
inherit: false,
|
||||
expects_response: Some(5),
|
||||
ipc: serde_json::to_vec(&t::FsAction::DeleteState(
|
||||
ipc: serde_json::to_vec(&t::StateAction::DeleteState(
|
||||
self.process.metadata.our.process.clone(),
|
||||
))
|
||||
.unwrap(),
|
||||
@ -171,7 +175,7 @@ impl StandardHost for process::ProcessWasi {
|
||||
&mut self,
|
||||
name: Option<String>,
|
||||
wasm_path: String, // must be located within package's drive
|
||||
on_panic: wit::OnPanic,
|
||||
on_exit: wit::OnExit,
|
||||
capabilities: wit::Capabilities,
|
||||
public: bool,
|
||||
) -> Result<Result<wit::ProcessId, wit::SpawnError>> {
|
||||
@ -181,11 +185,18 @@ impl StandardHost for process::ProcessWasi {
|
||||
node: self.process.metadata.our.node.clone(),
|
||||
process: VFS_PROCESS_ID.en_wit(),
|
||||
};
|
||||
let our_drive_name = [
|
||||
// TODO: note, drive could just be your basic process maybe.
|
||||
let path = format!(
|
||||
"/{}/{}/{}",
|
||||
self.process.metadata.our.process.to_string(),
|
||||
self.process.metadata.our.process.package(),
|
||||
self.process.metadata.our.process.publisher(),
|
||||
]
|
||||
.join(":");
|
||||
wasm_path
|
||||
);
|
||||
// let our_drive_name = [
|
||||
// self.process.metadata.our.process.package(),
|
||||
// self.process.metadata.our.process.publisher(),
|
||||
// ]
|
||||
// .join(":");
|
||||
let Ok(Ok((_, hash_response))) = process::send_and_await_response(
|
||||
self,
|
||||
None,
|
||||
@ -194,8 +205,8 @@ impl StandardHost for process::ProcessWasi {
|
||||
inherit: false,
|
||||
expects_response: Some(5),
|
||||
ipc: serde_json::to_vec(&t::VfsRequest {
|
||||
drive: our_drive_name.clone(),
|
||||
action: t::VfsAction::GetHash(wasm_path.clone()),
|
||||
path: path.clone(),
|
||||
action: t::VfsAction::Read,
|
||||
})
|
||||
.unwrap(),
|
||||
metadata: None,
|
||||
@ -214,29 +225,7 @@ impl StandardHost for process::ProcessWasi {
|
||||
self.process.last_payload = old_last_payload;
|
||||
return Ok(Err(wit::SpawnError::NoFileAtPath));
|
||||
};
|
||||
let t::VfsResponse::GetHash(Some(hash)) = serde_json::from_slice(&ipc).unwrap() else {
|
||||
// reset payload to what it was
|
||||
self.process.last_payload = old_last_payload;
|
||||
return Ok(Err(wit::SpawnError::NoFileAtPath));
|
||||
};
|
||||
let Ok(Ok(_)) = process::send_and_await_response(
|
||||
self,
|
||||
None,
|
||||
vfs_address,
|
||||
wit::Request {
|
||||
inherit: false,
|
||||
expects_response: Some(5),
|
||||
ipc: serde_json::to_vec(&t::VfsRequest {
|
||||
drive: our_drive_name,
|
||||
action: t::VfsAction::GetEntry(wasm_path.clone()),
|
||||
})
|
||||
.unwrap(),
|
||||
metadata: None,
|
||||
},
|
||||
None,
|
||||
)
|
||||
.await
|
||||
else {
|
||||
let t::VfsResponse::Read = serde_json::from_slice(&ipc).unwrap() else {
|
||||
// reset payload to what it was
|
||||
self.process.last_payload = old_last_payload;
|
||||
return Ok(Err(wit::SpawnError::NoFileAtPath));
|
||||
@ -271,8 +260,8 @@ impl StandardHost for process::ProcessWasi {
|
||||
expects_response: Some(5), // TODO evaluate
|
||||
ipc: serde_json::to_vec(&t::KernelCommand::InitializeProcess {
|
||||
id: new_process_id.clone(),
|
||||
wasm_bytes_handle: hash,
|
||||
on_panic: t::de_wit_on_panic(on_panic),
|
||||
wasm_bytes_handle: path,
|
||||
on_exit: t::OnExit::de_wit(on_exit),
|
||||
initial_capabilities: match capabilities {
|
||||
wit::Capabilities::None => HashSet::new(),
|
||||
wit::Capabilities::All => {
|
||||
|
@ -23,7 +23,7 @@ pub fn encode_keyfile(
|
||||
password: String,
|
||||
username: String,
|
||||
routers: Vec<String>,
|
||||
networking_key: Document,
|
||||
networking_key: &[u8],
|
||||
jwt: Vec<u8>,
|
||||
file_key: Vec<u8>,
|
||||
) -> Vec<u8> {
|
||||
@ -49,9 +49,7 @@ pub fn encode_keyfile(
|
||||
let jwt_nonce = Aes256Gcm::generate_nonce(&mut OsRng);
|
||||
let file_nonce = Aes256Gcm::generate_nonce(&mut OsRng);
|
||||
|
||||
let keyciphertext: Vec<u8> = cipher
|
||||
.encrypt(&network_nonce, networking_key.as_ref())
|
||||
.unwrap();
|
||||
let keyciphertext: Vec<u8> = cipher.encrypt(&network_nonce, networking_key).unwrap();
|
||||
let jwtciphertext: Vec<u8> = cipher.encrypt(&jwt_nonce, jwt.as_ref()).unwrap();
|
||||
let fileciphertext: Vec<u8> = cipher.encrypt(&file_nonce, file_key.as_ref()).unwrap();
|
||||
|
||||
@ -66,9 +64,9 @@ pub fn encode_keyfile(
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn decode_keyfile(keyfile: Vec<u8>, password: &str) -> Result<Keyfile, &'static str> {
|
||||
pub fn decode_keyfile(keyfile: &[u8], password: &str) -> Result<Keyfile, &'static str> {
|
||||
let (username, routers, salt, key_enc, jwt_enc, file_enc) =
|
||||
bincode::deserialize::<(String, Vec<String>, Vec<u8>, Vec<u8>, Vec<u8>, Vec<u8>)>(&keyfile)
|
||||
bincode::deserialize::<(String, Vec<String>, Vec<u8>, Vec<u8>, Vec<u8>, Vec<u8>)>(keyfile)
|
||||
.map_err(|_| "failed to deserialize keyfile")?;
|
||||
|
||||
// rederive disk key
|
||||
@ -112,9 +110,9 @@ pub fn decode_keyfile(keyfile: Vec<u8>, password: &str) -> Result<Keyfile, &'sta
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_username_and_routers(keyfile: Vec<u8>) -> Result<(String, Vec<String>), &'static str> {
|
||||
pub fn get_username_and_routers(keyfile: &[u8]) -> Result<(String, Vec<String>), &'static str> {
|
||||
let (username, routers, _salt, _key_enc, _jwt_enc, _file_enc) =
|
||||
bincode::deserialize::<(String, Vec<String>, Vec<u8>, Vec<u8>, Vec<u8>, Vec<u8>)>(&keyfile)
|
||||
bincode::deserialize::<(String, Vec<String>, Vec<u8>, Vec<u8>, Vec<u8>, Vec<u8>)>(keyfile)
|
||||
.map_err(|_| "failed to deserialize keyfile")?;
|
||||
|
||||
Ok((username, routers))
|
||||
|
520
src/kv.rs
Normal file
520
src/kv.rs
Normal file
@ -0,0 +1,520 @@
|
||||
use anyhow::Result;
|
||||
use dashmap::DashMap;
|
||||
// use rocksdb::checkpoint::Checkpoint;
|
||||
use rocksdb::OptimisticTransactionDB;
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use std::sync::Arc;
|
||||
use tokio::fs;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use crate::types::*;
|
||||
|
||||
pub async fn kv(
|
||||
our_node: String,
|
||||
send_to_loop: MessageSender,
|
||||
send_to_terminal: PrintSender,
|
||||
mut recv_from_loop: MessageReceiver,
|
||||
send_to_caps_oracle: CapMessageSender,
|
||||
home_directory_path: String,
|
||||
) -> anyhow::Result<()> {
|
||||
let kv_path = format!("{}/kv", &home_directory_path);
|
||||
|
||||
if let Err(e) = fs::create_dir_all(&kv_path).await {
|
||||
panic!("failed creating kv dir! {:?}", e);
|
||||
}
|
||||
|
||||
let open_kvs: Arc<DashMap<(PackageId, String), OptimisticTransactionDB>> =
|
||||
Arc::new(DashMap::new());
|
||||
let txs: Arc<DashMap<u64, Vec<(KvAction, Option<Vec<u8>>)>>> = Arc::new(DashMap::new());
|
||||
|
||||
let mut process_queues: HashMap<ProcessId, Arc<Mutex<VecDeque<KernelMessage>>>> =
|
||||
HashMap::new();
|
||||
|
||||
loop {
|
||||
tokio::select! {
|
||||
Some(km) = recv_from_loop.recv() => {
|
||||
if our_node.clone() != km.source.node {
|
||||
println!(
|
||||
"kv: request must come from our_node={}, got: {}",
|
||||
our_node,
|
||||
km.source.node,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
let queue = process_queues
|
||||
.entry(km.source.process.clone())
|
||||
.or_insert_with(|| Arc::new(Mutex::new(VecDeque::new())))
|
||||
.clone();
|
||||
|
||||
{
|
||||
let mut queue_lock = queue.lock().await;
|
||||
queue_lock.push_back(km.clone());
|
||||
}
|
||||
|
||||
// clone Arcs
|
||||
let our_node = our_node.clone();
|
||||
let send_to_caps_oracle = send_to_caps_oracle.clone();
|
||||
let send_to_terminal = send_to_terminal.clone();
|
||||
let send_to_loop = send_to_loop.clone();
|
||||
let open_kvs = open_kvs.clone();
|
||||
let txs = txs.clone();
|
||||
let kv_path = kv_path.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
let mut queue_lock = queue.lock().await;
|
||||
if let Some(km) = queue_lock.pop_front() {
|
||||
if let Err(e) = handle_request(
|
||||
our_node.clone(),
|
||||
km.clone(),
|
||||
open_kvs.clone(),
|
||||
txs.clone(),
|
||||
send_to_loop.clone(),
|
||||
send_to_terminal.clone(),
|
||||
send_to_caps_oracle.clone(),
|
||||
kv_path.clone(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
let _ = send_to_loop
|
||||
.send(make_error_message(our_node.clone(), &km, e))
|
||||
.await;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_request(
|
||||
our_node: String,
|
||||
km: KernelMessage,
|
||||
open_kvs: Arc<DashMap<(PackageId, String), OptimisticTransactionDB>>,
|
||||
txs: Arc<DashMap<u64, Vec<(KvAction, Option<Vec<u8>>)>>>,
|
||||
send_to_loop: MessageSender,
|
||||
send_to_terminal: PrintSender,
|
||||
send_to_caps_oracle: CapMessageSender,
|
||||
kv_path: String,
|
||||
) -> Result<(), KvError> {
|
||||
let KernelMessage {
|
||||
id,
|
||||
source,
|
||||
message,
|
||||
payload,
|
||||
..
|
||||
} = km.clone();
|
||||
let Message::Request(Request {
|
||||
ipc,
|
||||
expects_response,
|
||||
metadata,
|
||||
..
|
||||
}) = message.clone()
|
||||
else {
|
||||
return Err(KvError::InputError {
|
||||
error: "not a request".into(),
|
||||
});
|
||||
};
|
||||
|
||||
let request: KvRequest = match serde_json::from_slice(&ipc) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
println!("kv: got invalid Request: {}", e);
|
||||
return Err(KvError::InputError {
|
||||
error: "didn't serialize to KvAction.".into(),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
check_caps(
|
||||
our_node.clone(),
|
||||
source.clone(),
|
||||
open_kvs.clone(),
|
||||
send_to_caps_oracle.clone(),
|
||||
&request,
|
||||
kv_path.clone(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let (ipc, bytes) = match &request.action {
|
||||
KvAction::New => {
|
||||
// handled in check_caps.
|
||||
(serde_json::to_vec(&KvResponse::Ok).unwrap(), None)
|
||||
}
|
||||
KvAction::Get { key } => {
|
||||
let db = match open_kvs.get(&(request.package_id, request.db)) {
|
||||
None => {
|
||||
return Err(KvError::NoDb);
|
||||
}
|
||||
Some(db) => db,
|
||||
};
|
||||
|
||||
match db.get(&key) {
|
||||
Ok(Some(value)) => (
|
||||
serde_json::to_vec(&KvResponse::Get { key: key.to_vec() }).unwrap(),
|
||||
Some(value),
|
||||
),
|
||||
Ok(None) => {
|
||||
return Err(KvError::KeyNotFound);
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(KvError::RocksDBError {
|
||||
action: request.action.to_string(),
|
||||
error: e.to_string(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
KvAction::BeginTx => {
|
||||
let tx_id = rand::random::<u64>();
|
||||
txs.insert(tx_id, Vec::new());
|
||||
(
|
||||
serde_json::to_vec(&KvResponse::BeginTx { tx_id }).unwrap(),
|
||||
None,
|
||||
)
|
||||
}
|
||||
KvAction::Set { key, tx_id } => {
|
||||
let db = match open_kvs.get(&(request.package_id, request.db)) {
|
||||
None => {
|
||||
return Err(KvError::NoDb);
|
||||
}
|
||||
Some(db) => db,
|
||||
};
|
||||
let Some(payload) = payload else {
|
||||
return Err(KvError::InputError {
|
||||
error: "no payload".into(),
|
||||
});
|
||||
};
|
||||
|
||||
match tx_id {
|
||||
None => {
|
||||
db.put(key, payload.bytes)?;
|
||||
}
|
||||
Some(tx_id) => {
|
||||
let mut tx = match txs.get_mut(&tx_id) {
|
||||
None => {
|
||||
return Err(KvError::NoTx);
|
||||
}
|
||||
Some(tx) => tx,
|
||||
};
|
||||
tx.push((request.action.clone(), Some(payload.bytes)));
|
||||
}
|
||||
}
|
||||
|
||||
(serde_json::to_vec(&KvResponse::Ok).unwrap(), None)
|
||||
}
|
||||
KvAction::Delete { key, tx_id } => {
|
||||
let db = match open_kvs.get(&(request.package_id, request.db)) {
|
||||
None => {
|
||||
return Err(KvError::NoDb);
|
||||
}
|
||||
Some(db) => db,
|
||||
};
|
||||
match tx_id {
|
||||
None => {
|
||||
db.delete(key)?;
|
||||
}
|
||||
Some(tx_id) => {
|
||||
let mut tx = match txs.get_mut(&tx_id) {
|
||||
None => {
|
||||
return Err(KvError::NoTx);
|
||||
}
|
||||
Some(tx) => tx,
|
||||
};
|
||||
tx.push((request.action.clone(), None));
|
||||
}
|
||||
}
|
||||
(serde_json::to_vec(&KvResponse::Ok).unwrap(), None)
|
||||
}
|
||||
KvAction::Commit { tx_id } => {
|
||||
let db = match open_kvs.get(&(request.package_id, request.db)) {
|
||||
None => {
|
||||
return Err(KvError::NoDb);
|
||||
}
|
||||
Some(db) => db,
|
||||
};
|
||||
|
||||
let txs = match txs.remove(&tx_id).map(|(_, tx)| tx) {
|
||||
None => {
|
||||
return Err(KvError::NoTx);
|
||||
}
|
||||
Some(tx) => tx,
|
||||
};
|
||||
let tx = db.transaction();
|
||||
|
||||
for (action, payload) in txs {
|
||||
match action {
|
||||
KvAction::Set { key, .. } => {
|
||||
if let Some(payload) = payload {
|
||||
tx.put(&key, &payload)?;
|
||||
}
|
||||
}
|
||||
KvAction::Delete { key, .. } => {
|
||||
tx.delete(&key)?;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
match tx.commit() {
|
||||
Ok(_) => (serde_json::to_vec(&KvResponse::Ok).unwrap(), None),
|
||||
Err(e) => {
|
||||
return Err(KvError::RocksDBError {
|
||||
action: request.action.to_string(),
|
||||
error: e.to_string(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
KvAction::Backup => {
|
||||
// loop through all db directories and backup.
|
||||
//
|
||||
(serde_json::to_vec(&KvResponse::Ok).unwrap(), None)
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(target) = km.rsvp.or_else(|| {
|
||||
expects_response.map(|_| Address {
|
||||
node: our_node.clone(),
|
||||
process: source.process.clone(),
|
||||
})
|
||||
}) {
|
||||
let response = KernelMessage {
|
||||
id,
|
||||
source: Address {
|
||||
node: our_node.clone(),
|
||||
process: KV_PROCESS_ID.clone(),
|
||||
},
|
||||
target,
|
||||
rsvp: None,
|
||||
message: Message::Response((
|
||||
Response {
|
||||
inherit: false,
|
||||
ipc,
|
||||
metadata,
|
||||
},
|
||||
None,
|
||||
)),
|
||||
payload: bytes.map(|bytes| Payload {
|
||||
mime: Some("application/octet-stream".into()),
|
||||
bytes,
|
||||
}),
|
||||
signed_capabilities: None,
|
||||
};
|
||||
|
||||
let _ = send_to_loop.send(response).await;
|
||||
} else {
|
||||
send_to_terminal
|
||||
.send(Printout {
|
||||
verbosity: 2,
|
||||
content: format!(
|
||||
"kv: not sending response: {:?}",
|
||||
serde_json::from_slice::<KvResponse>(&ipc)
|
||||
),
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn check_caps(
|
||||
our_node: String,
|
||||
source: Address,
|
||||
open_kvs: Arc<DashMap<(PackageId, String), OptimisticTransactionDB>>,
|
||||
mut send_to_caps_oracle: CapMessageSender,
|
||||
request: &KvRequest,
|
||||
kv_path: String,
|
||||
) -> Result<(), KvError> {
|
||||
let (send_cap_bool, recv_cap_bool) = tokio::sync::oneshot::channel();
|
||||
let src_package_id = PackageId::new(source.process.package(), source.process.publisher());
|
||||
|
||||
match &request.action {
|
||||
KvAction::Delete { .. }
|
||||
| KvAction::Set { .. }
|
||||
| KvAction::BeginTx
|
||||
| KvAction::Commit { .. } => {
|
||||
send_to_caps_oracle
|
||||
.send(CapMessage::Has {
|
||||
on: source.process.clone(),
|
||||
cap: Capability {
|
||||
issuer: Address {
|
||||
node: our_node.clone(),
|
||||
process: KV_PROCESS_ID.clone(),
|
||||
},
|
||||
params: serde_json::to_string(&serde_json::json!({
|
||||
"kind": "write",
|
||||
"db": request.db.to_string(),
|
||||
}))
|
||||
.unwrap(),
|
||||
},
|
||||
responder: send_cap_bool,
|
||||
})
|
||||
.await?;
|
||||
let has_cap = recv_cap_bool.await?;
|
||||
if !has_cap {
|
||||
return Err(KvError::NoCap {
|
||||
error: request.action.to_string(),
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
KvAction::Get { .. } => {
|
||||
send_to_caps_oracle
|
||||
.send(CapMessage::Has {
|
||||
on: source.process.clone(),
|
||||
cap: Capability {
|
||||
issuer: Address {
|
||||
node: our_node.clone(),
|
||||
process: KV_PROCESS_ID.clone(),
|
||||
},
|
||||
params: serde_json::to_string(&serde_json::json!({
|
||||
"kind": "read",
|
||||
"db": request.db.to_string(),
|
||||
}))
|
||||
.unwrap(),
|
||||
},
|
||||
responder: send_cap_bool,
|
||||
})
|
||||
.await?;
|
||||
let has_cap = recv_cap_bool.await?;
|
||||
if !has_cap {
|
||||
return Err(KvError::NoCap {
|
||||
error: request.action.to_string(),
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
KvAction::New { .. } => {
|
||||
if src_package_id != request.package_id {
|
||||
return Err(KvError::NoCap {
|
||||
error: request.action.to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
add_capability(
|
||||
"read",
|
||||
&request.db.to_string(),
|
||||
&our_node,
|
||||
&source,
|
||||
&mut send_to_caps_oracle,
|
||||
)
|
||||
.await?;
|
||||
add_capability(
|
||||
"write",
|
||||
&request.db.to_string(),
|
||||
&our_node,
|
||||
&source,
|
||||
&mut send_to_caps_oracle,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let db_path = format!("{}{}", kv_path, request.db.to_string());
|
||||
|
||||
fs::create_dir_all(&db_path).await?;
|
||||
|
||||
let db = OptimisticTransactionDB::open_default(&db_path)?;
|
||||
|
||||
open_kvs.insert((request.package_id.clone(), request.db.clone()), db);
|
||||
Ok(())
|
||||
}
|
||||
KvAction::Backup { .. } => {
|
||||
if source.process != *STATE_PROCESS_ID {
|
||||
return Err(KvError::NoCap {
|
||||
error: request.action.to_string(),
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn add_capability(
|
||||
kind: &str,
|
||||
db: &str,
|
||||
our_node: &str,
|
||||
source: &Address,
|
||||
send_to_caps_oracle: &mut CapMessageSender,
|
||||
) -> Result<(), KvError> {
|
||||
let cap = Capability {
|
||||
issuer: Address {
|
||||
node: our_node.to_string(),
|
||||
process: KV_PROCESS_ID.clone(),
|
||||
},
|
||||
params: serde_json::to_string(&serde_json::json!({ "kind": kind, "db": db })).unwrap(),
|
||||
};
|
||||
let (send_cap_bool, recv_cap_bool) = tokio::sync::oneshot::channel();
|
||||
send_to_caps_oracle
|
||||
.send(CapMessage::Add {
|
||||
on: source.process.clone(),
|
||||
cap,
|
||||
responder: send_cap_bool,
|
||||
})
|
||||
.await?;
|
||||
let _ = recv_cap_bool.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn make_error_message(our_name: String, km: &KernelMessage, error: KvError) -> KernelMessage {
|
||||
KernelMessage {
|
||||
id: km.id,
|
||||
source: Address {
|
||||
node: our_name.clone(),
|
||||
process: KV_PROCESS_ID.clone(),
|
||||
},
|
||||
target: match &km.rsvp {
|
||||
None => km.source.clone(),
|
||||
Some(rsvp) => rsvp.clone(),
|
||||
},
|
||||
rsvp: None,
|
||||
message: Message::Response((
|
||||
Response {
|
||||
inherit: false,
|
||||
ipc: serde_json::to_vec(&KvResponse::Err { error: error }).unwrap(),
|
||||
metadata: None,
|
||||
},
|
||||
None,
|
||||
)),
|
||||
payload: None,
|
||||
signed_capabilities: None,
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for KvAction {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<tokio::sync::oneshot::error::RecvError> for KvError {
|
||||
fn from(err: tokio::sync::oneshot::error::RecvError) -> Self {
|
||||
KvError::NoCap {
|
||||
error: err.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<tokio::sync::mpsc::error::SendError<CapMessage>> for KvError {
|
||||
fn from(err: tokio::sync::mpsc::error::SendError<CapMessage>) -> Self {
|
||||
KvError::NoCap {
|
||||
error: err.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for KvError {
|
||||
fn from(err: std::io::Error) -> Self {
|
||||
KvError::IOError {
|
||||
error: err.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<rocksdb::Error> for KvError {
|
||||
fn from(error: rocksdb::Error) -> Self {
|
||||
KvError::RocksDBError {
|
||||
action: "".into(),
|
||||
error: error.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
# Local LLM Integration
|
||||
1. Clone and build [llama.cpp](https://github.com/ggerganov/llama.cpp) on the same machine where you will run your uqbar node
|
||||
- follow their README for details on how to do this. In most cases simply running `make` works
|
||||
- make sure to get your model as a .gguf file
|
||||
2. Within the llama.cpp directory, run this command in llama.cpp on the same machine you will run your uqbar node: `./server --port <PORT>`
|
||||
- Note: you can pass in whatever other command line arguments to the llama cpp server you want depending on your preferences/hardware/model/etc.
|
||||
3. Run your Uqbar node with `--features llm` and `--llm http://localhost:<PORT>`. For example `cargo +nightly run --features llm --release home --rpc wss://eth-sepolia.g.alchemy.com/v2/<YOUR_API_KEY> --llm http://localhost:<PORT>`
|
180
src/llm/mod.rs
180
src/llm/mod.rs
@ -1,180 +0,0 @@
|
||||
use crate::llm::types::*;
|
||||
use crate::types::*;
|
||||
use anyhow::Result;
|
||||
use reqwest::Response as ReqwestResponse;
|
||||
|
||||
mod types;
|
||||
|
||||
pub async fn llm(
|
||||
our_name: String,
|
||||
send_to_loop: MessageSender,
|
||||
mut recv_in_client: MessageReceiver,
|
||||
llm_url: String,
|
||||
print_tx: PrintSender,
|
||||
) -> Result<()> {
|
||||
while let Some(message) = recv_in_client.recv().await {
|
||||
let KernelMessage {
|
||||
id,
|
||||
source,
|
||||
rsvp,
|
||||
message:
|
||||
Message::Request(Request {
|
||||
expects_response,
|
||||
ipc,
|
||||
..
|
||||
}),
|
||||
..
|
||||
} = message.clone()
|
||||
else {
|
||||
return Err(anyhow::anyhow!("llm: bad message"));
|
||||
};
|
||||
|
||||
let our_name = our_name.clone();
|
||||
let llm_url = llm_url.clone();
|
||||
let send_to_loop = send_to_loop.clone();
|
||||
let print_tx = print_tx.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
if let Err(e) = handle_message(
|
||||
our_name.clone(),
|
||||
send_to_loop.clone(),
|
||||
llm_url.clone(),
|
||||
id,
|
||||
rsvp,
|
||||
expects_response,
|
||||
source.clone(),
|
||||
ipc,
|
||||
print_tx.clone(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
send_to_loop
|
||||
.send(make_error_message(our_name.clone(), id, source, e))
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
});
|
||||
}
|
||||
Err(anyhow::anyhow!("llm: exited"))
|
||||
}
|
||||
|
||||
async fn handle_message(
|
||||
our: String,
|
||||
send_to_loop: MessageSender,
|
||||
llm_url: String,
|
||||
id: u64,
|
||||
rsvp: Option<Address>,
|
||||
expects_response: Option<u64>,
|
||||
source: Address,
|
||||
json: Vec<u8>,
|
||||
_print_tx: PrintSender,
|
||||
) -> Result<(), LlmError> {
|
||||
let target = if expects_response.is_some() {
|
||||
source.clone()
|
||||
} else if source.process == ProcessId::from_str("terminal:terminal:uqbar").unwrap() {
|
||||
source.clone()
|
||||
} else {
|
||||
let Some(rsvp) = rsvp else {
|
||||
return Err(LlmError::BadRsvp);
|
||||
};
|
||||
rsvp.clone()
|
||||
};
|
||||
|
||||
let req: LlmPrompt = match serde_json::from_slice(&json) {
|
||||
Ok(req) => req,
|
||||
Err(e) => {
|
||||
return Err(LlmError::BadJson {
|
||||
json: String::from_utf8(json).unwrap_or_default(),
|
||||
error: format!("{}", e),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
|
||||
let res: ReqwestResponse = match client
|
||||
.post(&format!("{}/completion", llm_url))
|
||||
.json(&req)
|
||||
.send()
|
||||
.await
|
||||
{
|
||||
Ok(res) => res,
|
||||
Err(e) => {
|
||||
return Err(LlmError::RequestFailed {
|
||||
error: format!("{}", e),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
let llm_response = match res.json::<LlmResponse>().await {
|
||||
Ok(response) => response,
|
||||
Err(e) => {
|
||||
return Err(LlmError::DeserializationToLlmResponseFailed {
|
||||
error: format!("{}", e),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
let _ = _print_tx
|
||||
.send(Printout {
|
||||
verbosity: 0,
|
||||
content: format!("llm: {:?}", llm_response.clone().content),
|
||||
})
|
||||
.await;
|
||||
|
||||
let message = KernelMessage {
|
||||
id,
|
||||
source: Address {
|
||||
node: our,
|
||||
process: ProcessId::new(Some("llm"), "sys", "uqbar"),
|
||||
},
|
||||
target,
|
||||
rsvp: None,
|
||||
message: Message::Response((
|
||||
Response {
|
||||
inherit: false,
|
||||
ipc: serde_json::to_vec::<Result<LlmResponse, LlmError>>(&Ok(llm_response))
|
||||
.unwrap(),
|
||||
metadata: None,
|
||||
},
|
||||
None,
|
||||
)),
|
||||
payload: None,
|
||||
signed_capabilities: None,
|
||||
};
|
||||
|
||||
send_to_loop.send(message).await.unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
//
|
||||
// helpers
|
||||
//
|
||||
fn make_error_message(
|
||||
our_name: String,
|
||||
id: u64,
|
||||
source: Address,
|
||||
error: LlmError,
|
||||
) -> KernelMessage {
|
||||
KernelMessage {
|
||||
id,
|
||||
source: source.clone(),
|
||||
target: Address {
|
||||
node: our_name.clone(),
|
||||
process: source.process.clone(),
|
||||
},
|
||||
rsvp: None,
|
||||
message: Message::Response((
|
||||
Response {
|
||||
inherit: false,
|
||||
ipc: serde_json::to_vec::<Result<HttpClientResponse, LlmError>>(&Err(error))
|
||||
.unwrap(),
|
||||
metadata: None,
|
||||
},
|
||||
None,
|
||||
)),
|
||||
payload: None,
|
||||
signed_capabilities: None,
|
||||
}
|
||||
}
|
114
src/llm/types.rs
114
src/llm/types.rs
@ -1,114 +0,0 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct LlmPrompt {
|
||||
prompt: String, // TODO can be a string or an array of strings
|
||||
temperature: Option<f64>,
|
||||
top_k: Option<usize>,
|
||||
top_p: Option<f64>,
|
||||
n_predict: Option<isize>, // isize to accommodate -1
|
||||
n_keep: Option<isize>, // isize to accommodate -1
|
||||
stream: Option<bool>,
|
||||
stop: Option<Vec<String>>,
|
||||
tfs_z: Option<f64>,
|
||||
typical_p: Option<f64>,
|
||||
repeat_penalty: Option<f64>,
|
||||
repeat_last_n: Option<isize>, // isize to accommodate -1
|
||||
penalize_nl: Option<bool>,
|
||||
presence_penalty: Option<f64>,
|
||||
frequency_penalty: Option<f64>,
|
||||
mirostat: Option<u8>, // u8 as it's 0, 1, or 2
|
||||
mirostat_tau: Option<f64>,
|
||||
mirostat_eta: Option<f64>,
|
||||
grammar: Option<String>,
|
||||
seed: Option<isize>, // isize to accommodate -1
|
||||
ignore_eos: Option<bool>,
|
||||
logit_bias: Option<Vec<(usize, f64)>>,
|
||||
n_probs: Option<usize>,
|
||||
image_data: Option<Vec<ImageData>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct ImageData {
|
||||
data: String, // Base64 string
|
||||
id: usize,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
pub struct LlmResponse {
|
||||
pub content: String,
|
||||
pub generation_settings: GenerationSettings,
|
||||
pub model: String,
|
||||
pub prompt: String,
|
||||
pub slot_id: u64,
|
||||
pub stop: bool,
|
||||
pub stopped_eos: bool,
|
||||
pub stopped_limit: bool,
|
||||
pub stopped_word: bool,
|
||||
pub stopping_word: String,
|
||||
pub timings: Timings,
|
||||
pub tokens_cached: u64,
|
||||
pub tokens_evaluated: u64,
|
||||
pub tokens_predicted: u64,
|
||||
pub truncated: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
pub struct GenerationSettings {
|
||||
pub frequency_penalty: f64,
|
||||
pub grammar: String,
|
||||
pub ignore_eos: bool,
|
||||
pub logit_bias: Vec<serde_json::Value>, // This should be changed to the appropriate type
|
||||
pub mirostat: u64,
|
||||
pub mirostat_eta: f64,
|
||||
pub mirostat_tau: f64,
|
||||
pub model: String,
|
||||
pub n_ctx: u64,
|
||||
pub n_keep: u64,
|
||||
pub n_predict: u64,
|
||||
pub n_probs: u64,
|
||||
pub penalize_nl: bool,
|
||||
pub presence_penalty: f64,
|
||||
pub repeat_last_n: u64,
|
||||
pub repeat_penalty: f64,
|
||||
pub seed: u64,
|
||||
pub stop: Vec<serde_json::Value>, // This should be changed to the appropriate type
|
||||
pub stream: bool,
|
||||
pub temp: f64,
|
||||
pub tfs_z: f64,
|
||||
pub top_k: u64,
|
||||
pub top_p: f64,
|
||||
pub typical_p: f64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
pub struct Timings {
|
||||
pub predicted_ms: f64,
|
||||
pub predicted_n: u64,
|
||||
pub predicted_per_second: f64,
|
||||
pub predicted_per_token_ms: f64,
|
||||
pub prompt_ms: f64,
|
||||
pub prompt_n: u64,
|
||||
pub prompt_per_second: f64,
|
||||
pub prompt_per_token_ms: f64,
|
||||
}
|
||||
|
||||
#[derive(Error, Debug, Serialize, Deserialize)]
|
||||
pub enum LlmError {
|
||||
#[error("llm: rsvp is None but message is expecting response")]
|
||||
BadRsvp,
|
||||
#[error("llm: no json in request")]
|
||||
NoJson,
|
||||
#[error(
|
||||
"llm: JSON payload could not be parsed to LlmPrompt: {error}. Got {:?}.",
|
||||
json
|
||||
)]
|
||||
BadJson { json: String, error: String },
|
||||
#[error("llm: http method not supported: {:?}", method)]
|
||||
BadMethod { method: String },
|
||||
#[error("llm: failed to execute request {:?}", error)]
|
||||
RequestFailed { error: String },
|
||||
#[error("llm: failed to deserialize response {:?}", error)]
|
||||
DeserializationToLlmResponseFailed { error: String },
|
||||
}
|
224
src/main.rs
224
src/main.rs
@ -12,37 +12,34 @@ use tokio::{fs, time::timeout};
|
||||
use ring::{rand::SystemRandom, signature, signature::KeyPair};
|
||||
|
||||
mod eth_rpc;
|
||||
mod filesystem;
|
||||
mod http;
|
||||
mod kernel;
|
||||
mod keygen;
|
||||
mod kv;
|
||||
mod net;
|
||||
mod register;
|
||||
mod sqlite;
|
||||
mod state;
|
||||
mod terminal;
|
||||
mod timer;
|
||||
mod types;
|
||||
mod vfs;
|
||||
|
||||
// extensions
|
||||
#[cfg(feature = "llm")]
|
||||
mod llm;
|
||||
|
||||
const EVENT_LOOP_CHANNEL_CAPACITY: usize = 10_000;
|
||||
const EVENT_LOOP_DEBUG_CHANNEL_CAPACITY: usize = 50;
|
||||
const TERMINAL_CHANNEL_CAPACITY: usize = 32;
|
||||
const WEBSOCKET_SENDER_CHANNEL_CAPACITY: usize = 32;
|
||||
const FILESYSTEM_CHANNEL_CAPACITY: usize = 32;
|
||||
const HTTP_CHANNEL_CAPACITY: usize = 32;
|
||||
const HTTP_CLIENT_CHANNEL_CAPACITY: usize = 32;
|
||||
const ETH_RPC_CHANNEL_CAPACITY: usize = 32;
|
||||
const VFS_CHANNEL_CAPACITY: usize = 1_000;
|
||||
const CAP_CHANNEL_CAPACITY: usize = 1_000;
|
||||
#[cfg(feature = "llm")]
|
||||
const LLM_CHANNEL_CAPACITY: usize = 32;
|
||||
const KV_CHANNEL_CAPACITY: usize = 1_000;
|
||||
const SQLITE_CHANNEL_CAPACITY: usize = 1_000;
|
||||
|
||||
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
/// This can and should be an environment variable / setting. It configures networking
|
||||
/// Tshis can and should be an environment variable / setting. It configures networking
|
||||
/// such that indirect nodes always use routers, even when target is a direct node,
|
||||
/// such that only their routers can ever see their physical networking details.
|
||||
const REVEAL_IP: bool = true;
|
||||
@ -52,7 +49,7 @@ async fn serve_register_fe(
|
||||
our_ip: String,
|
||||
http_server_port: u16,
|
||||
rpc_url: String,
|
||||
) -> (Identity, Keyfile) {
|
||||
) -> (Identity, Vec<u8>, Keyfile) {
|
||||
// check if we have keys saved on disk, encrypted
|
||||
// if so, prompt user for "password" to decrypt with
|
||||
|
||||
@ -66,10 +63,9 @@ async fn serve_register_fe(
|
||||
// that updates their PKI info on-chain.
|
||||
let (kill_tx, kill_rx) = oneshot::channel::<bool>();
|
||||
|
||||
let disk_keyfile = match fs::read(format!("{}/.keys", home_directory_path)).await {
|
||||
Ok(keyfile) => keyfile,
|
||||
Err(_) => Vec::new(),
|
||||
};
|
||||
let disk_keyfile: Option<Vec<u8>> = fs::read(format!("{}/.keys", home_directory_path))
|
||||
.await
|
||||
.ok();
|
||||
|
||||
let (tx, mut rx) = mpsc::channel::<(Identity, Keyfile, Vec<u8>)>(1);
|
||||
let (our, decoded_keyfile, encoded_keyfile) = tokio::select! {
|
||||
@ -81,20 +77,16 @@ async fn serve_register_fe(
|
||||
}
|
||||
};
|
||||
|
||||
println!(
|
||||
"saving encrypted networking keys to {}/.keys",
|
||||
home_directory_path
|
||||
);
|
||||
|
||||
fs::write(format!("{}/.keys", home_directory_path), encoded_keyfile)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
println!("registration complete!");
|
||||
fs::write(
|
||||
format!("{}/.keys", home_directory_path),
|
||||
encoded_keyfile.clone(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let _ = kill_tx.send(true);
|
||||
|
||||
(our, decoded_keyfile)
|
||||
(our, encoded_keyfile, decoded_keyfile)
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
@ -124,9 +116,6 @@ async fn main() {
|
||||
.value_parser(value_parser!(u16)),
|
||||
);
|
||||
|
||||
#[cfg(feature = "llm")]
|
||||
let app = app.arg(arg!(--llm <LLM_URL> "LLM endpoint"));
|
||||
|
||||
let matches = app.get_matches();
|
||||
|
||||
let home_directory_path = matches.get_one::<String>("home").unwrap();
|
||||
@ -146,9 +135,6 @@ async fn main() {
|
||||
matches.get_one::<String>("fake-node-name"),
|
||||
);
|
||||
|
||||
#[cfg(feature = "llm")]
|
||||
let llm_url = matches.get_one::<String>("llm").unwrap();
|
||||
|
||||
if let Err(e) = fs::create_dir_all(home_directory_path).await {
|
||||
panic!("failed to create home directory: {:?}", e);
|
||||
}
|
||||
@ -169,9 +155,15 @@ async fn main() {
|
||||
// websocket sender receives send messages via this channel, kernel send messages
|
||||
let (net_message_sender, net_message_receiver): (MessageSender, MessageReceiver) =
|
||||
mpsc::channel(WEBSOCKET_SENDER_CHANNEL_CAPACITY);
|
||||
// filesystem receives request messages via this channel, kernel sends messages
|
||||
let (fs_message_sender, fs_message_receiver): (MessageSender, MessageReceiver) =
|
||||
mpsc::channel(FILESYSTEM_CHANNEL_CAPACITY);
|
||||
// kernel_state sender and receiver
|
||||
let (state_sender, state_receiver): (MessageSender, MessageReceiver) =
|
||||
mpsc::channel(VFS_CHANNEL_CAPACITY);
|
||||
// kv sender and receiver
|
||||
let (kv_sender, kv_receiver): (MessageSender, MessageReceiver) =
|
||||
mpsc::channel(KV_CHANNEL_CAPACITY);
|
||||
// sqlite sender and receiver
|
||||
let (sqlite_sender, sqlite_receiver): (MessageSender, MessageReceiver) =
|
||||
mpsc::channel(SQLITE_CHANNEL_CAPACITY);
|
||||
// http server channel w/ websockets (eyre)
|
||||
let (http_server_sender, http_server_receiver): (MessageSender, MessageReceiver) =
|
||||
mpsc::channel(HTTP_CHANNEL_CAPACITY);
|
||||
@ -188,75 +180,6 @@ async fn main() {
|
||||
// terminal receives prints via this channel, all other modules send prints
|
||||
let (print_sender, print_receiver): (PrintSender, PrintReceiver) =
|
||||
mpsc::channel(TERMINAL_CHANNEL_CAPACITY);
|
||||
// optional llm extension
|
||||
#[cfg(feature = "llm")]
|
||||
let (llm_sender, llm_receiver): (MessageSender, MessageReceiver) =
|
||||
mpsc::channel(LLM_CHANNEL_CAPACITY);
|
||||
|
||||
// fs config in .env file (todo add -- arguments cleanly (with clap?))
|
||||
dotenv::dotenv().ok();
|
||||
|
||||
let mem_buffer_limit = env::var("MEM_BUFFER_LIMIT")
|
||||
.ok()
|
||||
.and_then(|s| s.parse().ok())
|
||||
.unwrap_or(1024 * 1024 * 5); // 5mb default
|
||||
|
||||
let read_cache_limit = env::var("READ_CACHE_LIMIT")
|
||||
.ok()
|
||||
.and_then(|s| s.parse().ok())
|
||||
.unwrap_or(1024 * 1024 * 5); // 5mb default
|
||||
|
||||
let chunk_size = env::var("CHUNK_SIZE")
|
||||
.ok()
|
||||
.and_then(|s| s.parse().ok())
|
||||
.unwrap_or(1024 * 256); // 256kb default
|
||||
|
||||
let flush_to_cold_interval = env::var("FLUSH_TO_COLD_INTERVAL")
|
||||
.ok()
|
||||
.and_then(|s| s.parse().ok())
|
||||
.unwrap_or(60); // 60s default
|
||||
|
||||
let encryption = env::var("ENCRYPTION")
|
||||
.ok()
|
||||
.and_then(|s| s.parse().ok())
|
||||
.unwrap_or(true); // default true
|
||||
|
||||
let cloud_enabled = env::var("CLOUD_ENABLED")
|
||||
.ok()
|
||||
.and_then(|s| s.parse().ok())
|
||||
.unwrap_or(false); // default false
|
||||
|
||||
let s3_config = if let (Ok(access_key), Ok(secret_key), Ok(region), Ok(bucket), Ok(endpoint)) = (
|
||||
env::var("S3_ACCESS_KEY"),
|
||||
env::var("S3_SECRET_KEY"),
|
||||
env::var("S3_REGION"),
|
||||
env::var("S3_BUCKET"),
|
||||
env::var("S3_ENDPOINT"),
|
||||
) {
|
||||
Some(S3Config {
|
||||
access_key,
|
||||
secret_key,
|
||||
region,
|
||||
bucket,
|
||||
endpoint,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let fs_config = FsConfig {
|
||||
s3_config,
|
||||
mem_buffer_limit,
|
||||
read_cache_limit,
|
||||
chunk_size,
|
||||
flush_to_cold_interval,
|
||||
encryption,
|
||||
cloud_enabled,
|
||||
};
|
||||
|
||||
// shutdown signal send and await to fs
|
||||
let (fs_kill_send, fs_kill_recv) = oneshot::channel::<()>();
|
||||
let (fs_kill_confirm_send, fs_kill_confirm_recv) = oneshot::channel::<()>();
|
||||
|
||||
println!("finding public IP address...");
|
||||
let our_ip: std::net::Ipv4Addr = {
|
||||
@ -272,13 +195,21 @@ async fn main() {
|
||||
};
|
||||
|
||||
let http_server_port = http::utils::find_open_port(port).await.unwrap();
|
||||
println!("runtime bound port {}\r", http_server_port);
|
||||
if http_server_port != port {
|
||||
let error_message = format!(
|
||||
"uqbar: couldn't bind {}; first available port found {}. Set an available port with `--port` and try again.",
|
||||
port,
|
||||
http_server_port,
|
||||
);
|
||||
println!("{error_message}");
|
||||
panic!("{error_message}");
|
||||
}
|
||||
println!(
|
||||
"login or register at http://localhost:{}\r",
|
||||
http_server_port
|
||||
);
|
||||
#[cfg(not(feature = "simulation-mode"))]
|
||||
let (our, decoded_keyfile) = serve_register_fe(
|
||||
let (our, encoded_keyfile, decoded_keyfile) = serve_register_fe(
|
||||
&home_directory_path,
|
||||
our_ip.to_string(),
|
||||
http_server_port.clone(),
|
||||
@ -286,7 +217,7 @@ async fn main() {
|
||||
)
|
||||
.await;
|
||||
#[cfg(feature = "simulation-mode")]
|
||||
let (our, decoded_keyfile) = match fake_node_name {
|
||||
let (our, encoded_keyfile, decoded_keyfile) = match fake_node_name {
|
||||
None => {
|
||||
match password {
|
||||
None => match rpc_url {
|
||||
@ -305,7 +236,7 @@ async fn main() {
|
||||
match fs::read(format!("{}/.keys", home_directory_path)).await {
|
||||
Err(e) => panic!("could not read keyfile: {}", e),
|
||||
Ok(keyfile) => {
|
||||
match keygen::decode_keyfile(keyfile, &password) {
|
||||
match keygen::decode_keyfile(&keyfile, &password) {
|
||||
Err(e) => panic!("could not decode keyfile: {}", e),
|
||||
Ok(decoded_keyfile) => {
|
||||
let our = Identity {
|
||||
@ -322,7 +253,7 @@ async fn main() {
|
||||
ws_routing: None, // TODO
|
||||
allowed_routers: decoded_keyfile.routers.clone(),
|
||||
};
|
||||
(our, decoded_keyfile)
|
||||
(our, keyfile, decoded_keyfile)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -363,16 +294,19 @@ async fn main() {
|
||||
password,
|
||||
name.clone(),
|
||||
decoded_keyfile.routers.clone(),
|
||||
networking_keypair,
|
||||
networking_keypair.as_ref(),
|
||||
decoded_keyfile.jwt_secret_bytes.clone(),
|
||||
decoded_keyfile.file_key.clone(),
|
||||
);
|
||||
|
||||
fs::write(format!("{}/.keys", home_directory_path), encoded_keyfile)
|
||||
.await
|
||||
.unwrap();
|
||||
fs::write(
|
||||
format!("{}/.keys", home_directory_path),
|
||||
encoded_keyfile.clone(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
(our, decoded_keyfile)
|
||||
(our, encoded_keyfile, decoded_keyfile)
|
||||
}
|
||||
};
|
||||
|
||||
@ -380,11 +314,6 @@ async fn main() {
|
||||
// where public means that any process can always message it.
|
||||
#[allow(unused_mut)]
|
||||
let mut runtime_extensions = vec![
|
||||
(
|
||||
ProcessId::new(Some("filesystem"), "sys", "uqbar"),
|
||||
fs_message_sender,
|
||||
false,
|
||||
),
|
||||
(
|
||||
ProcessId::new(Some("http_server"), "sys", "uqbar"),
|
||||
http_server_sender,
|
||||
@ -410,6 +339,17 @@ async fn main() {
|
||||
vfs_message_sender,
|
||||
true,
|
||||
),
|
||||
(
|
||||
ProcessId::new(Some("state"), "sys", "uqbar"),
|
||||
state_sender,
|
||||
true,
|
||||
),
|
||||
(ProcessId::new(Some("kv"), "sys", "uqbar"), kv_sender, true),
|
||||
(
|
||||
ProcessId::new(Some("sqlite"), "sys", "uqbar"),
|
||||
sqlite_sender,
|
||||
true,
|
||||
),
|
||||
];
|
||||
|
||||
#[cfg(feature = "llm")]
|
||||
@ -419,15 +359,13 @@ async fn main() {
|
||||
true,
|
||||
));
|
||||
|
||||
let (kernel_process_map, manifest, vfs_messages) = filesystem::load_fs(
|
||||
let (kernel_process_map, db) = state::load_state(
|
||||
our.name.clone(),
|
||||
home_directory_path.clone(),
|
||||
decoded_keyfile.file_key,
|
||||
fs_config,
|
||||
runtime_extensions.clone(),
|
||||
)
|
||||
.await
|
||||
.expect("fs load failed!");
|
||||
.expect("state load failed!");
|
||||
|
||||
/*
|
||||
* the kernel module will handle our userspace processes and receives
|
||||
@ -471,18 +409,34 @@ async fn main() {
|
||||
kernel_message_sender.clone(),
|
||||
net_message_receiver,
|
||||
));
|
||||
tasks.spawn(filesystem::fs_sender(
|
||||
tasks.spawn(state::state_sender(
|
||||
our.name.clone(),
|
||||
manifest,
|
||||
kernel_message_sender.clone(),
|
||||
print_sender.clone(),
|
||||
fs_message_receiver,
|
||||
fs_kill_recv,
|
||||
fs_kill_confirm_send,
|
||||
state_receiver,
|
||||
db,
|
||||
home_directory_path.clone(),
|
||||
));
|
||||
tasks.spawn(kv::kv(
|
||||
our.name.clone(),
|
||||
kernel_message_sender.clone(),
|
||||
print_sender.clone(),
|
||||
kv_receiver,
|
||||
caps_oracle_sender.clone(),
|
||||
home_directory_path.clone(),
|
||||
));
|
||||
tasks.spawn(sqlite::sqlite(
|
||||
our.name.clone(),
|
||||
kernel_message_sender.clone(),
|
||||
print_sender.clone(),
|
||||
sqlite_receiver,
|
||||
caps_oracle_sender.clone(),
|
||||
home_directory_path.clone(),
|
||||
));
|
||||
tasks.spawn(http::server::http_server(
|
||||
our.name.clone(),
|
||||
http_server_port,
|
||||
encoded_keyfile,
|
||||
decoded_keyfile.jwt_secret_bytes.clone(),
|
||||
http_server_receiver,
|
||||
kernel_message_sender.clone(),
|
||||
@ -514,18 +468,8 @@ async fn main() {
|
||||
print_sender.clone(),
|
||||
vfs_message_receiver,
|
||||
caps_oracle_sender.clone(),
|
||||
vfs_messages,
|
||||
home_directory_path.clone(),
|
||||
));
|
||||
#[cfg(feature = "llm")]
|
||||
{
|
||||
tasks.spawn(llm::llm(
|
||||
our.name.clone(),
|
||||
kernel_message_sender.clone(),
|
||||
llm_receiver,
|
||||
llm_url.to_string(),
|
||||
print_sender.clone(),
|
||||
));
|
||||
}
|
||||
// if a runtime task exits, try to recover it,
|
||||
// unless it was terminal signaling a quit
|
||||
let quit_msg: String = tokio::select! {
|
||||
@ -551,10 +495,6 @@ async fn main() {
|
||||
}
|
||||
};
|
||||
|
||||
// shutdown signal to fs for flush
|
||||
let _ = fs_kill_send.send(());
|
||||
let _ = fs_kill_confirm_recv.await;
|
||||
|
||||
// gracefully abort all running processes in kernel
|
||||
let _ = kernel_message_sender
|
||||
.send(KernelMessage {
|
||||
|
@ -65,7 +65,7 @@ pub async fn maintain_connection(
|
||||
if km.source.node != peer_name {
|
||||
let _ = print_tx.send(Printout {
|
||||
verbosity: 0,
|
||||
content: format!("net: got message with spoofed source from {peer_name}")
|
||||
content: format!("net: got message with spoofed source from {peer_name}!")
|
||||
}).await;
|
||||
break
|
||||
} else {
|
||||
@ -136,7 +136,9 @@ pub async fn maintain_passthrough(mut conn: PassthroughConnection) {
|
||||
maybe_recv = conn.read_stream_1.next() => {
|
||||
match maybe_recv {
|
||||
Some(Ok(msg)) => {
|
||||
conn.write_stream_2.send(msg).await.expect("net error: fatal: kernel died");
|
||||
let Ok(()) = conn.write_stream_2.send(msg).await else {
|
||||
break
|
||||
};
|
||||
last_message = std::time::Instant::now();
|
||||
}
|
||||
_ => break,
|
||||
@ -145,7 +147,9 @@ pub async fn maintain_passthrough(mut conn: PassthroughConnection) {
|
||||
maybe_recv = conn.read_stream_2.next() => {
|
||||
match maybe_recv {
|
||||
Some(Ok(msg)) => {
|
||||
conn.write_stream_1.send(msg).await.expect("net error: fatal: kernel died");
|
||||
let Ok(()) = conn.write_stream_1.send(msg).await else {
|
||||
break
|
||||
};
|
||||
last_message = std::time::Instant::now();
|
||||
}
|
||||
_ => break,
|
||||
|
387
src/register.rs
387
src/register.rs
@ -1,15 +1,13 @@
|
||||
use aes_gcm::aead::KeyInit;
|
||||
|
||||
use ethers::prelude::{abigen, namehash, Address as EthAddress, Provider, U256};
|
||||
use ethers_providers::Ws;
|
||||
use hmac::Hmac;
|
||||
use jwt::SignWithKey;
|
||||
use ring::pkcs8::Document;
|
||||
use ring::rand::SystemRandom;
|
||||
use ring::signature;
|
||||
use ring::signature::KeyPair;
|
||||
use sha2::Sha256;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::{mpsc, oneshot};
|
||||
use warp::{
|
||||
http::{
|
||||
@ -77,14 +75,14 @@ fn _hex_string_to_u8_array(hex_str: &str) -> Result<[u8; 32], &'static str> {
|
||||
Ok(bytes)
|
||||
}
|
||||
|
||||
pub fn generate_jwt(jwt_secret_bytes: &[u8], username: String) -> Option<String> {
|
||||
pub fn generate_jwt(jwt_secret_bytes: &[u8], username: &str) -> Option<String> {
|
||||
let jwt_secret: Hmac<Sha256> = match Hmac::new_from_slice(jwt_secret_bytes) {
|
||||
Ok(secret) => secret,
|
||||
Err(_) => return None,
|
||||
};
|
||||
|
||||
let claims = crate::http::types::JwtClaims {
|
||||
username: username.clone(),
|
||||
username: username.to_string(),
|
||||
expiration: 0,
|
||||
};
|
||||
|
||||
@ -101,16 +99,34 @@ pub async fn register(
|
||||
ip: String,
|
||||
port: u16,
|
||||
rpc_url: String,
|
||||
keyfile: Vec<u8>,
|
||||
keyfile: Option<Vec<u8>>,
|
||||
) {
|
||||
let our_temp_arc = Arc::new(Mutex::new(None)); // Networking info is generated and passed to the UI, but not used until confirmed
|
||||
let our_ws_info = our_temp_arc.clone();
|
||||
// Networking info is generated and passed to the UI, but not used until confirmed
|
||||
let (public_key, serialized_networking_keypair) = keygen::generate_networking_key();
|
||||
let net_keypair = Arc::new(serialized_networking_keypair.as_ref().to_vec());
|
||||
let tx = Arc::new(tx);
|
||||
|
||||
let net_keypair_arc = Arc::new(Mutex::new(None));
|
||||
let net_keypair_ws_info = net_keypair_arc.clone();
|
||||
// TODO: if IP is localhost, don't allow registration as direct
|
||||
let ws_port = crate::http::utils::find_open_port(9000).await.unwrap();
|
||||
|
||||
let keyfile_arc = Arc::new(Mutex::new(Some(keyfile)));
|
||||
let keyfile_vet = keyfile_arc.clone();
|
||||
// This is a temporary identity, passed to the UI. If it is confirmed through a /boot or /confirm-change-network-keys, then it will be used to replace the current identity
|
||||
let our_temp_id = Arc::new(Identity {
|
||||
networking_key: format!("0x{}", public_key),
|
||||
name: "".to_string(),
|
||||
ws_routing: Some((ip.clone(), ws_port)),
|
||||
allowed_routers: vec![
|
||||
"uqbar-router-1.uq".into(), // "0x8d9e54427c50660c6d4802f63edca86a9ca5fd6a78070c4635950e9d149ed441".into(),
|
||||
"uqbar-router-2.uq".into(), // "0x06d331ed65843ecf0860c73292005d8103af20820546b2f8f9007d01f60595b1".into(),
|
||||
"uqbar-router-3.uq".into(), // "0xe6ab611eb62e8aee0460295667f8179cda4315982717db4b0b3da6022deecac1".into(),
|
||||
],
|
||||
});
|
||||
|
||||
let keyfile = warp::any().map(move || keyfile.clone());
|
||||
let our_temp_id = warp::any().map(move || our_temp_id.clone());
|
||||
let net_keypair = warp::any().map(move || net_keypair.clone());
|
||||
let tx = warp::any().map(move || tx.clone());
|
||||
let ip = warp::any().map(move || ip.clone());
|
||||
let rpc_url = warp::any().map(move || rpc_url.clone());
|
||||
|
||||
let static_files = warp::path("static").and(warp::fs::dir("./src/register-ui/build/static/"));
|
||||
|
||||
@ -118,73 +134,60 @@ pub async fn register(
|
||||
.and(warp::get())
|
||||
.and(warp::fs::file("./src/register-ui/build/index.html"));
|
||||
|
||||
let keyfile_info_copy = keyfile_arc.clone();
|
||||
let boot_tx = tx.clone();
|
||||
let boot_our_arc = our_temp_arc.clone();
|
||||
let boot_net_keypair_arc = net_keypair_arc.clone();
|
||||
let import_tx = tx.clone();
|
||||
let import_ip = ip.clone();
|
||||
let import_rpc_url = rpc_url.clone();
|
||||
let login_tx = tx.clone();
|
||||
let login_keyfile_arc = keyfile_arc.clone();
|
||||
let generate_keys_ip = ip.clone();
|
||||
|
||||
let api = warp::path("info")
|
||||
.and(
|
||||
warp::get()
|
||||
.and(warp::any().map(move || keyfile_info_copy.clone()))
|
||||
.and(keyfile.clone())
|
||||
.and_then(get_unencrypted_info),
|
||||
)
|
||||
.or(warp::path("generate-networking-info").and(
|
||||
warp::post()
|
||||
.and(warp::any().map(move || generate_keys_ip.clone()))
|
||||
.and(warp::any().map(move || our_ws_info.clone()))
|
||||
.and(warp::any().map(move || net_keypair_ws_info.clone()))
|
||||
.and(our_temp_id.clone())
|
||||
.and_then(generate_networking_info),
|
||||
))
|
||||
.or(warp::path("vet-keyfile").and(
|
||||
warp::post()
|
||||
.and(warp::body::content_length_limit(1024 * 16))
|
||||
.and(warp::body::json())
|
||||
.and(warp::any().map(move || keyfile_vet.clone()))
|
||||
.and(keyfile.clone())
|
||||
.and_then(handle_keyfile_vet),
|
||||
))
|
||||
.or(warp::path("boot").and(
|
||||
warp::post()
|
||||
.and(warp::body::content_length_limit(1024 * 16))
|
||||
.and(warp::body::json())
|
||||
.and(warp::any().map(move || boot_tx.clone()))
|
||||
.and(warp::any().map(move || boot_our_arc.lock().unwrap().take().unwrap()))
|
||||
.and(warp::any().map(move || boot_net_keypair_arc.lock().unwrap().take().unwrap()))
|
||||
.and(tx.clone())
|
||||
.and(our_temp_id.clone())
|
||||
.and(net_keypair.clone())
|
||||
.and_then(handle_boot),
|
||||
))
|
||||
.or(warp::path("import-keyfile").and(
|
||||
warp::post()
|
||||
.and(warp::body::content_length_limit(1024 * 16))
|
||||
.and(warp::body::json())
|
||||
.and(warp::any().map(move || import_ip.clone()))
|
||||
.and(warp::any().map(move || import_rpc_url.clone()))
|
||||
.and(warp::any().map(move || import_tx.clone()))
|
||||
.and(ip.clone())
|
||||
.and(rpc_url.clone())
|
||||
.and(tx.clone())
|
||||
.and_then(handle_import_keyfile),
|
||||
))
|
||||
.or(warp::path("login").and(
|
||||
warp::post()
|
||||
.and(warp::body::content_length_limit(1024 * 16))
|
||||
.and(warp::body::json())
|
||||
.and(warp::any().map(move || ip.clone()))
|
||||
.and(warp::any().map(move || rpc_url.clone()))
|
||||
.and(warp::any().map(move || login_tx.clone()))
|
||||
.and(warp::any().map(move || login_keyfile_arc.lock().unwrap().take().unwrap()))
|
||||
.and(ip)
|
||||
.and(rpc_url)
|
||||
.and(tx.clone())
|
||||
.and(keyfile.clone())
|
||||
.and_then(handle_login),
|
||||
))
|
||||
.or(warp::path("confirm-change-network-keys").and(
|
||||
warp::post()
|
||||
.and(warp::body::content_length_limit(1024 * 16))
|
||||
.and(warp::body::json())
|
||||
.and(warp::any().map(move || tx.clone()))
|
||||
.and(warp::any().map(move || our_temp_arc.lock().unwrap().take().unwrap()))
|
||||
.and(warp::any().map(move || net_keypair_arc.lock().unwrap().take().unwrap()))
|
||||
.and(warp::any().map(move || keyfile_arc.lock().unwrap().take().unwrap()))
|
||||
.and(tx)
|
||||
.and(our_temp_id)
|
||||
.and(net_keypair)
|
||||
.and(keyfile)
|
||||
.and_then(confirm_change_network_keys),
|
||||
));
|
||||
|
||||
@ -208,101 +211,72 @@ pub async fn register(
|
||||
.await;
|
||||
}
|
||||
|
||||
async fn get_unencrypted_info(
|
||||
keyfile_arc: Arc<Mutex<Option<Vec<u8>>>>,
|
||||
) -> Result<impl Reply, Rejection> {
|
||||
async fn get_unencrypted_info(keyfile: Option<Vec<u8>>) -> Result<impl Reply, Rejection> {
|
||||
let (name, allowed_routers) = {
|
||||
match keyfile_arc.lock().unwrap().clone() {
|
||||
Some(encoded_keyfile) => match keygen::get_username_and_routers(encoded_keyfile) {
|
||||
match keyfile {
|
||||
Some(encoded_keyfile) => match keygen::get_username_and_routers(&encoded_keyfile) {
|
||||
Ok(k) => k,
|
||||
Err(_) => {
|
||||
return Ok(warp::reply::with_status(
|
||||
warp::reply::json(&"Failed to decode keyfile".to_string()),
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
warp::reply::json(&"Incorrect password"),
|
||||
StatusCode::UNAUTHORIZED,
|
||||
)
|
||||
.into_response())
|
||||
}
|
||||
},
|
||||
None => {
|
||||
return Ok(warp::reply::with_status(
|
||||
warp::reply::json(&"Keyfile not present".to_string()),
|
||||
warp::reply::json(&"Keyfile not present"),
|
||||
StatusCode::NOT_FOUND,
|
||||
)
|
||||
.into_response())
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let our = UnencryptedIdentity {
|
||||
name,
|
||||
allowed_routers,
|
||||
};
|
||||
|
||||
Ok(warp::reply::with_status(Ok(warp::reply::json(&our)), StatusCode::OK).into_response())
|
||||
Ok(warp::reply::with_status(
|
||||
Ok(warp::reply::json(&UnencryptedIdentity {
|
||||
name,
|
||||
allowed_routers,
|
||||
})),
|
||||
StatusCode::OK,
|
||||
)
|
||||
.into_response())
|
||||
}
|
||||
|
||||
async fn generate_networking_info(
|
||||
ip: String,
|
||||
our_temp_arc: Arc<Mutex<Option<Identity>>>,
|
||||
networking_keypair_arc: Arc<Mutex<Option<Document>>>,
|
||||
) -> Result<impl Reply, Rejection> {
|
||||
let (public_key, serialized_networking_keypair) = keygen::generate_networking_key();
|
||||
*networking_keypair_arc.lock().unwrap() = Some(serialized_networking_keypair);
|
||||
|
||||
// TODO: if IP is localhost, don't allow registration as direct
|
||||
let ws_port = crate::http::utils::find_open_port(9000).await.unwrap();
|
||||
|
||||
// This is a temporary identity, passed to the UI. If it is confirmed through a /boot or /confirm-change-network-keys, then it will be used to replace the current identity
|
||||
let our_temp = Identity {
|
||||
networking_key: format!("0x{}", public_key),
|
||||
name: "".to_string(),
|
||||
ws_routing: Some((ip, ws_port)),
|
||||
allowed_routers: vec![
|
||||
"uqbar-router-1.uq".into(), // "0x8d9e54427c50660c6d4802f63edca86a9ca5fd6a78070c4635950e9d149ed441".into(),
|
||||
"uqbar-router-2.uq".into(), // "0x06d331ed65843ecf0860c73292005d8103af20820546b2f8f9007d01f60595b1".into(),
|
||||
"uqbar-router-3.uq".into(), // "0xe6ab611eb62e8aee0460295667f8179cda4315982717db4b0b3da6022deecac1".into(),
|
||||
],
|
||||
};
|
||||
|
||||
*our_temp_arc.lock().unwrap() = Some(our_temp.clone());
|
||||
|
||||
Ok(warp::reply::json(&our_temp))
|
||||
async fn generate_networking_info(our_temp_id: Arc<Identity>) -> Result<impl Reply, Rejection> {
|
||||
Ok(warp::reply::json(our_temp_id.as_ref()))
|
||||
}
|
||||
|
||||
async fn handle_keyfile_vet(
|
||||
payload: KeyfileVet,
|
||||
keyfile_arc: Arc<Mutex<Option<Vec<u8>>>>,
|
||||
keyfile: Option<Vec<u8>>,
|
||||
) -> Result<impl Reply, Rejection> {
|
||||
let encoded_keyfile = match payload.keyfile.is_empty() {
|
||||
true => keyfile_arc.lock().unwrap().clone().unwrap(),
|
||||
false => base64::decode(payload.keyfile).unwrap(),
|
||||
true => keyfile.ok_or(warp::reject())?,
|
||||
false => base64::decode(payload.keyfile).map_err(|_| warp::reject())?,
|
||||
};
|
||||
|
||||
let decoded_keyfile = match keygen::decode_keyfile(encoded_keyfile, &payload.password) {
|
||||
Ok(k) => k,
|
||||
Err(_) => return Err(warp::reject()),
|
||||
};
|
||||
let decoded_keyfile =
|
||||
keygen::decode_keyfile(&encoded_keyfile, &payload.password).map_err(|_| warp::reject())?;
|
||||
|
||||
let keyfile_vetted = KeyfileVetted {
|
||||
Ok(warp::reply::json(&KeyfileVetted {
|
||||
username: decoded_keyfile.username,
|
||||
networking_key: format!(
|
||||
"0x{}",
|
||||
hex::encode(decoded_keyfile.networking_keypair.public_key().as_ref())
|
||||
),
|
||||
routers: decoded_keyfile.routers,
|
||||
};
|
||||
|
||||
Ok(warp::reply::json(&keyfile_vetted))
|
||||
}))
|
||||
}
|
||||
|
||||
async fn handle_boot(
|
||||
info: BootInfo,
|
||||
sender: RegistrationSender,
|
||||
mut our: Identity,
|
||||
networking_keypair: Document,
|
||||
sender: Arc<RegistrationSender>,
|
||||
our: Arc<Identity>,
|
||||
networking_keypair: Arc<Vec<u8>>,
|
||||
) -> Result<impl Reply, Rejection> {
|
||||
let mut our = our.as_ref().clone();
|
||||
our.name = info.username;
|
||||
|
||||
if info.direct {
|
||||
our.allowed_routers = vec![];
|
||||
} else {
|
||||
@ -326,35 +300,26 @@ async fn handle_boot(
|
||||
info.password,
|
||||
decoded_keyfile.username.clone(),
|
||||
decoded_keyfile.routers.clone(),
|
||||
networking_keypair,
|
||||
networking_keypair.as_ref(),
|
||||
decoded_keyfile.jwt_secret_bytes.clone(),
|
||||
decoded_keyfile.file_key.clone(),
|
||||
);
|
||||
|
||||
let encoded_keyfile_str = base64::encode(encoded_keyfile.clone());
|
||||
|
||||
success_response(
|
||||
sender,
|
||||
our,
|
||||
decoded_keyfile,
|
||||
encoded_keyfile,
|
||||
encoded_keyfile_str,
|
||||
)
|
||||
.await
|
||||
success_response(sender, our, decoded_keyfile, encoded_keyfile).await
|
||||
}
|
||||
|
||||
async fn handle_import_keyfile(
|
||||
info: ImportKeyfileInfo,
|
||||
ip: String,
|
||||
_rpc_url: String,
|
||||
sender: RegistrationSender,
|
||||
sender: Arc<RegistrationSender>,
|
||||
) -> Result<impl Reply, Rejection> {
|
||||
// if keyfile was not present in node and is present from user upload
|
||||
let encoded_keyfile = match base64::decode(info.keyfile.clone()) {
|
||||
Ok(k) => k,
|
||||
Err(_) => {
|
||||
return Ok(warp::reply::with_status(
|
||||
warp::reply::json(&"Keyfile not valid base64".to_string()),
|
||||
warp::reply::json(&"Keyfile not valid base64"),
|
||||
StatusCode::BAD_REQUEST,
|
||||
)
|
||||
.into_response())
|
||||
@ -363,39 +328,38 @@ async fn handle_import_keyfile(
|
||||
|
||||
let Some(ws_port) = crate::http::utils::find_open_port(9000).await else {
|
||||
return Ok(warp::reply::with_status(
|
||||
warp::reply::json(&"Unable to find free port".to_string()),
|
||||
warp::reply::json(&"Unable to find free port"),
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
)
|
||||
.into_response());
|
||||
};
|
||||
|
||||
let (decoded_keyfile, our) =
|
||||
match keygen::decode_keyfile(encoded_keyfile.clone(), &info.password) {
|
||||
Ok(k) => {
|
||||
let our = Identity {
|
||||
name: k.username.clone(),
|
||||
networking_key: format!(
|
||||
"0x{}",
|
||||
hex::encode(k.networking_keypair.public_key().as_ref())
|
||||
),
|
||||
ws_routing: if k.routers.is_empty() {
|
||||
Some((ip, ws_port))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
allowed_routers: k.routers.clone(),
|
||||
};
|
||||
let (decoded_keyfile, our) = match keygen::decode_keyfile(&encoded_keyfile, &info.password) {
|
||||
Ok(k) => {
|
||||
let our = Identity {
|
||||
name: k.username.clone(),
|
||||
networking_key: format!(
|
||||
"0x{}",
|
||||
hex::encode(k.networking_keypair.public_key().as_ref())
|
||||
),
|
||||
ws_routing: if k.routers.is_empty() {
|
||||
Some((ip, ws_port))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
allowed_routers: k.routers.clone(),
|
||||
};
|
||||
|
||||
(k, our)
|
||||
}
|
||||
Err(_) => {
|
||||
return Ok(warp::reply::with_status(
|
||||
warp::reply::json(&"Failed to decode keyfile".to_string()),
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
)
|
||||
.into_response())
|
||||
}
|
||||
};
|
||||
(k, our)
|
||||
}
|
||||
Err(_) => {
|
||||
return Ok(warp::reply::with_status(
|
||||
warp::reply::json(&"Incorrect Password".to_string()),
|
||||
StatusCode::UNAUTHORIZED,
|
||||
)
|
||||
.into_response())
|
||||
}
|
||||
};
|
||||
|
||||
// if !networking_info_valid(rpc_url, ip, ws_port, &our).await {
|
||||
// return Ok(warp::reply::with_status(
|
||||
@ -405,114 +369,89 @@ async fn handle_import_keyfile(
|
||||
// .into_response());
|
||||
// }
|
||||
|
||||
let encoded_keyfile_str = info.keyfile.clone();
|
||||
|
||||
success_response(
|
||||
sender,
|
||||
our,
|
||||
decoded_keyfile,
|
||||
encoded_keyfile,
|
||||
encoded_keyfile_str,
|
||||
)
|
||||
.await
|
||||
success_response(sender, our, decoded_keyfile, encoded_keyfile).await
|
||||
}
|
||||
|
||||
async fn handle_login(
|
||||
info: LoginInfo,
|
||||
ip: String,
|
||||
_rpc_url: String,
|
||||
sender: RegistrationSender,
|
||||
encoded_keyfile: Vec<u8>,
|
||||
sender: Arc<RegistrationSender>,
|
||||
encoded_keyfile: Option<Vec<u8>>,
|
||||
) -> Result<impl Reply, Rejection> {
|
||||
if encoded_keyfile.is_empty() {
|
||||
if encoded_keyfile.is_none() {
|
||||
return Ok(warp::reply::with_status(
|
||||
warp::reply::json(&"Keyfile not present".to_string()),
|
||||
warp::reply::json(&"Keyfile not present"),
|
||||
StatusCode::NOT_FOUND,
|
||||
)
|
||||
.into_response());
|
||||
}
|
||||
let encoded_keyfile = encoded_keyfile.unwrap();
|
||||
|
||||
let Some(ws_port) = crate::http::utils::find_open_port(9000).await else {
|
||||
return Ok(warp::reply::with_status(
|
||||
warp::reply::json(&"Unable to find free port".to_string()),
|
||||
warp::reply::json(&"Unable to find free port"),
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
)
|
||||
.into_response());
|
||||
};
|
||||
|
||||
let (decoded_keyfile, our) =
|
||||
match keygen::decode_keyfile(encoded_keyfile.clone(), &info.password) {
|
||||
Ok(k) => {
|
||||
let our = Identity {
|
||||
name: k.username.clone(),
|
||||
networking_key: format!(
|
||||
"0x{}",
|
||||
hex::encode(k.networking_keypair.public_key().as_ref())
|
||||
),
|
||||
ws_routing: if k.routers.is_empty() {
|
||||
Some((ip, ws_port))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
allowed_routers: k.routers.clone(),
|
||||
};
|
||||
let (decoded_keyfile, our) = match keygen::decode_keyfile(&encoded_keyfile, &info.password) {
|
||||
Ok(k) => {
|
||||
let our = Identity {
|
||||
name: k.username.clone(),
|
||||
networking_key: format!(
|
||||
"0x{}",
|
||||
hex::encode(k.networking_keypair.public_key().as_ref())
|
||||
),
|
||||
ws_routing: if k.routers.is_empty() {
|
||||
Some((ip, ws_port))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
allowed_routers: k.routers.clone(),
|
||||
};
|
||||
|
||||
(k, our)
|
||||
}
|
||||
Err(_) => {
|
||||
return Ok(warp::reply::with_status(
|
||||
warp::reply::json(&"Failed to decode keyfile".to_string()),
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
)
|
||||
.into_response())
|
||||
}
|
||||
};
|
||||
(k, our)
|
||||
}
|
||||
Err(_) => {
|
||||
return Ok(warp::reply::with_status(
|
||||
warp::reply::json(&"Incorrect Password"),
|
||||
StatusCode::UNAUTHORIZED,
|
||||
)
|
||||
.into_response())
|
||||
}
|
||||
};
|
||||
|
||||
// if !networking_info_valid(rpc_url, ip, ws_port, &our).await {
|
||||
// return Ok(warp::reply::with_status(
|
||||
// warp::reply::json(&"Networking info invalid".to_string()),
|
||||
// StatusCode::UNAUTHORIZED,
|
||||
// )
|
||||
// .into_response());
|
||||
// }
|
||||
|
||||
let encoded_keyfile_str = base64::encode(encoded_keyfile.clone());
|
||||
|
||||
success_response(
|
||||
sender,
|
||||
our,
|
||||
decoded_keyfile,
|
||||
encoded_keyfile,
|
||||
encoded_keyfile_str,
|
||||
)
|
||||
.await
|
||||
success_response(sender, our, decoded_keyfile, encoded_keyfile).await
|
||||
}
|
||||
|
||||
async fn confirm_change_network_keys(
|
||||
info: LoginAndResetInfo,
|
||||
sender: RegistrationSender,
|
||||
mut our: Identity, // the arc of our temporary identity
|
||||
networking_keypair: Document,
|
||||
encoded_keyfile: Vec<u8>,
|
||||
sender: Arc<RegistrationSender>,
|
||||
our: Arc<Identity>,
|
||||
networking_keypair: Arc<Vec<u8>>,
|
||||
encoded_keyfile: Option<Vec<u8>>,
|
||||
) -> Result<impl Reply, Rejection> {
|
||||
if encoded_keyfile.is_empty() {
|
||||
if encoded_keyfile.is_none() {
|
||||
return Ok(warp::reply::with_status(
|
||||
warp::reply::json(&"Keyfile not present".to_string()),
|
||||
warp::reply::json(&"Keyfile not present"),
|
||||
StatusCode::NOT_FOUND,
|
||||
)
|
||||
.into_response());
|
||||
}
|
||||
let encoded_keyfile = encoded_keyfile.unwrap();
|
||||
let mut our = our.as_ref().clone();
|
||||
|
||||
// Get our name from our current keyfile
|
||||
let old_decoded_keyfile = match keygen::decode_keyfile(encoded_keyfile.clone(), &info.password)
|
||||
{
|
||||
let old_decoded_keyfile = match keygen::decode_keyfile(&encoded_keyfile, &info.password) {
|
||||
Ok(k) => {
|
||||
our.name = k.username.clone();
|
||||
k
|
||||
}
|
||||
Err(_) => {
|
||||
return Ok(warp::reply::with_status(
|
||||
warp::reply::json(&"Invalid password".to_string()),
|
||||
warp::reply::json(&"Invalid password"),
|
||||
StatusCode::UNAUTHORIZED,
|
||||
)
|
||||
.into_response());
|
||||
@ -539,35 +478,26 @@ async fn confirm_change_network_keys(
|
||||
info.password,
|
||||
decoded_keyfile.username.clone(),
|
||||
decoded_keyfile.routers.clone(),
|
||||
networking_keypair,
|
||||
networking_keypair.as_ref(),
|
||||
decoded_keyfile.jwt_secret_bytes.clone(),
|
||||
decoded_keyfile.file_key.clone(),
|
||||
);
|
||||
|
||||
let encoded_keyfile_str = base64::encode(encoded_keyfile.clone());
|
||||
|
||||
success_response(
|
||||
sender,
|
||||
our,
|
||||
decoded_keyfile,
|
||||
encoded_keyfile,
|
||||
encoded_keyfile_str,
|
||||
)
|
||||
.await
|
||||
success_response(sender, our.clone(), decoded_keyfile, encoded_keyfile).await
|
||||
}
|
||||
|
||||
async fn success_response(
|
||||
sender: RegistrationSender,
|
||||
sender: Arc<RegistrationSender>,
|
||||
our: Identity,
|
||||
decoded_keyfile: Keyfile,
|
||||
encoded_keyfile: Vec<u8>,
|
||||
encoded_keyfile_str: String,
|
||||
) -> Result<warp::reply::Response, Rejection> {
|
||||
let token = match generate_jwt(&decoded_keyfile.jwt_secret_bytes, our.name.clone()) {
|
||||
let encoded_keyfile_str = base64::encode(&encoded_keyfile);
|
||||
let token = match generate_jwt(&decoded_keyfile.jwt_secret_bytes, &our.name) {
|
||||
Some(token) => token,
|
||||
None => {
|
||||
return Ok(warp::reply::with_status(
|
||||
warp::reply::json(&"Failed to generate JWT".to_string()),
|
||||
warp::reply::json(&"Failed to generate JWT"),
|
||||
StatusCode::SERVICE_UNAVAILABLE,
|
||||
)
|
||||
.into_response())
|
||||
@ -591,26 +521,13 @@ async fn success_response(
|
||||
}
|
||||
Err(_) => {
|
||||
return Ok(warp::reply::with_status(
|
||||
warp::reply::json(&"Failed to generate Auth JWT".to_string()),
|
||||
warp::reply::json(&"Failed to generate Auth JWT"),
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
)
|
||||
.into_response())
|
||||
}
|
||||
}
|
||||
|
||||
// match HeaderValue::from_str(&format!("uqbar-ws-auth_{}={};", &our.name, &token)) {
|
||||
// Ok(v) => {
|
||||
// headers.append(SET_COOKIE, v);
|
||||
// },
|
||||
// Err(_) => {
|
||||
// return Ok(warp::reply::with_status(
|
||||
// warp::reply::json(&"Failed to generate WS JWT".to_string()),
|
||||
// StatusCode::INTERNAL_SERVER_ERROR,
|
||||
// )
|
||||
// .into_response())
|
||||
// }
|
||||
// }
|
||||
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
|
570
src/sqlite.rs
Normal file
570
src/sqlite.rs
Normal file
@ -0,0 +1,570 @@
|
||||
use anyhow::Result;
|
||||
use dashmap::DashMap;
|
||||
use rusqlite::types::{FromSql, FromSqlError, ToSql, ValueRef};
|
||||
use rusqlite::Connection;
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use std::sync::Arc;
|
||||
use tokio::fs;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use crate::types::*;
|
||||
|
||||
pub async fn sqlite(
|
||||
our_node: String,
|
||||
send_to_loop: MessageSender,
|
||||
send_to_terminal: PrintSender,
|
||||
mut recv_from_loop: MessageReceiver,
|
||||
send_to_caps_oracle: CapMessageSender,
|
||||
home_directory_path: String,
|
||||
) -> anyhow::Result<()> {
|
||||
let sqlite_path = format!("{}/sqlite", &home_directory_path);
|
||||
|
||||
if let Err(e) = fs::create_dir_all(&sqlite_path).await {
|
||||
panic!("failed creating sqlite dir! {:?}", e);
|
||||
}
|
||||
|
||||
let open_dbs: Arc<DashMap<(PackageId, String), Mutex<Connection>>> = Arc::new(DashMap::new());
|
||||
let txs: Arc<DashMap<u64, Vec<(String, Vec<SqlValue>)>>> = Arc::new(DashMap::new());
|
||||
|
||||
let mut process_queues: HashMap<ProcessId, Arc<Mutex<VecDeque<KernelMessage>>>> =
|
||||
HashMap::new();
|
||||
|
||||
loop {
|
||||
tokio::select! {
|
||||
Some(km) = recv_from_loop.recv() => {
|
||||
if our_node.clone() != km.source.node {
|
||||
println!(
|
||||
"sqlite: request must come from our_node={}, got: {}",
|
||||
our_node,
|
||||
km.source.node,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
let queue = process_queues
|
||||
.entry(km.source.process.clone())
|
||||
.or_insert_with(|| Arc::new(Mutex::new(VecDeque::new())))
|
||||
.clone();
|
||||
|
||||
{
|
||||
let mut queue_lock = queue.lock().await;
|
||||
queue_lock.push_back(km.clone());
|
||||
}
|
||||
|
||||
// clone Arcs
|
||||
let our_node = our_node.clone();
|
||||
let send_to_caps_oracle = send_to_caps_oracle.clone();
|
||||
let send_to_terminal = send_to_terminal.clone();
|
||||
let send_to_loop = send_to_loop.clone();
|
||||
let open_dbs = open_dbs.clone();
|
||||
let txs = txs.clone();
|
||||
let sqlite_path = sqlite_path.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
let mut queue_lock = queue.lock().await;
|
||||
if let Some(km) = queue_lock.pop_front() {
|
||||
if let Err(e) = handle_request(
|
||||
our_node.clone(),
|
||||
km.clone(),
|
||||
open_dbs.clone(),
|
||||
txs.clone(),
|
||||
send_to_loop.clone(),
|
||||
send_to_terminal.clone(),
|
||||
send_to_caps_oracle.clone(),
|
||||
sqlite_path.clone(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
let _ = send_to_loop
|
||||
.send(make_error_message(our_node.clone(), &km, e))
|
||||
.await;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_request(
|
||||
our_node: String,
|
||||
km: KernelMessage,
|
||||
open_dbs: Arc<DashMap<(PackageId, String), Mutex<Connection>>>,
|
||||
txs: Arc<DashMap<u64, Vec<(String, Vec<SqlValue>)>>>,
|
||||
send_to_loop: MessageSender,
|
||||
send_to_terminal: PrintSender,
|
||||
send_to_caps_oracle: CapMessageSender,
|
||||
sqlite_path: String,
|
||||
) -> Result<(), SqliteError> {
|
||||
let KernelMessage {
|
||||
id,
|
||||
source,
|
||||
message,
|
||||
payload,
|
||||
..
|
||||
} = km.clone();
|
||||
let Message::Request(Request {
|
||||
ipc,
|
||||
expects_response,
|
||||
metadata,
|
||||
..
|
||||
}) = message.clone()
|
||||
else {
|
||||
return Err(SqliteError::InputError {
|
||||
error: "not a request".into(),
|
||||
});
|
||||
};
|
||||
|
||||
let request: SqliteRequest = match serde_json::from_slice(&ipc) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
println!("sqlite: got invalid Request: {}", e);
|
||||
return Err(SqliteError::InputError {
|
||||
error: "didn't serialize to SqliteRequest.".into(),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
check_caps(
|
||||
our_node.clone(),
|
||||
source.clone(),
|
||||
open_dbs.clone(),
|
||||
send_to_caps_oracle.clone(),
|
||||
&request,
|
||||
sqlite_path.clone(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let (ipc, bytes) = match request.action {
|
||||
SqliteAction::New => {
|
||||
// handled in check_caps
|
||||
//
|
||||
(serde_json::to_vec(&SqliteResponse::Ok).unwrap(), None)
|
||||
}
|
||||
SqliteAction::Read { query } => {
|
||||
let db = match open_dbs.get(&(request.package_id, request.db)) {
|
||||
Some(db) => db,
|
||||
None => {
|
||||
return Err(SqliteError::NoDb);
|
||||
}
|
||||
};
|
||||
let db = db.lock().await;
|
||||
|
||||
let parameters = get_json_params(payload)?;
|
||||
|
||||
let mut statement = db.prepare(&query)?;
|
||||
let column_names: Vec<String> = statement
|
||||
.column_names()
|
||||
.iter()
|
||||
.map(|c| c.to_string())
|
||||
.collect();
|
||||
|
||||
let results: Vec<HashMap<String, serde_json::Value>> = statement
|
||||
.query_map(rusqlite::params_from_iter(parameters.iter()), |row| {
|
||||
let mut map = HashMap::new();
|
||||
for (i, column_name) in column_names.iter().enumerate() {
|
||||
let value: SqlValue = row.get(i)?;
|
||||
let value_json = match value {
|
||||
SqlValue::Integer(int) => serde_json::Value::Number(int.into()),
|
||||
SqlValue::Real(real) => serde_json::Value::Number(
|
||||
serde_json::Number::from_f64(real).unwrap(),
|
||||
),
|
||||
SqlValue::Text(text) => serde_json::Value::String(text),
|
||||
SqlValue::Blob(blob) => serde_json::Value::String(base64::encode(blob)), // or another representation if you prefer
|
||||
_ => serde_json::Value::Null,
|
||||
};
|
||||
map.insert(column_name.clone(), value_json);
|
||||
}
|
||||
Ok(map)
|
||||
})?
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
let results = serde_json::json!(results).to_string();
|
||||
let results_bytes = results.as_bytes().to_vec();
|
||||
|
||||
(
|
||||
serde_json::to_vec(&SqliteResponse::Read).unwrap(),
|
||||
Some(results_bytes),
|
||||
)
|
||||
}
|
||||
SqliteAction::Write { statement, tx_id } => {
|
||||
let db = match open_dbs.get(&(request.package_id, request.db)) {
|
||||
Some(db) => db,
|
||||
None => {
|
||||
return Err(SqliteError::NoDb);
|
||||
}
|
||||
};
|
||||
let db = db.lock().await;
|
||||
|
||||
let parameters = get_json_params(payload)?;
|
||||
|
||||
match tx_id {
|
||||
Some(tx_id) => {
|
||||
txs.entry(tx_id)
|
||||
.or_insert_with(Vec::new)
|
||||
.push((statement.clone(), parameters));
|
||||
}
|
||||
None => {
|
||||
let mut stmt = db.prepare(&statement)?;
|
||||
stmt.execute(rusqlite::params_from_iter(parameters.iter()))?;
|
||||
}
|
||||
};
|
||||
(serde_json::to_vec(&SqliteResponse::Ok).unwrap(), None)
|
||||
}
|
||||
SqliteAction::BeginTx => {
|
||||
let tx_id = rand::random::<u64>();
|
||||
txs.insert(tx_id, Vec::new());
|
||||
|
||||
(
|
||||
serde_json::to_vec(&SqliteResponse::BeginTx { tx_id }).unwrap(),
|
||||
None,
|
||||
)
|
||||
}
|
||||
SqliteAction::Commit { tx_id } => {
|
||||
let db = match open_dbs.get(&(request.package_id, request.db)) {
|
||||
Some(db) => db,
|
||||
None => {
|
||||
return Err(SqliteError::NoDb);
|
||||
}
|
||||
};
|
||||
let mut db = db.lock().await;
|
||||
|
||||
let txs = match txs.remove(&tx_id).map(|(_, tx)| tx) {
|
||||
None => {
|
||||
return Err(SqliteError::NoTx);
|
||||
}
|
||||
Some(tx) => tx,
|
||||
};
|
||||
|
||||
let tx = db.transaction()?;
|
||||
for (query, params) in txs {
|
||||
tx.execute(&query, rusqlite::params_from_iter(params.iter()))?;
|
||||
}
|
||||
|
||||
tx.commit()?;
|
||||
(serde_json::to_vec(&SqliteResponse::Ok).unwrap(), None)
|
||||
}
|
||||
SqliteAction::Backup => {
|
||||
// execute WAL flush.
|
||||
//
|
||||
(serde_json::to_vec(&SqliteResponse::Ok).unwrap(), None)
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(target) = km.rsvp.or_else(|| {
|
||||
expects_response.map(|_| Address {
|
||||
node: our_node.clone(),
|
||||
process: source.process.clone(),
|
||||
})
|
||||
}) {
|
||||
let response = KernelMessage {
|
||||
id,
|
||||
source: Address {
|
||||
node: our_node.clone(),
|
||||
process: SQLITE_PROCESS_ID.clone(),
|
||||
},
|
||||
target,
|
||||
rsvp: None,
|
||||
message: Message::Response((
|
||||
Response {
|
||||
inherit: false,
|
||||
ipc,
|
||||
metadata,
|
||||
},
|
||||
None,
|
||||
)),
|
||||
payload: bytes.map(|bytes| Payload {
|
||||
mime: Some("application/octet-stream".into()),
|
||||
bytes,
|
||||
}),
|
||||
signed_capabilities: None,
|
||||
};
|
||||
|
||||
let _ = send_to_loop.send(response).await;
|
||||
} else {
|
||||
send_to_terminal
|
||||
.send(Printout {
|
||||
verbosity: 2,
|
||||
content: format!(
|
||||
"sqlite: not sending response: {:?}",
|
||||
serde_json::from_slice::<SqliteResponse>(&ipc)
|
||||
),
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn check_caps(
|
||||
our_node: String,
|
||||
source: Address,
|
||||
open_dbs: Arc<DashMap<(PackageId, String), Mutex<Connection>>>,
|
||||
mut send_to_caps_oracle: CapMessageSender,
|
||||
request: &SqliteRequest,
|
||||
sqlite_path: String,
|
||||
) -> Result<(), SqliteError> {
|
||||
let (send_cap_bool, recv_cap_bool) = tokio::sync::oneshot::channel();
|
||||
let src_package_id = PackageId::new(source.process.package(), source.process.publisher());
|
||||
|
||||
match &request.action {
|
||||
SqliteAction::Write { .. } | SqliteAction::BeginTx | SqliteAction::Commit { .. } => {
|
||||
send_to_caps_oracle
|
||||
.send(CapMessage::Has {
|
||||
on: source.process.clone(),
|
||||
cap: Capability {
|
||||
issuer: Address {
|
||||
node: our_node.clone(),
|
||||
process: SQLITE_PROCESS_ID.clone(),
|
||||
},
|
||||
params: serde_json::to_string(&serde_json::json!({
|
||||
"kind": "write",
|
||||
"db": request.db.to_string(),
|
||||
}))
|
||||
.unwrap(),
|
||||
},
|
||||
responder: send_cap_bool,
|
||||
})
|
||||
.await?;
|
||||
let has_cap = recv_cap_bool.await?;
|
||||
if !has_cap {
|
||||
return Err(SqliteError::NoCap {
|
||||
error: request.action.to_string(),
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
SqliteAction::Read { .. } => {
|
||||
send_to_caps_oracle
|
||||
.send(CapMessage::Has {
|
||||
on: source.process.clone(),
|
||||
cap: Capability {
|
||||
issuer: Address {
|
||||
node: our_node.clone(),
|
||||
process: SQLITE_PROCESS_ID.clone(),
|
||||
},
|
||||
params: serde_json::to_string(&serde_json::json!({
|
||||
"kind": "read",
|
||||
"db": request.db.to_string(),
|
||||
}))
|
||||
.unwrap(),
|
||||
},
|
||||
responder: send_cap_bool,
|
||||
})
|
||||
.await?;
|
||||
let has_cap = recv_cap_bool.await?;
|
||||
if !has_cap {
|
||||
return Err(SqliteError::NoCap {
|
||||
error: request.action.to_string(),
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
SqliteAction::New => {
|
||||
if src_package_id != request.package_id {
|
||||
return Err(SqliteError::NoCap {
|
||||
error: request.action.to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
add_capability(
|
||||
"read",
|
||||
&request.db.to_string(),
|
||||
&our_node,
|
||||
&source,
|
||||
&mut send_to_caps_oracle,
|
||||
)
|
||||
.await?;
|
||||
add_capability(
|
||||
"write",
|
||||
&request.db.to_string(),
|
||||
&our_node,
|
||||
&source,
|
||||
&mut send_to_caps_oracle,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let db_path = format!("{}{}", sqlite_path, request.db.to_string());
|
||||
|
||||
fs::create_dir_all(&db_path).await?;
|
||||
|
||||
let db = Connection::open(&db_path)?;
|
||||
db.execute("PRAGMA journal_mode=WAL;", [])?;
|
||||
|
||||
open_dbs.insert(
|
||||
(request.package_id.clone(), request.db.clone()),
|
||||
Mutex::new(db),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
SqliteAction::Backup => {
|
||||
if source.process != *STATE_PROCESS_ID {
|
||||
return Err(SqliteError::NoCap {
|
||||
error: request.action.to_string(),
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn add_capability(
|
||||
kind: &str,
|
||||
db: &str,
|
||||
our_node: &str,
|
||||
source: &Address,
|
||||
send_to_caps_oracle: &mut CapMessageSender,
|
||||
) -> Result<(), SqliteError> {
|
||||
let cap = Capability {
|
||||
issuer: Address {
|
||||
node: our_node.to_string(),
|
||||
process: SQLITE_PROCESS_ID.clone(),
|
||||
},
|
||||
params: serde_json::to_string(&serde_json::json!({ "kind": kind, "db": db })).unwrap(),
|
||||
};
|
||||
let (send_cap_bool, recv_cap_bool) = tokio::sync::oneshot::channel();
|
||||
send_to_caps_oracle
|
||||
.send(CapMessage::Add {
|
||||
on: source.process.clone(),
|
||||
cap,
|
||||
responder: send_cap_bool,
|
||||
})
|
||||
.await?;
|
||||
let _ = recv_cap_bool.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn json_to_sqlite(value: &serde_json::Value) -> Result<SqlValue, SqliteError> {
|
||||
match value {
|
||||
serde_json::Value::Number(n) => {
|
||||
if let Some(int_val) = n.as_i64() {
|
||||
Ok(SqlValue::Integer(int_val))
|
||||
} else if let Some(float_val) = n.as_f64() {
|
||||
Ok(SqlValue::Real(float_val))
|
||||
} else {
|
||||
Err(SqliteError::InvalidParameters)
|
||||
}
|
||||
}
|
||||
serde_json::Value::String(s) => {
|
||||
match base64::decode(&s) {
|
||||
Ok(decoded_bytes) => {
|
||||
// convert to SQLite Blob if it's a valid base64 string
|
||||
Ok(SqlValue::Blob(decoded_bytes))
|
||||
}
|
||||
Err(_) => {
|
||||
// if it's not base64, just use the string itself
|
||||
Ok(SqlValue::Text(s.clone()))
|
||||
}
|
||||
}
|
||||
}
|
||||
serde_json::Value::Bool(b) => Ok(SqlValue::Boolean(*b)),
|
||||
serde_json::Value::Null => Ok(SqlValue::Null),
|
||||
_ => Err(SqliteError::InvalidParameters),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_json_params(payload: Option<Payload>) -> Result<Vec<SqlValue>, SqliteError> {
|
||||
match payload {
|
||||
None => Ok(vec![]),
|
||||
Some(payload) => match serde_json::from_slice::<serde_json::Value>(&payload.bytes) {
|
||||
Ok(serde_json::Value::Array(vec)) => vec
|
||||
.iter()
|
||||
.map(|value| json_to_sqlite(value))
|
||||
.collect::<Result<Vec<_>, _>>(),
|
||||
_ => Err(SqliteError::InvalidParameters),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn make_error_message(our_name: String, km: &KernelMessage, error: SqliteError) -> KernelMessage {
|
||||
KernelMessage {
|
||||
id: km.id,
|
||||
source: Address {
|
||||
node: our_name.clone(),
|
||||
process: KV_PROCESS_ID.clone(),
|
||||
},
|
||||
target: match &km.rsvp {
|
||||
None => km.source.clone(),
|
||||
Some(rsvp) => rsvp.clone(),
|
||||
},
|
||||
rsvp: None,
|
||||
message: Message::Response((
|
||||
Response {
|
||||
inherit: false,
|
||||
ipc: serde_json::to_vec(&SqliteResponse::Err { error: error }).unwrap(),
|
||||
metadata: None,
|
||||
},
|
||||
None,
|
||||
)),
|
||||
payload: None,
|
||||
signed_capabilities: None,
|
||||
}
|
||||
}
|
||||
impl ToSql for SqlValue {
|
||||
fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput> {
|
||||
match self {
|
||||
SqlValue::Integer(i) => i.to_sql(),
|
||||
SqlValue::Real(f) => f.to_sql(),
|
||||
SqlValue::Text(ref s) => s.to_sql(),
|
||||
SqlValue::Blob(ref b) => b.to_sql(),
|
||||
SqlValue::Boolean(b) => b.to_sql(),
|
||||
SqlValue::Null => Ok(rusqlite::types::ToSqlOutput::Owned(
|
||||
rusqlite::types::Value::Null,
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromSql for SqlValue {
|
||||
fn column_result(value: ValueRef<'_>) -> Result<Self, FromSqlError> {
|
||||
match value {
|
||||
ValueRef::Integer(i) => Ok(SqlValue::Integer(i)),
|
||||
ValueRef::Real(f) => Ok(SqlValue::Real(f)),
|
||||
ValueRef::Text(t) => {
|
||||
let text_str = std::str::from_utf8(t).map_err(|_| FromSqlError::InvalidType)?;
|
||||
Ok(SqlValue::Text(text_str.to_string()))
|
||||
}
|
||||
ValueRef::Blob(b) => Ok(SqlValue::Blob(b.to_vec())),
|
||||
_ => Err(FromSqlError::InvalidType),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for SqliteAction {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for SqliteError {
|
||||
fn from(err: std::io::Error) -> Self {
|
||||
SqliteError::IOError {
|
||||
error: err.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<rusqlite::Error> for SqliteError {
|
||||
fn from(err: rusqlite::Error) -> Self {
|
||||
SqliteError::RusqliteError {
|
||||
error: err.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<tokio::sync::oneshot::error::RecvError> for SqliteError {
|
||||
fn from(err: tokio::sync::oneshot::error::RecvError) -> Self {
|
||||
SqliteError::NoCap {
|
||||
error: err.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<tokio::sync::mpsc::error::SendError<CapMessage>> for SqliteError {
|
||||
fn from(err: tokio::sync::mpsc::error::SendError<CapMessage>) -> Self {
|
||||
SqliteError::NoCap {
|
||||
error: err.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
650
src/state.rs
Normal file
650
src/state.rs
Normal file
@ -0,0 +1,650 @@
|
||||
use anyhow::Result;
|
||||
use rocksdb::checkpoint::Checkpoint;
|
||||
use rocksdb::{Options, DB};
|
||||
use std::collections::{HashMap, HashSet, VecDeque};
|
||||
use std::io::Read;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use tokio::fs;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use crate::types::*;
|
||||
|
||||
pub async fn load_state(
|
||||
our_name: String,
|
||||
home_directory_path: String,
|
||||
runtime_extensions: Vec<(ProcessId, MessageSender, bool)>,
|
||||
) -> Result<(ProcessMap, DB), StateError> {
|
||||
let state_path = format!("{}/kernel", &home_directory_path);
|
||||
|
||||
if let Err(e) = fs::create_dir_all(&state_path).await {
|
||||
panic!("failed creating kernel state dir! {:?}", e);
|
||||
}
|
||||
|
||||
// more granular kernel_state in column families
|
||||
|
||||
// let mut options = Option::default().unwrap();
|
||||
// options.create_if_missing(true);
|
||||
//let db = DB::open_default(&state_directory_path_str).unwrap();
|
||||
let mut opts = Options::default();
|
||||
opts.create_if_missing(true);
|
||||
// let cf_name = "kernel_state";
|
||||
// let cf_descriptor = ColumnFamilyDescriptor::new(cf_name, Options::default());
|
||||
let db = DB::open_default(state_path).unwrap();
|
||||
let mut process_map: ProcessMap = HashMap::new();
|
||||
|
||||
let kernel_id = process_to_vec(KERNEL_PROCESS_ID.clone());
|
||||
match db.get(&kernel_id) {
|
||||
Ok(Some(value)) => {
|
||||
process_map = bincode::deserialize::<ProcessMap>(&value).unwrap();
|
||||
}
|
||||
Ok(None) => {
|
||||
bootstrap(
|
||||
&our_name,
|
||||
home_directory_path.clone(),
|
||||
runtime_extensions.clone(),
|
||||
&mut process_map,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
db.put(&kernel_id, bincode::serialize(&process_map).unwrap())
|
||||
.unwrap();
|
||||
}
|
||||
Err(e) => {
|
||||
panic!("failed to load kernel state from db: {:?}", e);
|
||||
}
|
||||
}
|
||||
|
||||
Ok((process_map, db))
|
||||
}
|
||||
|
||||
pub async fn state_sender(
|
||||
our_name: String,
|
||||
send_to_loop: MessageSender,
|
||||
send_to_terminal: PrintSender,
|
||||
mut recv_state: MessageReceiver,
|
||||
db: DB,
|
||||
home_directory_path: String,
|
||||
) -> Result<(), anyhow::Error> {
|
||||
let db = Arc::new(db);
|
||||
|
||||
let mut process_queues: HashMap<ProcessId, Arc<Mutex<VecDeque<KernelMessage>>>> =
|
||||
HashMap::new();
|
||||
|
||||
loop {
|
||||
tokio::select! {
|
||||
Some(km) = recv_state.recv() => {
|
||||
if our_name != km.source.node {
|
||||
println!(
|
||||
"state: request must come from our_name={}, got: {}",
|
||||
our_name, &km,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
let queue = process_queues
|
||||
.entry(km.source.process.clone())
|
||||
.or_insert_with(|| Arc::new(Mutex::new(VecDeque::new())))
|
||||
.clone();
|
||||
|
||||
{
|
||||
let mut queue_lock = queue.lock().await;
|
||||
queue_lock.push_back(km.clone());
|
||||
}
|
||||
|
||||
let db_clone = db.clone();
|
||||
let send_to_loop = send_to_loop.clone();
|
||||
let send_to_terminal = send_to_terminal.clone();
|
||||
let our_name = our_name.clone();
|
||||
let home_directory_path = home_directory_path.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
let mut queue_lock = queue.lock().await;
|
||||
if let Some(km) = queue_lock.pop_front() {
|
||||
if let Err(e) = handle_request(
|
||||
our_name.clone(),
|
||||
km.clone(),
|
||||
db_clone,
|
||||
send_to_loop.clone(),
|
||||
send_to_terminal,
|
||||
home_directory_path,
|
||||
)
|
||||
.await
|
||||
{
|
||||
let _ = send_to_loop
|
||||
.send(make_error_message(our_name.clone(), &km, e))
|
||||
.await;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_request(
|
||||
our_name: String,
|
||||
kernel_message: KernelMessage,
|
||||
db: Arc<DB>,
|
||||
send_to_loop: MessageSender,
|
||||
_send_to_terminal: PrintSender,
|
||||
home_directory_path: String,
|
||||
) -> Result<(), StateError> {
|
||||
let KernelMessage {
|
||||
id,
|
||||
source,
|
||||
rsvp,
|
||||
message,
|
||||
payload,
|
||||
..
|
||||
} = kernel_message;
|
||||
let Message::Request(Request {
|
||||
expects_response,
|
||||
ipc,
|
||||
metadata, // for kernel
|
||||
..
|
||||
}) = message
|
||||
else {
|
||||
return Err(StateError::BadRequest {
|
||||
error: "not a request".into(),
|
||||
});
|
||||
};
|
||||
|
||||
let action: StateAction = match serde_json::from_slice(&ipc) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Err(StateError::BadJson {
|
||||
error: format!("parse into StateAction failed: {:?}", e),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
let (ipc, bytes) = match action {
|
||||
StateAction::SetState(process_id) => {
|
||||
let key = process_to_vec(process_id);
|
||||
|
||||
let Some(ref payload) = payload else {
|
||||
return Err(StateError::BadBytes {
|
||||
action: "SetState".into(),
|
||||
});
|
||||
};
|
||||
|
||||
db.put(key, &payload.bytes)
|
||||
.map_err(|e| StateError::RocksDBError {
|
||||
action: "SetState".into(),
|
||||
error: e.to_string(),
|
||||
})?;
|
||||
|
||||
(serde_json::to_vec(&StateResponse::SetState).unwrap(), None)
|
||||
}
|
||||
StateAction::GetState(process_id) => {
|
||||
let key = process_to_vec(process_id.clone());
|
||||
match db.get(key) {
|
||||
Ok(Some(value)) => (
|
||||
serde_json::to_vec(&StateResponse::GetState).unwrap(),
|
||||
Some(value),
|
||||
),
|
||||
Ok(None) => {
|
||||
return Err(StateError::NotFound {
|
||||
process_id: process_id.clone(),
|
||||
});
|
||||
}
|
||||
Err(e) => {
|
||||
println!("get state error: {:?}", e);
|
||||
return Err(StateError::RocksDBError {
|
||||
action: "GetState".into(),
|
||||
error: e.to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
StateAction::DeleteState(process_id) => {
|
||||
let key = process_to_vec(process_id);
|
||||
match db.delete(key) {
|
||||
Ok(_) => (
|
||||
serde_json::to_vec(&StateResponse::DeleteState).unwrap(),
|
||||
None,
|
||||
),
|
||||
Err(e) => {
|
||||
println!("delete state error: {:?}", e);
|
||||
return Err(StateError::RocksDBError {
|
||||
action: "DeleteState".into(),
|
||||
error: e.to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
StateAction::Backup => {
|
||||
// handle Backup action
|
||||
println!("got backup");
|
||||
let checkpoint_dir = format!("{}/kernel/checkpoint", &home_directory_path);
|
||||
|
||||
if Path::new(&checkpoint_dir).exists() {
|
||||
let _ = fs::remove_dir_all(&checkpoint_dir).await;
|
||||
}
|
||||
let checkpoint = Checkpoint::new(&db).unwrap();
|
||||
checkpoint.create_checkpoint(&checkpoint_dir).unwrap();
|
||||
(serde_json::to_vec(&StateResponse::Backup).unwrap(), None)
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(target) = rsvp.or_else(|| {
|
||||
expects_response.map(|_| Address {
|
||||
node: our_name.clone(),
|
||||
process: source.process.clone(),
|
||||
})
|
||||
}) {
|
||||
let response = KernelMessage {
|
||||
id,
|
||||
source: Address {
|
||||
node: our_name.clone(),
|
||||
process: STATE_PROCESS_ID.clone(),
|
||||
},
|
||||
target,
|
||||
rsvp: None,
|
||||
message: Message::Response((
|
||||
Response {
|
||||
inherit: false,
|
||||
ipc,
|
||||
metadata,
|
||||
},
|
||||
None,
|
||||
)),
|
||||
payload: bytes.map(|bytes| Payload {
|
||||
mime: Some("application/octet-stream".into()),
|
||||
bytes,
|
||||
}),
|
||||
signed_capabilities: None,
|
||||
};
|
||||
|
||||
let _ = send_to_loop.send(response).await;
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// function run only upon fresh boot.
|
||||
///
|
||||
/// for each folder in /modules, looks for a package.zip file, extracts the contents,
|
||||
/// sends the contents to VFS, and reads the manifest.json.
|
||||
///
|
||||
/// the manifest.json contains instructions for which processes to boot and what
|
||||
/// capabilities to give them. since we are inside runtime, can spawn those out of
|
||||
/// thin air.
|
||||
async fn bootstrap(
|
||||
our_name: &str,
|
||||
home_directory_path: String,
|
||||
runtime_extensions: Vec<(ProcessId, MessageSender, bool)>,
|
||||
process_map: &mut ProcessMap,
|
||||
) -> Result<()> {
|
||||
println!("bootstrapping node...\r");
|
||||
|
||||
let mut runtime_caps: HashSet<Capability> = HashSet::new();
|
||||
// kernel is a special case
|
||||
runtime_caps.insert(Capability {
|
||||
issuer: Address {
|
||||
node: our_name.to_string(),
|
||||
process: ProcessId::from_str("kernel:sys:uqbar").unwrap(),
|
||||
},
|
||||
params: "\"messaging\"".into(),
|
||||
});
|
||||
// net is a special case
|
||||
runtime_caps.insert(Capability {
|
||||
issuer: Address {
|
||||
node: our_name.to_string(),
|
||||
process: ProcessId::from_str("net:sys:uqbar").unwrap(),
|
||||
},
|
||||
params: "\"messaging\"".into(),
|
||||
});
|
||||
for runtime_module in runtime_extensions.clone() {
|
||||
runtime_caps.insert(Capability {
|
||||
issuer: Address {
|
||||
node: our_name.to_string(),
|
||||
process: runtime_module.0,
|
||||
},
|
||||
params: "\"messaging\"".into(),
|
||||
});
|
||||
}
|
||||
// give all runtime processes the ability to send messages across the network
|
||||
runtime_caps.insert(Capability {
|
||||
issuer: Address {
|
||||
node: our_name.to_string(),
|
||||
process: KERNEL_PROCESS_ID.clone(),
|
||||
},
|
||||
params: "\"network\"".into(),
|
||||
});
|
||||
|
||||
// finally, save runtime modules in state map as well, somewhat fakely
|
||||
// special cases for kernel and net
|
||||
process_map
|
||||
.entry(ProcessId::from_str("kernel:sys:uqbar").unwrap())
|
||||
.or_insert(PersistedProcess {
|
||||
wasm_bytes_handle: "".into(),
|
||||
on_exit: OnExit::Restart,
|
||||
capabilities: runtime_caps.clone(),
|
||||
public: false,
|
||||
});
|
||||
process_map
|
||||
.entry(ProcessId::from_str("net:sys:uqbar").unwrap())
|
||||
.or_insert(PersistedProcess {
|
||||
wasm_bytes_handle: "".into(),
|
||||
on_exit: OnExit::Restart,
|
||||
capabilities: runtime_caps.clone(),
|
||||
public: false,
|
||||
});
|
||||
for runtime_module in runtime_extensions {
|
||||
process_map
|
||||
.entry(runtime_module.0)
|
||||
.or_insert(PersistedProcess {
|
||||
wasm_bytes_handle: "".into(),
|
||||
on_exit: OnExit::Restart,
|
||||
capabilities: runtime_caps.clone(),
|
||||
public: runtime_module.2,
|
||||
});
|
||||
}
|
||||
|
||||
let packages: Vec<(String, zip::ZipArchive<std::io::Cursor<Vec<u8>>>)> =
|
||||
get_zipped_packages().await;
|
||||
|
||||
for (package_name, mut package) in packages {
|
||||
// special case tester: only load it in if in simulation mode
|
||||
if package_name == "tester" {
|
||||
#[cfg(not(feature = "simulation-mode"))]
|
||||
continue;
|
||||
#[cfg(feature = "simulation-mode")]
|
||||
{}
|
||||
}
|
||||
|
||||
println!("fs: handling package {package_name}...\r");
|
||||
// get and read metadata.json
|
||||
let Ok(mut package_metadata_zip) = package.by_name("metadata.json") else {
|
||||
println!(
|
||||
"fs: missing metadata for package {}, skipping",
|
||||
package_name
|
||||
);
|
||||
continue;
|
||||
};
|
||||
let mut metadata_content = Vec::new();
|
||||
package_metadata_zip
|
||||
.read_to_end(&mut metadata_content)
|
||||
.unwrap();
|
||||
drop(package_metadata_zip);
|
||||
let package_metadata: serde_json::Value =
|
||||
serde_json::from_slice(&metadata_content).expect("fs: metadata parse error");
|
||||
|
||||
println!("fs: found package metadata: {:?}\r", package_metadata);
|
||||
|
||||
let package_name = package_metadata["package"]
|
||||
.as_str()
|
||||
.expect("fs: metadata parse error: bad package name");
|
||||
|
||||
let package_publisher = package_metadata["publisher"]
|
||||
.as_str()
|
||||
.expect("fs: metadata parse error: bad publisher name");
|
||||
|
||||
// create a new package in VFS
|
||||
let our_drive_name = [package_name, package_publisher].join(":");
|
||||
let pkg_path = format!("{}/vfs/{}/pkg", &home_directory_path, &our_drive_name);
|
||||
fs::create_dir_all(&pkg_path)
|
||||
.await
|
||||
.expect("bootstrap vfs dir pkg creation failed!");
|
||||
|
||||
let drive_path = format!("/{}/pkg", &our_drive_name);
|
||||
|
||||
// for each file in package.zip, recursively through all dirs, send a newfile KM to VFS
|
||||
for i in 0..package.len() {
|
||||
let mut file = package.by_index(i).unwrap();
|
||||
if file.is_file() {
|
||||
let file_path = file
|
||||
.enclosed_name()
|
||||
.expect("fs: name error reading package.zip")
|
||||
.to_owned();
|
||||
let mut file_path = file_path.to_string_lossy().to_string();
|
||||
if !file_path.starts_with('/') {
|
||||
file_path = format!("/{}", file_path);
|
||||
}
|
||||
println!("fs: found file {}...\r", file_path);
|
||||
let mut file_content = Vec::new();
|
||||
file.read_to_end(&mut file_content).unwrap();
|
||||
let path = format!("{}/{}", &pkg_path, file_path);
|
||||
fs::write(&path, file_content).await.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
// get and read manifest.json
|
||||
let Ok(mut package_manifest_zip) = package.by_name("manifest.json") else {
|
||||
println!(
|
||||
"fs: missing manifest for package {}, skipping",
|
||||
package_name
|
||||
);
|
||||
continue;
|
||||
};
|
||||
let mut manifest_content = Vec::new();
|
||||
package_manifest_zip
|
||||
.read_to_end(&mut manifest_content)
|
||||
.unwrap();
|
||||
drop(package_manifest_zip);
|
||||
let package_manifest = String::from_utf8(manifest_content)?;
|
||||
let package_manifest = serde_json::from_str::<Vec<PackageManifestEntry>>(&package_manifest)
|
||||
.expect("fs: manifest parse error");
|
||||
|
||||
// for each process-entry in manifest.json:
|
||||
for mut entry in package_manifest {
|
||||
let wasm_bytes = &mut Vec::new();
|
||||
let mut file_path = entry.process_wasm_path.to_string();
|
||||
if file_path.starts_with('/') {
|
||||
file_path = file_path[1..].to_string();
|
||||
}
|
||||
package
|
||||
.by_name(&file_path)
|
||||
.expect("fs: no wasm found in package!")
|
||||
.read_to_end(wasm_bytes)
|
||||
.unwrap();
|
||||
|
||||
// spawn the requested capabilities
|
||||
// remember: out of thin air, because this is the root distro
|
||||
let mut requested_caps = HashSet::new();
|
||||
let our_process_id = format!(
|
||||
"{}:{}:{}",
|
||||
entry.process_name, package_name, package_publisher
|
||||
);
|
||||
entry.request_messaging = Some(entry.request_messaging.unwrap_or_default());
|
||||
if let Some(ref mut request_messaging) = entry.request_messaging {
|
||||
request_messaging.push(serde_json::Value::String(our_process_id.clone()));
|
||||
for value in request_messaging {
|
||||
match value {
|
||||
serde_json::Value::String(process_name) => {
|
||||
requested_caps.insert(Capability {
|
||||
issuer: Address {
|
||||
node: our_name.to_string(),
|
||||
process: ProcessId::from_str(process_name).unwrap(),
|
||||
},
|
||||
params: "\"messaging\"".into(),
|
||||
});
|
||||
}
|
||||
serde_json::Value::Object(map) => {
|
||||
if let Some(process_name) = map.get("process") {
|
||||
if let Some(params) = map.get("params") {
|
||||
requested_caps.insert(Capability {
|
||||
issuer: Address {
|
||||
node: our_name.to_string(),
|
||||
process: ProcessId::from_str(
|
||||
process_name.as_str().unwrap(),
|
||||
)
|
||||
.unwrap(),
|
||||
},
|
||||
params: params.to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// other json types
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// grant capabilities to other initially spawned processes, distro
|
||||
if let Some(to_grant) = &entry.grant_messaging {
|
||||
for value in to_grant {
|
||||
let mut capability = None;
|
||||
let mut to_process = None;
|
||||
match value {
|
||||
serde_json::Value::String(process_name) => {
|
||||
if let Ok(parsed_process_id) = ProcessId::from_str(process_name) {
|
||||
capability = Some(Capability {
|
||||
issuer: Address {
|
||||
node: our_name.to_string(),
|
||||
process: ProcessId::from_str(process_name).unwrap(),
|
||||
},
|
||||
params: "\"messaging\"".into(),
|
||||
});
|
||||
to_process = Some(parsed_process_id);
|
||||
}
|
||||
}
|
||||
serde_json::Value::Object(map) => {
|
||||
if let Some(process_name) = map.get("process") {
|
||||
if let Ok(parsed_process_id) =
|
||||
ProcessId::from_str(&process_name.as_str().unwrap())
|
||||
{
|
||||
if let Some(params) = map.get("params") {
|
||||
capability = Some(Capability {
|
||||
issuer: Address {
|
||||
node: our_name.to_string(),
|
||||
process: ProcessId::from_str(
|
||||
process_name.as_str().unwrap(),
|
||||
)
|
||||
.unwrap(),
|
||||
},
|
||||
params: params.to_string(),
|
||||
});
|
||||
to_process = Some(parsed_process_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(cap) = capability {
|
||||
if let Some(process) = process_map.get_mut(&to_process.unwrap()) {
|
||||
process.capabilities.insert(cap);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if entry.request_networking {
|
||||
requested_caps.insert(Capability {
|
||||
issuer: Address {
|
||||
node: our_name.to_string(),
|
||||
process: KERNEL_PROCESS_ID.clone(),
|
||||
},
|
||||
params: "\"network\"".into(),
|
||||
});
|
||||
}
|
||||
|
||||
// give access to package_name vfs
|
||||
requested_caps.insert(Capability {
|
||||
issuer: Address {
|
||||
node: our_name.into(),
|
||||
process: VFS_PROCESS_ID.clone(),
|
||||
},
|
||||
params: serde_json::to_string(&serde_json::json!({
|
||||
"kind": "read",
|
||||
"drive": drive_path,
|
||||
}))
|
||||
.unwrap(),
|
||||
});
|
||||
requested_caps.insert(Capability {
|
||||
issuer: Address {
|
||||
node: our_name.into(),
|
||||
process: VFS_PROCESS_ID.clone(),
|
||||
},
|
||||
params: serde_json::to_string(&serde_json::json!({
|
||||
"kind": "write",
|
||||
"drive": drive_path,
|
||||
}))
|
||||
.unwrap(),
|
||||
});
|
||||
|
||||
let public_process = entry.public;
|
||||
|
||||
let wasm_bytes_handle = format!("{}/{}", &drive_path, &file_path);
|
||||
|
||||
process_map.insert(
|
||||
ProcessId::new(Some(&entry.process_name), package_name, package_publisher),
|
||||
PersistedProcess {
|
||||
wasm_bytes_handle,
|
||||
on_exit: entry.on_exit,
|
||||
capabilities: requested_caps,
|
||||
public: public_process,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// go into /target folder and get all .zip package files
|
||||
async fn get_zipped_packages() -> Vec<(String, zip::ZipArchive<std::io::Cursor<Vec<u8>>>)> {
|
||||
println!("fs: reading distro packages...\r");
|
||||
let target_path = std::path::Path::new("target");
|
||||
|
||||
let mut packages = Vec::new();
|
||||
|
||||
if let Ok(mut entries) = fs::read_dir(target_path).await {
|
||||
while let Ok(Some(entry)) = entries.next_entry().await {
|
||||
if entry.file_name().to_string_lossy().ends_with(".zip") {
|
||||
let package_name = entry
|
||||
.file_name()
|
||||
.to_string_lossy()
|
||||
.trim_end_matches(".zip")
|
||||
.to_string();
|
||||
if let Ok(bytes) = fs::read(entry.path()).await {
|
||||
if let Ok(zip) = zip::ZipArchive::new(std::io::Cursor::new(bytes)) {
|
||||
// add to list of packages
|
||||
println!("fs: found package: {}\r", package_name);
|
||||
packages.push((package_name, zip));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
packages
|
||||
}
|
||||
|
||||
fn make_error_message(our_name: String, km: &KernelMessage, error: StateError) -> KernelMessage {
|
||||
KernelMessage {
|
||||
id: km.id,
|
||||
source: Address {
|
||||
node: our_name.clone(),
|
||||
process: STATE_PROCESS_ID.clone(),
|
||||
},
|
||||
target: match &km.rsvp {
|
||||
None => km.source.clone(),
|
||||
Some(rsvp) => rsvp.clone(),
|
||||
},
|
||||
rsvp: None,
|
||||
message: Message::Response((
|
||||
Response {
|
||||
inherit: false,
|
||||
ipc: serde_json::to_vec(&StateResponse::Err(error)).unwrap(),
|
||||
metadata: None,
|
||||
},
|
||||
None,
|
||||
)),
|
||||
payload: None,
|
||||
signed_capabilities: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn process_to_vec(process: ProcessId) -> Vec<u8> {
|
||||
process.to_string().as_bytes().to_vec()
|
||||
}
|
@ -146,7 +146,13 @@ pub async fn terminal(
|
||||
stdout,
|
||||
cursor::MoveTo(0, win_rows - 1),
|
||||
terminal::Clear(ClearType::CurrentLine),
|
||||
Print(format!("{} {}/{} {:02}:{:02} ",
|
||||
Print(format!("{}{} {}/{} {:02}:{:02} ",
|
||||
match printout.verbosity {
|
||||
0 => "",
|
||||
1 => "1️⃣ ",
|
||||
2 => "2️⃣ ",
|
||||
_ => "3️⃣ ",
|
||||
},
|
||||
now.weekday(),
|
||||
now.month(),
|
||||
now.day(),
|
||||
|
450
src/types.rs
450
src/types.rs
@ -7,13 +7,15 @@ use thiserror::Error;
|
||||
lazy_static::lazy_static! {
|
||||
pub static ref ENCRYPTOR_PROCESS_ID: ProcessId = ProcessId::new(Some("encryptor"), "sys", "uqbar");
|
||||
pub static ref ETH_RPC_PROCESS_ID: ProcessId = ProcessId::new(Some("eth_rpc"), "sys", "uqbar");
|
||||
pub static ref FILESYSTEM_PROCESS_ID: ProcessId = ProcessId::new(Some("filesystem"), "sys", "uqbar");
|
||||
pub static ref HTTP_CLIENT_PROCESS_ID: ProcessId = ProcessId::new(Some("http_client"), "sys", "uqbar");
|
||||
pub static ref HTTP_SERVER_PROCESS_ID: ProcessId = ProcessId::new(Some("http_server"), "sys", "uqbar");
|
||||
pub static ref KERNEL_PROCESS_ID: ProcessId = ProcessId::new(Some("kernel"), "sys", "uqbar");
|
||||
pub static ref TERMINAL_PROCESS_ID: ProcessId = ProcessId::new(Some("terminal"), "terminal", "uqbar");
|
||||
pub static ref TIMER_PROCESS_ID: ProcessId = ProcessId::new(Some("timer"), "sys", "uqbar");
|
||||
pub static ref VFS_PROCESS_ID: ProcessId = ProcessId::new(Some("vfs"), "sys", "uqbar");
|
||||
pub static ref STATE_PROCESS_ID: ProcessId = ProcessId::new(Some("state"), "sys", "uqbar");
|
||||
pub static ref KV_PROCESS_ID: ProcessId = ProcessId::new(Some("kv"), "sys", "uqbar");
|
||||
pub static ref SQLITE_PROCESS_ID: ProcessId = ProcessId::new(Some("sqlite"), "sys", "uqbar");
|
||||
}
|
||||
|
||||
//
|
||||
@ -66,13 +68,13 @@ pub struct PackageId {
|
||||
}
|
||||
|
||||
impl PackageId {
|
||||
pub fn _new(package_name: &str, publisher_node: &str) -> Self {
|
||||
pub fn new(package_name: &str, publisher_node: &str) -> Self {
|
||||
PackageId {
|
||||
package_name: package_name.into(),
|
||||
publisher_node: publisher_node.into(),
|
||||
}
|
||||
}
|
||||
pub fn _from_str(input: &str) -> Result<Self, ProcessIdParseError> {
|
||||
pub fn from_str(input: &str) -> Result<Self, ProcessIdParseError> {
|
||||
// split string on colons into 2 segments
|
||||
let mut segments = input.split(':');
|
||||
let package_name = segments
|
||||
@ -428,18 +430,54 @@ pub enum SendErrorKind {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub enum OnPanic {
|
||||
pub enum OnExit {
|
||||
None,
|
||||
Restart,
|
||||
Requests(Vec<(Address, Request, Option<Payload>)>),
|
||||
}
|
||||
|
||||
impl OnPanic {
|
||||
impl OnExit {
|
||||
pub fn is_restart(&self) -> bool {
|
||||
match self {
|
||||
OnPanic::None => false,
|
||||
OnPanic::Restart => true,
|
||||
OnPanic::Requests(_) => false,
|
||||
OnExit::None => false,
|
||||
OnExit::Restart => true,
|
||||
OnExit::Requests(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn en_wit(&self) -> wit::OnExit {
|
||||
match self {
|
||||
OnExit::None => wit::OnExit::None,
|
||||
OnExit::Restart => wit::OnExit::Restart,
|
||||
OnExit::Requests(reqs) => wit::OnExit::Requests(
|
||||
reqs.iter()
|
||||
.map(|(address, request, payload)| {
|
||||
(
|
||||
address.en_wit(),
|
||||
en_wit_request(request.clone()),
|
||||
en_wit_payload(payload.clone()),
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn de_wit(wit: wit::OnExit) -> Self {
|
||||
match wit {
|
||||
wit::OnExit::None => OnExit::None,
|
||||
wit::OnExit::Restart => OnExit::Restart,
|
||||
wit::OnExit::Requests(reqs) => OnExit::Requests(
|
||||
reqs.into_iter()
|
||||
.map(|(address, request, payload)| {
|
||||
(
|
||||
Address::de_wit(address),
|
||||
de_wit_request(request),
|
||||
de_wit_payload(payload),
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -585,23 +623,6 @@ pub fn en_wit_send_error_kind(kind: SendErrorKind) -> wit::SendErrorKind {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn de_wit_on_panic(wit: wit::OnPanic) -> OnPanic {
|
||||
match wit {
|
||||
wit::OnPanic::None => OnPanic::None,
|
||||
wit::OnPanic::Restart => OnPanic::Restart,
|
||||
wit::OnPanic::Requests(reqs) => OnPanic::Requests(
|
||||
reqs.into_iter()
|
||||
.map(|(address, request, payload)| {
|
||||
(
|
||||
Address::de_wit(address),
|
||||
de_wit_request(request),
|
||||
de_wit_payload(payload),
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
//
|
||||
// END SYNC WITH process_lib
|
||||
//
|
||||
@ -715,8 +736,8 @@ pub struct IdentityTransaction {
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct ProcessMetadata {
|
||||
pub our: Address,
|
||||
pub wasm_bytes_handle: u128,
|
||||
pub on_panic: OnPanic,
|
||||
pub wasm_bytes_handle: String,
|
||||
pub on_exit: OnExit,
|
||||
pub public: bool,
|
||||
}
|
||||
|
||||
@ -791,8 +812,8 @@ pub enum KernelCommand {
|
||||
/// for the new process if `public` is false.
|
||||
InitializeProcess {
|
||||
id: ProcessId,
|
||||
wasm_bytes_handle: u128,
|
||||
on_panic: OnPanic,
|
||||
wasm_bytes_handle: String,
|
||||
on_exit: OnExit,
|
||||
initial_capabilities: HashSet<SignedCapability>,
|
||||
public: bool,
|
||||
},
|
||||
@ -846,10 +867,8 @@ pub type ProcessMap = HashMap<ProcessId, PersistedProcess>;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct PersistedProcess {
|
||||
pub wasm_bytes_handle: u128,
|
||||
// pub drive: String,
|
||||
// pub full_path: String,
|
||||
pub on_panic: OnPanic,
|
||||
pub wasm_bytes_handle: String,
|
||||
pub on_exit: OnExit,
|
||||
pub capabilities: HashSet<Capability>,
|
||||
pub public: bool, // marks if a process allows messages from any process
|
||||
}
|
||||
@ -870,6 +889,7 @@ pub struct PackageMetadata {
|
||||
pub package: String,
|
||||
pub publisher: String,
|
||||
pub version: PackageVersion,
|
||||
pub wit_version: Option<(u32, u32, u32)>,
|
||||
pub description: Option<String>,
|
||||
pub website: Option<String>,
|
||||
}
|
||||
@ -879,214 +899,266 @@ pub struct PackageMetadata {
|
||||
pub struct PackageManifestEntry {
|
||||
pub process_name: String,
|
||||
pub process_wasm_path: String,
|
||||
pub on_panic: OnPanic,
|
||||
pub on_exit: OnExit,
|
||||
pub request_networking: bool,
|
||||
pub request_messaging: Option<Vec<String>>,
|
||||
pub grant_messaging: Option<Vec<String>>,
|
||||
pub request_messaging: Option<Vec<serde_json::Value>>,
|
||||
pub grant_messaging: Option<Vec<serde_json::Value>>,
|
||||
pub public: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub enum FsAction {
|
||||
Write(Option<u128>),
|
||||
WriteOffset((u128, u64)),
|
||||
Append(Option<u128>),
|
||||
Read(u128),
|
||||
ReadChunk(ReadChunkRequest),
|
||||
Delete(u128),
|
||||
Length(u128),
|
||||
SetLength((u128, u64)),
|
||||
pub enum StateAction {
|
||||
GetState(ProcessId),
|
||||
SetState(ProcessId),
|
||||
DeleteState(ProcessId),
|
||||
Backup,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct ReadChunkRequest {
|
||||
pub file: u128,
|
||||
pub start: u64,
|
||||
pub length: u64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
pub enum FsResponse {
|
||||
Write(u128),
|
||||
Read(u128),
|
||||
ReadChunk(u128), // TODO: remove?
|
||||
Append(u128),
|
||||
Delete(u128),
|
||||
Length(u64),
|
||||
pub enum StateResponse {
|
||||
GetState,
|
||||
SetState,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct S3Config {
|
||||
pub access_key: String,
|
||||
pub secret_key: String,
|
||||
pub region: String,
|
||||
pub bucket: String,
|
||||
pub endpoint: String,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FsConfig {
|
||||
pub s3_config: Option<S3Config>,
|
||||
pub mem_buffer_limit: usize,
|
||||
pub read_cache_limit: usize,
|
||||
pub chunk_size: usize,
|
||||
pub flush_to_cold_interval: usize,
|
||||
pub encryption: bool,
|
||||
pub cloud_enabled: bool,
|
||||
// pub flush_to_wal_interval: usize,
|
||||
DeleteState,
|
||||
Backup,
|
||||
Err(StateError),
|
||||
}
|
||||
|
||||
#[derive(Error, Debug, Serialize, Deserialize)]
|
||||
pub enum FsError {
|
||||
#[error("fs: Bytes payload required for {action}.")]
|
||||
pub enum StateError {
|
||||
#[error("kernel_state: rocksdb internal error: {error}")]
|
||||
RocksDBError { action: String, error: String },
|
||||
#[error("kernel_state: startup error")]
|
||||
StartupError { action: String },
|
||||
#[error("kernel_state: bytes payload required for {action}")]
|
||||
BadBytes { action: String },
|
||||
#[error(
|
||||
"fs: JSON payload could not be parsed to FsAction: {:?}, error: {:?}.",
|
||||
json,
|
||||
error
|
||||
)]
|
||||
BadJson { json: String, error: String },
|
||||
#[error("fs: No JSON payload.")]
|
||||
NoJson,
|
||||
#[error("fs: Read failed to file {file}: {error}.")]
|
||||
ReadFailed { file: u128, error: String },
|
||||
#[error("fs: Write failed to file {file}: {error}.")]
|
||||
WriteFailed { file: u128, error: String },
|
||||
#[error("fs: file not found: {file}")]
|
||||
NotFound { file: u128 },
|
||||
#[error("fs: S3 error: {error}")]
|
||||
S3Error { error: String },
|
||||
#[error("fs: IO error: {error}")]
|
||||
#[error("kernel_state: bad request error: {error}")]
|
||||
BadRequest { error: String },
|
||||
#[error("kernel_state: Bad JSON payload: {error}")]
|
||||
BadJson { error: String },
|
||||
#[error("kernel_state: state not found for ProcessId {process_id}")]
|
||||
NotFound { process_id: ProcessId },
|
||||
#[error("kernel_state: IO error: {error}")]
|
||||
IOError { error: String },
|
||||
#[error("fs: Encryption error: {error}")]
|
||||
EncryptionError { error: String },
|
||||
#[error("fs: Limit error: {error}")]
|
||||
LimitError { error: String },
|
||||
#[error("fs: memory buffer error: {error}")]
|
||||
MemoryBufferError { error: String },
|
||||
#[error("fs: length operation error: {error}")]
|
||||
LengthError { error: String },
|
||||
#[error("fs: creating fs dir failed at path: {path}: {error}")]
|
||||
CreateInitialDirError { path: String, error: String },
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl FsError {
|
||||
impl StateError {
|
||||
pub fn kind(&self) -> &str {
|
||||
match *self {
|
||||
FsError::BadBytes { .. } => "BadBytes",
|
||||
FsError::BadJson { .. } => "BadJson",
|
||||
FsError::NoJson { .. } => "NoJson",
|
||||
FsError::ReadFailed { .. } => "ReadFailed",
|
||||
FsError::WriteFailed { .. } => "WriteFailed",
|
||||
FsError::S3Error { .. } => "S3Error",
|
||||
FsError::IOError { .. } => "IOError",
|
||||
FsError::EncryptionError { .. } => "EncryptionError",
|
||||
FsError::LimitError { .. } => "LimitError",
|
||||
FsError::MemoryBufferError { .. } => "MemoryBufferError",
|
||||
FsError::NotFound { .. } => "NotFound",
|
||||
FsError::LengthError { .. } => "LengthError",
|
||||
FsError::CreateInitialDirError { .. } => "CreateInitialDirError",
|
||||
StateError::RocksDBError { .. } => "RocksDBError",
|
||||
StateError::StartupError { .. } => "StartupError",
|
||||
StateError::BadBytes { .. } => "BadBytes",
|
||||
StateError::BadRequest { .. } => "BadRequest",
|
||||
StateError::BadJson { .. } => "NoJson",
|
||||
StateError::NotFound { .. } => "NotFound",
|
||||
StateError::IOError { .. } => "IOError",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct VfsRequest {
|
||||
pub drive: String,
|
||||
pub path: String,
|
||||
pub action: VfsAction,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum VfsAction {
|
||||
New,
|
||||
Add {
|
||||
full_path: String,
|
||||
entry_type: AddEntryType,
|
||||
},
|
||||
Rename {
|
||||
full_path: String,
|
||||
new_full_path: String,
|
||||
},
|
||||
Delete(String),
|
||||
WriteOffset {
|
||||
full_path: String,
|
||||
offset: u64,
|
||||
},
|
||||
Append(String),
|
||||
SetSize {
|
||||
full_path: String,
|
||||
size: u64,
|
||||
},
|
||||
GetPath(u128),
|
||||
GetHash(String),
|
||||
GetEntry(String),
|
||||
GetFileChunk {
|
||||
full_path: String,
|
||||
offset: u64,
|
||||
length: u64,
|
||||
},
|
||||
GetEntryLength(String),
|
||||
CreateDrive,
|
||||
CreateDir,
|
||||
CreateDirAll,
|
||||
CreateFile,
|
||||
OpenFile,
|
||||
CloseFile,
|
||||
WriteAll,
|
||||
Write,
|
||||
ReWrite,
|
||||
WriteAt(u64),
|
||||
Append,
|
||||
SyncAll,
|
||||
Read,
|
||||
ReadDir,
|
||||
ReadToEnd,
|
||||
ReadExact(u64),
|
||||
ReadToString,
|
||||
Seek(SeekFrom),
|
||||
RemoveFile,
|
||||
RemoveDir,
|
||||
RemoveDirAll,
|
||||
Rename(String),
|
||||
AddZip,
|
||||
Len,
|
||||
SetLen(u64),
|
||||
Hash,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum AddEntryType {
|
||||
Dir,
|
||||
NewFile, // add a new file to fs and add name in vfs
|
||||
ExistingFile { hash: u128 }, // link an existing file in fs to a new name in vfs
|
||||
ZipArchive,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum GetEntryType {
|
||||
Dir,
|
||||
File,
|
||||
pub enum SeekFrom {
|
||||
Start(u64),
|
||||
End(i64),
|
||||
Current(i64),
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum VfsResponse {
|
||||
Ok,
|
||||
Err(VfsError),
|
||||
GetPath(Option<String>),
|
||||
GetHash(Option<u128>),
|
||||
GetEntry {
|
||||
// file bytes in payload, if entry was a file
|
||||
is_file: bool,
|
||||
children: Vec<String>,
|
||||
},
|
||||
GetFileChunk, // chunk in payload, if file exists
|
||||
GetEntryLength(Option<u64>),
|
||||
Read,
|
||||
ReadDir(Vec<String>),
|
||||
ReadToString(String),
|
||||
Len(u64),
|
||||
Hash([u8; 32]),
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[derive(Error, Debug, Serialize, Deserialize)]
|
||||
pub enum VfsError {
|
||||
BadJson,
|
||||
BadPayload,
|
||||
BadDriveName,
|
||||
BadDescriptor,
|
||||
NoCap,
|
||||
EntryNotFound,
|
||||
PersistError,
|
||||
InternalError, // String
|
||||
#[error("vfs: No capability for action {action} at path {path}")]
|
||||
NoCap { action: String, path: String },
|
||||
#[error("vfs: Bytes payload required for {action} at path {path}")]
|
||||
BadBytes { action: String, path: String },
|
||||
#[error("vfs: bad request error: {error}")]
|
||||
BadRequest { error: String },
|
||||
#[error("vfs: error parsing path: {path}, error: {error}")]
|
||||
ParseError { error: String, path: String },
|
||||
#[error("vfs: IO error: {error}, at path {path}")]
|
||||
IOError { error: String, path: String },
|
||||
#[error("vfs: kernel capability channel error: {error}")]
|
||||
CapChannelFail { error: String },
|
||||
#[error("vfs: Bad JSON payload: {error}")]
|
||||
BadJson { error: String },
|
||||
#[error("vfs: File not found at path {path}")]
|
||||
NotFound { path: String },
|
||||
#[error("vfs: Creating directory failed at path: {path}: {error}")]
|
||||
CreateDirError { path: String, error: String },
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl VfsError {
|
||||
pub fn kind(&self) -> &str {
|
||||
match *self {
|
||||
VfsError::BadJson => "BadJson",
|
||||
VfsError::BadPayload => "BadPayload",
|
||||
VfsError::BadDriveName => "BadDriveName",
|
||||
VfsError::BadDescriptor => "BadDescriptor",
|
||||
VfsError::NoCap => "NoCap",
|
||||
VfsError::EntryNotFound => "EntryNotFound",
|
||||
VfsError::PersistError => "PersistError",
|
||||
VfsError::InternalError => "InternalError",
|
||||
VfsError::NoCap { .. } => "NoCap",
|
||||
VfsError::BadBytes { .. } => "BadBytes",
|
||||
VfsError::BadRequest { .. } => "BadRequest",
|
||||
VfsError::ParseError { .. } => "ParseError",
|
||||
VfsError::IOError { .. } => "IOError",
|
||||
VfsError::CapChannelFail { .. } => "CapChannelFail",
|
||||
VfsError::BadJson { .. } => "NoJson",
|
||||
VfsError::NotFound { .. } => "NotFound",
|
||||
VfsError::CreateDirError { .. } => "CreateDirError",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct KvRequest {
|
||||
pub package_id: PackageId,
|
||||
pub db: String,
|
||||
pub action: KvAction,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub enum KvAction {
|
||||
New,
|
||||
Set { key: Vec<u8>, tx_id: Option<u64> },
|
||||
Delete { key: Vec<u8>, tx_id: Option<u64> },
|
||||
Get { key: Vec<u8> },
|
||||
BeginTx,
|
||||
Commit { tx_id: u64 },
|
||||
Backup,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum KvResponse {
|
||||
Ok,
|
||||
BeginTx { tx_id: u64 },
|
||||
Get { key: Vec<u8> },
|
||||
Err { error: KvError },
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Error)]
|
||||
pub enum KvError {
|
||||
#[error("kv: DbDoesNotExist")]
|
||||
NoDb,
|
||||
#[error("kv: DbAlreadyExists")]
|
||||
DbAlreadyExists,
|
||||
#[error("kv: KeyNotFound")]
|
||||
KeyNotFound,
|
||||
#[error("kv: no Tx found")]
|
||||
NoTx,
|
||||
#[error("kv: No capability: {error}")]
|
||||
NoCap { error: String },
|
||||
#[error("kv: rocksdb internal error: {error}")]
|
||||
RocksDBError { action: String, error: String },
|
||||
#[error("kv: input bytes/json/key error: {error}")]
|
||||
InputError { error: String },
|
||||
#[error("kv: IO error: {error}")]
|
||||
IOError { error: String },
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct SqliteRequest {
|
||||
pub package_id: PackageId,
|
||||
pub db: String,
|
||||
pub action: SqliteAction,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum SqliteAction {
|
||||
New,
|
||||
Write {
|
||||
statement: String,
|
||||
tx_id: Option<u64>,
|
||||
},
|
||||
Read {
|
||||
query: String,
|
||||
},
|
||||
BeginTx,
|
||||
Commit {
|
||||
tx_id: u64,
|
||||
},
|
||||
Backup,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum SqliteResponse {
|
||||
Ok,
|
||||
Read,
|
||||
BeginTx { tx_id: u64 },
|
||||
Err { error: SqliteError },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum SqlValue {
|
||||
Integer(i64),
|
||||
Real(f64),
|
||||
Text(String),
|
||||
Blob(Vec<u8>),
|
||||
Boolean(bool),
|
||||
Null,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Error)]
|
||||
pub enum SqliteError {
|
||||
#[error("sqlite: DbDoesNotExist")]
|
||||
NoDb,
|
||||
#[error("sqlite: DbAlreadyExists")]
|
||||
DbAlreadyExists,
|
||||
#[error("sqlite: NoTx")]
|
||||
NoTx,
|
||||
#[error("sqlite: No capability: {error}")]
|
||||
NoCap { error: String },
|
||||
#[error("sqlite: UnexpectedResponse")]
|
||||
UnexpectedResponse,
|
||||
#[error("sqlite: NotAWriteKeyword")]
|
||||
NotAWriteKeyword,
|
||||
#[error("sqlite: NotAReadKeyword")]
|
||||
NotAReadKeyword,
|
||||
#[error("sqlite: Invalid Parameters")]
|
||||
InvalidParameters,
|
||||
#[error("sqlite: IO error: {error}")]
|
||||
IOError { error: String },
|
||||
#[error("sqlite: rusqlite error: {error}")]
|
||||
RusqliteError { error: String },
|
||||
#[error("sqlite: input bytes/json/key error: {error}")]
|
||||
InputError { error: String },
|
||||
}
|
||||
|
2092
src/vfs.rs
2092
src/vfs.rs
File diff suppressed because it is too large
Load Diff
Binary file not shown.
188
wit/uqbar.wit
188
wit/uqbar.wit
@ -1,188 +0,0 @@
|
||||
package uqbar:process@0.4.0;
|
||||
|
||||
interface standard {
|
||||
// JSON is passed over WASM boundary as a string.
|
||||
type json = string;
|
||||
|
||||
type node-id = string;
|
||||
|
||||
// context, like ipc, is a protocol-defined serialized byte array.
|
||||
// it is used when building a Request to save information
|
||||
// that will not be part of a Response, in order to more
|
||||
// easily handle ("contextualize") that Response.
|
||||
type context = list<u8>;
|
||||
|
||||
record process-id {
|
||||
process-name: string,
|
||||
package-name: string,
|
||||
publisher-node: node-id,
|
||||
}
|
||||
|
||||
// TODO better name for this
|
||||
record address {
|
||||
node: node-id,
|
||||
process: process-id,
|
||||
}
|
||||
|
||||
record payload {
|
||||
mime: option<string>,
|
||||
bytes: list<u8>,
|
||||
}
|
||||
|
||||
record request {
|
||||
// if true, this request inherits context AND payload of incipient
|
||||
// request, and cannot have its own context.
|
||||
inherit: bool,
|
||||
// if Some, this request expects a response in the number of seconds given
|
||||
expects-response: option<u64>,
|
||||
ipc: list<u8>,
|
||||
metadata: option<json>,
|
||||
// to grab payload, use get_payload()
|
||||
}
|
||||
|
||||
record response {
|
||||
inherit: bool,
|
||||
ipc: list<u8>,
|
||||
metadata: option<json>,
|
||||
// to grab payload, use get_payload()
|
||||
}
|
||||
|
||||
// a message can be a request or a response.
|
||||
// within a response, there is a result which surfaces any error
|
||||
// that happened because of a request.
|
||||
// a successful response will contain the context of the request
|
||||
// it matches, if any was set.
|
||||
variant message {
|
||||
request(request),
|
||||
response(tuple<response, option<context>>),
|
||||
}
|
||||
|
||||
variant capabilities {
|
||||
none,
|
||||
all,
|
||||
some(list<signed-capability>),
|
||||
}
|
||||
|
||||
record signed-capability {
|
||||
issuer: address,
|
||||
params: json,
|
||||
signature: list<u8>,
|
||||
}
|
||||
|
||||
// on-panic is a setting that determines what happens when a process panics.
|
||||
// NOTE: requests should have expects-response set to false, will always be set to that by kernel
|
||||
variant on-panic {
|
||||
none,
|
||||
restart,
|
||||
requests(list<tuple<address, request, option<payload>>>),
|
||||
}
|
||||
|
||||
// network errors come from trying to send a message to another node.
|
||||
// a message can fail by timing out, or by the node being entirely unreachable (offline).
|
||||
// in either case, the message is not delivered, and the process that sent it
|
||||
// receives that message along with any assigned context and/or payload,
|
||||
// and is free to handle it as it sees fit.
|
||||
// note that if the message is a response, the process can issue a response again,
|
||||
// and it will be directed to the same (remote) request as the original.
|
||||
record send-error {
|
||||
kind: send-error-kind,
|
||||
message: message,
|
||||
payload: option<payload>,
|
||||
}
|
||||
|
||||
enum send-error-kind {
|
||||
offline,
|
||||
timeout,
|
||||
}
|
||||
|
||||
enum spawn-error {
|
||||
name-taken,
|
||||
no-file-at-path,
|
||||
// TODO more here?
|
||||
}
|
||||
|
||||
// system utils:
|
||||
print-to-terminal: func(verbosity: u8, message: string);
|
||||
|
||||
// **more will be added here with regard to blockchains**
|
||||
get-eth-block: func() -> u64;
|
||||
|
||||
// process management:
|
||||
|
||||
set-on-panic: func(on-panic: on-panic);
|
||||
|
||||
get-state: func() -> option<list<u8>>;
|
||||
|
||||
set-state: func(bytes: list<u8>);
|
||||
|
||||
clear-state: func();
|
||||
|
||||
spawn: func(
|
||||
name: option<string>,
|
||||
wasm-path: string, // must be located within package's drive
|
||||
on-panic: on-panic,
|
||||
capabilities: capabilities,
|
||||
public: bool
|
||||
) -> result<process-id, spawn-error>;
|
||||
|
||||
// capabilities management
|
||||
|
||||
// gives us all our signed capabilities so we can send them to others
|
||||
get-capabilities: func() -> list<signed-capability>;
|
||||
|
||||
// gets a single specific capability
|
||||
get-capability: func(issuer: address, params: json) -> option<signed-capability>;
|
||||
|
||||
// attaches a specific signed capability to our next message
|
||||
attach-capability: func(capability: signed-capability);
|
||||
|
||||
// saves capabilities to our store, so we can use them
|
||||
save-capabilities: func(capabilities: list<signed-capability>);
|
||||
|
||||
// check to see if the sender of a prompting message has a given capability, issued by us
|
||||
// if the prompting message has a remote source, they must have attached it.
|
||||
has-capability: func(params: json) -> bool;
|
||||
|
||||
// generates a new capability with our process as the issuer and gives it to the target,
|
||||
// which must be a locally-running process.
|
||||
create-capability: func(to: process-id, params: json);
|
||||
|
||||
// take a signed capability and save it to a given locally-running process
|
||||
share-capability: func(to: process-id, capability: signed-capability);
|
||||
|
||||
|
||||
// message I/O:
|
||||
|
||||
// ingest next message when it arrives along with its source.
|
||||
// almost all long-running processes will call this in a loop
|
||||
receive: func() -> result<tuple<address, message>, tuple<send-error, option<context>>>;
|
||||
|
||||
// gets payload, if any, of the message we just received
|
||||
get-payload: func() -> option<payload>;
|
||||
|
||||
// send message(s) to target(s)
|
||||
send-request:
|
||||
func(target: address, request: request, context: option<context>, payload: option<payload>);
|
||||
|
||||
send-requests:
|
||||
func(requests: list<tuple<address, request, option<context>, option<payload>>>);
|
||||
|
||||
send-response:
|
||||
func(response: response, payload: option<payload>);
|
||||
|
||||
// send a single request, then block (internally) until its response
|
||||
// the type is Message but will always contain Response
|
||||
send-and-await-response:
|
||||
func(target: address, request: request, payload: option<payload>) ->
|
||||
result<tuple<address, message>, send-error>;
|
||||
}
|
||||
|
||||
world lib {
|
||||
import standard;
|
||||
}
|
||||
|
||||
world process {
|
||||
include lib;
|
||||
|
||||
export init: func(our: string);
|
||||
}
|
Loading…
Reference in New Issue
Block a user