From c9d7be20f637c1009cf3e17b24401806fa2264a9 Mon Sep 17 00:00:00 2001 From: Daniel Vigovszky Date: Wed, 11 Dec 2024 17:07:12 +0100 Subject: [PATCH 1/8] Update dependencies (#1172) * Migrated from warp to axum * Update dependencies * Update deps * Fix * Fix * Fix --- Cargo.lock | 1217 ++++++++--------- Cargo.toml | 132 +- Makefile.toml | 3 +- golem-api-grpc/Cargo.toml | 4 +- golem-api-grpc/build.rs | 2 +- golem-api-grpc/src/lib.rs | 2 +- golem-cli/Cargo.toml | 24 +- golem-cli/src/cloud.rs | 7 +- golem-cli/src/config.rs | 5 +- golem-cli/src/model.rs | 15 +- golem-cli/src/oss/clients/worker.rs | 1 + golem-client/Cargo.toml | 2 +- golem-common/Cargo.toml | 3 +- golem-common/src/client.rs | 14 +- golem-common/src/grpc.rs | 6 +- golem-common/src/model/mod.rs | 14 +- golem-common/src/model/plugin.rs | 11 - golem-common/src/newtype.rs | 11 +- .../Cargo.toml | 3 +- .../src/lib.rs | 10 - .../src/service/compile_worker.rs | 3 +- golem-component-service-base/Cargo.toml | 5 +- golem-component-service-base/src/config.rs | 5 +- .../src/service/component_compilation.rs | 3 +- golem-component-service/Cargo.toml | 1 - .../src/grpcapi/component.rs | 8 +- golem-component-service/src/grpcapi/mod.rs | 2 +- golem-component-service/src/grpcapi/plugin.rs | 3 +- golem-service-base/Cargo.toml | 3 +- golem-service-base/src/model.rs | 4 +- golem-service-base/src/observability.rs | 29 +- .../src/service/routing_table.rs | 3 +- golem-shard-manager/Cargo.toml | 4 +- golem-shard-manager/src/lib.rs | 2 +- golem-shard-manager/src/model.rs | 5 +- golem-test-framework/Cargo.toml | 4 +- .../src/components/redis/mod.rs | 2 +- .../components/worker_service/forwarding.rs | 11 +- golem-test-framework/src/config/env.rs | 2 +- golem-test-framework/src/dsl/mod.rs | 39 +- golem-worker-executor-base/Cargo.toml | 36 +- golem-worker-executor-base/src/grpc.rs | 18 +- golem-worker-executor-base/src/lib.rs | 2 +- .../src/services/component.rs | 8 +- .../src/services/plugins.rs | 6 +- .../src/services/shard_manager.rs | 3 +- .../src/services/worker_proxy.rs | 4 +- golem-worker-executor-base/tests/api.rs | 255 ++-- .../tests/compatibility/worker_recovery.rs | 29 +- .../tests/guest_languages1.rs | 69 +- .../tests/hot_update.rs | 71 +- .../tests/measure_test_component_mem.rs | 6 +- .../tests/transactions.rs | 95 +- golem-worker-executor-base/tests/wasi.rs | 190 ++- golem-worker-service-base/Cargo.toml | 9 +- .../http/http_api_definition.rs | 13 +- golem-worker-service-base/src/lib.rs | 11 - .../src/service/component/default.rs | 3 +- .../src/service/worker/routing_logic.rs | 12 +- golem-worker-service/Cargo.toml | 1 - golem-worker-service/src/grpcapi/mod.rs | 2 +- integration-tests/Cargo.toml | 3 +- integration-tests/tests/worker.rs | 38 +- wasm-ast/Cargo.toml | 22 +- wasm-ast/src/component/parser.rs | 37 +- wasm-ast/src/component/writer.rs | 4 +- wasm-ast/src/core/parser.rs | 158 ++- wasm-ast/src/core/writer.rs | 19 +- wasm-rpc-stubgen/Cargo.toml | 36 +- wasm-rpc/Cargo.toml | 28 +- wasm-rpc/src/protobuf.rs | 2 +- wasm-rpc/src/type_annotated_value.rs | 2 +- 72 files changed, 1430 insertions(+), 1386 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fc1f320d0..793418549 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -120,6 +120,12 @@ dependencies = [ "libc", ] +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + [[package]] name = "ansi_term" version = "0.12.1" @@ -1025,7 +1031,7 @@ dependencies = [ "pin-project-lite", "pin-utils", "ryu", - "serde 1.0.215", + "serde 1.0.216", "time", "tokio", "tokio-util", @@ -1054,34 +1060,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "axum" -version = "0.6.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" -dependencies = [ - "async-trait", - "axum-core 0.3.4", - "bitflags 1.3.2", - "bytes 1.9.0", - "futures-util", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.31", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde 1.0.215", - "sync_wrapper 0.1.2", - "tower 0.4.13", - "tower-layer", - "tower-service", -] - [[package]] name = "axum" version = "0.7.9" @@ -1089,7 +1067,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" dependencies = [ "async-trait", - "axum-core 0.4.5", + "axum-core", "bytes 1.9.0", "futures-util", "http 1.2.0", @@ -1101,11 +1079,11 @@ dependencies = [ "matchit", "memchr", "mime", - "multer 3.1.0", + "multer", "percent-encoding", "pin-project-lite", "rustversion", - "serde 1.0.215", + "serde 1.0.216", "serde_json", "serde_path_to_error", "serde_urlencoded", @@ -1117,23 +1095,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "axum-core" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" -dependencies = [ - "async-trait", - "bytes 1.9.0", - "futures-util", - "http 0.2.12", - "http-body 0.4.6", - "mime", - "rustversion", - "tower-layer", - "tower-service", -] - [[package]] name = "axum-core" version = "0.4.5" @@ -1253,7 +1214,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f11ea1a0346b94ef188834a65c068a03aec181c94896d481d7a0a40d85b0ce95" dependencies = [ "bincode_derive", - "serde 1.0.215", + "serde 1.0.216", ] [[package]] @@ -1282,7 +1243,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "rustc-hash", + "rustc-hash 1.1.0", "shlex", "syn 2.0.90", "which 4.4.2", @@ -1315,7 +1276,7 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" dependencies = [ - "serde 1.0.215", + "serde 1.0.216", ] [[package]] @@ -1397,7 +1358,7 @@ dependencies = [ "rustls-native-certs 0.7.3", "rustls-pemfile 2.2.0", "rustls-pki-types", - "serde 1.0.215", + "serde 1.0.216", "serde_derive", "serde_json", "serde_repr", @@ -1416,7 +1377,7 @@ version = "1.45.0-rc.26.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d7c5415e3a6bc6d3e99eff6268e488fd4ee25e7b28c10f08fa6760bd9de16e4" dependencies = [ - "serde 1.0.215", + "serde 1.0.216", "serde_repr", "serde_with", ] @@ -1429,7 +1390,7 @@ checksum = "1a68f1f47cdf0ec8ee4b941b2eee2a80cb796db73118c0dd09ac63fbe405be22" dependencies = [ "memchr", "regex-automata 0.4.9", - "serde 1.0.215", + "serde 1.0.216", ] [[package]] @@ -1478,7 +1439,7 @@ version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" dependencies = [ - "serde 1.0.215", + "serde 1.0.216", ] [[package]] @@ -1568,8 +1529,8 @@ dependencies = [ "bytes 1.9.0", "cargo-component-core", "cargo-config2", - "cargo_metadata", - "clap 4.5.23", + "cargo_metadata 0.18.1", + "clap", "futures", "heck 0.5.0", "indexmap 2.7.0", @@ -1581,7 +1542,7 @@ dependencies = [ "rand_core", "rpassword", "semver", - "serde 1.0.215", + "serde 1.0.216", "serde_json", "shell-escape", "tempfile", @@ -1608,14 +1569,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf60eee7916f926d079ac6dc1851bfd8e2869bbdfc3ff997013cf7b802565f86" dependencies = [ "anyhow", - "clap 4.5.23", + "clap", "futures", "indexmap 2.7.0", "libc", "log 0.4.22", "owo-colors", "semver", - "serde 1.0.215", + "serde 1.0.216", "tokio", "toml_edit 0.22.22", "unicode-width 0.1.14", @@ -1635,7 +1596,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1124054becb9262cc15c5e96e82f0d782f2aed3a3034d1f71a6385a6fa9e9595" dependencies = [ "home", - "serde 1.0.215", + "serde 1.0.216", "serde_derive", "toml_edit 0.22.22", ] @@ -1646,7 +1607,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" dependencies = [ - "serde 1.0.215", + "serde 1.0.216", ] [[package]] @@ -1658,18 +1619,32 @@ dependencies = [ "camino", "cargo-platform", "semver", - "serde 1.0.215", + "serde 1.0.216", "serde_json", "thiserror 1.0.69", ] +[[package]] +name = "cargo_metadata" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8769706aad5d996120af43197bf46ef6ad0fda35216b4505f926a365a232d924" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde 1.0.216", + "serde_json", + "thiserror 2.0.6", +] + [[package]] name = "cargo_toml" -version = "0.20.5" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88da5a13c620b4ca0078845707ea9c3faf11edbc3ffd8497d11d686211cd1ac0" +checksum = "5fbd1fe9db3ebf71b89060adaf7b0504c2d6a425cf061313099547e382c2e472" dependencies = [ - "serde 1.0.215", + "serde 1.0.216", "toml 0.8.19", ] @@ -1730,11 +1705,38 @@ dependencies = [ "iana-time-zone", "js-sys", "num-traits 0.2.19", - "serde 1.0.215", + "serde 1.0.216", "wasm-bindgen", "windows-targets 0.52.6", ] +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde 1.0.216", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + [[package]] name = "cipher" version = "0.4.4" @@ -1756,17 +1758,6 @@ dependencies = [ "libloading", ] -[[package]] -name = "clap" -version = "2.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" -dependencies = [ - "bitflags 1.3.2", - "textwrap 0.11.0", - "unicode-width 0.1.14", -] - [[package]] name = "clap" version = "4.5.23" @@ -1779,11 +1770,11 @@ dependencies = [ [[package]] name = "clap-verbosity-flag" -version = "2.2.3" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34c77f67047557f62582784fd7482884697731b2932c7d37ced54bce2312e1e2" +checksum = "54381ae56ad222eea3f529c692879e9c65e07945ae48d3dc4d1cb18dbec8cf44" dependencies = [ - "clap 4.5.23", + "clap", "log 0.4.22", ] @@ -1805,7 +1796,7 @@ version = "4.5.38" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9647a559c112175f17cf724dc72d3645680a883c58481332779192b0d8e7a01" dependencies = [ - "clap 4.5.23", + "clap", ] [[package]] @@ -1941,7 +1932,7 @@ dependencies = [ "lazy_static 1.5.0", "nom 5.1.3", "rust-ini", - "serde 1.0.215", + "serde 1.0.216", "serde-hjson", "serde_json", "toml 0.5.11", @@ -1963,22 +1954,22 @@ dependencies = [ [[package]] name = "console-api" -version = "0.7.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a257c22cd7e487dd4a13d413beabc512c5052f0bc048db0da6a84c3d8a6142fd" +checksum = "8030735ecb0d128428b64cd379809817e620a40e5001c54465b99ec5feec2857" dependencies = [ "futures-core", - "prost 0.12.6", - "prost-types 0.12.6", + "prost 0.13.4", + "prost-types 0.13.4", "tonic", "tracing-core", ] [[package]] name = "console-subscriber" -version = "0.3.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c4cc54bae66f7d9188996404abdf7fdfa23034ef8e43478c8810828abad758" +checksum = "6539aa9c6a4cd31f4b1c040f860a1eac9aa80e7df6b05d506a6e7179936d6a01" dependencies = [ "console-api", "crossbeam-channel", @@ -1986,9 +1977,10 @@ dependencies = [ "futures-task", "hdrhistogram", "humantime", - "prost 0.12.6", - "prost-types 0.12.6", - "serde 1.0.215", + "hyper-util", + "prost 0.13.4", + "prost-types 0.13.4", + "serde 1.0.216", "serde_json", "thread_local", "tokio", @@ -2166,7 +2158,7 @@ dependencies = [ "hashbrown 0.14.5", "log 0.4.22", "regalloc2", - "rustc-hash", + "rustc-hash 1.1.0", "smallvec", "target-lexicon", ] @@ -2197,7 +2189,7 @@ name = "cranelift-entity" version = "0.108.1" source = "git+https://github.com/golemcloud/wasmtime.git?branch=golem-wasmtime-v21.0.1#adae4ab236f1eb4216dab8f7e1db6f34470de9e7" dependencies = [ - "serde 1.0.215", + "serde 1.0.216", "serde_derive", ] @@ -2283,24 +2275,24 @@ dependencies = [ [[package]] name = "criterion" -version = "0.3.6" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f" +checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" dependencies = [ - "atty", + "anes", "cast", - "clap 2.34.0", + "ciborium", + "clap", "criterion-plot", - "csv", + "is-terminal", "itertools 0.10.5", - "lazy_static 1.5.0", "num-traits 0.2.19", + "once_cell", "oorandom", "plotters", "rayon", "regex", - "serde 1.0.215", - "serde_cbor", + "serde 1.0.216", "serde_derive", "serde_json", "tinytemplate", @@ -2309,9 +2301,9 @@ dependencies = [ [[package]] name = "criterion-plot" -version = "0.4.5" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" dependencies = [ "cast", "itertools 0.10.5", @@ -2385,6 +2377,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "crypto-bigint" version = "0.4.9" @@ -2429,7 +2427,7 @@ dependencies = [ "csv-core", "itoa", "ryu", - "serde 1.0.215", + "serde 1.0.216", ] [[package]] @@ -2524,11 +2522,12 @@ dependencies = [ [[package]] name = "dashmap" -version = "5.5.3" +version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" dependencies = [ "cfg-if", + "crossbeam-utils", "hashbrown 0.14.5", "lock_api", "once_cell", @@ -2592,7 +2591,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ "powerfmt", - "serde 1.0.215", + "serde 1.0.216", ] [[package]] @@ -2805,7 +2804,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "31951f49556e34d90ed28342e1df7e1cb7a229c4cab0aecc627b5d91edd41d07" dependencies = [ "base64 0.21.7", - "serde 1.0.215", + "serde 1.0.216", "serde_json", ] @@ -2899,19 +2898,31 @@ checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" dependencies = [ "curve25519-dalek", "ed25519", - "serde 1.0.215", + "serde 1.0.216", "sha2", "subtle", "zeroize", ] +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "either" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" dependencies = [ - "serde 1.0.215", + "serde 1.0.216", ] [[package]] @@ -2988,6 +2999,26 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "enum-ordinalize" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "enumflags2" version = "0.7.10" @@ -2995,7 +3026,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d232db7f5956f3f14313dc2f87985c58bd2c695ce124c8cdd984e08e15ac133d" dependencies = [ "enumflags2_derive", - "serde 1.0.215", + "serde 1.0.216", ] [[package]] @@ -3217,7 +3248,7 @@ checksum = "8cb01cd46b0cf372153850f4c6c272d9cbea2da513e07538405148f95bd789f3" dependencies = [ "atomic", "pear", - "serde 1.0.215", + "serde 1.0.216", "toml 0.8.19", "uncased", "version_check", @@ -3266,15 +3297,6 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ce81f49ae8a0482e4c55ea62ebbd7e5a686af544c00b9d090bba3ff9be97b3d" -[[package]] -name = "fluent-uri" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17c704e9dbe1ddd863da1e6ff3567795087b1eb201ce80d8fa81162e1516500d" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "flume" version = "0.11.1" @@ -3617,7 +3639,7 @@ dependencies = [ "bitflags 2.6.0", "debugid", "fxhash", - "serde 1.0.215", + "serde 1.0.216", "serde_json", ] @@ -3649,12 +3671,12 @@ dependencies = [ [[package]] name = "gethostname" -version = "0.4.3" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818" +checksum = "dc3655aa6818d65bc620d6911f05aa7b6aeb596291e1e9f79e52df85583d1e30" dependencies = [ - "libc", - "windows-targets 0.48.5", + "rustix 0.38.42", + "windows-targets 0.52.6", ] [[package]] @@ -3751,7 +3773,7 @@ version = "0.0.0" dependencies = [ "anyhow", "bytes 1.9.0", - "clap 4.5.23", + "clap", "futures", "golem-cli", "golem-common", @@ -3767,15 +3789,15 @@ dependencies = [ "http-body-util", "hyper 1.5.1", "include_dir", - "opentelemetry 0.24.0", - "opentelemetry-prometheus", - "opentelemetry_sdk", + "opentelemetry 0.27.1", + "opentelemetry-prometheus 0.27.0", + "opentelemetry_sdk 0.27.1", "poem", "prometheus", "regex", "reqwest 0.12.9", "rustls 0.23.19", - "serde 1.0.215", + "serde 1.0.216", "sozu-command-lib", "sozu-lib", "sqlx", @@ -3793,13 +3815,13 @@ dependencies = [ "async-trait", "bincode", "bytes 1.9.0", - "cargo_metadata", + "cargo_metadata 0.19.1", "futures-core", "golem-wasm-ast", "golem-wasm-rpc", - "prost 0.12.6", - "prost-types 0.12.6", - "serde 1.0.215", + "prost 0.13.4", + "prost-types 0.13.4", + "serde 1.0.216", "test-r", "tokio", "tonic", @@ -3819,12 +3841,12 @@ dependencies = [ "async_zip", "base64 0.22.1", "chrono", - "clap 4.5.23", + "clap", "clap-verbosity-flag", "clap_complete", "cli-table", "colored", - "derive_more 0.99.18", + "derive_more 1.0.0", "dirs 5.0.1", "env_logger 0.11.5", "futures-util", @@ -3837,7 +3859,7 @@ dependencies = [ "golem-wasm-ast", "golem-wasm-rpc", "golem-wasm-rpc-stubgen", - "h2 0.3.26", + "h2 0.4.7", "http 1.2.0", "humansize", "hyper 1.5.1", @@ -3855,7 +3877,7 @@ dependencies = [ "redis", "regex", "reqwest 0.12.9", - "serde 1.0.215", + "serde 1.0.216", "serde_json", "serde_json_path", "serde_yaml", @@ -3866,17 +3888,17 @@ dependencies = [ "test-r", "testcontainers", "testcontainers-modules", - "textwrap 0.16.1", + "textwrap", "tokio", "tokio-postgres", "tokio-stream", - "tokio-tungstenite 0.20.1", + "tokio-tungstenite 0.24.0", "tonic", "tonic-health", - "tower 0.4.13", + "tower 0.5.1", "tracing", "tracing-subscriber", - "tungstenite 0.20.1", + "tungstenite 0.24.0", "url", "uuid", "version-compare", @@ -3899,7 +3921,7 @@ dependencies = [ "http 1.2.0", "relative-path", "reqwest 0.12.9", - "serde 1.0.215", + "serde 1.0.216", "serde_json", "serde_yaml", "test-r", @@ -3919,7 +3941,7 @@ dependencies = [ "combine", "console-subscriber", "dashmap", - "derive_more 0.99.18", + "derive_more 1.0.0", "figment", "fred", "futures-core", @@ -3928,7 +3950,7 @@ dependencies = [ "golem-rib", "golem-wasm-ast", "golem-wasm-rpc", - "http 0.2.12", + "http 1.2.0", "humantime-serde", "iso8601-timestamp", "itertools 0.13.0", @@ -3936,28 +3958,27 @@ dependencies = [ "poem", "poem-openapi", "prometheus", - "prost 0.12.6", - "prost-types 0.12.6", + "prost 0.13.4", + "prost-types 0.13.4", "rand", "range-set-blaze", "regex", - "serde 1.0.215", + "serde 1.0.216", "serde_json", "serde_yaml", "sqlx", "test-r", - "thiserror 1.0.69", + "thiserror 2.0.6", "tokio", "toml 0.8.19", "tonic", "tracing", - "tracing-serde 0.1.3", + "tracing-serde", "tracing-subscriber", "tracing-test", "typed-path", "url", "uuid", - "wasm-wave", ] [[package]] @@ -3973,13 +3994,12 @@ dependencies = [ "golem-common", "golem-service-base", "golem-worker-executor-base", - "http 0.2.12", "http 1.2.0", "lazy_static 1.5.0", "prometheus", - "serde 1.0.215", + "serde 1.0.216", "test-r", - "thiserror 1.0.69", + "thiserror 2.0.6", "tokio", "tokio-stream", "tonic", @@ -4006,22 +4026,21 @@ dependencies = [ "golem-service-base", "golem-wasm-ast", "golem-wasm-rpc", - "http 0.2.12", "humantime-serde", "lazy_static 1.5.0", "mappable-rc", - "opentelemetry 0.24.0", - "opentelemetry-prometheus", - "opentelemetry_sdk", + "opentelemetry 0.27.1", + "opentelemetry-prometheus 0.27.0", + "opentelemetry_sdk 0.27.1", "poem", "poem-openapi", "prometheus", - "serde 1.0.215", + "serde 1.0.216", "serde_json", "sqlx", "tap", "test-r", - "thiserror 1.0.69", + "thiserror 2.0.6", "tokio", "tokio-stream", "tokio-util", @@ -4053,15 +4072,14 @@ dependencies = [ "golem-rib", "golem-service-base", "golem-wasm-ast", - "http 0.2.12", "http 1.2.0", "poem", "poem-openapi", - "prost 0.12.6", - "prost-types 0.12.6", + "prost 0.13.4", + "prost-types 0.13.4", "reqwest 0.12.9", "sanitize-filename", - "serde 1.0.215", + "serde 1.0.216", "serde_json", "sqlx", "tap", @@ -4069,7 +4087,7 @@ dependencies = [ "test-r", "testcontainers", "testcontainers-modules", - "thiserror 1.0.69", + "thiserror 2.0.6", "tokio", "tokio-stream", "tokio-util", @@ -4086,8 +4104,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c0bcbbedbbecc9c66f2349150cbeb1b9e9704958611af624fbf11ea7202c4d9" dependencies = [ "Inflector", - "cargo_metadata", - "clap 4.5.23", + "cargo_metadata 0.18.1", + "clap", "colored", "copy_dir", "derive_more 0.99.18", @@ -4097,7 +4115,7 @@ dependencies = [ "include_dir", "once_cell", "regex", - "serde 1.0.215", + "serde 1.0.216", "serde_json", "strum", "strum_macros", @@ -4109,14 +4127,14 @@ version = "0.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b33e98f6cc141902ffcc13d027d0bb9a4d3310e51ff182f67236384e8dfeb3ac" dependencies = [ - "clap 4.5.23", + "clap", "convert_case 0.6.0", "fmt", "indexmap 2.7.0", "indoc", "itertools 0.12.1", "openapiv3", - "serde 1.0.215", + "serde 1.0.216", "serde_yaml", ] @@ -4133,7 +4151,7 @@ dependencies = [ "golem-wasm-rpc", "poem-openapi", "semver", - "serde 1.0.215", + "serde 1.0.216", "serde_json", "test-r", "tokio", @@ -4152,6 +4170,7 @@ dependencies = [ "async_zip", "aws-config", "aws-sdk-s3", + "axum", "bigdecimal", "bincode", "bytes 1.9.0", @@ -4165,7 +4184,6 @@ dependencies = [ "golem-wasm-ast", "golem-wasm-rpc", "hex", - "http 0.2.12", "http 1.2.0", "humantime-serde", "hyper 1.5.1", @@ -4176,10 +4194,10 @@ dependencies = [ "poem-openapi", "prometheus", "proptest", - "prost-types 0.12.6", + "prost-types 0.13.4", "rand", "reqwest 0.12.9", - "serde 1.0.215", + "serde 1.0.216", "serde_json", "sha2", "sqlx", @@ -4187,7 +4205,7 @@ dependencies = [ "test-r", "testcontainers", "testcontainers-modules", - "thiserror 1.0.69", + "thiserror 2.0.6", "tokio", "tokio-stream", "tokio-util", @@ -4196,7 +4214,6 @@ dependencies = [ "tracing-futures", "url", "uuid", - "warp", "wasmtime", ] @@ -4215,19 +4232,18 @@ dependencies = [ "golem-api-grpc", "golem-common", "golem-service-base", - "http 0.2.12", "http 1.2.0", "humantime-serde", "itertools 0.13.0", "k8s-openapi", "kube", "prometheus", - "prost 0.12.6", + "prost 0.13.4", "rustls 0.23.19", - "serde 1.0.215", + "serde 1.0.216", "serde_json", "test-r", - "thiserror 1.0.69", + "thiserror 2.0.6", "tokio", "tokio-stream", "tonic", @@ -4237,7 +4253,6 @@ dependencies = [ "tracing-subscriber", "tracing-test", "url", - "warp", ] [[package]] @@ -4251,7 +4266,7 @@ dependencies = [ "async-trait", "bytes 1.9.0", "chrono", - "clap 4.5.23", + "clap", "cli-table", "colored", "console-subscriber", @@ -4269,7 +4284,7 @@ dependencies = [ "once_cell", "postgres", "redis", - "serde 1.0.215", + "serde 1.0.216", "serde_json", "serde_yaml", "test-r", @@ -4295,16 +4310,16 @@ dependencies = [ "mappable-rc", "poem-openapi", "pretty_assertions", - "prost 0.12.6", - "prost-build 0.12.6", - "serde 1.0.215", + "prost 0.13.4", + "prost-build 0.13.4", + "serde 1.0.216", "serde_json", "test-r", - "wasm-encoder 0.207.0", - "wasm-metadata 0.207.0", + "wasm-encoder 0.221.2", + "wasm-metadata 0.221.2", "wasm-wave", - "wasmparser 0.207.0", - "wasmprinter 0.207.0", + "wasmparser 0.221.2", + "wasmprinter 0.221.2", ] [[package]] @@ -4316,15 +4331,15 @@ dependencies = [ "async-trait", "bigdecimal", "bincode", - "cargo_metadata", + "cargo_metadata 0.19.1", "git-version", "golem-wasm-ast", "poem-openapi", "proptest", "proptest-arbitrary-interop", - "prost 0.12.6", - "prost-build 0.12.6", - "serde 1.0.215", + "prost 0.13.4", + "prost-build 0.13.4", + "serde 1.0.216", "serde_json", "test-r", "uuid", @@ -4344,7 +4359,7 @@ dependencies = [ "cargo-component", "cargo-component-core", "cargo_toml", - "clap 4.5.23", + "clap", "colored", "dir-diff", "fs_extra", @@ -4355,7 +4370,7 @@ dependencies = [ "id-arena", "indexmap 2.7.0", "indoc", - "itertools 0.12.1", + "itertools 0.13.0", "minijinja", "pretty_env_logger", "prettyplease", @@ -4363,7 +4378,7 @@ dependencies = [ "quote", "regex", "semver", - "serde 1.0.215", + "serde 1.0.216", "serde_json", "serde_yaml", "shlex", @@ -4402,7 +4417,7 @@ dependencies = [ "golem-worker-executor-base", "humantime-serde", "prometheus", - "serde 1.0.215", + "serde 1.0.216", "serde_json", "tempfile", "test-r", @@ -4431,13 +4446,14 @@ dependencies = [ "async-trait", "aws-config", "aws-sdk-s3", + "axum", "bincode", "bitflags 2.6.0", "bytes 1.9.0", "cap-fs-ext", "cap-std", "cap-time-ext", - "cargo_metadata", + "cargo_metadata 0.19.1", "chrono", "console-subscriber", "dashmap", @@ -4460,7 +4476,6 @@ dependencies = [ "golem-wasm-rpc", "golem-wit", "hex", - "http 0.2.12", "http 1.2.0", "http-body 1.0.1", "humansize", @@ -4477,12 +4492,12 @@ dependencies = [ "once_cell", "prometheus", "proptest", - "prost 0.12.6", + "prost 0.13.4", "rand", "redis", "ringbuf", "rustls 0.23.19", - "serde 1.0.215", + "serde 1.0.216", "serde_json", "sqlx", "sysinfo", @@ -4490,7 +4505,7 @@ dependencies = [ "test-r", "testcontainers", "testcontainers-modules", - "thiserror 1.0.69", + "thiserror 2.0.6", "tokio", "tokio-rustls 0.26.1", "tokio-stream", @@ -4502,11 +4517,10 @@ dependencies = [ "tracing-subscriber", "url", "uuid", - "warp", "wasmtime", "wasmtime-wasi", "wasmtime-wasi-http", - "windows-sys 0.52.0", + "windows-sys 0.59.0", "zstd", ] @@ -4519,7 +4533,7 @@ dependencies = [ "bincode", "bytes 1.9.0", "console-subscriber", - "derive_more 0.99.18", + "derive_more 1.0.0", "figment", "futures", "futures-util", @@ -4530,21 +4544,20 @@ dependencies = [ "golem-wasm-ast", "golem-wasm-rpc", "golem-worker-service-base", - "http 0.2.12", "http 1.2.0", "humantime-serde", "hyper 1.5.1", "lazy_static 1.5.0", "nom 7.1.3", "openapiv3", - "opentelemetry 0.24.0", - "opentelemetry-prometheus", - "opentelemetry_sdk", + "opentelemetry 0.27.1", + "opentelemetry-prometheus 0.27.0", + "opentelemetry_sdk 0.27.1", "poem", "poem-openapi", "prometheus", "regex", - "serde 1.0.215", + "serde 1.0.216", "serde_json", "serde_yaml", "strum", @@ -4575,7 +4588,7 @@ dependencies = [ "chrono", "conditional-trait-gen", "criterion", - "derive_more 0.99.18", + "derive_more 1.0.0", "fastrand 2.3.0", "figment", "fred", @@ -4587,7 +4600,6 @@ dependencies = [ "golem-service-base", "golem-wasm-ast", "golem-wasm-rpc", - "http 0.2.12", "http 1.2.0", "humantime-serde", "hyper 1.5.1", @@ -4596,18 +4608,18 @@ dependencies = [ "nom 7.1.3", "openapiv3", "openidconnect", - "opentelemetry 0.24.0", - "opentelemetry-prometheus", - "opentelemetry_sdk", + "opentelemetry 0.27.1", + "opentelemetry-prometheus 0.27.0", + "opentelemetry_sdk 0.27.1", "poem", "poem-openapi", "prometheus", - "prost 0.12.6", - "prost-types 0.12.6", + "prost 0.13.4", + "prost-types 0.13.4", "regex", "rsa", - "rustc-hash", - "serde 1.0.215", + "rustc-hash 2.1.0", + "serde 1.0.216", "serde_json", "serde_yaml", "sqlx", @@ -4617,7 +4629,7 @@ dependencies = [ "test-r", "testcontainers", "testcontainers-modules", - "thiserror 1.0.69", + "thiserror 2.0.6", "tokio", "tokio-stream", "tokio-util", @@ -4693,9 +4705,13 @@ dependencies = [ [[package]] name = "half" -version = "1.8.3" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] [[package]] name = "hashbrown" @@ -4720,7 +4736,7 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash", "allocator-api2", - "serde 1.0.215", + "serde 1.0.216", ] [[package]] @@ -4732,13 +4748,14 @@ dependencies = [ "allocator-api2", "equivalent", "foldhash", + "serde 1.0.216", ] [[package]] name = "hashlink" -version = "0.8.4" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" dependencies = [ "hashbrown 0.14.5", ] @@ -4757,21 +4774,6 @@ dependencies = [ "num-traits 0.2.19", ] -[[package]] -name = "headers" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" -dependencies = [ - "base64 0.21.7", - "bytes 1.9.0", - "headers-core 0.2.0", - "http 0.2.12", - "httpdate", - "mime", - "sha1", -] - [[package]] name = "headers" version = "0.4.0" @@ -4780,7 +4782,7 @@ checksum = "322106e6bd0cba2d5ead589ddb8150a13d7c4217cf80d7c4f682ca994ccc6aa9" dependencies = [ "base64 0.21.7", "bytes 1.9.0", - "headers-core 0.3.0", + "headers-core", "http 1.2.0", "httpdate", "mime", @@ -4789,20 +4791,11 @@ dependencies = [ [[package]] name = "headers-core" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" +checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" dependencies = [ - "http 0.2.12", -] - -[[package]] -name = "headers-core" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" -dependencies = [ - "http 1.2.0", + "http 1.2.0", ] [[package]] @@ -4810,9 +4803,6 @@ name = "heck" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -dependencies = [ - "unicode-segmentation", -] [[package]] name = "heck" @@ -4973,7 +4963,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57a3db5ea5923d99402c94e9feb261dc5ee9b4efa158b0315f788cf549cc200c" dependencies = [ "humantime", - "serde 1.0.215", + "serde 1.0.216", ] [[package]] @@ -5029,7 +5019,7 @@ checksum = "5d06dbdfbacf34d996c6fb540a71a684a7aae9056c71951163af8a8a4c07b9a4" dependencies = [ "bytes 1.9.0", "futures-util", - "headers 0.4.0", + "headers", "http 1.2.0", "hyper 1.5.1", "hyper-rustls 0.27.3", @@ -5091,18 +5081,6 @@ dependencies = [ "tower-service", ] -[[package]] -name = "hyper-timeout" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" -dependencies = [ - "hyper 0.14.31", - "pin-project-lite", - "tokio", - "tokio-io-timeout", -] - [[package]] name = "hyper-timeout" version = "0.5.2" @@ -5177,7 +5155,7 @@ dependencies = [ "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows-core", + "windows-core 0.52.0", ] [[package]] @@ -5395,7 +5373,7 @@ checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown 0.12.3", - "serde 1.0.215", + "serde 1.0.216", ] [[package]] @@ -5406,7 +5384,7 @@ checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", "hashbrown 0.15.2", - "serde 1.0.215", + "serde 1.0.216", ] [[package]] @@ -5464,8 +5442,8 @@ dependencies = [ "anyhow", "assert2", "async-trait", - "axum 0.7.9", - "clap 4.5.23", + "axum", + "clap", "console-subscriber", "golem-api-grpc", "golem-common", @@ -5475,14 +5453,13 @@ dependencies = [ "poem", "rand", "reqwest 0.12.9", - "serde 1.0.215", + "serde 1.0.216", "serde_json", "test-r", "tokio", "tracing", "tracing-subscriber", "wac-graph", - "warp", ] [[package]] @@ -5567,12 +5544,12 @@ dependencies = [ [[package]] name = "iso8601-timestamp" -version = "0.2.17" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d4e5d712dd664b11e778d1cfc06c79ba2700d6bc1771e44fb7b6a4656b487d" +checksum = "ef28a96196d23eb2125c3ea7fef3c7de8fa5e03dfe354d2041824289ff696377" dependencies = [ "generic-array 1.1.1", - "serde 1.0.215", + "serde 1.0.216", "time", ] @@ -5665,24 +5642,22 @@ dependencies = [ [[package]] name = "json-patch" -version = "2.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b1fb8864823fad91877e6caea0baca82e49e8db50f8e5c9f9a453e27d3330fc" +checksum = "863726d7afb6bc2590eeff7135d923545e5e964f004c2ccf8716c25e70a86f08" dependencies = [ "jsonptr", - "serde 1.0.215", + "serde 1.0.216", "serde_json", "thiserror 1.0.69", ] [[package]] name = "jsonpath-rust" -version = "0.5.1" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19d8fe85bd70ff715f31ce8c739194b423d79811a19602115d611a3ec85d6200" +checksum = "69a61b87f6a55cc6c28fed5739dd36b9642321ce63e4a5e4a4715d69106f4a10" dependencies = [ - "lazy_static 1.5.0", - "once_cell", "pest", "pest_derive", "regex", @@ -5692,24 +5667,23 @@ dependencies = [ [[package]] name = "jsonptr" -version = "0.4.7" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c6e529149475ca0b2820835d3dce8fcc41c6b943ca608d32f35b449255e4627" +checksum = "5dea2b27dd239b2556ed7a25ba842fe47fd602e7fc7433c2a8d6106d4d9edd70" dependencies = [ - "fluent-uri", - "serde 1.0.215", + "serde 1.0.216", "serde_json", ] [[package]] name = "k8s-openapi" -version = "0.22.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19501afb943ae5806548bc3ebd7f3374153ca057a38f480ef30adfde5ef09755" +checksum = "9c8847402328d8301354c94d605481f25a6bdc1ed65471fd96af8eca71141b13" dependencies = [ "base64 0.22.1", "chrono", - "serde 1.0.215", + "serde 1.0.216", "serde-value", "serde_json", ] @@ -5747,14 +5721,14 @@ dependencies = [ "nix 0.27.1", "tokio", "tracing", - "windows", + "windows 0.52.0", ] [[package]] name = "kube" -version = "0.92.1" +version = "0.97.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "231c5a5392d9e2a9b0d923199760d3f1dd73b95288f2871d16c7c90ba4954506" +checksum = "e5fd2596428f922f784ca43907c449f104d69055c811135684474143736c67ae" dependencies = [ "k8s-openapi", "kube-client", @@ -5765,9 +5739,9 @@ dependencies = [ [[package]] name = "kube-client" -version = "0.92.1" +version = "0.97.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f4bf54135062ff60e2a0dfb3e7a9c8e931fc4a535b4d6bd561e0a1371321c61" +checksum = "d539b6493d162ae5ab691762be972b6a1c20f6d8ddafaae305c0e2111b589d99" dependencies = [ "base64 0.22.1", "bytes 1.9.0", @@ -5781,7 +5755,7 @@ dependencies = [ "hyper 1.5.1", "hyper-http-proxy", "hyper-rustls 0.27.3", - "hyper-timeout 0.5.2", + "hyper-timeout", "hyper-util", "jsonpath-rust", "k8s-openapi", @@ -5789,23 +5763,23 @@ dependencies = [ "pem", "rustls 0.23.19", "rustls-pemfile 2.2.0", - "secrecy", - "serde 1.0.215", + "secrecy 0.10.3", + "serde 1.0.216", "serde_json", "serde_yaml", - "thiserror 1.0.69", + "thiserror 2.0.6", "tokio", "tokio-util", - "tower 0.4.13", + "tower 0.5.1", "tower-http", "tracing", ] [[package]] name = "kube-core" -version = "0.92.1" +version = "0.97.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40fb9bd8141cbc0fe6b0d9112d371679b4cb607b45c31dd68d92e40864a12975" +checksum = "98a87cc0046cf6b62cbb63ae1fbc366ee8ba29269f575289679473754ff5d7a7" dependencies = [ "chrono", "form_urlencoded", @@ -5813,16 +5787,17 @@ dependencies = [ "json-patch", "k8s-openapi", "schemars", - "serde 1.0.215", + "serde 1.0.216", + "serde-value", "serde_json", - "thiserror 1.0.69", + "thiserror 2.0.6", ] [[package]] name = "kube-derive" -version = "0.92.1" +version = "0.97.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08fc86f70076921fdf2f433bbd2a796dc08ac537dc1db1f062cfa63ed4fa15fb" +checksum = "65576922713e6154a89b5a8d2747adca15725b90fa64fc2b828774bf96d6acd8" dependencies = [ "darling", "proc-macro2", @@ -5833,27 +5808,27 @@ dependencies = [ [[package]] name = "kube-runtime" -version = "0.92.1" +version = "0.97.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7eb2fb986f81770eb55ec7f857e197019b31b38768d2410f6c1046ffac34225" +checksum = "4f348cc3e6c9be0ae17f300594bde541b667d10ab8934a119edd61ab5123c43e" dependencies = [ "ahash", "async-broadcast 0.7.1", "async-stream", "async-trait", "backoff", - "derivative", + "educe", "futures", - "hashbrown 0.14.5", + "hashbrown 0.15.2", "json-patch", "jsonptr", "k8s-openapi", "kube-client", "parking_lot", "pin-project 1.1.7", - "serde 1.0.215", + "serde 1.0.216", "serde_json", - "thiserror 1.0.69", + "thiserror 2.0.6", "tokio", "tokio-util", "tracing", @@ -5940,9 +5915,9 @@ dependencies = [ [[package]] name = "libsqlite3-sys" -version = "0.27.0" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" dependencies = [ "cc", "pkg-config", @@ -6010,18 +5985,18 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "logos" -version = "0.14.2" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c6b6e02facda28ca5fb8dbe4b152496ba3b1bd5a4b40bb2b1b2d8ad74e0f39b" +checksum = "7251356ef8cb7aec833ddf598c6cb24d17b689d20b993f9d11a3d764e34e6458" dependencies = [ "logos-derive", ] [[package]] name = "logos-codegen" -version = "0.14.3" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f3303189202bb8a052bcd93d66b6c03e6fe70d9c7c47c0ea5e974955e54c876" +checksum = "59f80069600c0d66734f5ff52cc42f2dabd6b29d205f333d61fd7832e9e9963f" dependencies = [ "beef", "fnv", @@ -6029,15 +6004,14 @@ dependencies = [ "proc-macro2", "quote", "regex-syntax 0.8.5", - "rustc_version", "syn 2.0.90", ] [[package]] name = "logos-derive" -version = "0.14.3" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "774a1c225576486e4fdf40b74646f672c542ca3608160d348749693ae9d456e6" +checksum = "24fb722b06a9dc12adb0963ed585f19fc61dc5413e6a9be9422ef92c091e731d" dependencies = [ "logos-codegen", ] @@ -6187,7 +6161,7 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c37e1b517d1dcd0e51dc36c4567b9d5a29262b3ec8da6cb5d35e27a8fb529b5" dependencies = [ - "serde 1.0.215", + "serde 1.0.216", ] [[package]] @@ -6230,24 +6204,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "multer" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01acbdc23469fd8fe07ab135923371d5f5a422fbf9c522158677c8eb15bc51c2" -dependencies = [ - "bytes 1.9.0", - "encoding_rs", - "futures-util", - "http 0.2.12", - "httparse", - "log 0.4.22", - "memchr", - "mime", - "spin", - "version_check", -] - [[package]] name = "multer" version = "3.1.0" @@ -6526,7 +6482,7 @@ dependencies = [ "http 0.2.12", "rand", "reqwest 0.11.27", - "serde 1.0.215", + "serde 1.0.216", "serde_json", "serde_path_to_error", "sha2", @@ -6589,7 +6545,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc02deea53ffe807708244e5914f6b099ad7015a207ee24317c22112e17d9c5c" dependencies = [ "indexmap 2.7.0", - "serde 1.0.215", + "serde 1.0.216", "serde_json", ] @@ -6612,7 +6568,7 @@ dependencies = [ "p384", "rand", "rsa", - "serde 1.0.215", + "serde 1.0.216", "serde-value", "serde_derive", "serde_json", @@ -6717,9 +6673,23 @@ checksum = "cc4191ce34aa274621861a7a9d68dbcf618d5b6c66b10081631b61fd81fbc015" dependencies = [ "once_cell", "opentelemetry 0.24.0", - "opentelemetry_sdk", + "opentelemetry_sdk 0.24.1", + "prometheus", + "protobuf", +] + +[[package]] +name = "opentelemetry-prometheus" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b834e966ea5e2d03dfe5f2253f03d22cce21403ee940265070eeee96cee0bcc" +dependencies = [ + "once_cell", + "opentelemetry 0.27.1", + "opentelemetry_sdk 0.27.1", "prometheus", "protobuf", + "tracing", ] [[package]] @@ -6741,10 +6711,26 @@ dependencies = [ "glob", "once_cell", "opentelemetry 0.24.0", + "thiserror 1.0.69", +] + +[[package]] +name = "opentelemetry_sdk" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "231e9d6ceef9b0b2546ddf52335785ce41252bc7474ee8ba05bfad277be13ab8" +dependencies = [ + "async-trait", + "futures-channel", + "futures-executor", + "futures-util", + "glob", + "opentelemetry 0.27.1", "percent-encoding", "rand", "serde_json", "thiserror 1.0.69", + "tracing", ] [[package]] @@ -6932,7 +6918,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1030c719b0ec2a2d25a5df729d6cff1acf3cc230bf766f4f97833591f7577b90" dependencies = [ "base64 0.21.7", - "serde 1.0.215", + "serde 1.0.216", ] [[package]] @@ -6959,7 +6945,7 @@ dependencies = [ "pbjson-build", "prost 0.12.6", "prost-build 0.12.6", - "serde 1.0.215", + "serde 1.0.216", ] [[package]] @@ -6992,7 +6978,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" dependencies = [ "base64 0.22.1", - "serde 1.0.215", + "serde 1.0.216", ] [[package]] @@ -7277,17 +7263,17 @@ dependencies = [ "chrono", "cookie", "futures-util", - "headers 0.4.0", + "headers", "http 1.2.0", "http-body-util", "hyper 1.5.1", "hyper-util", "mime", - "multer 3.1.0", + "multer", "nix 0.29.0", "opentelemetry 0.27.1", "opentelemetry-http", - "opentelemetry-prometheus", + "opentelemetry-prometheus 0.17.0", "opentelemetry-semantic-conventions", "parking_lot", "percent-encoding", @@ -7297,7 +7283,7 @@ dependencies = [ "quick-xml", "regex", "rfc7239", - "serde 1.0.215", + "serde 1.0.216", "serde_json", "serde_urlencoded", "serde_yaml", @@ -7346,7 +7332,7 @@ dependencies = [ "poem-openapi-derive", "quick-xml", "regex", - "serde 1.0.215", + "serde 1.0.216", "serde_json", "serde_urlencoded", "serde_yaml", @@ -7439,7 +7425,7 @@ dependencies = [ "cobs", "embedded-io 0.4.0", "embedded-io 0.6.1", - "serde 1.0.215", + "serde 1.0.216", ] [[package]] @@ -7867,7 +7853,7 @@ dependencies = [ "config", "directories", "petgraph", - "serde 1.0.215", + "serde 1.0.216", "serde-value", "tint", ] @@ -7885,7 +7871,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7649a7b4df05aed9ea7ec6f628c67c9953a43869b8bc50929569b2999d443fe" dependencies = [ "memchr", - "serde 1.0.215", + "serde 1.0.216", ] [[package]] @@ -7985,15 +7971,18 @@ checksum = "d3edd4d5d42c92f0a659926464d4cce56b562761267ecf0f469d85b7de384175" [[package]] name = "redis" -version = "0.25.4" +version = "0.27.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0d7a6955c7511f60f3ba9e86c6d02b3c3f144f8c24b288d1f4e18074ab8bbec" +checksum = "09d8f99a4090c89cc489a94833c901ead69bfbf3877b4867d5482e321ee875bc" dependencies = [ + "arc-swap", "async-trait", "bytes 1.9.0", "combine", "futures-util", + "itertools 0.13.0", "itoa", + "num-bigint", "percent-encoding", "pin-project-lite", "ryu", @@ -8054,7 +8043,7 @@ checksum = "ad156d539c879b7a24a363a2016d77961786e71f48f2e2fc8302a92abd2429a6" dependencies = [ "hashbrown 0.13.2", "log 0.4.22", - "rustc-hash", + "rustc-hash 1.1.0", "slice-group-by", "smallvec", ] @@ -8140,7 +8129,7 @@ dependencies = [ "pin-project-lite", "rustls 0.21.12", "rustls-pemfile 1.0.4", - "serde 1.0.215", + "serde 1.0.216", "serde_json", "serde_urlencoded", "sync_wrapper 0.1.2", @@ -8187,7 +8176,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "rustls-pemfile 2.2.0", - "serde 1.0.215", + "serde 1.0.216", "serde_json", "serde_urlencoded", "sync_wrapper 1.0.2", @@ -8319,6 +8308,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-hash" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" + [[package]] name = "rustc_version" version = "0.4.1" @@ -8516,7 +8511,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e0719c0520bdfc6f5a02c8bd8b20f9fc8785de57d4e117e144ade9c5f152626" dependencies = [ "rand", - "serde 1.0.215", + "serde 1.0.216", "time", ] @@ -8537,11 +8532,10 @@ dependencies = [ [[package]] name = "sanitize-filename" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ed72fbaf78e6f2d41744923916966c4fbe3d7c74e3037a8ee482f1115572603" +checksum = "bc984f4f9ceb736a7bb755c3e3bd17dc56370af2600c9780dcc48c66453da34d" dependencies = [ - "lazy_static 1.5.0", "regex", ] @@ -8562,7 +8556,7 @@ checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" dependencies = [ "dyn-clone", "schemars_derive", - "serde 1.0.215", + "serde 1.0.216", "serde_json", ] @@ -8578,12 +8572,6 @@ dependencies = [ "syn 2.0.90", ] -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - [[package]] name = "scopeguard" version = "1.2.0" @@ -8634,7 +8622,15 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" dependencies = [ - "serde 1.0.215", + "zeroize", +] + +[[package]] +name = "secrecy" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e891af845473308773346dc847b2c23ee78fe442e0472ac50e22a18a93d3ae5a" +dependencies = [ "zeroize", ] @@ -8652,7 +8648,7 @@ dependencies = [ "num", "once_cell", "rand", - "serde 1.0.215", + "serde 1.0.216", "sha2", "zbus", ] @@ -8699,7 +8695,7 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" dependencies = [ - "serde 1.0.215", + "serde 1.0.216", ] [[package]] @@ -8710,9 +8706,9 @@ checksum = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8" [[package]] name = "serde" -version = "1.0.215" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" dependencies = [ "serde_derive", ] @@ -8736,24 +8732,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" dependencies = [ "ordered-float", - "serde 1.0.215", -] - -[[package]] -name = "serde_cbor" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" -dependencies = [ - "half", - "serde 1.0.215", + "serde 1.0.216", ] [[package]] name = "serde_derive" -version = "1.0.215" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ "proc-macro2", "quote", @@ -8780,7 +8766,7 @@ dependencies = [ "itoa", "memchr", "ryu", - "serde 1.0.215", + "serde 1.0.216", ] [[package]] @@ -8792,7 +8778,7 @@ dependencies = [ "inventory", "nom 7.1.3", "regex", - "serde 1.0.215", + "serde 1.0.216", "serde_json", "serde_json_path_core", "serde_json_path_macros", @@ -8806,7 +8792,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea3bfd54a421bec8328aefede43ac9f18c8c7ded3b2afc8addd44b4813d99fd0" dependencies = [ "inventory", - "serde 1.0.215", + "serde 1.0.216", "serde_json", "thiserror 1.0.69", ] @@ -8840,7 +8826,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" dependencies = [ "itoa", - "serde 1.0.215", + "serde 1.0.216", ] [[package]] @@ -8849,7 +8835,7 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ce1fc6db65a611022b23a0dec6975d63fb80a302cb3388835ff02c097258d50" dependencies = [ - "serde 1.0.215", + "serde 1.0.216", ] [[package]] @@ -8869,7 +8855,7 @@ version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ - "serde 1.0.215", + "serde 1.0.216", ] [[package]] @@ -8881,7 +8867,7 @@ dependencies = [ "form_urlencoded", "itoa", "ryu", - "serde 1.0.215", + "serde 1.0.216", ] [[package]] @@ -8895,7 +8881,7 @@ dependencies = [ "hex", "indexmap 1.9.3", "indexmap 2.7.0", - "serde 1.0.215", + "serde 1.0.216", "serde_derive", "serde_json", "serde_with_macros", @@ -8923,7 +8909,7 @@ dependencies = [ "indexmap 2.7.0", "itoa", "ryu", - "serde 1.0.215", + "serde 1.0.216", "unsafe-libyaml", ] @@ -9117,7 +9103,7 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" dependencies = [ - "serde 1.0.215", + "serde 1.0.216", ] [[package]] @@ -9166,7 +9152,7 @@ dependencies = [ "prost-build 0.13.4", "rand", "rusty_ulid", - "serde 1.0.215", + "serde 1.0.216", "serde_json", "sha2", "thiserror 1.0.69", @@ -9263,9 +9249,9 @@ dependencies = [ [[package]] name = "sqlx" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9a2ccff1a000a5a59cd33da541d9f2fdcd9e6e8229cc200565942bff36d0aaa" +checksum = "93334716a037193fac19df402f8571269c84a00852f6a7066b5d2616dcd64d3e" dependencies = [ "sqlx-core", "sqlx-macros", @@ -9276,11 +9262,10 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24ba59a9342a3d9bab6c56c118be528b27c9b60e490080e9711a04dccac83ef6" +checksum = "d4d8060b456358185f7d50c55d9b5066ad956956fddec42ee2e8567134a8936e" dependencies = [ - "ahash", "atoi", "byteorder", "bytes 1.9.0", @@ -9288,12 +9273,13 @@ dependencies = [ "crc", "crossbeam-queue", "either", - "event-listener 2.5.3", + "event-listener 5.3.1", "futures-channel", "futures-core", "futures-intrusive", "futures-io", "futures-util", + "hashbrown 0.14.5", "hashlink", "hex", "indexmap 2.7.0", @@ -9302,7 +9288,7 @@ dependencies = [ "once_cell", "paste", "percent-encoding", - "serde 1.0.215", + "serde 1.0.216", "serde_json", "sha2", "smallvec", @@ -9317,38 +9303,38 @@ dependencies = [ [[package]] name = "sqlx-macros" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea40e2345eb2faa9e1e5e326db8c34711317d2b5e08d0d5741619048a803127" +checksum = "cac0692bcc9de3b073e8d747391827297e075c7710ff6276d9f7a1f3d58c6657" dependencies = [ "proc-macro2", "quote", "sqlx-core", "sqlx-macros-core", - "syn 1.0.109", + "syn 2.0.90", ] [[package]] name = "sqlx-macros-core" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5833ef53aaa16d860e92123292f1f6a3d53c34ba8b1969f152ef1a7bb803f3c8" +checksum = "1804e8a7c7865599c9c79be146dc8a9fd8cc86935fa641d3ea58e5f0688abaa5" dependencies = [ "dotenvy", "either", - "heck 0.4.1", + "heck 0.5.0", "hex", "once_cell", "proc-macro2", "quote", - "serde 1.0.215", + "serde 1.0.216", "serde_json", "sha2", "sqlx-core", "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 1.0.109", + "syn 2.0.90", "tempfile", "tokio", "url", @@ -9356,12 +9342,12 @@ dependencies = [ [[package]] name = "sqlx-mysql" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ed31390216d20e538e447a7a9b959e06ed9fc51c37b514b46eb758016ecd418" +checksum = "64bb4714269afa44aef2755150a0fc19d756fb580a67db8885608cf02f47d06a" dependencies = [ "atoi", - "base64 0.21.7", + "base64 0.22.1", "bitflags 2.6.0", "byteorder", "bytes 1.9.0", @@ -9386,7 +9372,7 @@ dependencies = [ "percent-encoding", "rand", "rsa", - "serde 1.0.215", + "serde 1.0.216", "sha1", "sha2", "smallvec", @@ -9400,12 +9386,12 @@ dependencies = [ [[package]] name = "sqlx-postgres" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c824eb80b894f926f89a0b9da0c7f435d27cdd35b8c655b114e58223918577e" +checksum = "6fa91a732d854c5d7726349bb4bb879bb9478993ceb764247660aee25f67c2f8" dependencies = [ "atoi", - "base64 0.21.7", + "base64 0.22.1", "bitflags 2.6.0", "byteorder", "chrono", @@ -9426,7 +9412,7 @@ dependencies = [ "memchr", "once_cell", "rand", - "serde 1.0.215", + "serde 1.0.216", "serde_json", "sha2", "smallvec", @@ -9440,9 +9426,9 @@ dependencies = [ [[package]] name = "sqlx-sqlite" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b244ef0a8414da0bed4bb1910426e890b19e5e9bccc27ada6b797d05c55ae0aa" +checksum = "d5b2cf34a45953bfd3daaf3db0f7a7878ab9b7a6b91b422d24a7a9e4c857b680" dependencies = [ "atoi", "chrono", @@ -9455,11 +9441,11 @@ dependencies = [ "libsqlite3-sys", "log 0.4.22", "percent-encoding", - "serde 1.0.215", + "serde 1.0.216", + "serde_urlencoded", "sqlx-core", "tracing", "url", - "urlencoding", "uuid", ] @@ -9611,17 +9597,16 @@ dependencies = [ [[package]] name = "sysinfo" -version = "0.30.13" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a5b4ddaee55fb2bea2bf0e5000747e5f5c0de765e5a5ff87f4cd106439f4bb3" +checksum = "948512566b1895f93b1592c7574baeb2de842f224f2aab158799ecadb8ebbb46" dependencies = [ - "cfg-if", "core-foundation-sys", "libc", + "memchr", "ntapi", - "once_cell", "rayon", - "windows", + "windows 0.57.0", ] [[package]] @@ -9750,7 +9735,7 @@ dependencies = [ "anstyle-query", "anstyle-wincon", "bincode", - "clap 4.5.23", + "clap", "escape8259", "futures", "interprocess", @@ -9794,7 +9779,7 @@ dependencies = [ "memchr", "parse-display", "pin-project-lite", - "serde 1.0.215", + "serde 1.0.216", "serde_json", "serde_with", "thiserror 1.0.69", @@ -9814,15 +9799,6 @@ dependencies = [ "testcontainers", ] -[[package]] -name = "textwrap" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width 0.1.14", -] - [[package]] name = "textwrap" version = "0.16.1" @@ -9894,7 +9870,7 @@ dependencies = [ "itoa", "num-conv", "powerfmt", - "serde 1.0.215", + "serde 1.0.216", "time-core", "time-macros", ] @@ -9940,7 +9916,7 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" dependencies = [ - "serde 1.0.215", + "serde 1.0.216", "serde_json", ] @@ -9978,16 +9954,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "tokio-io-timeout" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" -dependencies = [ - "pin-project-lite", - "tokio", -] - [[package]] name = "tokio-macros" version = "2.4.0" @@ -10107,40 +10073,28 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" -dependencies = [ - "futures-util", - "log 0.4.22", - "native-tls", - "tokio", - "tokio-native-tls", - "tungstenite 0.20.1", -] - -[[package]] -name = "tokio-tungstenite" -version = "0.21.0" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" +checksum = "c6989540ced10490aaf14e6bad2e3d33728a2813310a0c71d1574304c49631cd" dependencies = [ "futures-util", "log 0.4.22", "tokio", - "tungstenite 0.21.0", + "tungstenite 0.23.0", ] [[package]] name = "tokio-tungstenite" -version = "0.23.1" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6989540ced10490aaf14e6bad2e3d33728a2813310a0c71d1574304c49631cd" +checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" dependencies = [ "futures-util", "log 0.4.22", + "native-tls", "tokio", - "tungstenite 0.23.0", + "tokio-native-tls", + "tungstenite 0.24.0", ] [[package]] @@ -10164,7 +10118,7 @@ version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ - "serde 1.0.215", + "serde 1.0.216", ] [[package]] @@ -10173,7 +10127,7 @@ version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ - "serde 1.0.215", + "serde 1.0.216", "serde_spanned", "toml_datetime", "toml_edit 0.22.22", @@ -10185,7 +10139,7 @@ version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ - "serde 1.0.215", + "serde 1.0.216", ] [[package]] @@ -10206,7 +10160,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ "indexmap 2.7.0", - "serde 1.0.215", + "serde 1.0.216", "serde_spanned", "toml_datetime", "winnow 0.6.20", @@ -10214,24 +10168,27 @@ dependencies = [ [[package]] name = "tonic" -version = "0.11.0" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76c4eb7a4e9ef9d4763600161f12f5070b92a578e1b634db88a6887844c91a13" +checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" dependencies = [ "async-stream", "async-trait", - "axum 0.6.20", - "base64 0.21.7", + "axum", + "base64 0.22.1", "bytes 1.9.0", "flate2", - "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.31", - "hyper-timeout 0.4.1", + "h2 0.4.7", + "http 1.2.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.5.1", + "hyper-timeout", + "hyper-util", "percent-encoding", "pin-project 1.1.7", - "prost 0.12.6", + "prost 0.13.4", + "socket2 0.5.8", "tokio", "tokio-stream", "tower 0.4.13", @@ -10242,25 +10199,26 @@ dependencies = [ [[package]] name = "tonic-build" -version = "0.11.0" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4ef6dd70a610078cb4e338a0f79d06bc759ff1b22d2120c2ff02ae264ba9c2" +checksum = "9557ce109ea773b399c9b9e5dca39294110b74f1f342cb347a80d1fce8c26a11" dependencies = [ "prettyplease", "proc-macro2", - "prost-build 0.12.6", + "prost-build 0.13.4", + "prost-types 0.13.4", "quote", "syn 2.0.90", ] [[package]] name = "tonic-health" -version = "0.11.0" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cef6e24bc96871001a7e48e820ab240b3de2201e59b517cf52835df2f1d2350" +checksum = "1eaf34ddb812120f5c601162d5429933c9b527d901ab0e7f930d3147e33a09b2" dependencies = [ "async-stream", - "prost 0.12.6", + "prost 0.13.4", "tokio", "tokio-stream", "tonic", @@ -10268,12 +10226,12 @@ dependencies = [ [[package]] name = "tonic-reflection" -version = "0.11.0" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "548c227bd5c0fae5925812c4ec6c66ffcfced23ea370cb823f4d18f0fc1cb6a7" +checksum = "878d81f52e7fcfd80026b7fdb6a9b578b3c3653ba987f87f0dce4b64043cba27" dependencies = [ - "prost 0.12.6", - "prost-types 0.12.6", + "prost 0.13.4", + "prost-types 0.13.4", "tokio", "tokio-stream", "tonic", @@ -10316,6 +10274,7 @@ dependencies = [ "pin-project-lite", "sync_wrapper 0.1.2", "tokio", + "tokio-util", "tower-layer", "tower-service", "tracing", @@ -10323,16 +10282,15 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.5.2" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" +checksum = "403fa3b783d4b626a8ad51d766ab03cb6d2dbfc46b1c5d4448395e6628dc9697" dependencies = [ - "base64 0.21.7", + "base64 0.22.1", "bitflags 2.6.0", "bytes 1.9.0", "http 1.2.0", "http-body 1.0.1", - "http-body-util", "mime", "pin-project-lite", "tower-layer", @@ -10408,23 +10366,13 @@ dependencies = [ "tracing-core", ] -[[package]] -name = "tracing-serde" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" -dependencies = [ - "serde 1.0.215", - "tracing-core", -] - [[package]] name = "tracing-serde" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" dependencies = [ - "serde 1.0.215", + "serde 1.0.216", "tracing-core", ] @@ -10438,7 +10386,7 @@ dependencies = [ "nu-ansi-term", "once_cell", "regex", - "serde 1.0.215", + "serde 1.0.216", "serde_json", "sharded-slab", "smallvec", @@ -10446,7 +10394,7 @@ dependencies = [ "tracing", "tracing-core", "tracing-log", - "tracing-serde 0.2.0", + "tracing-serde", ] [[package]] @@ -10490,29 +10438,9 @@ checksum = "17f77d76d837a7830fe1d4f12b7b4ba4192c1888001c7164257e4bc6d21d96b4" [[package]] name = "tungstenite" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" -dependencies = [ - "byteorder", - "bytes 1.9.0", - "data-encoding", - "http 0.2.12", - "httparse", - "log 0.4.22", - "native-tls", - "rand", - "sha1", - "thiserror 1.0.69", - "url", - "utf-8", -] - -[[package]] -name = "tungstenite" -version = "0.21.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" +checksum = "6e2e2ce1e47ed2994fd43b04c8f618008d4cabdd5ee34027cf14f9d918edd9c8" dependencies = [ "byteorder", "bytes 1.9.0", @@ -10523,15 +10451,14 @@ dependencies = [ "rand", "sha1", "thiserror 1.0.69", - "url", "utf-8", ] [[package]] name = "tungstenite" -version = "0.23.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e2ce1e47ed2994fd43b04c8f618008d4cabdd5ee34027cf14f9d918edd9c8" +checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" dependencies = [ "byteorder", "bytes 1.9.0", @@ -10539,6 +10466,7 @@ dependencies = [ "http 1.2.0", "httparse", "log 0.4.22", + "native-tls", "rand", "sha1", "thiserror 1.0.69", @@ -10547,9 +10475,9 @@ dependencies = [ [[package]] name = "typed-path" -version = "0.9.3" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82205ffd44a9697e34fc145491aa47310f9871540bb7909eaa9365e0a9a46607" +checksum = "41713888c5ccfd99979fcd1afd47b71652e331b3d4a0e19d30769e80fec76cce" [[package]] name = "typenum" @@ -10689,7 +10617,7 @@ dependencies = [ "form_urlencoded", "idna", "percent-encoding", - "serde 1.0.215", + "serde 1.0.216", ] [[package]] @@ -10729,7 +10657,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" dependencies = [ "getrandom", - "serde 1.0.215", + "serde 1.0.216", "sha1_smol", ] @@ -10864,7 +10792,7 @@ checksum = "6a22d3c9026f2f6a628cf386963844cdb7baea3b3419ba090c9096da114f977d" dependencies = [ "indexmap 2.7.0", "itertools 0.12.1", - "serde 1.0.215", + "serde 1.0.216", "serde_with", "thiserror 1.0.69", "warg-crypto", @@ -10881,7 +10809,7 @@ dependencies = [ "async-recursion", "async-trait", "bytes 1.9.0", - "clap 4.5.23", + "clap", "dialoguer", "dirs 5.0.1", "futures-util", @@ -10894,9 +10822,9 @@ dependencies = [ "pathdiff", "ptree", "reqwest 0.12.9", - "secrecy", + "secrecy 0.8.0", "semver", - "serde 1.0.215", + "serde 1.0.216", "serde_json", "sha256", "tempfile", @@ -10931,8 +10859,8 @@ dependencies = [ "once_cell", "p256 0.13.2", "rand_core", - "secrecy", - "serde 1.0.215", + "secrecy 0.8.0", + "serde 1.0.216", "sha2", "signature 2.2.0", "thiserror 1.0.69", @@ -10953,7 +10881,7 @@ dependencies = [ "prost-types 0.12.6", "protox", "regex", - "serde 1.0.215", + "serde 1.0.216", "warg-crypto", ] @@ -10971,7 +10899,7 @@ dependencies = [ "prost 0.12.6", "prost-types 0.12.6", "semver", - "serde 1.0.215", + "serde 1.0.216", "serde_with", "thiserror 1.0.69", "warg-crypto", @@ -10994,35 +10922,6 @@ dependencies = [ "warg-protobuf", ] -[[package]] -name = "warp" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4378d202ff965b011c64817db11d5829506d3404edeadb61f190d111da3f231c" -dependencies = [ - "bytes 1.9.0", - "futures-channel", - "futures-util", - "headers 0.3.9", - "http 0.2.12", - "hyper 0.14.31", - "log 0.4.22", - "mime", - "mime_guess", - "multer 2.1.0", - "percent-encoding", - "pin-project 1.1.7", - "scoped-tls", - "serde 1.0.215", - "serde_json", - "serde_urlencoded", - "tokio", - "tokio-tungstenite 0.21.0", - "tokio-util", - "tower-service", - "tracing", -] - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -11114,7 +11013,7 @@ dependencies = [ "indexmap 2.7.0", "log 0.4.22", "petgraph", - "serde 1.0.215", + "serde 1.0.216", "serde_derive", "serde_yaml", "smallvec", @@ -11187,7 +11086,7 @@ checksum = "094aea3cb90e09f16ee25a4c0e324b3e8c934e7fd838bfa039aef5352f44a917" dependencies = [ "anyhow", "indexmap 2.7.0", - "serde 1.0.215", + "serde 1.0.216", "serde_derive", "serde_json", "spdx", @@ -11197,50 +11096,50 @@ dependencies = [ [[package]] name = "wasm-metadata" -version = "0.207.0" +version = "0.208.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2c44e62d325ce9253f88c01f0f67be121356767d12f2f13e701fdcd99e1f5b0" +checksum = "42a2c4280ad374a6db3d76d4bb61e2ec4b3b9ce5469cc4f2bbc5708047a2bbff" dependencies = [ "anyhow", "indexmap 2.7.0", - "serde 1.0.215", + "serde 1.0.216", "serde_derive", "serde_json", "spdx", - "wasm-encoder 0.207.0", - "wasmparser 0.207.0", + "wasm-encoder 0.208.1", + "wasmparser 0.208.1", ] [[package]] name = "wasm-metadata" -version = "0.208.1" +version = "0.209.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42a2c4280ad374a6db3d76d4bb61e2ec4b3b9ce5469cc4f2bbc5708047a2bbff" +checksum = "4d32029ce424f6d3c2b39b4419fb45a0e2d84fb0751e0c0a32b7ce8bd5d97f46" dependencies = [ "anyhow", "indexmap 2.7.0", - "serde 1.0.215", + "serde 1.0.216", "serde_derive", "serde_json", "spdx", - "wasm-encoder 0.208.1", - "wasmparser 0.208.1", + "wasm-encoder 0.209.1", + "wasmparser 0.209.1", ] [[package]] name = "wasm-metadata" -version = "0.209.1" +version = "0.221.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d32029ce424f6d3c2b39b4419fb45a0e2d84fb0751e0c0a32b7ce8bd5d97f46" +checksum = "a9a7018a96c4f55a8f339954c66e09728f2d6112689000e58f15f6a6d7436e8f" dependencies = [ "anyhow", "indexmap 2.7.0", - "serde 1.0.215", + "serde 1.0.216", "serde_derive", "serde_json", "spdx", - "wasm-encoder 0.209.1", - "wasmparser 0.209.1", + "wasm-encoder 0.221.2", + "wasmparser 0.221.2", ] [[package]] @@ -11328,7 +11227,7 @@ dependencies = [ "hashbrown 0.14.5", "indexmap 2.7.0", "semver", - "serde 1.0.215", + "serde 1.0.216", ] [[package]] @@ -11351,8 +11250,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9845c470a2e10b61dd42c385839cdd6496363ed63b5c9e420b5488b77bd22083" dependencies = [ "bitflags 2.6.0", + "hashbrown 0.15.2", "indexmap 2.7.0", "semver", + "serde 1.0.216", ] [[package]] @@ -11375,6 +11276,17 @@ dependencies = [ "wasmparser 0.207.0", ] +[[package]] +name = "wasmprinter" +version = "0.221.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a80742ff1b9e6d8c231ac7c7247782c6fc5bce503af760bca071811e5fc9ee56" +dependencies = [ + "anyhow", + "termcolor", + "wasmparser 0.221.2", +] + [[package]] name = "wasmtime" version = "21.0.1" @@ -11406,7 +11318,7 @@ dependencies = [ "rayon", "rustix 0.38.42", "semver", - "serde 1.0.215", + "serde 1.0.216", "serde_derive", "serde_json", "smallvec", @@ -11449,7 +11361,7 @@ dependencies = [ "log 0.4.22", "postcard", "rustix 0.38.42", - "serde 1.0.215", + "serde 1.0.216", "serde_derive", "sha2", "toml 0.8.19", @@ -11513,7 +11425,7 @@ dependencies = [ "object 0.33.0", "postcard", "rustc-demangle", - "serde 1.0.215", + "serde 1.0.216", "serde_derive", "target-lexicon", "wasm-encoder 0.207.0", @@ -11570,7 +11482,7 @@ version = "21.0.1" source = "git+https://github.com/golemcloud/wasmtime.git?branch=golem-wasmtime-v21.0.1#adae4ab236f1eb4216dab8f7e1db6f34470de9e7" dependencies = [ "cranelift-entity", - "serde 1.0.215", + "serde 1.0.216", "serde_derive", "smallvec", "wasmparser 0.207.0", @@ -11866,7 +11778,17 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" dependencies = [ - "windows-core", + "windows-core 0.52.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" +dependencies = [ + "windows-core 0.57.0", "windows-targets 0.52.6", ] @@ -11879,17 +11801,60 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-core" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-result 0.1.2", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-implement" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "windows-interface" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "windows-registry" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" dependencies = [ - "windows-result", + "windows-result 0.2.0", "windows-strings", "windows-targets 0.52.6", ] +[[package]] +name = "windows-result" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-result" version = "0.2.0" @@ -11905,7 +11870,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ - "windows-result", + "windows-result 0.2.0", "windows-targets 0.52.6", ] @@ -12179,7 +12144,7 @@ dependencies = [ "bitflags 2.6.0", "indexmap 2.7.0", "log 0.4.22", - "serde 1.0.215", + "serde 1.0.216", "serde_derive", "serde_json", "wasm-encoder 0.208.1", @@ -12198,7 +12163,7 @@ dependencies = [ "bitflags 2.6.0", "indexmap 2.7.0", "log 0.4.22", - "serde 1.0.215", + "serde 1.0.216", "serde_derive", "serde_json", "wasm-encoder 0.209.1", @@ -12216,7 +12181,7 @@ dependencies = [ "id-arena", "pretty_assertions", "semver", - "serde 1.0.215", + "serde 1.0.216", "wit-parser 0.221.2", ] @@ -12231,7 +12196,7 @@ dependencies = [ "indexmap 2.7.0", "log 0.4.22", "semver", - "serde 1.0.215", + "serde 1.0.216", "serde_derive", "serde_json", "unicode-xid", @@ -12249,7 +12214,7 @@ dependencies = [ "indexmap 2.7.0", "log 0.4.22", "semver", - "serde 1.0.215", + "serde 1.0.216", "serde_derive", "serde_json", "unicode-xid", @@ -12267,7 +12232,7 @@ dependencies = [ "indexmap 2.7.0", "log 0.4.22", "semver", - "serde 1.0.215", + "serde 1.0.216", "serde_derive", "serde_json", "unicode-xid", @@ -12285,7 +12250,7 @@ dependencies = [ "indexmap 2.7.0", "log 0.4.22", "semver", - "serde 1.0.215", + "serde 1.0.216", "serde_derive", "serde_json", "unicode-xid", @@ -12398,7 +12363,7 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" dependencies = [ - "serde 1.0.215", + "serde 1.0.216", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -12444,7 +12409,7 @@ dependencies = [ "once_cell", "ordered-stream", "rand", - "serde 1.0.215", + "serde 1.0.216", "serde_repr", "sha1", "static_assertions", @@ -12477,7 +12442,7 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "437d738d3750bed6ca9b8d423ccc7a8eb284f6b1d6d4e225a0e4e6258d864c8d" dependencies = [ - "serde 1.0.215", + "serde 1.0.216", "static_assertions", "zvariant", ] @@ -12589,7 +12554,7 @@ dependencies = [ "byteorder", "enumflags2", "libc", - "serde 1.0.215", + "serde 1.0.216", "static_assertions", "zvariant_derive", ] diff --git a/Cargo.toml b/Cargo.toml index 39fdd0122..096234cd8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,65 +69,66 @@ exclude = [ ] [workspace.dependencies] -anyhow = "1.0.79" -assert2 = "0.3.11" -async-fs = "2.1.0" +anyhow = "1.0.94" +assert2 = "0.3.15" +async-fs = "2.1.2" async-hash = "0.5.4" -async-trait = "0.1.77" +async-recursion = "1.1.1" +async-trait = "0.1.83" async_zip = "0.0.17" -aws-config = "1.1.3" -aws-sdk-s3 = "1.13.0" +aws-config = "1.5.10" +aws-sdk-s3 = "1.65.0" axum = { version = "0.7.9", features = ["multipart"] } -bigdecimal = "0.4.5" +bigdecimal = "0.4.7" bincode = { version = "2.0.0-rc.3", features = ["serde"] } -bytes = "1.5.0" -cap-std = "3.0.0" # keep in sync with wasmtime -chrono = { version = "0.4.32", features = ["serde"] } -clap = { version = "4.5.4", features = [ +bytes = "1.9.0" +cap-std = "3.4.2" # keep in sync with wasmtime +chrono = { version = "0.4.39", features = ["serde"] } +clap = { version = "4.5.23", features = [ "derive", "suggestions", "color", "help", ] } -cli-table = "0.4.7" +cli-table = "0.4.9" combine = "4.6.7" conditional-trait-gen = "0.4.1" -console-subscriber = "0.3.0" -ctor = "0.2.6" -dashmap = "5.5.3" -derive_more = "0.99.17" +console-subscriber = "0.4.1" +ctor = "0.2.9" +dashmap = "6.1.0" +derive_more = { version = "1.0.0", features = ["display", "into", "from_str"] } drop-stream = "0.3.2" -figment = { version = "0.10.14", features = ["toml", "env"] } -fred = { version = "9.0.3", features = [ +figment = { version = "0.10.19", features = ["toml", "env"] } +fred = { version = "=9.4.0", features = [ "metrics", "serde-json", "partial-tracing", -] } +] } # pinned to 9.x to avoid conflicting cookie-factory dependencies fs_extra = "1.3.0" futures = "0.3" -futures-core = "0.3.29" -futures-util = "0.3.29" +futures-core = "0.3.31" +futures-util = "0.3.31" git-version = "0.3.9" hex = "0.4.3" -http = "1.0.0" # keep in sync with wasmtime -http_02 = { package = "http", version = "0.2.11" } +http = "1.2.0" # keep in sync with wasmtime humansize = "2.1.3" humantime-serde = "1.1.1" -hyper = { version = "1.0.1", features = ["full"] } # keep in sync with wasmtime -iso8601-timestamp = "0.2.16" +hyper = { version = "1.5.1", features = ["full"] } # keep in sync with wasmtime +iso8601-timestamp = "0.3.2" itertools = "0.13.0" -k8s-openapi = { version = "0.22.0", features = ["earliest"] } -kube = { version = "0.92.0", features = ["runtime", "derive"] } -kube-derive = "0.92.0" -lazy_static = "1.4.0" +k8s-openapi = { version = "0.23.0", features = ["earliest"] } +kube = { version = "0.97.0", features = ["runtime", "derive"] } +kube-derive = "0.97.0" +lazy_static = "1.5.0" +log = "0.4.22" nom = "7.1.3" num-traits = "0.2.19" -once_cell = "1.19.0" +once_cell = "1.20.2" openapiv3 = "2.0.0" openidconnect = "3.5.0" -opentelemetry = "0.24.0" -opentelemetry-prometheus = "0.17.0" -opentelemetry_sdk = "0.24.1" +opentelemetry = "0.27.1" +opentelemetry-prometheus = "0.27.0" +opentelemetry_sdk = "0.27.1" phf = { version = "0.11.2", features = ["macros"] } poem-openapi = { version = "5.1.4", features = [ "swagger-ui", @@ -139,29 +140,29 @@ poem-openapi = { version = "5.1.4", features = [ "websocket", ] } poem = { version = "3.1.5", features = ["prometheus", "opentelemetry", "test"] } -postgres = "0.19.7" -prometheus = { version = "0.13.3", features = ["process"] } -proptest = "1.4.0" -prost = "0.12.6" -prost-types = "0.12.6" -redis = { version = "0.25.2", features = ["default", "tokio-comp"] } -regex = "1.10.3" -reqwest = { version = "0.12.5", features = [ +postgres = "0.19.9" +prometheus = { version = "0.13.4", features = ["process"] } +proptest = "1.5.0" +prost = "0.13.4" +prost-types = "0.13.4" +redis = { version = "0.27.6", features = ["default", "tokio-comp"] } +regex = "1.11.1" +reqwest = { version = "0.12.9", features = [ "gzip", "json", "multipart", "stream", ] } -rustls = { version = "0.23.10" } +rustls = { version = "0.23.19" } rand = "0.8.5" semver = "1.0.23" serde = { version = "1.0", features = ["derive"] } serde_json = { version = "1.0", features = ["raw_value"] } -serde_yaml = { version = "0.9.33 " } +serde_yaml = { version = "0.9.34" } sha2 = "0.10.8" sozu-command-lib = { version = "1.0.5", default-features = false } sozu-lib = { version = "1.0.5", default-features = false } -sqlx = { version = "0.7", features = [ +sqlx = { version = "0.8", features = [ "runtime-tokio", "sqlite", "postgres", @@ -169,19 +170,19 @@ sqlx = { version = "0.7", features = [ "migrate", "chrono", ] } -strum = "0.26.1" -strum_macros = "0.26.1" +strum = "0.26.3" +strum_macros = "0.26.4" tap = "1.0.1" -tempfile = "3.9.0" +tempfile = "3.14.0" testcontainers = { version = "0.23.1" } -testcontainers-modules = { version = "0.11.2", features = [ +testcontainers-modules = { version = "0.11.4", features = [ "postgres", "redis", "minio", ] } test-r = { version = "1.1.0", default-features = true } -thiserror = "1.0.56" -tokio = { version = "1.0", features = [ +thiserror = "2.0.6" +tokio = { version = "1.42", features = [ "macros", "rt-multi-thread", "sync", @@ -190,33 +191,32 @@ tokio = { version = "1.0", features = [ "tracing", "process", ] } -tokio-postgres = "0.7.10" -tokio-rustls = { version = "0.26.0" } +tokio-postgres = "0.7.12" +tokio-rustls = { version = "0.26.1" } tokio-stream = { version = "0.1", features = ["sync"] } -tokio-util = "0.7.10" -toml = "0.8.14" -tonic = { version = "0.11.0", features = ["gzip"] } -tonic-reflection = "0.11.0" -tonic-health = "0.11.0" -tracing = { version = "0.1.40", features = ["log"] } -tracing-opentelemetry = "0.25.0" -tracing-serde = "0.1.3" -tracing-subscriber = { version = "0.3.18", features = [ +tokio-util = "0.7.13" +toml = "0.8.19" +tonic = { version = "0.12.3", features = ["gzip"] } +tonic-reflection = "0.12.3" +tonic-health = "0.12.3" +tracing = { version = "0.1.41", features = ["log"] } +tracing-opentelemetry = "0.28.0" +tracing-serde = "0.2.0" +tracing-subscriber = { version = "0.3.19", features = [ "env-filter", "fmt", "std", "json", ] } tracing-test = "0.2.5" -typed-path = "0.9.3" -url = "2.5.0" -uuid = { version = "1.7.0", features = ["serde", "v4", "v5"] } -warp = "0.3.6" +typed-path = "0.10.0" +url = "2.5.4" +uuid = { version = "1.11.0", features = ["serde", "v4", "v5"] } wasm-wave = "=0.6.0" wasmtime = { version = "=21.0.1", features = ["component-model"] } wasmtime-wasi = { version = "=21.0.1" } wasmtime-wasi-http = { version = "=21.0.1" } -webpki-roots = { version = "0.26.0" } +webpki-roots = { version = "0.26.7" } xdg = "2.5.2" [patch.crates-io] diff --git a/Makefile.toml b/Makefile.toml index 8e5f33447..da1cb7a89 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -214,8 +214,9 @@ cargo test --package golem-worker-executor-base --test integration :tag:group3 - description = "Runs worker executor tests only (group 4/8)" env = { "RUST_BACKTRACE" = "1", "WASMTIME_BACKTRACE_DETAILS" = "1", "RUST_LOG" = "info", "RUST_TEST_TIME_INTEGRATION" = "5000,30000" } script = ''' -cargo test --package golem-worker-executor-base --test integration :tag:group4 -- --nocapture --report-time $JUNIT_OPTS +cargo test --package golem-worker-executor-base --test integration :tag:group4 -- --nocapture --report-time $JUNIT_OPTS --test-threads=1 ''' +# NOTE: temporarily set test-threads=1 to debug flakyness [tasks.worker-executor-tests-group5] description = "Runs worker executor tests only (group 5/8)" diff --git a/golem-api-grpc/Cargo.toml b/golem-api-grpc/Cargo.toml index 0a118a448..56be0dd13 100644 --- a/golem-api-grpc/Cargo.toml +++ b/golem-api-grpc/Cargo.toml @@ -30,5 +30,5 @@ uuid = { workspace = true } test-r = { workspace = true } [build-dependencies] -cargo_metadata = "0.18.1" -tonic-build = "0.11.0" +cargo_metadata = "0.19.1" +tonic-build = "0.12.3" diff --git a/golem-api-grpc/build.rs b/golem-api-grpc/build.rs index 0ea27912b..e1220880e 100644 --- a/golem-api-grpc/build.rs +++ b/golem-api-grpc/build.rs @@ -13,7 +13,7 @@ fn main() -> Result<(), Box> { .extern_path(".wasm.rpc", "::golem_wasm_rpc::protobuf") .extern_path(".wasm.ast", "::golem_wasm_ast::analysis::protobuf") .include_file("mod.rs") - .compile( + .compile_protos( &[ "proto/golem/rib/function_name.proto", "proto/golem/rib/type_name.proto", diff --git a/golem-api-grpc/src/lib.rs b/golem-api-grpc/src/lib.rs index 275b349e3..f72d04608 100644 --- a/golem-api-grpc/src/lib.rs +++ b/golem-api-grpc/src/lib.rs @@ -244,7 +244,7 @@ pub mod proto { value: Some(component_id_uuid), }; let target_worker_id = golem::worker::TargetWorkerId { - component_id: Some(component_id.clone()), + component_id: Some(component_id), name: Some("hello".to_string()), }; let worker_id = golem::worker::WorkerId { diff --git a/golem-cli/Cargo.toml b/golem-cli/Cargo.toml index 0f37bf129..e3b98879b 100644 --- a/golem-cli/Cargo.toml +++ b/golem-cli/Cargo.toml @@ -37,8 +37,8 @@ async_zip = { workspace = true, features = ["tokio", "tokio-fs", "deflate"] } base64 = "0.22.1" chrono = { workspace = true } clap = { workspace = true } -clap-verbosity-flag = "2.1.1" -clap_complete = { version = "4.5.13" } +clap-verbosity-flag = "3.0.1" +clap_complete = { version = "4.5.38" } cli-table = { workspace = true } colored = "2.1.0" derive_more = { workspace = true } @@ -46,17 +46,17 @@ dirs = "5.0.1" futures-util = { workspace = true } glob = "0.3.1" golem-examples = "1.1.0" -h2 = "0.3.24" +h2 = "0.4.7" http = { workspace = true } humansize = { workspace = true } hyper = { workspace = true } -indoc = "2.0.4" +indoc = "2.0.5" inquire = "0.7.5" iso8601 = "0.6.1" itertools = { workspace = true } lenient_bool = "0.1.1" -log = { version = "0.4.22" } -native-tls = "0.2.11" +log = { workspace = true } +native-tls = "0.2.12" openapiv3 = { workspace = true } phf = { workspace = true } rand = { workspace = true } @@ -72,11 +72,11 @@ testcontainers-modules = { workspace = true } textwrap = "0.16.1" tokio = { workspace = true } tokio-stream = { workspace = true, features = ["fs"] } -tokio-tungstenite = { version = "0.20.1", features = ["native-tls"] } -tower = "0.4.13" +tokio-tungstenite = { version = "0.24.0", features = ["native-tls"] } +tower = "0.5.1" tracing = { workspace = true } tracing-subscriber = { workspace = true } -tungstenite = "0.20.1" +tungstenite = "0.24.0" url = { workspace = true } uuid = { workspace = true } version-compare = "=0.0.11" @@ -86,9 +86,9 @@ wasm-wave = { workspace = true } [dev-dependencies] golem-test-framework = { path = "../golem-test-framework", version = "0.0.0" } -async-recursion = "1.0.5" -env_logger = "0.11.1" -log = "0.4.20" +async-recursion = { workspace = true } +env_logger = "0.11.5" +log = "0.4.22" postgres = { workspace = true } rand = { workspace = true } redis = { workspace = true } diff --git a/golem-cli/src/cloud.rs b/golem-cli/src/cloud.rs index 36f85e899..8176e1d45 100644 --- a/golem-cli/src/cloud.rs +++ b/golem-cli/src/cloud.rs @@ -13,7 +13,6 @@ // limitations under the License. use chrono::{DateTime, Utc}; -use derive_more::{Display, FromStr, Into}; use serde::{Deserialize, Serialize}; use std::fmt::{Debug, Display, Formatter}; use uuid::Uuid; @@ -43,12 +42,14 @@ pub struct CloudAuthenticationConfigData { pub expires_at: DateTime, } -#[derive(Clone, PartialEq, Eq, Debug, Display, FromStr, Serialize, Deserialize)] +#[derive( + Clone, PartialEq, Eq, Debug, derive_more::Display, derive_more::FromStr, Serialize, Deserialize, +)] pub struct AccountId { pub id: String, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Into, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, derive_more::Into, Serialize, Deserialize)] pub struct ProjectId(pub Uuid); impl Display for ProjectId { diff --git a/golem-cli/src/config.rs b/golem-cli/src/config.rs index 702d17083..ea521f19e 100644 --- a/golem-cli/src/config.rs +++ b/golem-cli/src/config.rs @@ -15,7 +15,6 @@ use crate::cloud::CloudAuthenticationConfig; use crate::init::CliKind; use crate::model::{Format, GolemError, HasFormatConfig}; -use derive_more::FromStr; use itertools::Itertools; use serde::{Deserialize, Serialize}; use std::collections::HashMap; @@ -45,7 +44,9 @@ pub struct Config { pub active_cloud_profile: Option, } -#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize, FromStr)] +#[derive( + Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize, derive_more::FromStr, +)] pub struct ProfileName(pub String); impl Display for ProfileName { diff --git a/golem-cli/src/model.rs b/golem-cli/src/model.rs index 3d21ec424..72e5e64bf 100644 --- a/golem-cli/src/model.rs +++ b/golem-cli/src/model.rs @@ -29,7 +29,6 @@ use clap::builder::{StringValueParser, TypedValueParser}; use clap::error::{ContextKind, ContextValue, ErrorKind}; use clap::{Arg, ArgMatches, Error, FromArgMatches, ValueEnum}; use clap_verbosity_flag::Verbosity; -use derive_more::{Display, FromStr}; use golem_client::model::{ApiDefinitionInfo, ApiSite, Provider, ScanCursor}; use golem_common::model::plugin::{ComponentPluginScope, DefaultPluginScope}; use golem_common::model::trim_date::TrimDateTime; @@ -339,7 +338,7 @@ impl From<&ComponentUriArg> for ComponentUriOrNameArgs { } } -#[derive(Clone, PartialEq, Eq, Debug, Display, FromStr)] +#[derive(Clone, PartialEq, Eq, Debug, derive_more::Display, derive_more::FromStr)] pub struct ComponentName(pub String); // TODO: Validate #[derive(Clone, PartialEq, Eq, Debug)] @@ -348,10 +347,12 @@ pub struct ComponentUriArg { pub explicit_name: bool, } -#[derive(Clone, PartialEq, Eq, Debug, Display, FromStr)] +#[derive(Clone, PartialEq, Eq, Debug, derive_more::Display, derive_more::FromStr)] pub struct WorkerName(pub String); // TODO: Validate -#[derive(Clone, PartialEq, Eq, Debug, Display, FromStr, Serialize, Deserialize)] +#[derive( + Clone, PartialEq, Eq, Debug, derive_more::Display, derive_more::FromStr, Serialize, Deserialize, +)] pub struct IdempotencyKey(pub String); // TODO: Validate impl IdempotencyKey { @@ -437,7 +438,7 @@ impl FromStr for ApiDefinitionIdWithVersion { } } -#[derive(Clone, PartialEq, Eq, Debug, Display, FromStr)] +#[derive(Clone, PartialEq, Eq, Debug, derive_more::Display, derive_more::FromStr)] pub struct ApiDefinitionId(pub String); // TODO: Validate #[derive(ValueEnum, Clone, Debug)] @@ -456,7 +457,7 @@ impl Display for ApiDefinitionFileFormat { } } -#[derive(Clone, PartialEq, Eq, Debug, Display, FromStr)] +#[derive(Clone, PartialEq, Eq, Debug, derive_more::Display, derive_more::FromStr)] pub struct ApiDefinitionVersion(pub String); // TODO: Validate #[derive(Clone)] @@ -532,7 +533,7 @@ impl FromStr for PathBufOrStdin { } } -#[derive(Clone, PartialEq, Eq, Debug, Display)] +#[derive(Clone, PartialEq, Eq, Debug, derive_more::Display)] pub enum WorkerUpdateMode { Automatic, Manual, diff --git a/golem-cli/src/oss/clients/worker.rs b/golem-cli/src/oss/clients/worker.rs index a9d3e9b92..79c057bfb 100644 --- a/golem-cli/src/oss/clients/worker.rs +++ b/golem-cli/src/oss/clients/worker.rs @@ -309,6 +309,7 @@ impl WorkerClient for WorkerCl .push("connect"); let mut request = url + .to_string() .into_client_request() .map_err(|e| GolemError(format!("Can't create request: {e}")))?; let headers = request.headers_mut(); diff --git a/golem-client/Cargo.toml b/golem-client/Cargo.toml index 3a805f69c..6aee4d829 100644 --- a/golem-client/Cargo.toml +++ b/golem-client/Cargo.toml @@ -34,4 +34,4 @@ test-r = { workspace = true } [build-dependencies] golem-openapi-client-generator = "0.0.12" -relative-path = "1.9.2" +relative-path = "1.9.3" diff --git a/golem-common/Cargo.toml b/golem-common/Cargo.toml index a0ae2ad19..a3d6e3641 100644 --- a/golem-common/Cargo.toml +++ b/golem-common/Cargo.toml @@ -30,8 +30,8 @@ figment = { workspace = true } fred = { workspace = true } futures-core = { workspace = true } git-version = { workspace = true } +http = { workspace = true } humantime-serde = { workspace = true } -http_02 = { workspace = true } iso8601-timestamp = { workspace = true } itertools = { workspace = true } lazy_static = { workspace = true } @@ -57,7 +57,6 @@ tracing-serde = { workspace = true } typed-path = { workspace = true } url = { workspace = true } uuid = { workspace = true } -wasm-wave = { workspace = true } [dev-dependencies] anyhow = { workspace = true } diff --git a/golem-common/src/client.rs b/golem-common/src/client.rs index 201cb344d..13b83830b 100644 --- a/golem-common/src/client.rs +++ b/golem-common/src/client.rs @@ -15,6 +15,7 @@ use crate::config::RetryConfig; use crate::retries::RetryState; use dashmap::DashMap; +use http::Uri; use std::future::Future; use std::pin::Pin; use std::sync::Arc; @@ -26,7 +27,7 @@ use tracing::{debug, debug_span, warn, Instrument}; #[derive(Clone)] pub struct GrpcClient { - endpoint: http_02::Uri, + endpoint: Uri, config: GrpcClientConfig, client: Arc>>>, client_factory: Arc T + Send + Sync + 'static>, @@ -37,7 +38,7 @@ impl GrpcClient { pub fn new( target_name: impl AsRef, client_factory: impl Fn(Channel) -> T + Send + Sync + 'static, - endpoint: http_02::Uri, + endpoint: Uri, config: GrpcClientConfig, ) -> Self { Self { @@ -114,7 +115,7 @@ impl GrpcClient { #[derive(Clone)] pub struct MultiTargetGrpcClient { config: GrpcClientConfig, - clients: Arc>>, + clients: Arc>>, client_factory: Arc T + Send + Sync>, target_name: String, } @@ -136,7 +137,7 @@ impl MultiTargetGrpcClient { pub async fn call( &self, description: impl AsRef, - endpoint: http_02::Uri, + endpoint: Uri, f: F, ) -> Result where @@ -182,10 +183,7 @@ impl MultiTargetGrpcClient { } } - fn get( - &self, - endpoint: http_02::Uri, - ) -> Result, tonic::transport::Error> { + fn get(&self, endpoint: Uri) -> Result, tonic::transport::Error> { let connect_timeout = self.config.connect_timeout; let entry = self .clients diff --git a/golem-common/src/grpc.rs b/golem-common/src/grpc.rs index d991c73a5..898e8eade 100644 --- a/golem-common/src/grpc.rs +++ b/golem-common/src/grpc.rs @@ -23,8 +23,7 @@ use crate::model::{ }; pub fn proto_component_id_string(component_id: &Option) -> Option { - component_id - .clone() + (*component_id) .and_then(|v| TryInto::::try_into(v).ok()) .map(|v| v.to_string()) } @@ -67,8 +66,7 @@ pub fn proto_promise_id_string(promise_id: &Option) -> Option pub fn proto_plugin_installation_id_string( component_id: &Option, ) -> Option { - component_id - .clone() + (*component_id) .and_then(|v| TryInto::::try_into(v).ok()) .map(|v| v.to_string()) } diff --git a/golem-common/src/model/mod.rs b/golem-common/src/model/mod.rs index c7b75e1d6..95dbba6a1 100644 --- a/golem-common/src/model/mod.rs +++ b/golem-common/src/model/mod.rs @@ -26,7 +26,6 @@ use bincode::enc::write::Writer; use bincode::enc::Encoder; use bincode::error::{DecodeError, EncodeError}; use bincode::{BorrowDecode, Decode, Encode}; -use derive_more::FromStr; use golem_api_grpc::proto::golem; use golem_api_grpc::proto::golem::shardmanager::{ Pod as GrpcPod, RoutingTable as GrpcRoutingTable, RoutingTableEntry as GrpcRoutingTableEntry, @@ -727,15 +726,6 @@ impl Pod { .build() .expect("Failed to build URI") } - - pub fn uri_02(&self) -> http_02::Uri { - http_02::Uri::builder() - .scheme("http") - .authority(format!("{}:{}", self.host, self.port).as_str()) - .path_and_query("/") - .build() - .expect("Failed to build URI") - } } impl From for Pod { @@ -1379,7 +1369,7 @@ pub struct TimestampedWorkerInvocation { Debug, PartialOrd, Ord, - FromStr, + derive_more::FromStr, Eq, Hash, PartialEq, @@ -2490,7 +2480,7 @@ impl TryFrom for WorkerEvent { } golem_api_grpc::proto::golem::worker::log_event::Event::Log(event) => { Ok(WorkerEvent::Log { - timestamp: event.timestamp.clone().ok_or("Missing timestamp")?.into(), + timestamp: event.timestamp.ok_or("Missing timestamp")?.into(), level: event.level().into(), context: event.context, message: event.message, diff --git a/golem-common/src/model/plugin.rs b/golem-common/src/model/plugin.rs index cd17a3191..ed2eb7acd 100644 --- a/golem-common/src/model/plugin.rs +++ b/golem-common/src/model/plugin.rs @@ -3,7 +3,6 @@ use crate::model::{ }; use crate::repo::RowMeta; use async_trait::async_trait; -use http_02::Uri; use poem_openapi::types::{ ParseError, ParseFromJSON, ParseFromParameter, ParseResult, ToJSON, Type, }; @@ -459,16 +458,6 @@ impl TryFrom &Uri { - todo!() - } - - pub fn transform_url(&self) -> &Uri { - todo!() - } -} - #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Object)] #[serde(rename_all = "camelCase")] #[oai(rename_all = "camelCase")] diff --git a/golem-common/src/newtype.rs b/golem-common/src/newtype.rs index 09fc11278..6a9332e3d 100644 --- a/golem-common/src/newtype.rs +++ b/golem-common/src/newtype.rs @@ -16,7 +16,16 @@ macro_rules! newtype_uuid { ($name:ident, $proto_type:path) => { #[derive( - Clone, Debug, PartialOrd, Ord, FromStr, Eq, Hash, PartialEq, Serialize, Deserialize, + Clone, + Debug, + PartialOrd, + Ord, + derive_more::FromStr, + Eq, + Hash, + PartialEq, + Serialize, + Deserialize, )] #[serde(transparent)] pub struct $name(pub Uuid); diff --git a/golem-component-compilation-service/Cargo.toml b/golem-component-compilation-service/Cargo.toml index cc6575dbd..f378ce570 100644 --- a/golem-component-compilation-service/Cargo.toml +++ b/golem-component-compilation-service/Cargo.toml @@ -23,9 +23,8 @@ async-trait = { workspace = true } console-subscriber = { workspace = true } figment = { workspace = true } futures = { workspace = true } -futures-util = "0.3.30" +futures-util = "0.3.31" http = { workspace = true } -http_02 = { workspace = true } lazy_static.workspace = true prometheus = { workspace = true } serde = { workspace = true } diff --git a/golem-component-compilation-service/src/lib.rs b/golem-component-compilation-service/src/lib.rs index 966f609d8..319434f76 100644 --- a/golem-component-compilation-service/src/lib.rs +++ b/golem-component-compilation-service/src/lib.rs @@ -172,13 +172,3 @@ fn create_wasmtime_config() -> wasmtime::Config { config } - -pub trait UriBackConversion { - fn as_http_02(&self) -> http_02::Uri; -} - -impl UriBackConversion for http::Uri { - fn as_http_02(&self) -> http_02::Uri { - self.to_string().parse().unwrap() - } -} diff --git a/golem-component-compilation-service/src/service/compile_worker.rs b/golem-component-compilation-service/src/service/compile_worker.rs index a8461da6f..2a08d6754 100644 --- a/golem-component-compilation-service/src/service/compile_worker.rs +++ b/golem-component-compilation-service/src/service/compile_worker.rs @@ -14,7 +14,6 @@ use crate::config::CompileWorkerConfig; use crate::model::*; -use crate::UriBackConversion; use futures_util::TryStreamExt; use golem_api_grpc::proto::golem::component::v1::component_service_client::ComponentServiceClient; use golem_api_grpc::proto::golem::component::v1::download_component_response; @@ -80,7 +79,7 @@ impl CompileWorker { .send_compressed(CompressionEncoding::Gzip) .accept_compressed(CompressionEncoding::Gzip) }, - uri.as_http_02(), + uri, GrpcClientConfig { retries_on_unavailable: config.retries.clone(), ..Default::default() // TODO diff --git a/golem-component-service-base/Cargo.toml b/golem-component-service-base/Cargo.toml index 6f6dfcfdf..989b730db 100644 --- a/golem-component-service-base/Cargo.toml +++ b/golem-component-service-base/Cargo.toml @@ -28,13 +28,12 @@ chrono = { workspace = true } conditional-trait-gen = { workspace = true } futures = { workspace = true } http = { workspace = true } -http_02 = { workspace = true } poem = { workspace = true } poem-openapi = { workspace = true } prost = { workspace = true } prost-types = { workspace = true } reqwest = { workspace = true } -sanitize-filename = "0.5.0" +sanitize-filename = "0.6.0" serde = { workspace = true } serde_json = { workspace = true } sqlx = { workspace = true } @@ -50,7 +49,7 @@ tracing-futures = { version = "0.2.5", features = ["futures-03"] } uuid = { workspace = true } [dev-dependencies] -fastrand = "2.0.2" +fastrand = "2.3.0" testcontainers = { workspace = true } testcontainers-modules = { workspace = true } test-r = { workspace = true } diff --git a/golem-component-service-base/src/config.rs b/golem-component-service-base/src/config.rs index 7ee5e3f78..2b6deb04a 100644 --- a/golem-component-service-base/src/config.rs +++ b/golem-component-service-base/src/config.rs @@ -13,6 +13,7 @@ // limitations under the License. use golem_common::model::Empty; +use http::Uri; use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Serialize, Deserialize)] @@ -66,8 +67,8 @@ pub struct ComponentCompilationEnabledConfig { } impl ComponentCompilationEnabledConfig { - pub fn uri(&self) -> http_02::Uri { - http_02::Uri::builder() + pub fn uri(&self) -> Uri { + Uri::builder() .scheme("http") .authority(format!("{}:{}", self.host, self.port).as_str()) .path_and_query("/") diff --git a/golem-component-service-base/src/service/component_compilation.rs b/golem-component-service-base/src/service/component_compilation.rs index 4e4c0d343..14b48dcb4 100644 --- a/golem-component-service-base/src/service/component_compilation.rs +++ b/golem-component-service-base/src/service/component_compilation.rs @@ -19,6 +19,7 @@ use golem_api_grpc::proto::golem::componentcompilation::v1::{ }; use golem_common::client::{GrpcClient, GrpcClientConfig}; use golem_common::model::ComponentId; +use http::Uri; use tonic::codec::CompressionEncoding; use tonic::transport::Channel; @@ -32,7 +33,7 @@ pub struct ComponentCompilationServiceDefault { } impl ComponentCompilationServiceDefault { - pub fn new(uri: http_02::Uri) -> Self { + pub fn new(uri: Uri) -> Self { let client = GrpcClient::new( "component-compilation-service", |channel| { diff --git a/golem-component-service/Cargo.toml b/golem-component-service/Cargo.toml index 72a42dcf0..dc872edac 100644 --- a/golem-component-service/Cargo.toml +++ b/golem-component-service/Cargo.toml @@ -26,7 +26,6 @@ async-trait = { workspace = true } console-subscriber = { workspace = true } figment = { workspace = true } futures-util = { workspace = true } -http_02 = { workspace = true } humantime-serde = { workspace = true } lazy_static = { workspace = true } mappable-rc = "0.1.1" diff --git a/golem-component-service/src/grpcapi/component.rs b/golem-component-service/src/grpcapi/component.rs index 23f05d635..00ca6082c 100644 --- a/golem-component-service/src/grpcapi/component.rs +++ b/golem-component-service/src/grpcapi/component.rs @@ -87,8 +87,7 @@ impl ComponentGrpcApi { source: &Option, ) -> Result { match source { - Some(id) => id - .clone() + Some(id) => (*id) .try_into() .map_err(|err| bad_request_error(&format!("Invalid component id: {err}"))), None => Err(bad_request_error("Missing component id")), @@ -331,7 +330,6 @@ impl ComponentGrpcApi { let installation_id = request .installation_id - .clone() .and_then(|id| id.try_into().ok()) .ok_or_else(|| bad_request_error("Missing installation id"))?; @@ -360,7 +358,6 @@ impl ComponentGrpcApi { let installation_id = request .installation_id - .clone() .and_then(|id| id.try_into().ok()) .ok_or_else(|| bad_request_error("Missing installation id"))?; @@ -575,8 +572,7 @@ impl ComponentService for ComponentGrpcApi { let record = recorded_grpc_api_request!( "update_component", - component_id = - proto_component_id_string(&header.as_ref().and_then(|r| r.component_id.clone())) + component_id = proto_component_id_string(&header.as_ref().and_then(|r| r.component_id)) ); let result = match header { diff --git a/golem-component-service/src/grpcapi/mod.rs b/golem-component-service/src/grpcapi/mod.rs index fa492e11b..c701c874c 100644 --- a/golem-component-service/src/grpcapi/mod.rs +++ b/golem-component-service/src/grpcapi/mod.rs @@ -45,7 +45,7 @@ pub async fn start_grpc_server( let reflection_service = tonic_reflection::server::Builder::configure() .register_encoded_file_descriptor_set(proto::FILE_DESCRIPTOR_SET) - .build() + .build_v1() .unwrap(); join_set.spawn( diff --git a/golem-component-service/src/grpcapi/plugin.rs b/golem-component-service/src/grpcapi/plugin.rs index 2f868b2d0..6687421c2 100644 --- a/golem-component-service/src/grpcapi/plugin.rs +++ b/golem-component-service/src/grpcapi/plugin.rs @@ -43,8 +43,7 @@ impl PluginGrpcApi { ) -> Result, ComponentError> { let plugins = match &request.scope { Some(scope) => { - let scope = scope - .clone() + let scope = (*scope) .try_into() .map_err(|err| bad_request_error(&format!("Invalid plugin scope: {err}")))?; diff --git a/golem-service-base/Cargo.toml b/golem-service-base/Cargo.toml index 20c8ee8e6..9ca20d536 100644 --- a/golem-service-base/Cargo.toml +++ b/golem-service-base/Cargo.toml @@ -23,6 +23,7 @@ async-fs = { workspace = true } async-hash = { workspace = true } async-trait = { workspace = true } async_zip = { workspace = true, features = ["tokio", "tokio-fs", "deflate"] } +axum = { workspace = true } aws-config = { workspace = true } aws-sdk-s3 = { workspace = true } bigdecimal = { workspace = true } @@ -34,7 +35,6 @@ dashmap = { workspace = true } futures = { workspace = true } hex = { workspace = true } http = { workspace = true } -http_02 = { workspace = true } humantime-serde = { workspace = true } hyper = { workspace = true } lazy_static = { workspace = true} @@ -67,7 +67,6 @@ tracing = { workspace = true } tracing-futures = { version = "0.2.5", features = ["futures-03"] } url = { workspace = true } uuid = { workspace = true } -warp = { workspace = true } wasmtime = { workspace = true } [dev-dependencies] diff --git a/golem-service-base/src/model.rs b/golem-service-base/src/model.rs index 3efc67697..2351a822e 100644 --- a/golem-service-base/src/model.rs +++ b/golem-service-base/src/model.rs @@ -1809,8 +1809,7 @@ impl TryFrom for Component { ) -> Result { let created_at = match &value.created_at { Some(t) => { - let t = - SystemTime::try_from(t.clone()).map_err(|_| "Failed to convert timestamp")?; + let t = SystemTime::try_from(*t).map_err(|_| "Failed to convert timestamp")?; Some(t.into()) } None => None, @@ -1837,7 +1836,6 @@ impl TryFrom for Component { Ok(Self { versioned_component_id: value .versioned_component_id - .clone() .ok_or("Missing versioned_component_id")? .try_into()?, component_name: ComponentName(value.component_name.clone()), diff --git a/golem-service-base/src/observability.rs b/golem-service-base/src/observability.rs index 75067a909..369929384 100644 --- a/golem-service-base/src/observability.rs +++ b/golem-service-base/src/observability.rs @@ -12,14 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -use http_02::{Response, StatusCode}; +use axum::body::Body; +use axum::response::IntoResponse; +use axum::routing::get; +use axum::Router; +use http::Response; use prometheus::{Encoder, Registry, TextEncoder}; use tokio::net::{TcpListener, ToSocketAddrs}; use tokio::task::JoinSet; -use tokio_stream::wrappers::TcpListenerStream; use tracing::{info, Instrument}; -use warp::hyper::Body; -use warp::Filter; pub async fn start_health_and_metrics_server( addr: impl ToSocketAddrs, @@ -27,23 +28,19 @@ pub async fn start_health_and_metrics_server( body_message: &'static str, join_set: &mut JoinSet>, ) -> Result { - let healthcheck = warp::path!("healthcheck").map(move || { - Response::builder() - .status(StatusCode::OK) - .body(Body::from(body_message)) - .unwrap() - }); + let app = Router::new() + .route("/healthcheck", get(move || async move { body_message })) + .route( + "/metrics", + get(|| async move { prometheus_metrics(registry.clone()) }), + ); let listener = TcpListener::bind(addr).await?; let local_addr = listener.local_addr()?; - let metrics = warp::path!("metrics").map(move || prometheus_metrics(registry.clone())); - join_set.spawn( async move { - warp::serve(healthcheck.or(metrics)) - .run_incoming(TcpListenerStream::new(listener)) - .await; + axum::serve(listener, app).await?; Ok(()) } .in_current_span(), @@ -54,7 +51,7 @@ pub async fn start_health_and_metrics_server( Ok(local_addr.port()) } -fn prometheus_metrics(registry: Registry) -> Response { +fn prometheus_metrics(registry: Registry) -> impl IntoResponse { let encoder = TextEncoder::new(); let mut buffer = Vec::new(); diff --git a/golem-service-base/src/service/routing_table.rs b/golem-service-base/src/service/routing_table.rs index ec2a80501..2da3f9620 100644 --- a/golem-service-base/src/service/routing_table.rs +++ b/golem-service-base/src/service/routing_table.rs @@ -18,6 +18,7 @@ use std::sync::Arc; use std::time::Duration; use async_trait::async_trait; +use http::Uri; use serde::Deserialize; use serde::Serialize; use tokio::sync::RwLock; @@ -100,7 +101,7 @@ pub struct RoutingTableConfig { } impl RoutingTableConfig { - pub fn url(&self) -> http_02::Uri { + pub fn url(&self) -> Uri { format!("http://{}:{}", self.host, self.port) .parse() .expect("Failed to parse shard manager URL") diff --git a/golem-shard-manager/Cargo.toml b/golem-shard-manager/Cargo.toml index 6287297ee..fc485ef14 100644 --- a/golem-shard-manager/Cargo.toml +++ b/golem-shard-manager/Cargo.toml @@ -27,7 +27,6 @@ figment = { workspace = true } fred = { workspace = true } futures = { workspace = true } http = { workspace = true } -http_02 = { workspace = true } humantime-serde = { workspace = true } itertools = { workspace = true } k8s-openapi = { workspace = true, optional = true } @@ -46,10 +45,9 @@ tonic-reflection = { workspace = true } tracing = { workspace = true } tracing-subscriber = { workspace = true } url = { workspace = true } -warp = { workspace = true } [dev-dependencies] -tracing-test = "0.2.4" +tracing-test = "0.2.5" test-r = { workspace = true } [features] diff --git a/golem-shard-manager/src/lib.rs b/golem-shard-manager/src/lib.rs index 79efc1cb4..7f2693e64 100644 --- a/golem-shard-manager/src/lib.rs +++ b/golem-shard-manager/src/lib.rs @@ -226,7 +226,7 @@ pub async fn run( let reflection_service = tonic_reflection::server::Builder::configure() .register_encoded_file_descriptor_set(proto::FILE_DESCRIPTOR_SET) - .build()?; + .build_v1()?; info!("Golem Shard Manager starting up..."); diff --git a/golem-shard-manager/src/model.rs b/golem-shard-manager/src/model.rs index 6bb4ae6bc..c957e26b1 100644 --- a/golem-shard-manager/src/model.rs +++ b/golem-shard-manager/src/model.rs @@ -20,6 +20,7 @@ use std::net::{IpAddr, SocketAddr, ToSocketAddrs}; use std::{fmt, vec}; use bincode::{Decode, Encode}; +use http::Uri; use itertools::Itertools; use serde::{Deserialize, Serialize}; use tonic::transport::Endpoint; @@ -56,8 +57,8 @@ impl Pod { Endpoint::from(self.uri()) } - pub fn uri(&self) -> http_02::Uri { - http_02::Uri::builder() + pub fn uri(&self) -> Uri { + Uri::builder() .scheme("http") .authority(format!("{}:{}", self.ip, self.port).as_str()) .path_and_query("") diff --git a/golem-test-framework/Cargo.toml b/golem-test-framework/Cargo.toml index bea5edf89..9c63b8bd8 100644 --- a/golem-test-framework/Cargo.toml +++ b/golem-test-framework/Cargo.toml @@ -23,9 +23,9 @@ async-dropper-simple = { version = "0.2.6", features = ["no-default-bound"] } async-scoped = "0.9.0" async-trait = { workspace = true } bytes = { workspace = true } +chrono = { workspace = true } clap = { workspace = true } cli-table = { workspace = true } -chrono = { workspace = true } colored = "2.1.0" console-subscriber = { workspace = true } itertools = { workspace = true } @@ -33,6 +33,7 @@ k8s-openapi = { workspace = true } kill_tree = { version = "0.2.4", features = ["tokio"] } kube = { workspace = true } kube-derive = { workspace = true } +log = { workspace = true } once_cell = { workspace = true } postgres = { workspace = true } redis = { workspace = true } @@ -49,7 +50,6 @@ tracing = { workspace = true } tracing-subscriber = { workspace = true } url = { workspace = true } uuid = { workspace = true } -log = { version = "0.4.22", features = [] } [dev-dependencies] test-r = { workspace = true } diff --git a/golem-test-framework/src/components/redis/mod.rs b/golem-test-framework/src/components/redis/mod.rs index 29bc2ddf9..12248cad5 100644 --- a/golem-test-framework/src/components/redis/mod.rs +++ b/golem-test-framework/src/components/redis/mod.rs @@ -75,7 +75,7 @@ pub trait Redis { fn flush_db(&self, db: u16) { let mut connection = self.get_connection(db); - redis::cmd("FLUSHDB").execute(&mut connection) + redis::cmd("FLUSHDB").exec(&mut connection).unwrap() } } diff --git a/golem-test-framework/src/components/worker_service/forwarding.rs b/golem-test-framework/src/components/worker_service/forwarding.rs index 62be6722c..3ca121346 100644 --- a/golem-test-framework/src/components/worker_service/forwarding.rs +++ b/golem-test-framework/src/components/worker_service/forwarding.rs @@ -81,13 +81,12 @@ impl WorkerService for ForwardingWorkerService { &self, request: LaunchNewWorkerRequest, ) -> crate::Result { - let component_id = request + let component_id = (*request .component_id .as_ref() - .ok_or(anyhow!("Requires component ID"))? - .clone() - .try_into() - .map_err(|err: String| anyhow!(err))?; + .ok_or(anyhow!("Requires component ID"))?) + .try_into() + .map_err(|err: String| anyhow!(err))?; let worker_id = WorkerId { component_id: request.component_id, name: request.name, @@ -618,7 +617,7 @@ impl WorkerService for ForwardingWorkerService { .into(), ), from_oplog_index: request.from_oplog_index, - cursor: request.cursor.clone(), + cursor: request.cursor, count: request.count, }) .await; diff --git a/golem-test-framework/src/config/env.rs b/golem-test-framework/src/config/env.rs index a8fc10fa2..98e7a48f5 100644 --- a/golem-test-framework/src/config/env.rs +++ b/golem-test-framework/src/config/env.rs @@ -416,7 +416,7 @@ impl EnvBasedTestDependencies { let redis = Self::make_redis(config.clone()).await; { let mut connection = redis.get_connection(0); - redis::cmd("FLUSHALL").execute(&mut connection); + redis::cmd("FLUSHALL").exec(&mut connection).unwrap(); } let rdb_and_component_service_join = { diff --git a/golem-test-framework/src/dsl/mod.rs b/golem-test-framework/src/dsl/mod.rs index 66686794f..05154e861 100644 --- a/golem-test-framework/src/dsl/mod.rs +++ b/golem-test-framework/src/dsl/mod.rs @@ -912,7 +912,7 @@ impl TestDsl for T { .get_oplog(GetOplogRequest { worker_id: Some(worker_id.clone().into()), from_oplog_index: from.into(), - cursor: cursor.clone(), + cursor, count: 100, }) .await?; @@ -961,7 +961,7 @@ impl TestDsl for T { .worker_service() .search_oplog(SearchOplogRequest { worker_id: Some(worker_id.clone().into()), - cursor: cursor.clone(), + cursor, count: 100, query: query.to_string(), }) @@ -1323,12 +1323,7 @@ pub fn to_worker_metadata( .expect("no account_id") .clone() .into(), - created_at: metadata - .created_at - .as_ref() - .expect("no created_at") - .clone() - .into(), + created_at: (*metadata.created_at.as_ref().expect("no created_at")).into(), last_known_status: WorkerStatusRecord { oplog_idx: OplogIndex::default(), status: metadata.status.try_into().expect("invalid status"), @@ -1340,12 +1335,11 @@ pub fn to_worker_metadata( .iter() .filter_map(|u| match &u.update { Some(Update::Pending(_)) => Some(TimestampedUpdateDescription { - timestamp: u + timestamp: (*u .timestamp .as_ref() - .expect("no timestamp on update record") - .clone() - .into(), + .expect("no timestamp on update record")) + .into(), oplog_index: OplogIndex::from_u64(0), description: UpdateDescription::Automatic { target_version: u.target_version, @@ -1359,12 +1353,11 @@ pub fn to_worker_metadata( .iter() .filter_map(|u| match &u.update { Some(Update::Failed(failed_update)) => Some(FailedUpdateRecord { - timestamp: u + timestamp: (*u .timestamp .as_ref() - .expect("no timestamp on update record") - .clone() - .into(), + .expect("no timestamp on update record")) + .into(), target_version: u.target_version, details: failed_update.details.clone(), }), @@ -1376,12 +1369,11 @@ pub fn to_worker_metadata( .iter() .filter_map(|u| match &u.update { Some(Update::Successful(_)) => Some(SuccessfulUpdateRecord { - timestamp: u + timestamp: (*u .timestamp .as_ref() - .expect("no timestamp on update record") - .clone() - .into(), + .expect("no timestamp on update record")) + .into(), target_version: u.target_version, }), _ => None, @@ -1399,12 +1391,11 @@ pub fn to_worker_metadata( ( WorkerResourceId(*k), WorkerResourceDescription { - created_at: v + created_at: (*v .created_at .as_ref() - .expect("no timestamp on resource metadata") - .clone() - .into(), + .expect("no timestamp on resource metadata")) + .into(), indexed_resource_key: v.indexed.clone().map(|i| i.into()), }, ) diff --git a/golem-worker-executor-base/Cargo.toml b/golem-worker-executor-base/Cargo.toml index f245b2331..ac95d1c4c 100644 --- a/golem-worker-executor-base/Cargo.toml +++ b/golem-worker-executor-base/Cargo.toml @@ -33,46 +33,45 @@ async-trait = { workspace = true } aws-config = { workspace = true } aws-sdk-s3 = { workspace = true } bincode = { workspace = true } -bitflags = "2.4.2" +bitflags = "2.6.0" bytes = { workspace = true } -cap-fs-ext = "3.0.0" # keep in sync with wasmtime +cap-fs-ext = "3.4.2" # keep in sync with wasmtime cap-std = { workspace = true } -cap-time-ext = "3.0.0" # keep in sync with wasmtime +cap-time-ext = "3.4.2" # keep in sync with wasmtime chrono = { workspace = true } dashmap = { workspace = true } drop-stream = { workspace = true } evicting_cache_map = "0.4.0" figment = { workspace = true } -flume = "0.11.0" +flume = "0.11.1" fred = { workspace = true } -fs-set-times = "0.20.1" +fs-set-times = "0.20.2" futures = { workspace = true } futures-util = { workspace = true } -gethostname = "0.4.3" +gethostname = "0.5.0" golem-wit = { version = "=1.1.0" } hex = { workspace = true } http = { workspace = true } -http_02 = { workspace = true } -http-body = "1.0.0" # keep in sync with wasmtime +http-body = "1.0.1" # keep in sync with wasmtime humansize = { workspace = true } humantime-serde = { workspace = true } hyper = { workspace = true } -io-extras = "0.18.0" +io-extras = "0.18.4" iso8601-timestamp = { workspace = true } itertools = { workspace = true } lazy_static = { workspace = true } -log = "0.4.20" +log = "0.4.22" md5 = "0.7.0" -metrohash = "1.0.6" -nonempty-collections = "0.2.5" +metrohash = "1.0.7" +nonempty-collections = "0.2.9" prometheus = { workspace = true } prost = { workspace = true } rand = { workspace = true } -ringbuf = "0.4.1" +ringbuf = "0.4.7" rustls = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } -sysinfo = "0.30.12" +sysinfo = "0.33.0" tempfile = { workspace = true } thiserror = { workspace = true } tokio = { workspace = true } @@ -85,11 +84,10 @@ tonic-reflection = { workspace = true } tracing = { workspace = true } url = { workspace = true } uuid = { workspace = true } -warp = { workspace = true } wasmtime = { workspace = true } wasmtime-wasi = { workspace = true } wasmtime-wasi-http = { workspace = true } -windows-sys = "0.52.0" +windows-sys = "0.59.0" zstd = "0.13" sqlx = { workspace = true } @@ -97,8 +95,9 @@ sqlx = { workspace = true } golem-test-framework = { path = "../golem-test-framework", version = "0.0.0" } assert2 = { workspace = true } +axum = { workspace = true } console-subscriber = { workspace = true } -goldenfile = "1.7.1" +goldenfile = "1.7.3" once_cell = { workspace = true } proptest = { workspace = true } rand = { workspace = true } @@ -108,10 +107,9 @@ testcontainers = { workspace = true } testcontainers-modules = { workspace = true } test-r = { workspace = true } tracing-subscriber = { workspace = true } -warp = { workspace = true } [build-dependencies] -cargo_metadata = "0.18.1" +cargo_metadata = "0.19.1" [[test]] name = "integration" diff --git a/golem-worker-executor-base/src/grpc.rs b/golem-worker-executor-base/src/grpc.rs index e0d8e46a2..2fe1cc89c 100644 --- a/golem-worker-executor-base/src/grpc.rs +++ b/golem-worker-executor-base/src/grpc.rs @@ -2398,7 +2398,7 @@ impl CanStartWorker for golem::workerexecutor::v1::ListDirectoryRequest { } fn account_limits(&self) -> Option { - self.account_limits.clone() + self.account_limits } fn worker_id(&self) -> Result { @@ -2432,7 +2432,7 @@ impl CanStartWorker for golem::workerexecutor::v1::GetFileContentsRequest { } fn account_limits(&self) -> Option { - self.account_limits.clone() + self.account_limits } fn worker_id(&self) -> Result { @@ -2466,7 +2466,7 @@ impl CanStartWorker for golem::workerexecutor::v1::InvokeWorkerRequest { } fn account_limits(&self) -> Option { - self.account_limits.clone() + self.account_limits } fn worker_id(&self) -> Result { @@ -2520,7 +2520,7 @@ impl CanStartWorker for golem::workerexecutor::v1::InvokeAndAwaitWorkerRequest { } fn account_limits(&self) -> Option { - self.account_limits.clone() + self.account_limits } fn worker_id(&self) -> Result { @@ -2564,16 +2564,6 @@ impl GrpcInvokeRequest for golem::workerexecutor::v1::InvokeAndAwaitWorkerReques } } -pub trait UriBackConversion { - fn as_http_02(&self) -> http_02::Uri; -} - -impl UriBackConversion for http::Uri { - fn as_http_02(&self) -> http_02::Uri { - self.to_string().parse().unwrap() - } -} - pub fn authorised_grpc_request(request: T, access_token: &Uuid) -> Request { let mut req = Request::new(request); req.metadata_mut().insert( diff --git a/golem-worker-executor-base/src/lib.rs b/golem-worker-executor-base/src/lib.rs index a630e23d2..ca93f75ad 100644 --- a/golem-worker-executor-base/src/lib.rs +++ b/golem-worker-executor-base/src/lib.rs @@ -200,7 +200,7 @@ pub trait Bootstrap { let reflection_service = tonic_reflection::server::Builder::configure() .register_encoded_file_descriptor_set(proto::FILE_DESCRIPTOR_SET) - .build()?; + .build_v1()?; let http_port = golem_service_base::observability::start_health_and_metrics_server( golem_config.http_addr()?, diff --git a/golem-worker-executor-base/src/services/component.rs b/golem-worker-executor-base/src/services/component.rs index 2a32298fd..fba3a95fd 100644 --- a/golem-worker-executor-base/src/services/component.rs +++ b/golem-worker-executor-base/src/services/component.rs @@ -17,7 +17,7 @@ use std::sync::Arc; use std::time::{Duration, Instant}; use crate::error::GolemError; -use crate::grpc::{authorised_grpc_request, is_grpc_retriable, GrpcError, UriBackConversion}; +use crate::grpc::{authorised_grpc_request, is_grpc_retriable, GrpcError}; use crate::metrics::component::record_compilation_time; use crate::services::compiled_component; use crate::services::compiled_component::CompiledComponentService; @@ -167,7 +167,7 @@ impl ComponentServiceGrpc { .send_compressed(CompressionEncoding::Gzip) .accept_compressed(CompressionEncoding::Gzip) }, - endpoint.as_http_02(), + endpoint, GrpcClientConfig { retries_on_unavailable: retry_config.clone(), ..Default::default() // TODO @@ -476,9 +476,7 @@ async fn get_metadata_via_grpc( memories: component .metadata .as_ref() - .map(|metadata| { - metadata.memories.iter().map(|m| m.clone().into()).collect() - }) + .map(|metadata| metadata.memories.iter().map(|m| (*m).into()).collect()) .unwrap_or_default(), exports: component .metadata diff --git a/golem-worker-executor-base/src/services/plugins.rs b/golem-worker-executor-base/src/services/plugins.rs index ddd8cd722..3ae838f93 100644 --- a/golem-worker-executor-base/src/services/plugins.rs +++ b/golem-worker-executor-base/src/services/plugins.rs @@ -13,7 +13,7 @@ // limitations under the License. use crate::error::GolemError; -use crate::grpc::{authorised_grpc_request, UriBackConversion}; +use crate::grpc::authorised_grpc_request; use crate::services::golem_config::PluginServiceConfig; use async_trait::async_trait; use golem_api_grpc::proto::golem::component::v1::component_service_client::ComponentServiceClient; @@ -284,7 +284,7 @@ impl DefaultGrpcPlugins { .send_compressed(CompressionEncoding::Gzip) .accept_compressed(CompressionEncoding::Gzip) }, - endpoint.as_http_02(), + endpoint.clone(), GrpcClientConfig { retries_on_unavailable: retry_config.clone(), ..Default::default() // TODO @@ -297,7 +297,7 @@ impl DefaultGrpcPlugins { .send_compressed(CompressionEncoding::Gzip) .accept_compressed(CompressionEncoding::Gzip) }, - endpoint.as_http_02(), + endpoint, GrpcClientConfig { retries_on_unavailable: retry_config.clone(), ..Default::default() diff --git a/golem-worker-executor-base/src/services/shard_manager.rs b/golem-worker-executor-base/src/services/shard_manager.rs index 4ff830084..b8a38f75e 100644 --- a/golem-worker-executor-base/src/services/shard_manager.rs +++ b/golem-worker-executor-base/src/services/shard_manager.rs @@ -25,7 +25,6 @@ use tonic::codec::CompressionEncoding; use tonic::transport::Channel; use crate::error::GolemError; -use crate::grpc::UriBackConversion; use crate::services::golem_config::{ShardManagerServiceConfig, ShardManagerServiceGrpcConfig}; /// Service providing access to the shard manager service @@ -59,7 +58,7 @@ impl ShardManagerServiceGrpc { .send_compressed(CompressionEncoding::Gzip) .accept_compressed(CompressionEncoding::Gzip) }, - config.uri().as_http_02(), + config.uri(), GrpcClientConfig { retries_on_unavailable: config.retries.clone(), ..Default::default() diff --git a/golem-worker-executor-base/src/services/worker_proxy.rs b/golem-worker-executor-base/src/services/worker_proxy.rs index 265f0f7fd..8ffb19043 100644 --- a/golem-worker-executor-base/src/services/worker_proxy.rs +++ b/golem-worker-executor-base/src/services/worker_proxy.rs @@ -13,7 +13,7 @@ // limitations under the License. use crate::error::GolemError; -use crate::grpc::{authorised_grpc_request, UriBackConversion}; +use crate::grpc::authorised_grpc_request; use async_trait::async_trait; use bincode::{Decode, Encode}; use golem_api_grpc::proto::golem::worker::v1::worker_service_client::WorkerServiceClient; @@ -157,7 +157,7 @@ impl RemoteWorkerProxy { .send_compressed(CompressionEncoding::Gzip) .accept_compressed(CompressionEncoding::Gzip) }, - endpoint.as_http_02(), + endpoint, Default::default(), // TODO ), access_token, diff --git a/golem-worker-executor-base/tests/api.rs b/golem-worker-executor-base/tests/api.rs index 755dc3a6b..e81ab3df9 100644 --- a/golem-worker-executor-base/tests/api.rs +++ b/golem-worker-executor-base/tests/api.rs @@ -14,41 +14,37 @@ use test_r::{inherit_test_dep, test}; -use std::collections::HashMap; -use std::env; -use std::io::Write; -use std::net::SocketAddr; -use std::os::unix::fs::FileExt; -use std::path::Path; -use std::sync::{Arc, Mutex}; -use std::time::{Duration, Instant}; - +use crate::common::{start, TestContext, TestWorkerExecutor}; +use crate::compatibility::worker_recovery::save_recovery_golden_file; +use crate::{LastUniqueId, Tracing, WorkerExecutorTestDependencies}; use assert2::check; -use http_02::{Response, StatusCode}; -use redis::Commands; - +use axum::routing::get; +use axum::Router; use golem_api_grpc::proto::golem::worker::v1::{worker_execution_error, ComponentParseFailed}; use golem_api_grpc::proto::golem::workerexecutor::v1::CompletePromiseRequest; +use golem_common::model::oplog::{IndexedResourceKey, OplogIndex, WorkerResourceId}; use golem_common::model::{ AccountId, ComponentId, FilterComparator, IdempotencyKey, PromiseId, ScanCursor, StringFilterComparator, TargetWorkerId, Timestamp, WorkerFilter, WorkerId, WorkerMetadata, WorkerResourceDescription, WorkerStatus, }; -use golem_wasm_rpc::Value; - -use crate::common::{start, TestContext, TestWorkerExecutor}; -use crate::compatibility::worker_recovery::save_recovery_golden_file; -use crate::{LastUniqueId, Tracing, WorkerExecutorTestDependencies}; -use golem_common::model::oplog::{IndexedResourceKey, OplogIndex, WorkerResourceId}; use golem_test_framework::config::TestDependencies; use golem_test_framework::dsl::{ drain_connection, is_worker_execution_error, stdout_event_matching, stdout_events, worker_error_message, TestDslUnsafe, }; +use golem_wasm_rpc::Value; +use redis::Commands; +use std::collections::HashMap; +use std::env; +use std::io::Write; +use std::net::SocketAddr; +use std::os::unix::fs::FileExt; +use std::path::Path; +use std::sync::{Arc, Mutex}; +use std::time::{Duration, Instant}; use tokio::time::sleep; -use tonic::transport::Body; use tracing::{debug, info}; -use warp::Filter; use wasmtime_wasi::runtime::spawn; inherit_test_dep!(WorkerExecutorTestDependencies); @@ -213,7 +209,7 @@ async fn shopping_cart_example( .invoke_and_await(&worker_id, "golem:it/api.{checkout}", vec![]) .await; - save_recovery_golden_file(&executor, "shopping_cart_example", &worker_id).await; + save_recovery_golden_file(&executor, &context, "shopping_cart_example", &worker_id).await; drop(executor); check!( @@ -1615,21 +1611,22 @@ async fn long_running_poll_loop_works_as_expected( let host_http_port = context.host_http_port(); let http_server = tokio::spawn(async move { - let route = warp::path::path("poll").and(warp::get()).map(move || { - let body = response_clone.lock().unwrap(); - Response::builder() - .status(StatusCode::OK) - .body(Body::from(body.clone())) - .unwrap() - }); - - warp::serve(route) - .run( - format!("0.0.0.0:{}", host_http_port) - .parse::() - .unwrap(), - ) - .await; + let route = Router::new().route( + "/poll", + get(move || async move { + let body = response_clone.lock().unwrap(); + body.clone() + }), + ); + + let listener = tokio::net::TcpListener::bind( + format!("0.0.0.0:{}", host_http_port) + .parse::() + .unwrap(), + ) + .await + .unwrap(); + axum::serve(listener, route).await.unwrap(); }); let component_id = executor.store_component("http-client-2").await; @@ -1682,21 +1679,22 @@ async fn long_running_poll_loop_interrupting_and_resuming_by_second_invocation( let host_http_port = context.host_http_port(); let http_server = tokio::spawn(async move { - let route = warp::path::path("poll").and(warp::get()).map(move || { - let body = response_clone.lock().unwrap(); - Response::builder() - .status(StatusCode::OK) - .body(Body::from(body.clone())) - .unwrap() - }); - - warp::serve(route) - .run( - format!("0.0.0.0:{}", host_http_port) - .parse::() - .unwrap(), - ) - .await; + let route = Router::new().route( + "/poll", + get(move || async move { + let body = response_clone.lock().unwrap(); + body.clone() + }), + ); + + let listener = tokio::net::TcpListener::bind( + format!("0.0.0.0:{}", host_http_port) + .parse::() + .unwrap(), + ) + .await + .unwrap(); + axum::serve(listener, route).await.unwrap(); }); let component_id = executor.store_component("http-client-2").await; @@ -1808,21 +1806,22 @@ async fn long_running_poll_loop_connection_breaks_on_interrupt( let host_http_port = context.host_http_port(); let http_server = tokio::spawn(async move { - let route = warp::path::path("poll").and(warp::get()).map(move || { - let body = response_clone.lock().unwrap(); - Response::builder() - .status(StatusCode::OK) - .body(Body::from(body.clone())) - .unwrap() - }); - - warp::serve(route) - .run( - format!("0.0.0.0:{}", host_http_port) - .parse::() - .unwrap(), - ) - .await; + let route = Router::new().route( + "/poll", + get(move || async move { + let body = response_clone.lock().unwrap(); + body.clone() + }), + ); + + let listener = tokio::net::TcpListener::bind( + format!("0.0.0.0:{}", host_http_port) + .parse::() + .unwrap(), + ) + .await + .unwrap(); + axum::serve(listener, route).await.unwrap(); }); let component_id = executor.store_component("http-client-2").await; @@ -1888,21 +1887,22 @@ async fn long_running_poll_loop_connection_retry_does_not_resume_interrupted_wor let host_http_port = context.host_http_port(); let http_server = tokio::spawn(async move { - let route = warp::path::path("poll").and(warp::get()).map(move || { - let body = response_clone.lock().unwrap(); - Response::builder() - .status(StatusCode::OK) - .body(Body::from(body.clone())) - .unwrap() - }); - - warp::serve(route) - .run( - format!("0.0.0.0:{}", host_http_port) - .parse::() - .unwrap(), - ) - .await; + let route = Router::new().route( + "/poll", + get(move || async move { + let body = response_clone.lock().unwrap(); + body.clone() + }), + ); + + let listener = tokio::net::TcpListener::bind( + format!("0.0.0.0:{}", host_http_port) + .parse::() + .unwrap(), + ) + .await + .unwrap(); + axum::serve(listener, route).await.unwrap(); }); let component_id = executor.store_component("http-client-2").await; @@ -1958,21 +1958,22 @@ async fn long_running_poll_loop_connection_can_be_restored_after_resume( let host_http_port = context.host_http_port(); let http_server = tokio::spawn(async move { - let route = warp::path::path("poll").and(warp::get()).map(move || { - let body = response_clone.lock().unwrap(); - Response::builder() - .status(StatusCode::OK) - .body(Body::from(body.clone())) - .unwrap() - }); - - warp::serve(route) - .run( - format!("0.0.0.0:{}", host_http_port) - .parse::() - .unwrap(), - ) - .await; + let route = Router::new().route( + "/poll", + get(move || async move { + let body = response_clone.lock().unwrap(); + body.clone() + }), + ); + + let listener = tokio::net::TcpListener::bind( + format!("0.0.0.0:{}", host_http_port) + .parse::() + .unwrap(), + ) + .await + .unwrap(); + axum::serve(listener, route).await.unwrap(); }); let component_id = executor.store_component("http-client-2").await; @@ -2059,21 +2060,22 @@ async fn long_running_poll_loop_worker_can_be_deleted_after_interrupt( let host_http_port = context.host_http_port(); let http_server = tokio::spawn(async move { - let route = warp::path::path("poll").and(warp::get()).map(move || { - let body = response_clone.lock().unwrap(); - Response::builder() - .status(StatusCode::OK) - .body(Body::from(body.clone())) - .unwrap() - }); - - warp::serve(route) - .run( - format!("0.0.0.0:{}", host_http_port) - .parse::() - .unwrap(), - ) - .await; + let route = Router::new().route( + "/poll", + get(move || async move { + let body = response_clone.lock().unwrap(); + body.clone() + }), + ); + + let listener = tokio::net::TcpListener::bind( + format!("0.0.0.0:{}", host_http_port) + .parse::() + .unwrap(), + ) + .await + .unwrap(); + axum::serve(listener, route).await.unwrap(); }); let component_id = executor.store_component("http-client-2").await; @@ -2565,21 +2567,22 @@ async fn invocation_queue_is_persistent( let host_http_port = context.host_http_port(); let http_server = tokio::spawn(async move { - let route = warp::path::path("poll").and(warp::get()).map(move || { - let body = response_clone.lock().unwrap(); - Response::builder() - .status(StatusCode::OK) - .body(Body::from(body.clone())) - .unwrap() - }); - - warp::serve(route) - .run( - format!("0.0.0.0:{}", host_http_port) - .parse::() - .unwrap(), - ) - .await; + let route = Router::new().route( + "/poll", + get(move || async move { + let body = response_clone.lock().unwrap(); + body.clone() + }), + ); + + let listener = tokio::net::TcpListener::bind( + format!("0.0.0.0:{}", host_http_port) + .parse::() + .unwrap(), + ) + .await + .unwrap(); + axum::serve(listener, route).await.unwrap(); }); let component_id = executor.store_component("http-client-2").await; diff --git a/golem-worker-executor-base/tests/compatibility/worker_recovery.rs b/golem-worker-executor-base/tests/compatibility/worker_recovery.rs index caf834e8e..48a11d4ee 100644 --- a/golem-worker-executor-base/tests/compatibility/worker_recovery.rs +++ b/golem-worker-executor-base/tests/compatibility/worker_recovery.rs @@ -40,9 +40,13 @@ async fn recover_shopping_cart_example( let context = TestContext::new(last_unique_id); let executor = start(deps, &context).await.unwrap(); - let worker_id = - restore_from_recovery_golden_file(&executor, "shopping_cart_example", &["shopping-cart"]) - .await; + let worker_id = restore_from_recovery_golden_file( + &executor, + &context, + "shopping_cart_example", + &["shopping-cart"], + ) + .await; executor.interrupt(&worker_id).await; executor.resume(&worker_id).await; @@ -63,6 +67,7 @@ async fn recover_shopping_cart_resource_example( let worker_id = restore_from_recovery_golden_file( &executor, + &context, "shopping_cart_resource_example", &["shopping-cart-resource"], ) @@ -87,6 +92,7 @@ async fn recover_environment_example( let worker_id = restore_from_recovery_golden_file( &executor, + &context, "environment_example", &["environment-service"], ) @@ -110,7 +116,8 @@ async fn recover_read_stdin( let executor = start(deps, &context).await.unwrap(); let worker_id = - restore_from_recovery_golden_file(&executor, "read_stdin_fails", &["read-stdin"]).await; + restore_from_recovery_golden_file(&executor, &context, "read_stdin_fails", &["read-stdin"]) + .await; executor.interrupt(&worker_id).await; let _ = golem_test_framework::dsl::TestDsl::resume(&executor, &worker_id).await; // this fails but we don't mind @@ -130,7 +137,7 @@ async fn recover_jump( let executor = start(deps, &context).await.unwrap(); let worker_id = - restore_from_recovery_golden_file(&executor, "jump", &["runtime-service"]).await; + restore_from_recovery_golden_file(&executor, &context, "jump", &["runtime-service"]).await; executor.interrupt(&worker_id).await; executor.resume(&worker_id).await; @@ -149,7 +156,8 @@ async fn recover_js_example_1( let context = TestContext::new(last_unique_id); let executor = start(deps, &context).await.unwrap(); - let worker_id = restore_from_recovery_golden_file(&executor, "js_example_1", &["js-1"]).await; + let worker_id = + restore_from_recovery_golden_file(&executor, &context, "js_example_1", &["js-1"]).await; executor.interrupt(&worker_id).await; executor.resume(&worker_id).await; @@ -170,6 +178,7 @@ async fn recover_auto_update_on_running( let worker_id = restore_from_recovery_golden_file( &executor, + &context, "auto_update_on_running", &["update-test-v1", "update-test-v2"], ) @@ -194,12 +203,14 @@ async fn recover_counter_resource_test_2( let caller_worker_id = restore_from_recovery_golden_file( &executor, + &context, "counter_resource_test_2_caller", &["caller_composed"], ) .await; let counter_worker_id = restore_from_recovery_golden_file( &executor, + &context, "counter_resource_test_2_counter", &["counters"], ) @@ -215,6 +226,7 @@ async fn recover_counter_resource_test_2( async fn restore_from_recovery_golden_file( executor: &TestWorkerExecutor, + context: &TestContext, name: &str, component_names: &[&str], ) -> WorkerId { @@ -245,7 +257,7 @@ async fn restore_from_recovery_golden_file( let oplog_key = &format!( "{}worker:oplog:{}", - executor.redis().prefix(), + context.redis_prefix(), worker_id.to_redis_key() ); @@ -277,6 +289,7 @@ async fn restore_from_recovery_golden_file( /// files should be verified (if they can be recovered) in separate test cases. pub async fn save_recovery_golden_file( executor: &TestWorkerExecutor, + context: &TestContext, name: &str, worker_id: &WorkerId, ) { @@ -288,7 +301,7 @@ pub async fn save_recovery_golden_file( let entries: Vec>>> = redis .xrange_all(format!( "{}worker:oplog:{}", - executor.redis().prefix(), + context.redis_prefix(), worker_id.to_redis_key() )) .await diff --git a/golem-worker-executor-base/tests/guest_languages1.rs b/golem-worker-executor-base/tests/guest_languages1.rs index 8e5c84f70..938a97b44 100644 --- a/golem-worker-executor-base/tests/guest_languages1.rs +++ b/golem-worker-executor-base/tests/guest_languages1.rs @@ -18,14 +18,16 @@ use assert2::{assert, check}; use std::collections::HashMap; use std::net::SocketAddr; +use axum::response::IntoResponse; +use axum::routing::post; +use axum::Router; +use bytes::Bytes; use chrono::Datelike; use golem_test_framework::dsl::{log_event_to_string, TestDslUnsafe}; use golem_wasm_rpc::Value; -use http_02::{Response, StatusCode}; +use http::HeaderMap; use std::sync::{Arc, Mutex}; use std::time::{Duration, Instant}; -use tonic::transport::Body; -use warp::Filter; use crate::common::{start, TestContext}; use crate::{LastUniqueId, Tracing, WorkerExecutorTestDependencies}; @@ -142,34 +144,41 @@ async fn tinygo_http_client( let captured_body: Arc>> = Arc::new(Mutex::new(None)); let captured_body_clone = captured_body.clone(); let http_host_port = context.host_http_port(); + + async fn request_handler( + captured_body_clone: Arc>>, + headers: HeaderMap, + body: Bytes, + ) -> impl IntoResponse { + let body_str = String::from_utf8(body.to_vec()).unwrap(); + { + let mut capture = captured_body_clone.lock().unwrap(); + *capture = Some(body_str.clone()); + println!("captured body: {}", body_str); + } + let header = headers.get("X-Test"); + format!( + "{{ \"percentage\" : 0.25, \"message\": \"response message {}\" }}", + header + .map(|h| h.to_str().unwrap().to_string()) + .unwrap_or("no X-Test header".to_string()), + ) + } + let http_server = tokio::spawn(async move { - let route = warp::path("post-example") - .and(warp::post()) - .and(warp::header::optional::("X-Test")) - .and(warp::body::bytes()) - .map(move |header: Option, body: bytes::Bytes| { - let body_str = String::from_utf8(body.to_vec()).unwrap(); - { - let mut capture = captured_body_clone.lock().unwrap(); - *capture = Some(body_str.clone()); - println!("captured body: {}", body_str); - } - Response::builder() - .status(StatusCode::OK) - .body(Body::from(format!( - "{{ \"percentage\" : 0.25, \"message\": \"response message {}\" }}", - header.unwrap_or("no X-Test header".to_string()), - ))) - .unwrap() - }); - - warp::serve(route) - .run( - format!("0.0.0.0:{}", http_host_port) - .parse::() - .unwrap(), - ) - .await; + let route = Router::new().route( + "/post-example", + post(|headers, body| request_handler(captured_body_clone, headers, body)), + ); + + let listener = tokio::net::TcpListener::bind( + format!("0.0.0.0:{}", http_host_port) + .parse::() + .unwrap(), + ) + .await + .unwrap(); + axum::serve(listener, route).await.unwrap(); }); let component_id = executor.store_component("tinygo-wasi-http").await; diff --git a/golem-worker-executor-base/tests/hot_update.rs b/golem-worker-executor-base/tests/hot_update.rs index 92b192277..cb70ed74c 100644 --- a/golem-worker-executor-base/tests/hot_update.rs +++ b/golem-worker-executor-base/tests/hot_update.rs @@ -17,18 +17,19 @@ use test_r::{inherit_test_dep, test}; use crate::{common, LastUniqueId, Tracing, WorkerExecutorTestDependencies}; use assert2::check; use async_mutex::Mutex; +use axum::routing::post; +use axum::Router; +use bytes::Bytes; use golem_test_framework::dsl::TestDslUnsafe; use golem_wasm_rpc::Value; -use http_02::{Response, StatusCode}; +use http::StatusCode; use log::info; use std::collections::HashMap; use std::net::SocketAddr; use std::sync::Arc; use tokio::spawn; use tokio::task::JoinHandle; -use tonic::transport::Body; use tracing::debug; -use warp::Filter; inherit_test_dep!(WorkerExecutorTestDependencies); inherit_test_dep!(LastUniqueId); @@ -71,42 +72,38 @@ impl TestHttpServer { let f1_blocker = Arc::new(Mutex::new(None::)); let f1_blocker_clone = f1_blocker.clone(); let handle = spawn(async move { - let route = warp::path("f1") - .and(warp::body::json()) - .and(warp::post()) - .then(move |body: u64| { - let f1_blocker_clone = f1_blocker_clone.clone(); - async move { - debug!("f1: {body}"); - - let mut guard = f1_blocker_clone.lock().await; - if let Some(blocker) = &*guard { - if blocker.value == body { - let F1Blocker { - reached, resume, .. - } = guard.take().unwrap(); - debug!("Reached f1 blocking point"); - reached.send(()).unwrap(); - debug!("Awaiting resume at f1 blocking point"); - resume.await.unwrap(); - debug!("Resuming from f1 blocking point"); - } + let route = Router::new().route( + "/f1", + post(move |body: Bytes| async move { + let body: u64 = String::from_utf8(body.to_vec()).unwrap().parse().unwrap(); + debug!("f1: {}", body); + + let mut guard = f1_blocker_clone.lock().await; + if let Some(blocker) = &*guard { + if blocker.value == body { + let F1Blocker { + reached, resume, .. + } = guard.take().unwrap(); + debug!("Reached f1 blocking point"); + reached.send(()).unwrap(); + debug!("Awaiting resume at f1 blocking point"); + resume.await.unwrap(); + debug!("Resuming from f1 blocking point"); } - - Response::builder() - .status(StatusCode::OK) - .body(Body::empty()) - .unwrap() } - }); - - warp::serve(route) - .run( - format!("0.0.0.0:{}", host_http_port) - .parse::() - .unwrap(), - ) - .await; + + StatusCode::OK + }), + ); + + let listener = tokio::net::TcpListener::bind( + format!("0.0.0.0:{}", host_http_port) + .parse::() + .unwrap(), + ) + .await + .unwrap(); + axum::serve(listener, route).await.unwrap(); }); Self { handle, f1_blocker } } diff --git a/golem-worker-executor-base/tests/measure_test_component_mem.rs b/golem-worker-executor-base/tests/measure_test_component_mem.rs index 10512ae1b..dd24d7674 100644 --- a/golem-worker-executor-base/tests/measure_test_component_mem.rs +++ b/golem-worker-executor-base/tests/measure_test_component_mem.rs @@ -15,7 +15,7 @@ use rand::thread_rng; use std::collections::BTreeMap; use std::fmt::Write; use std::path::Path; -use sysinfo::{Pid, System}; +use sysinfo::{Pid, ProcessesToUpdate, System}; use tracing::{error, info}; inherit_test_dep!(WorkerExecutorTestDependencies); @@ -117,7 +117,7 @@ async fn measure_component( for _idx in 0..2 { let pid = Pid::from_u32(std::process::id()); - system.refresh_process(pid); + system.refresh_processes(ProcessesToUpdate::Some(&[pid]), true); let process = system.process(pid).unwrap(); let before_memory = process.memory(); let before_vmemory = process.virtual_memory(); @@ -127,7 +127,7 @@ async fn measure_component( .await .unwrap(); - system.refresh_process(pid); + system.refresh_processes(ProcessesToUpdate::Some(&[pid]), true); let process = system.process(pid).unwrap(); let after_memory = process.memory(); let after_vmemory = process.virtual_memory(); diff --git a/golem-worker-executor-base/tests/transactions.rs b/golem-worker-executor-base/tests/transactions.rs index 4490bbb68..d01fe0ed4 100644 --- a/golem-worker-executor-base/tests/transactions.rs +++ b/golem-worker-executor-base/tests/transactions.rs @@ -17,6 +17,9 @@ use test_r::{inherit_test_dep, test}; use crate::common::{start, TestContext}; use crate::{LastUniqueId, Tracing, WorkerExecutorTestDependencies}; use assert2::check; +use axum::extract::Path; +use axum::routing::{delete, get, post}; +use axum::Router; use bytes::Bytes; use golem_common::model::{IdempotencyKey, TargetWorkerId}; use golem_test_framework::dsl::{ @@ -24,15 +27,12 @@ use golem_test_framework::dsl::{ TestDslUnsafe, }; use golem_wasm_rpc::Value; -use http_02::{Response, StatusCode}; use std::collections::HashMap; use std::net::SocketAddr; use std::sync::{Arc, Mutex}; use std::time::{Duration, SystemTime}; use tokio::task::JoinHandle; -use tonic::transport::Body; use tracing::{debug, instrument}; -use warp::Filter; inherit_test_dep!(WorkerExecutorTestDependencies); inherit_test_dep!(LastUniqueId); @@ -59,62 +59,53 @@ impl TestHttpServer { let events_clone3 = events.clone(); let handle = tokio::spawn(async move { let call_count_per_step = Arc::new(Mutex::new(HashMap::::new())); - let route = warp::path("step") - .and(warp::path::param()) - .and(warp::get()) - .map(move |step: u64| { - let mut steps = call_count_per_step.lock().unwrap(); - let step_count = steps.entry(step).and_modify(|e| *e += 1).or_insert(0); - - debug!("step: {step} occurrence {step_count}"); - if log_steps { - events_clone.lock().unwrap().push(format!("=> {step}")); - } - - match step_count { - n if *n < fail_per_step(step) => Response::builder() - .status(StatusCode::OK) - .body(Body::from("true")) - .unwrap(), - _ => Response::builder() - .status(StatusCode::OK) - .body(Body::from("false")) - .unwrap(), - } - }) - .or(warp::path("step") - .and(warp::path::param()) - .and(warp::delete()) - .map(move |step: u64| { + let route = Router::new() + .route( + "/step/:step", + get(move |step: Path| async move { + let step = step.0; + let mut steps = call_count_per_step.lock().unwrap(); + let step_count = steps.entry(step).and_modify(|e| *e += 1).or_insert(0); + + debug!("step: {} occurrence {step_count}", step); + if log_steps { + events_clone.lock().unwrap().push(format!("=> {step}")); + } + + match step_count { + n if *n < fail_per_step(step) => "true", + _ => "false", + } + }), + ) + .route( + "/step/:step", + delete(move |step: Path| async move { + let step = step.0; debug!("step: undo {step}"); if log_steps { events_clone2.lock().unwrap().push(format!("<= {step}")); } - Response::builder() - .status(StatusCode::OK) - .body(Body::from("false")) - .unwrap() - })) - .or(warp::path("side-effect") - .and(warp::post()) - .and(warp::body::bytes()) - .map(move |body: Bytes| { + "false" + }), + ) + .route( + "/side-effect", + post(move |body: Bytes| async move { let body = String::from_utf8(body.to_vec()).unwrap(); debug!("received POST message: {body}"); events_clone3.lock().unwrap().push(body.clone()); - Response::builder() - .status(StatusCode::OK) - .body("OK") - .unwrap() - })); - - warp::serve(route) - .run( - format!("0.0.0.0:{}", host_http_port) - .parse::() - .unwrap(), - ) - .await; + "OK" + }), + ); + let listener = tokio::net::TcpListener::bind( + format!("0.0.0.0:{}", host_http_port) + .parse::() + .unwrap(), + ) + .await + .unwrap(); + axum::serve(listener, route).await.unwrap(); }); Self { handle, events } } diff --git a/golem-worker-executor-base/tests/wasi.rs b/golem-worker-executor-base/tests/wasi.rs index 97e02e0a8..84f788da5 100644 --- a/golem-worker-executor-base/tests/wasi.rs +++ b/golem-worker-executor-base/tests/wasi.rs @@ -24,6 +24,11 @@ use std::time::{Duration, SystemTime}; use crate::common::{start, TestContext}; use crate::{LastUniqueId, Tracing, WorkerExecutorTestDependencies}; use assert2::{assert, check}; +use axum::response::Response; +use axum::routing::{get, post}; +use axum::{BoxError, Router}; +use bytes::Bytes; +use futures_util::stream; use golem_common::model::{ AccountId, ComponentFilePath, ComponentFilePermissions, ComponentFileSystemNode, ComponentFileSystemNodeDetails, ComponentType, IdempotencyKey, InitialComponentFile, @@ -33,12 +38,11 @@ use golem_test_framework::dsl::{ drain_connection, stderr_events, stdout_events, worker_error_message, TestDslUnsafe, }; use golem_wasm_rpc::Value; -use http_02::{Response, StatusCode}; +use http::{HeaderMap, StatusCode}; use tokio::spawn; use tokio::time::Instant; -use tonic::transport::Body; +use tokio_stream::StreamExt; use tracing::info; -use warp::Filter; inherit_test_dep!(WorkerExecutorTestDependencies); inherit_test_dep!(LastUniqueId); @@ -637,28 +641,23 @@ async fn http_client( let host_http_port = context.host_http_port(); let http_server = spawn(async move { - let route = warp::path::end() - .and(warp::post()) - .and(warp::header::("X-Test")) - .and(warp::body::bytes()) - .map(|header: String, body: bytes::Bytes| { - Response::builder() - .status(StatusCode::OK) - .body(Body::from(format!( - "response is {} {}", - header, - String::from_utf8(body.to_vec()).unwrap() - ))) - .unwrap() - }); + let route = Router::new().route( + "/", + post(move |headers: HeaderMap, body: Bytes| async move { + let header = headers.get("X-Test").unwrap().to_str().unwrap(); + let body = String::from_utf8(body.to_vec()).unwrap(); + format!("response is {header} {body}") + }), + ); - warp::serve(route) - .run( - format!("0.0.0.0:{}", host_http_port) - .parse::() - .unwrap(), - ) - .await; + let listener = tokio::net::TcpListener::bind( + format!("0.0.0.0:{}", host_http_port) + .parse::() + .unwrap(), + ) + .await + .unwrap(); + axum::serve(listener, route).await.unwrap(); }); let component_id = executor.store_component("http-client").await; @@ -700,32 +699,33 @@ async fn http_client_using_reqwest( let captured_body_clone = captured_body.clone(); let host_http_port = context.host_http_port(); let http_server = spawn(async move { - let route = warp::path("post-example") - .and(warp::post()) - .and(warp::header::optional::("X-Test")) - .and(warp::body::bytes()) - .map(move |header: Option, body: bytes::Bytes| { - let body_str = String::from_utf8(body.to_vec()).unwrap(); + let route = Router::new().route( + "/post-example", + post(move |headers: HeaderMap, body: Bytes| async move { + let header = headers + .get("X-Test") + .map(|h| h.to_str().unwrap().to_string()) + .unwrap_or("no X-Test header".to_string()); + let body = String::from_utf8(body.to_vec()).unwrap(); { let mut capture = captured_body_clone.lock().unwrap(); - *capture = Some(body_str.clone()); + *capture = Some(body.clone()); } - Response::builder() - .status(StatusCode::OK) - .body(Body::from(format!( - "{{ \"percentage\" : 0.25, \"message\": \"response message {}\" }}", - header.unwrap_or("no X-Test header".to_string()), - ))) - .unwrap() - }); + format!( + "{{ \"percentage\" : 0.25, \"message\": \"response message {}\" }}", + header + ) + }), + ); - warp::serve(route) - .run( - format!("0.0.0.0:{}", host_http_port) - .parse::() - .unwrap(), - ) - .await; + let listener = tokio::net::TcpListener::bind( + format!("0.0.0.0:{}", host_http_port) + .parse::() + .unwrap(), + ) + .await + .unwrap(); + axum::serve(listener, route).await.unwrap(); }); let component_id = executor.store_component("http-client-2").await; @@ -825,35 +825,28 @@ async fn http_client_response_persisted_between_invocations( let http_server = spawn(async move { let call_count = Arc::new(AtomicU8::new(0)); - let route = warp::path::end() - .and(warp::post()) - .and(warp::header::("X-Test")) - .and(warp::body::bytes()) - .map(move |header: String, body: bytes::Bytes| { + + let route = Router::new().route( + "/", + post(move |headers: HeaderMap, body: Bytes| async move { + let header = headers.get("X-Test").unwrap().to_str().unwrap(); + let body = String::from_utf8(body.to_vec()).unwrap(); let old_count = call_count.fetch_add(1, std::sync::atomic::Ordering::SeqCst); match old_count { - 0 => Response::builder() - .status(StatusCode::OK) - .body(Body::from(format!( - "response is {} {}", - header, - String::from_utf8(body.to_vec()).unwrap() - ))) - .unwrap(), - _ => Response::builder() - .status(StatusCode::NOT_FOUND) - .body(Body::empty()) - .unwrap(), + 0 => (StatusCode::OK, format!("response is {header} {body}")), + _ => (StatusCode::NOT_FOUND, "".to_string()), } - }); + }), + ); - warp::serve(route) - .run( - format!("0.0.0.0:{}", host_http_port) - .parse::() - .unwrap(), - ) - .await; + let listener = tokio::net::TcpListener::bind( + format!("0.0.0.0:{}", host_http_port) + .parse::() + .unwrap(), + ) + .await + .unwrap(); + axum::serve(listener, route).await.unwrap(); }); let component_id = executor.store_component("http-client").await; @@ -904,33 +897,34 @@ async fn http_client_interrupting_response_stream( let (signal_tx, mut signal_rx) = tokio::sync::mpsc::unbounded_channel(); let http_server = spawn(async move { - let route = warp::path("big-byte-array").and(warp::get()).map(move || { - let (sender, body) = Body::channel(); - let signal_tx = signal_tx.clone(); - let _handle = spawn(async move { - let mut sender = sender; - let buf = vec![0; 1024]; - for i in 0..100 { - sender.send_data(buf.clone().into()).await.unwrap(); - tokio::time::sleep(Duration::from_millis(20)).await; - if i == 50 { - signal_tx.send(()).unwrap(); - } - } - }); - Response::builder() - .status(StatusCode::OK) - .body(body) - .unwrap() - }); - - warp::serve(route) - .run( - format!("0.0.0.0:{}", host_http_port) - .parse::() - .unwrap(), - ) - .await; + let route = Router::new().route( + "/big-byte-array", + get(move || async move { + let stream = stream::iter(0..100) + .throttle(Duration::from_millis(20)) + .map(move |i| { + if i == 50 { + signal_tx.send(()).unwrap(); + } + Ok::(Bytes::from(vec![0; 1024])) + }); + + Response::builder() + .status(StatusCode::OK) + .header("Content-Type", "application/octet-stream") + .body(axum::body::Body::from_stream(stream)) + .unwrap() + }), + ); + + let listener = tokio::net::TcpListener::bind( + format!("0.0.0.0:{}", host_http_port) + .parse::() + .unwrap(), + ) + .await + .unwrap(); + axum::serve(listener, route).await.unwrap(); }); let component_id = executor.store_component("http-client-2").await; diff --git a/golem-worker-service-base/Cargo.toml b/golem-worker-service-base/Cargo.toml index 5f32e0108..b1e0a0059 100644 --- a/golem-worker-service-base/Cargo.toml +++ b/golem-worker-service-base/Cargo.toml @@ -39,7 +39,6 @@ figment = { workspace = true } futures = { workspace = true } futures-util = { workspace = true } http = { workspace = true } -http_02 = { workspace = true } humantime-serde = { workspace = true } hyper = { workspace = true } lazy_static = { workspace = true } @@ -56,8 +55,8 @@ prometheus = { workspace = true } prost = { workspace = true } prost-types = { workspace = true } regex = { workspace = true } -rustc-hash = "1.1.0" -rsa = "0.9.6" +rustc-hash = "2.1.0" +rsa = "0.9.7" serde = { workspace = true } serde_json = { workspace = true } serde_yaml = { workspace = true } @@ -86,8 +85,8 @@ uuid = { workspace = true } wasm-wave = { workspace = true } [dev-dependencies] -criterion = { version = "0.3", features = ["html_reports"] } -fastrand = "2.0.2" +criterion = { version = "0.5", features = ["html_reports"] } +fastrand = "2.3.0" testcontainers = { workspace = true } testcontainers-modules = { workspace = true } test-r = { workspace = true } diff --git a/golem-worker-service-base/src/gateway_api_definition/http/http_api_definition.rs b/golem-worker-service-base/src/gateway_api_definition/http/http_api_definition.rs index 5c2cc0fb4..89967dbcf 100644 --- a/golem-worker-service-base/src/gateway_api_definition/http/http_api_definition.rs +++ b/golem-worker-service-base/src/gateway_api_definition/http/http_api_definition.rs @@ -26,7 +26,6 @@ use crate::service::gateway::api_definition::ApiDefinitionError; use crate::service::gateway::api_definition_validator::ValidationErrors; use crate::service::gateway::security_scheme::SecuritySchemeService; use bincode::{Decode, Encode}; -use derive_more::Display; use golem_api_grpc::proto::golem::apidefinition as grpc_apidefinition; use golem_api_grpc::proto::golem::apidefinition::HttpRoute; use golem_service_base::model::{Component, VersionedComponentId}; @@ -257,7 +256,17 @@ impl CompiledHttpApiDefinition { } #[derive( - Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Display, Encode, Decode, Enum, + Debug, + Clone, + PartialEq, + Eq, + Hash, + Serialize, + Deserialize, + derive_more::Display, + Encode, + Decode, + Enum, )] pub enum MethodPattern { Get, diff --git a/golem-worker-service-base/src/lib.rs b/golem-worker-service-base/src/lib.rs index 24391e301..6e9d12b57 100644 --- a/golem-worker-service-base/src/lib.rs +++ b/golem-worker-service-base/src/lib.rs @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -use ::http::Uri; use golem_common::golem_version; use service::worker::WorkerRequestMetadata; @@ -41,16 +40,6 @@ test_r::enable!(); const VERSION: &str = golem_version!(); -pub trait UriBackConversion { - fn as_http_02(&self) -> http_02::Uri; -} - -impl UriBackConversion for Uri { - fn as_http_02(&self) -> http_02::Uri { - self.to_string().parse().unwrap() - } -} - pub fn empty_worker_metadata() -> WorkerRequestMetadata { WorkerRequestMetadata { account_id: Some(golem_common::model::AccountId::placeholder()), diff --git a/golem-worker-service-base/src/service/component/default.rs b/golem-worker-service-base/src/service/component/default.rs index bd80b1904..67fbbc47e 100644 --- a/golem-worker-service-base/src/service/component/default.rs +++ b/golem-worker-service-base/src/service/component/default.rs @@ -14,7 +14,6 @@ use crate::service::component::ComponentServiceError; use crate::service::with_metadata; -use crate::UriBackConversion; use async_trait::async_trait; use golem_api_grpc::proto::golem::component::v1::component_service_client::ComponentServiceClient; use golem_api_grpc::proto::golem::component::v1::{ @@ -75,7 +74,7 @@ impl RemoteComponentService { .send_compressed(CompressionEncoding::Gzip) .accept_compressed(CompressionEncoding::Gzip) }, - uri.as_http_02(), + uri, GrpcClientConfig { retries_on_unavailable: retry_config.clone(), ..Default::default() // TODO diff --git a/golem-worker-service-base/src/service/worker/routing_logic.rs b/golem-worker-service-base/src/service/worker/routing_logic.rs index b78d1f0f1..007e80f81 100644 --- a/golem-worker-service-base/src/service/worker/routing_logic.rs +++ b/golem-worker-service-base/src/service/worker/routing_logic.rs @@ -118,7 +118,7 @@ impl CallOnExecutor for WorkerId { Some( context .worker_executor_clients() - .call(description, pod.uri_02(), f) + .call(description, pod.uri(), f) .await .map_err(|err| { CallWorkerExecutorErrorWithContext::failed_to_connect_to_pod( @@ -214,7 +214,7 @@ impl CallOnExecutor for RandomExecutor { Some( context .worker_executor_clients() - .call(description, pod.uri_02(), f) + .call(description, pod.uri(), f) .await .map_err(|status| { CallWorkerExecutorErrorWithContext::failed_to_connect_to_pod( @@ -275,7 +275,7 @@ impl CallOnExecutor for AllExecutors { let description = description.clone(); async move { worker_executor_clients - .call(description, pod.uri_02(), f) + .call(description, pod.uri(), f) .await .map_err(|err| (err, pod)) } @@ -529,8 +529,8 @@ impl<'a> RetryState<'a> { Some(delay) => { info!( invalidated, - error = format!("{error:?}"), - pod = format!("{:?}", pod.as_ref().map(|p| p.uri_02())), + ?error, + ?pod, delay_ms = delay.as_millis(), "Call on executor - retry" ); @@ -575,7 +575,7 @@ impl<'a> RetryState<'a> { } fn format_pod(pod: &Option) -> String { - format!("{:?}", pod.as_ref().map(|p| p.uri_02())) + format!("{:?}", pod.as_ref().map(|p| p.uri())) } struct RetrySpan { diff --git a/golem-worker-service/Cargo.toml b/golem-worker-service/Cargo.toml index 00d2a8881..b3af371b5 100644 --- a/golem-worker-service/Cargo.toml +++ b/golem-worker-service/Cargo.toml @@ -36,7 +36,6 @@ figment = { workspace = true } futures = { workspace = true } futures-util = { workspace = true } http = { workspace = true } -http_02 = { workspace = true } humantime-serde = { workspace = true } hyper = { workspace = true } lazy_static = { workspace = true } diff --git a/golem-worker-service/src/grpcapi/mod.rs b/golem-worker-service/src/grpcapi/mod.rs index 6053ec4cb..0fbe66ec8 100644 --- a/golem-worker-service/src/grpcapi/mod.rs +++ b/golem-worker-service/src/grpcapi/mod.rs @@ -50,7 +50,7 @@ pub async fn start_grpc_server( let reflection_service = tonic_reflection::server::Builder::configure() .register_encoded_file_descriptor_set(proto::FILE_DESCRIPTOR_SET) - .build() + .build_v1() .unwrap(); join_set.spawn( diff --git a/integration-tests/Cargo.toml b/integration-tests/Cargo.toml index 798d328d1..49b748654 100644 --- a/integration-tests/Cargo.toml +++ b/integration-tests/Cargo.toml @@ -21,7 +21,7 @@ async-trait = { workspace = true } axum = { workspace = true } clap = { workspace = true } console-subscriber = { workspace = true } -plotters = "0.3.6" +plotters = "0.3.7" poem = { workspace = true } rand = { workspace = true } reqwest = { workspace = true } @@ -30,7 +30,6 @@ serde_json = { workspace = true } tokio = { workspace = true } tracing = { workspace = true } tracing-subscriber = { workspace = true } -warp = { workspace = true } [dev-dependencies] test-r = { workspace = true } diff --git a/integration-tests/tests/worker.rs b/integration-tests/tests/worker.rs index 7314aee81..a06297d66 100644 --- a/integration-tests/tests/worker.rs +++ b/integration-tests/tests/worker.rs @@ -24,6 +24,9 @@ use std::path::PathBuf; use std::sync::{Arc, Mutex}; use crate::Tracing; +use axum::extract::Query; +use axum::routing::get; +use axum::Router; use golem_common::model::oplog::{OplogIndex, WorkerResourceId}; use golem_common::model::public_oplog::{ExportedFunctionInvokedParameters, PublicOplogEntry}; use golem_common::model::{ @@ -38,9 +41,6 @@ use serde_json::json; use std::time::{Duration, SystemTime}; use tokio::time::sleep; use tracing::log::info; -use warp::http::{Response, StatusCode}; -use warp::hyper::Body; -use warp::Filter; inherit_test_dep!(Tracing); inherit_test_dep!(EnvBasedTestDependencies); @@ -971,10 +971,9 @@ async fn get_running_workers(deps: &EnvBasedTestDependencies, _tracing: &Tracing let polling_worker_ids_clone = polling_worker_ids.clone(); let http_server = tokio::spawn(async move { - let route = warp::path::path("poll") - .and(warp::get()) - .and(warp::query::>()) - .map(move |query: HashMap| { + let route = Router::new().route( + "/poll", + get(move |query: Query>| async move { let component_id = query.get("component_id"); let worker_name = query.get("worker_name"); if let (Some(component_id), Some(worker_name)) = (component_id, worker_name) { @@ -986,19 +985,18 @@ async fn get_running_workers(deps: &EnvBasedTestDependencies, _tracing: &Tracing let mut ids = polling_worker_ids_clone.lock().unwrap(); ids.insert(worker_id.clone()); } - Response::builder() - .status(StatusCode::OK) - .body(Body::from("initial")) - .unwrap() - }); - - warp::serve(route) - .run( - format!("0.0.0.0:{}", host_http_port) - .parse::() - .unwrap(), - ) - .await; + "initial" + }), + ); + + let listener = tokio::net::TcpListener::bind( + format!("0.0.0.0:{}", host_http_port) + .parse::() + .unwrap(), + ) + .await + .unwrap(); + axum::serve(listener, route).await.unwrap(); }); let mut env = HashMap::new(); diff --git a/wasm-ast/Cargo.toml b/wasm-ast/Cargo.toml index 347dfa3b0..44542ac89 100644 --- a/wasm-ast/Cargo.toml +++ b/wasm-ast/Cargo.toml @@ -8,26 +8,26 @@ repository = "https://github.com/golemcloud/golem-wasm-ast/" description = "WASM AST" [dependencies] -bincode = { version = "2.0.0-rc.3", optional = true } +bincode = { workspace = true, optional = true } leb128 = { version = "0.2.5", optional = true } mappable-rc = "0.1.1" -poem-openapi = { version = "5.0", optional = true } -prost = { version = "0.12", optional = true } -serde = { version = "1.0", optional = true, features = ["derive"] } -serde_json = { version = "1.0", optional = true } -wasmparser = { version = "0.207.0", optional = true } -wasm-encoder = { version = "0.207.0", optional = true } -wasm-metadata = { version = "0.207.0", optional = true } +poem-openapi = { workspace = true, optional = true } +prost = { workspace = true, optional = true } +serde = { workspace = true, optional = true, features = ["derive"] } +serde_json = { workspace = true, optional = true } +wasmparser = { version = "0.221.2", optional = true } +wasm-encoder = { version = "0.221.2", optional = true } +wasm-metadata = { version = "0.221.2", optional = true } wasm-wave = { workspace = true, optional = true } [dev-dependencies] colored-diff = "0.2.3" -pretty_assertions = "1.4.0" +pretty_assertions = "1.4.1" test-r = { workspace = true } -wasmprinter = "0.207.0" +wasmprinter = "0.221.2" [build-dependencies] -prost-build = "0.12.6" +prost-build = "0.13.4" [features] default = ["parser", "writer", "component", "metadata", "analysis", "wave", "json", "bincode", "poem_openapi", "protobuf"] diff --git a/wasm-ast/src/component/parser.rs b/wasm-ast/src/component/parser.rs index 8fe4ecea6..808b79ebc 100644 --- a/wasm-ast/src/component/parser.rs +++ b/wasm-ast/src/component/parser.rs @@ -15,7 +15,7 @@ use crate::component::*; use crate::core::{Data, TryFromExprSource}; use crate::Sections; -use wasmparser::{Chunk, Parser, Payload}; +use wasmparser::{CanonicalFunction, Chunk, Parser, Payload}; impl TryFrom> for InstantiationArg { type Error = String; @@ -70,9 +70,12 @@ impl TryFrom> for ModuleDeclaration { fn try_from(value: wasmparser::ModuleTypeDeclaration) -> Result { match value { - wasmparser::ModuleTypeDeclaration::Type(subtype) => Ok(ModuleDeclaration::Type { - typ: subtype.try_into()?, - }), + wasmparser::ModuleTypeDeclaration::Type(recgroup) => { + let subtype = recgroup.into_types().next().ok_or("Empty rec group")?; + Ok(ModuleDeclaration::Type { + typ: subtype.try_into()?, + }) + } wasmparser::ModuleTypeDeclaration::Export { name, ty } => { Ok(ModuleDeclaration::Export { name: name.to_string(), @@ -97,14 +100,17 @@ impl TryFrom for FuncType { fn try_from(value: wasmparser::SubType) -> Result { if value.is_final { - match value.composite_type { - wasmparser::CompositeType::Func(func_type) => Ok(func_type.try_into()?), - wasmparser::CompositeType::Array(_) => { + match value.composite_type.inner { + wasmparser::CompositeInnerType::Func(func_type) => Ok(func_type.try_into()?), + wasmparser::CompositeInnerType::Array(_) => { Err("GC proposal is not supported".to_string()) } - wasmparser::CompositeType::Struct(_) => { + wasmparser::CompositeInnerType::Struct(_) => { Err("GC proposal is not supported".to_string()) } + wasmparser::CompositeInnerType::Cont(_) => { + Err("Task switching proposal is not supported".to_string()) + } } } else { Err("GC proposal is not supported".to_string()) @@ -117,9 +123,9 @@ impl TryFrom> for CoreType { fn try_from(value: wasmparser::CoreType) -> Result { match value { - wasmparser::CoreType::Sub(subtype) => { - let func_type = subtype.try_into()?; - Ok(CoreType::Function(func_type)) + wasmparser::CoreType::Rec(recgroup) => { + let subtype = recgroup.into_types().next().ok_or("Empty rec group")?; + Ok(CoreType::Function(subtype.try_into()?)) } wasmparser::CoreType::Module(module_type_decl) => Ok(CoreType::Module( module_type_decl @@ -624,6 +630,12 @@ impl TryFrom for Canon { wasmparser::CanonicalFunction::ResourceRep { resource } => { Ok(Canon::ResourceRep { type_idx: resource }) } + CanonicalFunction::ThreadSpawn { .. } => { + Err("Threads proposal is not supported".to_string()) + } + CanonicalFunction::ThreadHwConcurrency => { + Err("Threads proposal is not supported".to_string()) + } } } } @@ -818,6 +830,9 @@ where Payload::UnknownSection { .. } => { return Err("Unexpected unknown section in component".to_string()); } + _ => { + return Err("Unexpected section in component".to_string()); + } } } diff --git a/wasm-ast/src/component/writer.rs b/wasm-ast/src/component/writer.rs index 1b8e7767b..cccd050c8 100644 --- a/wasm-ast/src/component/writer.rs +++ b/wasm-ast/src/component/writer.rs @@ -112,12 +112,12 @@ impl TryFrom<&CoreType> for wasm_encoder::CoreTypeSection { } fn add_to_core_type_encoder( - encoder: wasm_encoder::CoreTypeEncoder, + encoder: wasm_encoder::ComponentCoreTypeEncoder, value: &CoreType, ) -> Result<(), String> { match value { CoreType::Function(func_type) => { - encoder.function( + encoder.core().function( func_type .input .values diff --git a/wasm-ast/src/core/parser.rs b/wasm-ast/src/core/parser.rs index cdd7d2ed9..401ae04ee 100644 --- a/wasm-ast/src/core/parser.rs +++ b/wasm-ast/src/core/parser.rs @@ -205,24 +205,12 @@ impl TryFrom for RefType { type Error = String; fn try_from(value: wasmparser::HeapType) -> Result { - match value { - wasmparser::HeapType::Concrete(_) => Err("GC proposal is not supported".to_string()), - wasmparser::HeapType::Func => Ok(RefType::FuncRef), - wasmparser::HeapType::Extern => Ok(RefType::ExternRef), - wasmparser::HeapType::Any => Err("GC proposal is not supported".to_string()), - wasmparser::HeapType::None => Err("GC proposal is not supported".to_string()), - wasmparser::HeapType::NoExtern => Err("GC proposal is not supported".to_string()), - wasmparser::HeapType::NoFunc => Err("GC proposal is not supported".to_string()), - wasmparser::HeapType::Eq => Err("GC proposal is not supported".to_string()), - wasmparser::HeapType::Struct => Err("GC proposal is not supported".to_string()), - wasmparser::HeapType::Array => Err("GC proposal is not supported".to_string()), - wasmparser::HeapType::I31 => Err("GC proposal is not supported".to_string()), - wasmparser::HeapType::Exn => { - Err("Exception handling proposal is not supported".to_string()) - } - wasmparser::HeapType::NoExn => { - Err("Exception handling proposal is not supported".to_string()) - } + if value == wasmparser::HeapType::EXTERN { + Ok(RefType::ExternRef) + } else if value == wasmparser::HeapType::FUNC { + Ok(RefType::FuncRef) + } else { + Err("GC proposal is not supported".to_string()) } } } @@ -1688,6 +1676,139 @@ impl TryFrom> for Expr { Operator::GlobalAtomicSet { .. } => { return Err("Shared Everything Threads proposal is not supported".to_string()); } + Operator::GlobalAtomicRmwAdd { .. } => { + return Err("Shared Everything Threads proposal is not supported".to_string()); + } + Operator::GlobalAtomicRmwSub { .. } => { + return Err("Shared Everything Threads proposal is not supported".to_string()); + } + Operator::GlobalAtomicRmwAnd { .. } => { + return Err("Shared Everything Threads proposal is not supported".to_string()); + } + Operator::GlobalAtomicRmwOr { .. } => { + return Err("Shared Everything Threads proposal is not supported".to_string()); + } + Operator::GlobalAtomicRmwXor { .. } => { + return Err("Shared Everything Threads proposal is not supported".to_string()); + } + Operator::GlobalAtomicRmwXchg { .. } => { + return Err("Shared Everything Threads proposal is not supported".to_string()); + } + Operator::GlobalAtomicRmwCmpxchg { .. } => { + return Err("Shared Everything Threads proposal is not supported".to_string()); + } + Operator::TableAtomicGet { .. } => { + return Err("Shared Everything Threads proposal is not supported".to_string()); + } + Operator::TableAtomicSet { .. } => { + return Err("Shared Everything Threads proposal is not supported".to_string()); + } + Operator::TableAtomicRmwXchg { .. } => { + return Err("Shared Everything Threads proposal is not supported".to_string()); + } + Operator::TableAtomicRmwCmpxchg { .. } => { + return Err("Shared Everything Threads proposal is not supported".to_string()); + } + Operator::StructAtomicGet { .. } => { + return Err("Shared Everything Threads proposal is not supported".to_string()); + } + Operator::StructAtomicGetS { .. } => { + return Err("Shared Everything Threads proposal is not supported".to_string()); + } + Operator::StructAtomicGetU { .. } => { + return Err("Shared Everything Threads proposal is not supported".to_string()); + } + Operator::StructAtomicSet { .. } => { + return Err("Shared Everything Threads proposal is not supported".to_string()); + } + Operator::StructAtomicRmwAdd { .. } => { + return Err("Shared Everything Threads proposal is not supported".to_string()); + } + Operator::StructAtomicRmwSub { .. } => { + return Err("Shared Everything Threads proposal is not supported".to_string()); + } + Operator::StructAtomicRmwAnd { .. } => { + return Err("Shared Everything Threads proposal is not supported".to_string()); + } + Operator::StructAtomicRmwOr { .. } => { + return Err("Shared Everything Threads proposal is not supported".to_string()); + } + Operator::StructAtomicRmwXor { .. } => { + return Err("Shared Everything Threads proposal is not supported".to_string()); + } + Operator::StructAtomicRmwXchg { .. } => { + return Err("Shared Everything Threads proposal is not supported".to_string()); + } + Operator::StructAtomicRmwCmpxchg { .. } => { + return Err("Shared Everything Threads proposal is not supported".to_string()); + } + Operator::ArrayAtomicGet { .. } => { + return Err("Shared Everything Threads proposal is not supported".to_string()); + } + Operator::ArrayAtomicGetS { .. } => { + return Err("Shared Everything Threads proposal is not supported".to_string()); + } + Operator::ArrayAtomicGetU { .. } => { + return Err("Shared Everything Threads proposal is not supported".to_string()); + } + Operator::ArrayAtomicSet { .. } => { + return Err("Shared Everything Threads proposal is not supported".to_string()); + } + Operator::ArrayAtomicRmwAdd { .. } => { + return Err("Shared Everything Threads proposal is not supported".to_string()); + } + Operator::ArrayAtomicRmwSub { .. } => { + return Err("Shared Everything Threads proposal is not supported".to_string()); + } + Operator::ArrayAtomicRmwAnd { .. } => { + return Err("Shared Everything Threads proposal is not supported".to_string()); + } + Operator::ArrayAtomicRmwOr { .. } => { + return Err("Shared Everything Threads proposal is not supported".to_string()); + } + Operator::ArrayAtomicRmwXor { .. } => { + return Err("Shared Everything Threads proposal is not supported".to_string()); + } + Operator::ArrayAtomicRmwXchg { .. } => { + return Err("Shared Everything Threads proposal is not supported".to_string()); + } + Operator::ArrayAtomicRmwCmpxchg { .. } => { + return Err("Shared Everything Threads proposal is not supported".to_string()); + } + Operator::RefI31Shared => { + return Err("Shared Everything Threads proposal is not supported".to_string()); + } + Operator::ContNew { .. } => { + return Err("Task Switching proposal is not supported".to_string()); + } + Operator::ContBind { .. } => { + return Err("Task Switching proposal is not supported".to_string()); + } + Operator::Suspend { .. } => { + return Err("Task Switching proposal is not supported".to_string()); + } + Operator::Resume { .. } => { + return Err("Task Switching proposal is not supported".to_string()); + } + Operator::ResumeThrow { .. } => { + return Err("Task Switching proposal is not supported".to_string()); + } + Operator::Switch { .. } => { + return Err("Task Switching proposal is not supported".to_string()); + } + Operator::I64Add128 => { + return Err("Wide Arithmetic proposal is not supported".to_string()); + } + Operator::I64Sub128 => { + return Err("Wide Arithmetic proposal is not supported".to_string()); + } + Operator::I64MulWideS => { + return Err("Wide Arithmetic proposal is not supported".to_string()); + } + Operator::I64MulWideU => { + return Err("Wide Arithmetic proposal is not supported".to_string()); + } + _ => return Err(format!("Unexpected operator: {:?}", op)), }; if let Some(instr) = instr { @@ -1818,6 +1939,7 @@ where return Err("Unexpected component export section in core module".to_string()), Payload::UnknownSection { .. } => return Err("Unexpected unknown section in core module".to_string()), + _ => return Err("Unexpected payload in core module".to_string()), } } Ok(Sections::from_flat(sections)) diff --git a/wasm-ast/src/core/writer.rs b/wasm-ast/src/core/writer.rs index 025117cc3..7c6998389 100644 --- a/wasm-ast/src/core/writer.rs +++ b/wasm-ast/src/core/writer.rs @@ -47,7 +47,7 @@ impl From<&FuncType> for wasm_encoder::TypeSection { } fn add_to_type_section(section: &mut wasm_encoder::TypeSection, value: &FuncType) { - section.function( + section.ty().function( value.input.values.iter().map(|v| v.into()), value.output.values.iter().map(|v| v.into()), ); @@ -89,8 +89,8 @@ fn add_to_code_section( impl From<&RefType> for wasm_encoder::HeapType { fn from(value: &RefType) -> Self { match value { - RefType::FuncRef => wasm_encoder::HeapType::Func, - RefType::ExternRef => wasm_encoder::HeapType::Extern, + RefType::ExternRef => wasm_encoder::HeapType::EXTERN, + RefType::FuncRef => wasm_encoder::HeapType::FUNC, } } } @@ -122,6 +122,7 @@ impl From<&TableType> for wasm_encoder::TableType { table64: false, // 64 bit tables are not supported yet minimum: value.limits.min, maximum: value.limits.max, + shared: false, // shard-everything proposal is not supported yet } } } @@ -240,7 +241,7 @@ fn add_to_elem_section( }) .cloned() .collect(); - let elements = wasm_encoder::Elements::Functions(&func_indices); + let elements = wasm_encoder::Elements::Functions(Cow::Owned(func_indices)); match &value.mode { ElemMode::Passive => section.passive(elements), ElemMode::Active { table_idx, offset } => section.active( @@ -264,8 +265,10 @@ fn add_to_elem_section( (&Expr { instrs }).try_into() }) .collect::, String>>()?; - let elements = - wasm_encoder::Elements::Expressions(wasm_encoder::RefType::EXTERNREF, &init); + let elements = wasm_encoder::Elements::Expressions( + wasm_encoder::RefType::EXTERNREF, + Cow::Owned(init), + ); match &value.mode { ElemMode::Passive => section.passive(elements), ElemMode::Active { table_idx, offset } => section.active( @@ -1569,8 +1572,8 @@ fn encode_instr(instr: &Instr, target: &mut F) -> Result<( Instr::Call(func_idx) => target.emit(wasm_encoder::Instruction::Call(*func_idx)), Instr::CallIndirect(table_idx, type_idx) => { target.emit(wasm_encoder::Instruction::CallIndirect { - table: *table_idx, - ty: *type_idx, + table_index: *table_idx, + type_index: *type_idx, }) } } diff --git a/wasm-rpc-stubgen/Cargo.toml b/wasm-rpc-stubgen/Cargo.toml index fa1a6c7c8..5bf61258f 100644 --- a/wasm-rpc-stubgen/Cargo.toml +++ b/wasm-rpc-stubgen/Cargo.toml @@ -25,12 +25,12 @@ name = "add_dep" harness = false [dependencies] -anyhow = "1.0.79" -assert2 = { workspace = true } +anyhow = { workspace = true } +blake3 = "1.5.5" cargo-component = "=0.13.2" cargo-component-core = "=0.13.2" -cargo_toml = "0.20.2" -clap = { version = "4.5.7", features = ["derive"] } +cargo_toml = "0.21.0" +clap = { workspace = true, features = ["derive"] } colored = "2.1.0" dir-diff = "0.3.3" fs_extra = { workspace = true } @@ -39,31 +39,31 @@ golem-wasm-ast = { path = "../wasm-ast", version = "0.0.0" } golem-wasm-rpc = { path = "../wasm-rpc", version = "0.0.0", default-features = false, features = ["host"] } heck = "0.5.0" id-arena = "2.2.1" -indexmap = "2.2.6" +indexmap = "2.7.0" indoc = "2.0.5" -itertools = "0.12.1" +itertools = "0.13.0" minijinja = "2.5.0" pretty_env_logger = "0.5.0" -prettyplease = "0.2.20" -proc-macro2 = "1.0.85" -quote = "1.0.36" -regex = "1.10.4" +prettyplease = "0.2.25" +proc-macro2 = "1.0.92" +quote = "1.0.37" +regex = { workspace = true } semver = "1.0.23" -serde = { version = "1.0.203", features = ["derive"] } -serde_json = "1.0.128" -serde_yaml = "0.9.33" -syn = "2.0.66" +serde = { workspace = true, features = ["derive"] } +serde_json = { workspace = true } +serde_yaml = { workspace = true } +shlex = "1.3.0" +syn = "2.0.90" tempfile = { workspace = true } tokio = { workspace = true } -toml = "0.8.14" +toml = "0.8.19" wac-graph = "=0.6.1" walkdir = "2.5.0" wit-bindgen-rust = "=0.26.0" wit-encoder = "=0.221.2" wit-parser = "=0.221.2" -shlex = "1.3.0" -blake3 = "1.5.5" [dev-dependencies] -test-r = { workspace = true } \ No newline at end of file +assert2 = { workspace = true } +test-r = { workspace = true } diff --git a/wasm-rpc/Cargo.toml b/wasm-rpc/Cargo.toml index 026b5d581..8b4ea733e 100644 --- a/wasm-rpc/Cargo.toml +++ b/wasm-rpc/Cargo.toml @@ -15,32 +15,32 @@ crate-type = ["cdylib", "rlib"] harness = false [dependencies] -wit-bindgen-rt = { version = "0.26.0", features = ["bitflags"] } +wit-bindgen-rt = { version = "=0.26.0", features = ["bitflags"] } -arbitrary = { version = "1.3.2", features = ["derive"], optional = true } -async-recursion = { version = "1.1.1", optional = true } -async-trait = { version = "0.1.77", optional = true } -bigdecimal = { version = "0.4.5", optional = true } -bincode = { version = "2.0.0-rc.3", optional = true } +arbitrary = { version = "1.4.1", features = ["derive"], optional = true } +async-recursion = { workspace = true, optional = true } +async-trait = { workspace = true, optional = true } +bigdecimal = { workspace = true, optional = true } +bincode = { workspace = true, optional = true } git-version = "0.3.9" golem-wasm-ast = { path = "../wasm-ast", version = "0.0.0", optional = true } -poem-openapi = { version = "5.1.4", optional = true } -serde = { version = "1.0", optional = true } -serde_json = { version = "1.0", optional = true } -prost = { version = "0.12", optional = true } -uuid = "1.10.0" +poem-openapi = { workspace = true, optional = true } +serde = { workspace = true, optional = true } +serde_json = { workspace = true, optional = true } +prost = { workspace = true, optional = true } +uuid = { workspace = true } wasmtime = { workspace = true, optional = true } wasmtime-wasi = { workspace = true, optional = true } wasm-wave = { workspace = true, optional = true } [dev-dependencies] -proptest = "1.4.0" +proptest = { workspace = true } proptest-arbitrary-interop = "0.1.0" test-r = { workspace = true } [build-dependencies] -prost-build = "0.12.6" -cargo_metadata = "0.18.1" +prost-build = "0.13.4" +cargo_metadata = "0.19.1" [features] default = ["host"] diff --git a/wasm-rpc/src/protobuf.rs b/wasm-rpc/src/protobuf.rs index 3480500bf..014c45a10 100644 --- a/wasm-rpc/src/protobuf.rs +++ b/wasm-rpc/src/protobuf.rs @@ -334,7 +334,7 @@ impl TryFrom<&type_annotated_value::TypeAnnotatedValue> for Type { }))) } type_annotated_value::TypeAnnotatedValue::Handle(TypedHandle { typ, .. }) => { - if let Some(typ) = typ.clone() { + if let Some(typ) = *typ { Ok(r#type::Type::Handle(typ)) } else { Err("Missing type for Handle".to_string()) diff --git a/wasm-rpc/src/type_annotated_value.rs b/wasm-rpc/src/type_annotated_value.rs index ca719db9e..d90ad88b9 100644 --- a/wasm-rpc/src/type_annotated_value.rs +++ b/wasm-rpc/src/type_annotated_value.rs @@ -852,7 +852,7 @@ fn create_from_type(val: &Value, typ: &Type) -> Result Date: Thu, 12 Dec 2024 20:23:05 +1100 Subject: [PATCH 2/8] Make sure gateway works with single executable - make sqlite store for session (#1177) --- golem-worker-service-base/src/app_config.rs | 11 +- .../src/gateway_execution/gateway_session.rs | 202 +++++++++++++++++- .../tests/services_tests.rs | 106 ++++++++- golem-worker-service/src/service/mod.rs | 40 ++-- golem/src/launch.rs | 11 + 5 files changed, 344 insertions(+), 26 deletions(-) diff --git a/golem-worker-service-base/src/app_config.rs b/golem-worker-service-base/src/app_config.rs index 9a0754482..9f4543d1d 100644 --- a/golem-worker-service-base/src/app_config.rs +++ b/golem-worker-service-base/src/app_config.rs @@ -33,7 +33,7 @@ use golem_service_base::service::routing_table::RoutingTableConfig; pub struct WorkerServiceBaseConfig { pub environment: String, pub tracing: TracingConfig, - pub gateway_session_storage: KeyValueStorageConfig, + pub gateway_session_storage: GatewaySessionStorageConfig, pub db: DbConfig, pub component_service: ComponentServiceConfig, pub port: u16, @@ -46,17 +46,18 @@ pub struct WorkerServiceBaseConfig { #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(tag = "type", content = "config")] -pub enum KeyValueStorageConfig { +pub enum GatewaySessionStorageConfig { Redis(RedisConfig), + Sqlite(DbSqliteConfig), } -impl Default for KeyValueStorageConfig { +impl Default for GatewaySessionStorageConfig { fn default() -> Self { Self::default_redis() } } -impl KeyValueStorageConfig { +impl GatewaySessionStorageConfig { pub fn default_redis() -> Self { Self::Redis(RedisConfig::default()) } @@ -76,7 +77,7 @@ impl Default for WorkerServiceBaseConfig { database: "../data/golem_worker.sqlite".to_string(), max_connections: 10, }), - gateway_session_storage: KeyValueStorageConfig::default_redis(), + gateway_session_storage: GatewaySessionStorageConfig::default_redis(), component_service: ComponentServiceConfig::default(), tracing: TracingConfig::local_dev("worker-service"), port: 9005, diff --git a/golem-worker-service-base/src/gateway_execution/gateway_session.rs b/golem-worker-service-base/src/gateway_execution/gateway_session.rs index c094f7458..799238e89 100644 --- a/golem-worker-service-base/src/gateway_execution/gateway_session.rs +++ b/golem-worker-service-base/src/gateway_execution/gateway_session.rs @@ -19,10 +19,15 @@ use bytes::Bytes; use fred::interfaces::RedisResult; use golem_common::redis::RedisPool; use golem_common::SafeDisplay; +use golem_service_base::storage::sqlite::SqlitePool; +use sqlx::Row; use std::collections::HashMap; use std::hash::Hash; use std::sync::Arc; -use tracing::error; +use std::time::Duration; +use tokio::task; +use tokio::time::interval; +use tracing::{error, info}; #[async_trait] pub trait GatewaySession { @@ -127,12 +132,12 @@ pub struct SessionData { #[derive(Clone)] pub struct RedisGatewaySession { redis: RedisPool, - expire: i64, + expiration: RedisGatewaySessionExpiration, } impl RedisGatewaySession { - pub fn new(redis: RedisPool, expire: i64) -> Self { - Self { redis, expire } + pub fn new(redis: RedisPool, expiration: RedisGatewaySessionExpiration) -> Self { + Self { redis, expiration } } pub fn redis_key(session_id: &SessionId) -> String { @@ -140,6 +145,23 @@ impl RedisGatewaySession { } } +#[derive(Clone)] +pub struct RedisGatewaySessionExpiration { + pub session_expiry: Duration, +} + +impl RedisGatewaySessionExpiration { + pub fn new(session_expiry: Duration) -> Self { + Self { session_expiry } + } +} + +impl Default for RedisGatewaySessionExpiration { + fn default() -> Self { + Self::new(Duration::from_secs(60 * 60)) + } +} + #[async_trait] impl GatewaySession for RedisGatewaySession { async fn insert( @@ -167,7 +189,10 @@ impl GatewaySession for RedisGatewaySession { self.redis .with("gateway_session", "insert") - .expire(Self::redis_key(&session_id), self.expire) + .expire( + Self::redis_key(&session_id), + self.expiration.session_expiry.as_secs() as i64, + ) .await .map_err(|e| { error!("Failed to set expiry on session data in Redis: {}", e); @@ -203,3 +228,170 @@ impl GatewaySession for RedisGatewaySession { } } } + +#[derive(Debug, Clone)] +pub struct SqliteGatewaySession { + pool: SqlitePool, + expiration: SqliteGatewaySessionExpiration, +} + +#[derive(Debug, Clone)] +pub struct SqliteGatewaySessionExpiration { + pub session_expiry: Duration, + pub cleanup_interval: Duration, +} + +impl SqliteGatewaySessionExpiration { + pub fn new(session_expiry: Duration, cleanup_interval: Duration) -> Self { + Self { + session_expiry, + cleanup_interval, + } + } +} + +impl Default for SqliteGatewaySessionExpiration { + fn default() -> Self { + Self::new(Duration::from_secs(60 * 60), Duration::from_secs(60)) + } +} + +impl SqliteGatewaySession { + pub async fn new( + pool: SqlitePool, + expiration: SqliteGatewaySessionExpiration, + ) -> Result { + let result = Self { pool, expiration }; + + result.init().await?; + + let cloned_session = result.clone(); + + Self::spawn_expiration_task( + cloned_session.expiration.cleanup_interval, + cloned_session.pool, + ); + + Ok(result) + } + + async fn init(&self) -> Result<(), String> { + self.pool + .execute(sqlx::query( + r#" + CREATE TABLE IF NOT EXISTS gateway_session ( + session_id TEXT NOT NULL, + data_key TEXT NOT NULL, + data_value BLOB NOT NULL, + expiry_time INTEGER NOT NULL, + PRIMARY KEY (session_id, data_key) + ); + "#, + )) + .await?; + + info!("Initialized gateway session SQLite table"); + + Ok(()) + } + + pub fn spawn_expiration_task(cleanup_internal: Duration, db_pool: SqlitePool) { + task::spawn(async move { + let mut cleanup_interval = interval(cleanup_internal); + + loop { + cleanup_interval.tick().await; + + if let Err(e) = Self::cleanup_expired(db_pool.clone(), Self::current_time()).await { + error!("Failed to expire sessions: {}", e); + } + } + }); + } + + pub async fn cleanup_expired(pool: SqlitePool, current_time: i64) -> Result<(), String> { + let query = + sqlx::query("DELETE FROM gateway_session WHERE expiry_time < ?;").bind(current_time); + + pool.with("gateway_session", "cleanup_expired") + .execute(query) + .await + .map(|_| ()) + } + + pub fn current_time() -> i64 { + chrono::Utc::now().timestamp() + } +} + +#[async_trait] +impl GatewaySession for SqliteGatewaySession { + async fn insert( + &self, + session_id: SessionId, + data_key: DataKey, + data_value: DataValue, + ) -> Result<(), GatewaySessionError> { + let expiry_time = Self::current_time() + self.expiration.session_expiry.as_secs() as i64; + + let serialized_value: &[u8] = &golem_common::serialization::serialize(&data_value) + .map_err(|e| GatewaySessionError::InternalError(e.to_string()))?; + + let result = self + .pool + .execute( + sqlx::query( + r#" + INSERT INTO gateway_session (session_id, data_key, data_value, expiry_time) + VALUES (?, ?, ?, ?); + "#, + ) + .bind(session_id.0) + .bind(data_key.0) + .bind(serialized_value) + .bind(expiry_time), + ) + .await; + + result.map_err(|e| { + error!("Failed to insert session data into SQLite: {}", e); + GatewaySessionError::InternalError(e.to_string()) + })?; + + Ok(()) + } + + async fn get( + &self, + session_id: &SessionId, + data_key: &DataKey, + ) -> Result { + let query = sqlx::query( + "SELECT data_value FROM gateway_session WHERE session_id = ? AND data_key = ?;", + ) + .bind(&session_id.0) + .bind(&data_key.0); + + let result = self + .pool + .with("gateway_sesssion", "get") + .fetch_optional(query) + .await + .map_err(|e| GatewaySessionError::InternalError(e.to_string()))?; + + match result { + Some(row) => { + let row = row.get::, _>(0); + + let data_value = golem_common::serialization::deserialize(&row) + .map_err(|e| GatewaySessionError::InternalError(e.to_string()))?; + + Ok(data_value) + } + None => Err(GatewaySessionError::MissingValue { + session_id: session_id.clone(), + data_key: data_key.clone(), + }), + } + } +} diff --git a/golem-worker-service-base/tests/services_tests.rs b/golem-worker-service-base/tests/services_tests.rs index 55951c1c3..532f882d3 100644 --- a/golem-worker-service-base/tests/services_tests.rs +++ b/golem-worker-service-base/tests/services_tests.rs @@ -42,13 +42,15 @@ use golem_worker_service_base::service::gateway::http_api_definition_validator:: use chrono::Utc; use golem_common::model::component_constraint::FunctionConstraintCollection; use golem_common::redis::RedisPool; +use golem_service_base::storage::sqlite::SqlitePool; use golem_wasm_ast::analysis::analysed_type::str; use golem_worker_service_base::api; use golem_worker_service_base::gateway_api_deployment::{ ApiDeploymentRequest, ApiSite, ApiSiteString, }; use golem_worker_service_base::gateway_execution::gateway_session::{ - DataKey, DataValue, GatewaySession, GatewaySessionError, RedisGatewaySession, SessionId, + DataKey, DataValue, GatewaySession, GatewaySessionError, RedisGatewaySession, + RedisGatewaySessionExpiration, SessionId, SqliteGatewaySession, SqliteGatewaySessionExpiration, }; use golem_worker_service_base::gateway_security::{ AuthorizationUrl, DefaultIdentityProvider, GolemIdentityProviderMetadata, IdentityProvider, @@ -70,6 +72,7 @@ use openidconnect::{ TokenUrl, UserInfoUrl, }; use std::sync::Arc; +use std::time::Duration; use testcontainers::runners::AsyncRunner; use testcontainers::{ContainerAsync, ImageExt}; use testcontainers_modules::postgres::Postgres; @@ -178,7 +181,80 @@ pub async fn test_with_postgres_db() { } #[test] -pub async fn test_gateway_session_expiry() { +pub async fn test_gateway_session_with_sqlite() { + let db = SqliteDb::default(); + let db_config = DbSqliteConfig { + database: db.db_path.clone(), + max_connections: 10, + }; + + let db_pool = db::create_sqlite_pool(&db_config).await.unwrap(); + + let data_value = DataValue(serde_json::Value::String( + Nonce::new_random().secret().to_string(), + )); + + let value = insert_and_get_session_with_sqlite( + SessionId("test1".to_string()), + DataKey::nonce(), + data_value.clone(), + db_pool.clone(), + ) + .await + .expect("Expecting a value for longer expiry"); + + assert_eq!(value, data_value.clone()); +} + +#[test] +pub async fn test_gateway_session_with_sqlite_expired() { + let db = SqliteDb::default(); + let db_config = DbSqliteConfig { + database: db.db_path.clone(), + max_connections: 10, + }; + + let db_pool = db::create_sqlite_pool(&db_config).await.unwrap(); + + let data_value = DataValue(serde_json::Value::String( + Nonce::new_random().secret().to_string(), + )); + + let expiration = + SqliteGatewaySessionExpiration::new(Duration::from_secs(1), Duration::from_secs(1)); + + let pool = SqlitePool::new(db_pool) + .await + .expect("Failed to create sqlite pool"); + + let sqlite_session = SqliteGatewaySession::new(pool.clone(), expiration.clone()) + .await + .expect("Failed to create sqlite session"); + + let session_store = Arc::new(sqlite_session); + + let data_key = DataKey::nonce(); + let session_id = SessionId("test1".to_string()); + + session_store + .insert(session_id.clone(), data_key.clone(), data_value) + .await + .expect("Insert to session failed"); + + SqliteGatewaySession::cleanup_expired(pool, SqliteGatewaySession::current_time() + 10) + .await + .expect("Failed to cleanup expired sessions"); + + let result = session_store.get(&session_id, &data_key).await; + + assert!(matches!( + result, + Err(GatewaySessionError::MissingValue { .. }) + )); +} + +#[test] +pub async fn test_gateway_session_redis() { let (redis_config, _container) = start_docker_redis().await; let redis = RedisPool::configured(&redis_config).await.unwrap(); @@ -225,7 +301,7 @@ async fn insert_and_get_with_redis( ) -> Result { let session_store = Arc::new(RedisGatewaySession::new( redis.clone(), - redis_expiry_in_seconds as i64, + RedisGatewaySessionExpiration::new(Duration::from_secs(redis_expiry_in_seconds)), )); session_store @@ -236,6 +312,30 @@ async fn insert_and_get_with_redis( session_store.get(&session_id, &data_key).await } +async fn insert_and_get_session_with_sqlite( + session_id: SessionId, + data_key: DataKey, + data_value: DataValue, + db_pool: sqlx::SqlitePool, +) -> Result { + let sqlite_session = SqliteGatewaySession::new( + SqlitePool::new(db_pool) + .await + .map_err(|err| GatewaySessionError::InternalError(err.to_string()))?, + SqliteGatewaySessionExpiration::default(), + ) + .await + .map_err(|err| GatewaySessionError::InternalError(err.to_string()))?; + + let session_store = Arc::new(sqlite_session); + + session_store + .insert(session_id.clone(), data_key.clone(), data_value) + .await?; + + session_store.get(&session_id, &data_key).await +} + #[test] pub async fn test_with_sqlite_db() { let db = SqliteDb::default(); diff --git a/golem-worker-service/src/service/mod.rs b/golem-worker-service/src/service/mod.rs index f85a3c502..6347fca37 100644 --- a/golem-worker-service/src/service/mod.rs +++ b/golem-worker-service/src/service/mod.rs @@ -29,7 +29,7 @@ use golem_worker_service_base::gateway_api_definition::http::{ }; use golem_service_base::auth::{DefaultNamespace, EmptyAuthCtx}; -use golem_worker_service_base::app_config::{KeyValueStorageConfig, WorkerServiceBaseConfig}; +use golem_worker_service_base::app_config::{GatewaySessionStorageConfig, WorkerServiceBaseConfig}; use golem_worker_service_base::gateway_execution::api_definition_lookup::{ ApiDefinitionsLookup, HttpApiDefinitionLookup, @@ -53,7 +53,8 @@ use golem_common::config::DbConfig; use golem_common::redis::RedisPool; use golem_service_base::db; use golem_worker_service_base::gateway_execution::gateway_session::{ - GatewaySession, RedisGatewaySession, + GatewaySession, RedisGatewaySession, RedisGatewaySessionExpiration, SqliteGatewaySession, + SqliteGatewaySessionExpiration, }; use golem_worker_service_base::gateway_request::http_request::InputHttpRequest; use golem_worker_service_base::gateway_security::DefaultIdentityProvider; @@ -142,17 +143,30 @@ impl Services { worker_service.clone(), )); - let gateway_session_store = match &config.gateway_session_storage { - KeyValueStorageConfig::Redis(redis_config) => { - let redis = RedisPool::configured(redis_config) - .await - .map_err(|e| e.to_string())?; - - let gateway_session_with_redis = RedisGatewaySession::new(redis, 60 * 60); - - Arc::new(gateway_session_with_redis) - } - }; + let gateway_session_store: Arc = + match &config.gateway_session_storage { + GatewaySessionStorageConfig::Redis(redis_config) => { + let redis = RedisPool::configured(redis_config) + .await + .map_err(|e| e.to_string())?; + + let gateway_session_with_redis = + RedisGatewaySession::new(redis, RedisGatewaySessionExpiration::default()); + + Arc::new(gateway_session_with_redis) + } + GatewaySessionStorageConfig::Sqlite(sqlite_config) => { + let pool = SqlitePool::configured(sqlite_config) + .await + .map_err(|e| e.to_string())?; + + let gateway_session_with_sqlite = + SqliteGatewaySession::new(pool, SqliteGatewaySessionExpiration::default()) + .await?; + + Arc::new(gateway_session_with_sqlite) + } + }; let (api_definition_repo, api_deployment_repo, security_scheme_repo) = match config .db diff --git a/golem/src/launch.rs b/golem/src/launch.rs index cbc3e9208..2483d1e26 100644 --- a/golem/src/launch.rs +++ b/golem/src/launch.rs @@ -223,6 +223,17 @@ fn worker_service_config( .to_string(), max_connections: 32, }), + gateway_session_storage: + golem_worker_service_base::app_config::GatewaySessionStorageConfig::Sqlite( + DbSqliteConfig { + database: args + .data_dir + .join("gateway-sessions.db") + .to_string_lossy() + .to_string(), + max_connections: 32, + }, + ), blob_storage: blob_storage_config(args), component_service: golem_worker_service_base::app_config::ComponentServiceConfig { host: "127.0.0.1".to_string(), From e1ecc664b3359c31bd28f695d3dafee4bac9acfb Mon Sep 17 00:00:00 2001 From: Daniel Vigovszky Date: Fri, 13 Dec 2024 08:55:55 +0100 Subject: [PATCH 3/8] Crate features and dependency cleanup (#1176) * feature&dep cleanup step 1 * Rib tests and fixes * Fix one more test * Fix more tests * Fix last test * Fix tests * Features in golem-common * Follow changes in all crates * Restore backward compatibility * Avoid diverging logic between tests service layer and controller * Make sure all tests pass * Reformat * Fix stub mode of wasm-rpc --------- Co-authored-by: Afsal Thaj --- Cargo.lock | 4 - golem-api-grpc/Cargo.toml | 4 +- golem-cli/Cargo.toml | 8 +- golem-cli/src/model/invoke_result_view.rs | 10 +- golem-cli/src/model/text.rs | 4 +- golem-cli/src/service/worker.rs | 4 +- golem-client/Cargo.toml | 6 +- golem-common/Cargo.toml | 45 +- golem-common/src/client.rs | 2 +- golem-common/src/config.rs | 13 +- golem-common/src/lib.rs | 23 + golem-common/src/model/component.rs | 27 +- .../src/model/component_constraint.rs | 159 +- golem-common/src/model/component_metadata.rs | 417 ++-- golem-common/src/model/mod.rs | 1154 ++-------- golem-common/src/model/oplog.rs | 64 +- golem-common/src/model/plugin.rs | 530 ++--- golem-common/src/model/poem.rs | 275 +++ golem-common/src/model/protobuf.rs | 763 +++++++ golem-common/src/model/public_oplog.rs | 1863 +++++++++-------- golem-common/src/model/regions.rs | 4 +- golem-common/src/newtype.rs | 34 +- golem-common/src/retriable_error.rs | 7 +- golem-common/src/retries.rs | 4 +- golem-common/src/serialization.rs | 4 +- .../src/config.rs | 3 +- .../src/service/compile_worker.rs | 2 +- .../src/service/component.rs | 2 +- golem-rib/Cargo.toml | 19 +- golem-rib/src/call_type.rs | 121 +- golem-rib/src/compiler/byte_code.rs | 144 +- golem-rib/src/compiler/compiler_output.rs | 88 +- golem-rib/src/compiler/ir.rs | 925 ++++---- .../src/compiler/worker_functions_in_rib.rs | 140 +- golem-rib/src/expr.rs | 978 ++++----- golem-rib/src/function_name.rs | 895 ++++---- golem-rib/src/interpreter/env.rs | 21 +- .../src/interpreter/interpreter_input.rs | 6 +- .../src/interpreter/interpreter_result.rs | 30 +- .../interpreter/interpreter_stack_value.rs | 258 ++- golem-rib/src/interpreter/literal.rs | 108 +- golem-rib/src/interpreter/rib_interpreter.rs | 529 ++--- golem-rib/src/interpreter/stack.rs | 222 +- golem-rib/src/interpreter/tests/mod.rs | 314 ++- golem-rib/src/parser/type_name.rs | 322 +-- golem-rib/src/type_inference/mod.rs | 17 +- .../src/type_inference/rib_input_type.rs | 41 +- .../src/type_inference/rib_output_type.rs | 38 +- golem-rib/src/type_registry.rs | 112 +- golem-rib/src/variable_id.rs | 103 +- golem-service-base/src/config.rs | 3 +- golem-shard-manager/src/healthcheck.rs | 4 +- .../src/shard_manager_config.rs | 5 +- .../src/durable_host/golem/mod.rs | 2 +- .../src/durable_host/golem/v11.rs | 2 +- .../src/durable_host/mod.rs | 2 +- golem-worker-executor-base/src/invocation.rs | 11 +- .../src/model/public_oplog/mod.rs | 4 +- .../src/services/component.rs | 2 +- .../src/services/golem_config.rs | 3 +- .../src/services/plugins.rs | 2 +- golem-worker-executor-base/src/worker.rs | 2 +- .../tests/compatibility/v1.rs | 20 +- .../tests/compatibility/v1_1.rs | 2 +- .../src/api/custom_http_request_api.rs | 115 +- golem-worker-service-base/src/app_config.rs | 3 +- .../gateway_binding_compiled.rs | 47 +- .../file_server_binding_handler.rs | 64 +- .../gateway_binding_resolver.rs | 8 +- .../gateway_http_input_executor.rs | 239 ++- .../rib_input_value_resolver.rs | 10 + .../src/gateway_execution/to_response.rs | 58 +- .../src/gateway_middleware/http/cors.rs | 16 +- .../src/gateway_rib_interpreter/mod.rs | 18 +- golem-worker-service-base/src/getter.rs | 77 +- golem-worker-service-base/src/headers.rs | 28 +- .../src/service/component/default.rs | 2 +- .../src/service/worker/default.rs | 2 +- .../src/service/worker/routing_logic.rs | 2 +- .../tests/api_gateway_end_to_end_tests.rs | 256 +-- .../tests/services_tests.rs | 4 +- golem-worker-service/src/service/mod.rs | 2 +- wasm-ast/src/component/writer.rs | 2 +- wasm-rpc/Cargo.toml | 13 +- wasm-rpc/src/lib.rs | 65 +- wasm-rpc/src/protobuf.rs | 8 +- wasm-rpc/src/text.rs | 1257 ++++++++--- wasm-rpc/src/type_annotated_value.rs | 491 +---- wasm-rpc/src/value_and_type.rs | 534 +++++ wasm-rpc/src/wasmtime.rs | 8 +- 90 files changed, 7685 insertions(+), 6574 deletions(-) create mode 100644 golem-common/src/model/poem.rs create mode 100644 golem-common/src/model/protobuf.rs create mode 100644 wasm-rpc/src/value_and_type.rs diff --git a/Cargo.lock b/Cargo.lock index 793418549..bbc1fb0b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3944,7 +3944,6 @@ dependencies = [ "derive_more 1.0.0", "figment", "fred", - "futures-core", "git-version", "golem-api-grpc", "golem-rib", @@ -4142,7 +4141,6 @@ dependencies = [ name = "golem-rib" version = "0.0.0" dependencies = [ - "async-trait", "bigdecimal", "bincode", "combine", @@ -4154,8 +4152,6 @@ dependencies = [ "serde 1.0.216", "serde_json", "test-r", - "tokio", - "wasm-wave", ] [[package]] diff --git a/golem-api-grpc/Cargo.toml b/golem-api-grpc/Cargo.toml index 56be0dd13..72e0fd349 100644 --- a/golem-api-grpc/Cargo.toml +++ b/golem-api-grpc/Cargo.toml @@ -11,8 +11,8 @@ description = "GRPC API for Golem services" harness = false [dependencies] -golem-wasm-ast = { path = "../wasm-ast", version = "0.0.0" } -golem-wasm-rpc = { path = "../wasm-rpc", version = "0.0.0", default-features = false, features = ["host"] } +golem-wasm-ast = { path = "../wasm-ast", version = "0.0.0", default-features = false, features = ["protobuf"] } +golem-wasm-rpc = { path = "../wasm-rpc", version = "0.0.0", default-features = false, features = ["protobuf"] } async-trait = { workspace = true } bincode = { workspace = true } diff --git a/golem-cli/Cargo.toml b/golem-cli/Cargo.toml index e3b98879b..81b143e9e 100644 --- a/golem-cli/Cargo.toml +++ b/golem-cli/Cargo.toml @@ -24,10 +24,10 @@ harness = false [dependencies] golem-client = { path = "../golem-client", version = "0.0.0" } -golem-common = { path = "../golem-common", version = "0.0.0" } -golem-rib = { path = "../golem-rib", version = "0.0.0" } -golem-wasm-ast = { path = "../wasm-ast", version = "0.0.0" } -golem-wasm-rpc = { path = "../wasm-rpc", version = "0.0.0", default-features = false, features = ["host"] } +golem-common = { path = "../golem-common", version = "0.0.0", default-features = false } +golem-rib = { path = "../golem-rib", version = "0.0.0", default-features = false } +golem-wasm-ast = { path = "../wasm-ast", version = "0.0.0", default-features = false, features = ["analysis"] } +golem-wasm-rpc = { path = "../wasm-rpc", version = "0.0.0", default-features = false } golem-wasm-rpc-stubgen = { path = "../wasm-rpc-stubgen", version = "0.0.0" } anyhow.workspace = true diff --git a/golem-cli/src/model/invoke_result_view.rs b/golem-cli/src/model/invoke_result_view.rs index cfba45579..2bc8e4894 100644 --- a/golem-cli/src/model/invoke_result_view.rs +++ b/golem-cli/src/model/invoke_result_view.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use golem_wasm_rpc::{protobuf, type_annotated_value_to_string}; +use golem_wasm_rpc::{print_type_annotated_value, protobuf}; use serde::{Deserialize, Serialize}; use serde_json::value::Value; use tracing::{debug, info}; @@ -94,7 +94,7 @@ impl InvokeResultView { fn try_wave_format( parsed: protobuf::type_annotated_value::TypeAnnotatedValue, ) -> Result { - match type_annotated_value_to_string(&parsed) { + match print_type_annotated_value(&parsed) { Ok(res) => Ok(res), Err(err) => { info!("Failed to format parsed value as wave: {err:?}"); @@ -122,7 +122,7 @@ mod tests { use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; use golem_wasm_rpc::protobuf::TypeAnnotatedValue as RootTypeAnnotatedValue; use golem_wasm_rpc::protobuf::TypedTuple; - use golem_wasm_rpc::{TypeAnnotatedValueConstructors, Uri}; + use golem_wasm_rpc::TypeAnnotatedValueConstructors; use uuid::Uuid; use golem_client::model::{ @@ -195,9 +195,7 @@ mod tests { fn fallback_to_json() { let res = parse( vec![golem_wasm_rpc::Value::Handle { - uri: Uri { - value: "".to_string(), - }, + uri: "".to_string(), resource_id: 1, }], vec![handle(AnalysedResourceId(1), AnalysedResourceMode::Owned)], diff --git a/golem-cli/src/model/text.rs b/golem-cli/src/model/text.rs index 89a2188ab..962167121 100644 --- a/golem-cli/src/model/text.rs +++ b/golem-cli/src/model/text.rs @@ -776,7 +776,7 @@ pub mod worker { }; use golem_common::uri::oss::urn::{ComponentUrn, WorkerUrn}; use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; - use golem_wasm_rpc::{type_annotated_value_to_string, ValueAndType}; + use golem_wasm_rpc::{print_type_annotated_value, ValueAndType}; use indoc::{formatdoc, indoc, printdoc}; use itertools::Itertools; use serde::{Deserialize, Serialize}; @@ -1335,7 +1335,7 @@ pub mod worker { fn print_value(value: &ValueAndType) -> String { let tav: TypeAnnotatedValue = value.try_into().expect("Failed to convert value to string"); - type_annotated_value_to_string(&tav).expect("Failed to convert value to string") + print_type_annotated_value(&tav).expect("Failed to convert value to string") } } diff --git a/golem-cli/src/service/worker.rs b/golem-cli/src/service/worker.rs index 29dad749e..472bf5774 100644 --- a/golem-cli/src/service/worker.rs +++ b/golem-cli/src/service/worker.rs @@ -33,8 +33,8 @@ use golem_common::uri::oss::url::{ComponentUrl, WorkerUrl}; use golem_common::uri::oss::urn::{ComponentUrn, WorkerUrn}; use golem_wasm_ast::analysis::{AnalysedExport, AnalysedFunction, AnalysedInstance}; use golem_wasm_rpc::json::TypeAnnotatedValueJsonExtensions; +use golem_wasm_rpc::parse_type_annotated_value; use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; -use golem_wasm_rpc::type_annotated_value_from_str; use itertools::Itertools; use serde_json::Value; use std::sync::Arc; @@ -237,7 +237,7 @@ async fn resolve_worker_component_version( fn parse_parameter(wave: &str, typ: &AnalysedType) -> Result { // Avoid converting from typ to AnalysedType - match type_annotated_value_from_str(typ, wave) { + match parse_type_annotated_value(typ, wave) { Ok(value) => Ok(value), Err(err) => Err(GolemError(format!( "Failed to parse wave parameter {wave}: {err:?}" diff --git a/golem-client/Cargo.toml b/golem-client/Cargo.toml index 6aee4d829..e56ddd0b4 100644 --- a/golem-client/Cargo.toml +++ b/golem-client/Cargo.toml @@ -13,9 +13,9 @@ include = ["src/**/*", "Cargo.toml", "build.rs", "openapi/**/*"] harness = false [dependencies] -golem-common = { path = "../golem-common", version = "0.0.0" } -golem-wasm-ast = { path = "../wasm-ast", version = "0.0.0" } -golem-wasm-rpc = { path = "../wasm-rpc", version = "0.0.0", default-features = false, features = ["host"] } +golem-common = { path = "../golem-common", version = "0.0.0", default-features = false } +golem-wasm-ast = { path = "../wasm-ast", version = "0.0.0", default-features = false, features = ["analysis"] } +golem-wasm-rpc = { path = "../wasm-rpc", version = "0.0.0", default-features = false } async-trait = { workspace = true } bytes = { workspace = true } diff --git a/golem-common/Cargo.toml b/golem-common/Cargo.toml index a3d6e3641..0c0be4834 100644 --- a/golem-common/Cargo.toml +++ b/golem-common/Cargo.toml @@ -7,14 +7,24 @@ homepage = "https://golem.cloud" repository = "https://github.com/golemcloud/golem" description = "Shared code between Golem services" +[features] +default = ["config", "observability", "poem", "protobuf", "redis", "sql", "tokio"] + +config = ["dep:figment"] +observability = ["dep:console-subscriber", "dep:prometheus", "dep:tracing", "dep:tracing-subscriber", "dep:tracing-serde"] +poem = ["dep:poem", "dep:poem-openapi", "golem-wasm-ast/poem_openapi", "golem-wasm-ast/poem_openapi", "golem-rib/poem"] +protobuf = ["dep:prost", "dep:prost-types", "dep:tonic", "dep:golem-api-grpc", "golem-rib/protobuf", "golem-wasm-ast/protobuf", "golem-wasm-rpc/protobuf"] +redis = ["dep:fred"] +sql = ["dep:sqlx"] +tokio = ["dep:tokio"] [lib] harness = false [dependencies] -golem-api-grpc = { path = "../golem-api-grpc", version = "0.0.0" } -golem-rib = { path = "../golem-rib", version = "0.0.0" } -golem-wasm-ast = { path = "../wasm-ast", version = "0.0.0" } +golem-api-grpc = { path = "../golem-api-grpc", version = "0.0.0", optional = true } +golem-rib = { path = "../golem-rib", version = "0.0.0", default-features = false, features = ["protobuf", "poem", "json_in_errors"] } # TODO: make these optionals +golem-wasm-ast = { path = "../wasm-ast", version = "0.0.0", default-features = false, features = ["metadata"] } golem-wasm-rpc = { path = "../wasm-rpc", version = "0.0.0", default-features = false, features = ["host"] } anyhow = { workspace = true } @@ -23,37 +33,36 @@ bincode = { workspace = true } bytes = { workspace = true } chrono = { workspace = true } combine = { workspace = true } -console-subscriber = { workspace = true } +console-subscriber = { workspace = true, optional = true } dashmap = { workspace = true } derive_more = { workspace = true } -figment = { workspace = true } -fred = { workspace = true } -futures-core = { workspace = true } +figment = { workspace = true, optional = true } +fred = { workspace = true, optional = true } git-version = { workspace = true } http = { workspace = true } humantime-serde = { workspace = true } iso8601-timestamp = { workspace = true } itertools = { workspace = true } lazy_static = { workspace = true } -poem = { workspace = true } -poem-openapi = { workspace = true } -prometheus = { workspace = true } -prost = { workspace = true } -prost-types = { workspace = true } +poem = { workspace = true, optional = true } +poem-openapi = { workspace = true, optional = true } +prometheus = { workspace = true, optional = true } +prost = { workspace = true, optional = true } +prost-types = { workspace = true, optional = true } rand = { workspace = true } range-set-blaze = "0.1.16" regex = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } serde_yaml = { workspace = true } -sqlx = { workspace = true } +sqlx = { workspace = true, optional = true } thiserror = { workspace = true } toml = { workspace = true } -tokio = { workspace = true } -tonic = { workspace = true } -tracing = { workspace = true } -tracing-subscriber = { workspace = true } -tracing-serde = { workspace = true } +tokio = { workspace = true, optional = true } +tonic = { workspace = true, optional = true } +tracing = { workspace = true, optional = true } +tracing-subscriber = { workspace = true, optional = true } +tracing-serde = { workspace = true, optional = true } typed-path = { workspace = true } url = { workspace = true } uuid = { workspace = true } diff --git a/golem-common/src/client.rs b/golem-common/src/client.rs index 13b83830b..edab2b9b5 100644 --- a/golem-common/src/client.rs +++ b/golem-common/src/client.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::config::RetryConfig; +use crate::model::RetryConfig; use crate::retries::RetryState; use dashmap::DashMap; use http::Uri; diff --git a/golem-common/src/config.rs b/golem-common/src/config.rs index 580c04a5d..d83693533 100644 --- a/golem-common/src/config.rs +++ b/golem-common/src/config.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use bincode::{Decode, Encode}; +use crate::model::RetryConfig; use figment::providers::{Env, Format, Serialized, Toml}; use figment::value::Value; use figment::Figment; @@ -378,17 +378,6 @@ impl Default for RedisConfig { } } -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Encode, Decode)] -pub struct RetryConfig { - pub max_attempts: u32, - #[serde(with = "humantime_serde")] - pub min_delay: Duration, - #[serde(with = "humantime_serde")] - pub max_delay: Duration, - pub multiplier: f64, - pub max_jitter_factor: Option, -} - impl Default for RetryConfig { fn default() -> Self { Self::max_attempts_5() diff --git a/golem-common/src/lib.rs b/golem-common/src/lib.rs index 59d44573b..51102004f 100644 --- a/golem-common/src/lib.rs +++ b/golem-common/src/lib.rs @@ -15,22 +15,45 @@ use std::fmt; use std::fmt::{Display, Formatter}; +#[cfg(feature = "tokio")] pub mod cache; + +#[cfg(feature = "protobuf")] pub mod client; + +#[cfg(feature = "config")] pub mod config; pub mod golem_version; + +#[cfg(feature = "protobuf")] pub mod grpc; + +#[cfg(feature = "poem")] pub mod json_yaml; + +#[cfg(feature = "observability")] pub mod metrics; + pub mod model; pub mod newtype; + +#[cfg(feature = "redis")] pub mod redis; + +#[cfg(feature = "sql")] pub mod repo; + pub mod retriable_error; + +#[cfg(feature = "tokio")] pub mod retries; + pub mod serialization; + +#[cfg(feature = "observability")] pub mod tracing; + pub mod uri; #[cfg(test)] diff --git a/golem-common/src/model/component.rs b/golem-common/src/model/component.rs index 9f9f74eee..1f0d943c3 100644 --- a/golem-common/src/model/component.rs +++ b/golem-common/src/model/component.rs @@ -13,14 +13,8 @@ // limitations under the License. use crate::model::plugin::{DefaultPluginOwner, PluginOwner}; -use crate::model::{AccountId, HasAccountId}; -use crate::repo::RowMeta; -use poem_openapi::types::{ParseFromJSON, ToJSON}; -use poem_openapi::Object; +use crate::model::{AccountId, HasAccountId, PoemTypeRequirements}; use serde::{Deserialize, Serialize}; -use sqlx::postgres::PgRow; -use sqlx::sqlite::SqliteRow; -use sqlx::{Postgres, Sqlite}; use std::fmt::{Debug, Display}; use std::str::FromStr; @@ -33,17 +27,16 @@ pub trait ComponentOwner: + PartialEq + Serialize + for<'de> Deserialize<'de> - + poem_openapi::types::Type - + ParseFromJSON - + ToJSON + + PoemTypeRequirements + Send + Sync + 'static { - type Row: RowMeta - + RowMeta - + for<'r> sqlx::FromRow<'r, SqliteRow> - + for<'r> sqlx::FromRow<'r, PgRow> + #[cfg(feature = "sql")] + type Row: crate::repo::RowMeta + + crate::repo::RowMeta + + for<'r> sqlx::FromRow<'r, sqlx::sqlite::SqliteRow> + + for<'r> sqlx::FromRow<'r, sqlx::postgres::PgRow> + From + TryInto + Into<::Row> @@ -57,9 +50,10 @@ pub trait ComponentOwner: type PluginOwner: PluginOwner + From; } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Object)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] +#[cfg_attr(feature = "poem", oai(rename_all = "camelCase"))] #[serde(rename_all = "camelCase")] -#[oai(rename_all = "camelCase")] pub struct DefaultComponentOwner; impl Display for DefaultComponentOwner { @@ -93,6 +87,7 @@ impl From for DefaultPluginOwner { } impl ComponentOwner for DefaultComponentOwner { + #[cfg(feature = "sql")] type Row = crate::repo::component::DefaultComponentOwnerRow; type PluginOwner = DefaultPluginOwner; } diff --git a/golem-common/src/model/component_constraint.rs b/golem-common/src/model/component_constraint.rs index 8b57fa9c0..ae50907c6 100644 --- a/golem-common/src/model/component_constraint.rs +++ b/golem-common/src/model/component_constraint.rs @@ -1,5 +1,3 @@ -use golem_api_grpc::proto::golem::component::FunctionConstraint as FunctionConstraintProto; -use golem_api_grpc::proto::golem::component::FunctionConstraintCollection as FunctionConstraintCollectionProto; use golem_wasm_ast::analysis::AnalysedType; use rib::{RegistryKey, WorkerFunctionType, WorkerFunctionsInRib}; use std::collections::HashMap; @@ -13,40 +11,6 @@ pub struct FunctionConstraintCollection { pub function_constraints: Vec, } -impl TryFrom - for FunctionConstraintCollection -{ - type Error = String; - - fn try_from( - value: golem_api_grpc::proto::golem::component::FunctionConstraintCollection, - ) -> Result { - let collection = FunctionConstraintCollection { - function_constraints: value - .constraints - .iter() - .map(|constraint_proto| FunctionConstraint::try_from(constraint_proto.clone())) - .collect::>()?, - }; - - Ok(collection) - } -} - -impl From for FunctionConstraintCollectionProto { - fn from(value: FunctionConstraintCollection) -> Self { - FunctionConstraintCollectionProto { - constraints: value - .function_constraints - .iter() - .map(|function_constraint| { - FunctionConstraintProto::from(function_constraint.clone()) - }) - .collect(), - } - } -} - impl From for WorkerFunctionsInRib { fn from(value: FunctionConstraintCollection) -> Self { WorkerFunctionsInRib { @@ -165,52 +129,95 @@ impl FunctionConstraint { } } -impl TryFrom for FunctionConstraint { - type Error = String; - - fn try_from(value: FunctionConstraintProto) -> Result { - let return_types = value - .return_types - .iter() - .map(AnalysedType::try_from) - .collect::>()?; +#[cfg(feature = "protobuf")] +mod protobuf { + use crate::model::component_constraint::{FunctionConstraint, FunctionConstraintCollection}; + use golem_api_grpc::proto::golem::component::FunctionConstraint as FunctionConstraintProto; + use golem_api_grpc::proto::golem::component::FunctionConstraintCollection as FunctionConstraintCollectionProto; + use golem_wasm_ast::analysis::AnalysedType; + use rib::RegistryKey; + + impl TryFrom + for FunctionConstraintCollection + { + type Error = String; + + fn try_from( + value: golem_api_grpc::proto::golem::component::FunctionConstraintCollection, + ) -> Result { + let collection = FunctionConstraintCollection { + function_constraints: value + .constraints + .iter() + .map(|constraint_proto| FunctionConstraint::try_from(constraint_proto.clone())) + .collect::>()?, + }; + + Ok(collection) + } + } - let parameter_types = value - .parameter_types - .iter() - .map(AnalysedType::try_from) - .collect::>()?; - - let registry_key_proto = value.function_key.ok_or("Function key missing")?; - let function_key = RegistryKey::try_from(registry_key_proto)?; - let usage_count = value.usage_count; - - Ok(Self { - function_key, - return_types, - parameter_types, - usage_count, - }) + impl From for FunctionConstraintCollectionProto { + fn from(value: FunctionConstraintCollection) -> Self { + FunctionConstraintCollectionProto { + constraints: value + .function_constraints + .iter() + .map(|function_constraint| { + FunctionConstraintProto::from(function_constraint.clone()) + }) + .collect(), + } + } } -} -impl From for FunctionConstraintProto { - fn from(value: FunctionConstraint) -> Self { - let registry_key = value.function_key.into(); + impl TryFrom for FunctionConstraint { + type Error = String; - FunctionConstraintProto { - function_key: Some(registry_key), - parameter_types: value - .parameter_types - .iter() - .map(|analysed_type| analysed_type.into()) - .collect(), - return_types: value + fn try_from(value: FunctionConstraintProto) -> Result { + let return_types = value .return_types .iter() - .map(|analysed_type| analysed_type.into()) - .collect(), - usage_count: value.usage_count, + .map(AnalysedType::try_from) + .collect::>()?; + + let parameter_types = value + .parameter_types + .iter() + .map(AnalysedType::try_from) + .collect::>()?; + + let registry_key_proto = value.function_key.ok_or("Function key missing")?; + let function_key = RegistryKey::try_from(registry_key_proto)?; + let usage_count = value.usage_count; + + Ok(Self { + function_key, + return_types, + parameter_types, + usage_count, + }) + } + } + + impl From for FunctionConstraintProto { + fn from(value: FunctionConstraint) -> Self { + let registry_key = value.function_key.into(); + + FunctionConstraintProto { + function_key: Some(registry_key), + parameter_types: value + .parameter_types + .iter() + .map(|analysed_type| analysed_type.into()) + .collect(), + return_types: value + .return_types + .iter() + .map(|analysed_type| analysed_type.into()) + .collect(), + usage_count: value.usage_count, + } } } } diff --git a/golem-common/src/model/component_metadata.rs b/golem-common/src/model/component_metadata.rs index 4df17cddb..f6e8895b1 100644 --- a/golem-common/src/model/component_metadata.rs +++ b/golem-common/src/model/component_metadata.rs @@ -24,10 +24,12 @@ use golem_wasm_ast::{ component::Component, IgnoreAllButMetadata, }; -use poem_openapi::Object; use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Object, Encode, Decode)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Encode, Decode)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] +#[cfg_attr(feature = "poem", oai(rename_all = "camelCase"))] +#[serde(rename_all = "camelCase")] pub struct ComponentMetadata { pub exports: Vec, pub producers: Vec, @@ -42,169 +44,41 @@ impl ComponentMetadata { } #[derive( - Debug, - Clone, - PartialEq, - Eq, - Hash, - Ord, - PartialOrd, - Serialize, - Deserialize, - Object, - Encode, - Decode, + Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd, Serialize, Deserialize, Encode, Decode, )] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] +#[cfg_attr(feature = "poem", oai(rename_all = "camelCase"))] +#[serde(rename_all = "camelCase")] pub struct ProducerField { pub name: String, pub values: Vec, } #[derive( - Debug, - Clone, - PartialEq, - Eq, - Hash, - Ord, - PartialOrd, - Serialize, - Deserialize, - Object, - Encode, - Decode, + Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd, Serialize, Deserialize, Encode, Decode, )] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] +#[cfg_attr(feature = "poem", oai(rename_all = "camelCase"))] +#[serde(rename_all = "camelCase")] pub struct VersionedName { pub name: String, pub version: String, } -impl From for VersionedName { - fn from(value: golem_api_grpc::proto::golem::component::VersionedName) -> Self { - Self { - name: value.name, - version: value.version, - } - } -} - -impl From for golem_api_grpc::proto::golem::component::VersionedName { - fn from(value: VersionedName) -> Self { - Self { - name: value.name, - version: value.version, - } - } -} - -impl From for ProducerField { - fn from(value: golem_api_grpc::proto::golem::component::ProducerField) -> Self { - Self { - name: value.name, - values: value.values.into_iter().map(|value| value.into()).collect(), - } - } -} - -impl From for golem_api_grpc::proto::golem::component::ProducerField { - fn from(value: ProducerField) -> Self { - Self { - name: value.name, - values: value.values.into_iter().map(|value| value.into()).collect(), - } - } -} - #[derive( - Debug, - Clone, - PartialEq, - Eq, - Hash, - Ord, - PartialOrd, - Serialize, - Deserialize, - Object, - Encode, - Decode, + Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd, Serialize, Deserialize, Encode, Decode, )] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] +#[cfg_attr(feature = "poem", oai(rename_all = "camelCase"))] +#[serde(rename_all = "camelCase")] pub struct Producers { pub fields: Vec, } -impl From for Producers { - fn from(value: golem_api_grpc::proto::golem::component::Producers) -> Self { - Self { - fields: value.fields.into_iter().map(|field| field.into()).collect(), - } - } -} - -impl From for golem_api_grpc::proto::golem::component::Producers { - fn from(value: Producers) -> Self { - Self { - fields: value.fields.into_iter().map(|field| field.into()).collect(), - } - } -} - -impl From for Producers { - fn from(value: golem_wasm_ast::metadata::Producers) -> Self { - Self { - fields: value - .fields - .into_iter() - .map(|p| p.into()) - .collect::>(), - } - } -} - -impl From for golem_wasm_ast::metadata::Producers { - fn from(value: Producers) -> Self { - Self { - fields: value - .fields - .into_iter() - .map(|p| p.into()) - .collect::>(), - } - } -} - -impl From for ProducerField { - fn from(value: golem_wasm_ast::metadata::ProducersField) -> Self { - Self { - name: value.name, - values: value - .values - .into_iter() - .map(|value| VersionedName { - name: value.name, - version: value.version, - }) - .collect(), - } - } -} - -impl From for golem_wasm_ast::metadata::ProducersField { - fn from(value: ProducerField) -> Self { - Self { - name: value.name, - values: value - .values - .into_iter() - .map(|value| golem_wasm_ast::metadata::VersionedName { - name: value.name, - version: value.version, - }) - .collect(), - } - } -} -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Object, Encode, Decode)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Encode, Decode)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] +#[cfg_attr(feature = "poem", oai(rename_all = "camelCase"))] +#[serde(rename_all = "camelCase")] pub struct LinearMemory { /// Initial size of the linear memory in bytes pub initial: u64, @@ -216,8 +90,8 @@ impl LinearMemory { const PAGE_SIZE: u64 = 65536; } -impl From for LinearMemory { - fn from(value: golem_wasm_ast::core::Mem) -> Self { +impl From for LinearMemory { + fn from(value: Mem) -> Self { Self { initial: value.mem_type.limits.min * LinearMemory::PAGE_SIZE, maximum: value @@ -229,24 +103,6 @@ impl From for LinearMemory { } } -impl From for LinearMemory { - fn from(value: golem_api_grpc::proto::golem::component::LinearMemory) -> Self { - Self { - initial: value.initial, - maximum: value.maximum, - } - } -} - -impl From for golem_api_grpc::proto::golem::component::LinearMemory { - fn from(value: LinearMemory) -> Self { - Self { - initial: value.initial, - maximum: value.maximum, - } - } -} - impl From for ComponentMetadata { fn from(value: RawComponentMetadata) -> Self { let producers = value @@ -267,54 +123,6 @@ impl From for ComponentMetadata { } } -impl TryFrom for ComponentMetadata { - type Error = String; - - fn try_from( - value: golem_api_grpc::proto::golem::component::ComponentMetadata, - ) -> Result { - Ok(Self { - exports: value - .exports - .into_iter() - .map(|export| export.try_into()) - .collect::>()?, - producers: value - .producers - .into_iter() - .map(|producer| producer.into()) - .collect(), - memories: value - .memories - .into_iter() - .map(|memory| memory.into()) - .collect(), - }) - } -} - -impl From for golem_api_grpc::proto::golem::component::ComponentMetadata { - fn from(value: ComponentMetadata) -> Self { - Self { - exports: value - .exports - .into_iter() - .map(|export| export.into()) - .collect(), - producers: value - .producers - .into_iter() - .map(|producer| producer.into()) - .collect(), - memories: value - .memories - .into_iter() - .map(|memory| memory.into()) - .collect(), - } - } -} - // Metadata of Component in terms of golem_wasm_ast types pub struct RawComponentMetadata { pub exports: Vec, @@ -358,6 +166,62 @@ impl RawComponentMetadata { } } +impl From for Producers { + fn from(value: golem_wasm_ast::metadata::Producers) -> Self { + Self { + fields: value + .fields + .into_iter() + .map(|p| p.into()) + .collect::>(), + } + } +} + +impl From for golem_wasm_ast::metadata::Producers { + fn from(value: Producers) -> Self { + Self { + fields: value + .fields + .into_iter() + .map(|p| p.into()) + .collect::>(), + } + } +} + +impl From for ProducerField { + fn from(value: golem_wasm_ast::metadata::ProducersField) -> Self { + Self { + name: value.name, + values: value + .values + .into_iter() + .map(|value| VersionedName { + name: value.name, + version: value.version, + }) + .collect(), + } + } +} + +impl From for golem_wasm_ast::metadata::ProducersField { + fn from(value: ProducerField) -> Self { + Self { + name: value.name, + values: value + .values + .into_iter() + .map(|value| golem_wasm_ast::metadata::VersionedName { + name: value.name, + version: value.version, + }) + .collect(), + } + } +} + #[derive(Debug, thiserror::Error)] pub enum ComponentProcessingError { Parsing(String), @@ -429,3 +293,128 @@ fn drop_from_constructor(constructor: &AnalysedFunction) -> AnalysedFunction { results: vec![], } } + +#[cfg(feature = "protobuf")] +mod protobuf { + use crate::model::component_metadata::{ + ComponentMetadata, LinearMemory, ProducerField, Producers, VersionedName, + }; + + impl From for VersionedName { + fn from(value: golem_api_grpc::proto::golem::component::VersionedName) -> Self { + Self { + name: value.name, + version: value.version, + } + } + } + + impl From for golem_api_grpc::proto::golem::component::VersionedName { + fn from(value: VersionedName) -> Self { + Self { + name: value.name, + version: value.version, + } + } + } + + impl From for ProducerField { + fn from(value: golem_api_grpc::proto::golem::component::ProducerField) -> Self { + Self { + name: value.name, + values: value.values.into_iter().map(|value| value.into()).collect(), + } + } + } + + impl From for golem_api_grpc::proto::golem::component::ProducerField { + fn from(value: ProducerField) -> Self { + Self { + name: value.name, + values: value.values.into_iter().map(|value| value.into()).collect(), + } + } + } + + impl From for Producers { + fn from(value: golem_api_grpc::proto::golem::component::Producers) -> Self { + Self { + fields: value.fields.into_iter().map(|field| field.into()).collect(), + } + } + } + + impl From for golem_api_grpc::proto::golem::component::Producers { + fn from(value: Producers) -> Self { + Self { + fields: value.fields.into_iter().map(|field| field.into()).collect(), + } + } + } + + impl From for LinearMemory { + fn from(value: golem_api_grpc::proto::golem::component::LinearMemory) -> Self { + Self { + initial: value.initial, + maximum: value.maximum, + } + } + } + + impl From for golem_api_grpc::proto::golem::component::LinearMemory { + fn from(value: LinearMemory) -> Self { + Self { + initial: value.initial, + maximum: value.maximum, + } + } + } + + impl TryFrom for ComponentMetadata { + type Error = String; + + fn try_from( + value: golem_api_grpc::proto::golem::component::ComponentMetadata, + ) -> Result { + Ok(Self { + exports: value + .exports + .into_iter() + .map(|export| export.try_into()) + .collect::>()?, + producers: value + .producers + .into_iter() + .map(|producer| producer.into()) + .collect(), + memories: value + .memories + .into_iter() + .map(|memory| memory.into()) + .collect(), + }) + } + } + + impl From for golem_api_grpc::proto::golem::component::ComponentMetadata { + fn from(value: ComponentMetadata) -> Self { + Self { + exports: value + .exports + .into_iter() + .map(|export| export.into()) + .collect(), + producers: value + .producers + .into_iter() + .map(|producer| producer.into()) + .collect(), + memories: value + .memories + .into_iter() + .map(|memory| memory.into()) + .collect(), + } + } + } +} diff --git a/golem-common/src/model/mod.rs b/golem-common/src/model/mod.rs index 95dbba6a1..cdba257b5 100644 --- a/golem-common/src/model/mod.rs +++ b/golem-common/src/model/mod.rs @@ -12,39 +12,28 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::config::RetryConfig; use crate::model::oplog::{ IndexedResourceKey, OplogEntry, OplogIndex, TimestampedUpdateDescription, WorkerResourceId, }; use crate::model::regions::DeletedRegions; use crate::newtype_uuid; use crate::uri::oss::urn::WorkerUrn; -use anyhow; use bincode::de::read::Reader; use bincode::de::{BorrowDecoder, Decoder}; use bincode::enc::write::Writer; use bincode::enc::Encoder; use bincode::error::{DecodeError, EncodeError}; use bincode::{BorrowDecode, Decode, Encode}; -use golem_api_grpc::proto::golem; -use golem_api_grpc::proto::golem::shardmanager::{ - Pod as GrpcPod, RoutingTable as GrpcRoutingTable, RoutingTableEntry as GrpcRoutingTableEntry, -}; -use golem_api_grpc::proto::golem::worker::Cursor; + use golem_wasm_ast::analysis::analysed_type::{ field, list, r#enum, record, s64, str, tuple, u32, u64, }; use golem_wasm_ast::analysis::{analysed_type, AnalysedType}; use golem_wasm_rpc::IntoValue; -use poem::http::Uri; -use poem_openapi::registry::{MetaSchema, MetaSchemaRef}; -use poem_openapi::types::{ParseFromJSON, ParseFromParameter, ParseResult, ToJSON}; -use poem_openapi::{Enum, NewType, Object, Union}; +use http::Uri; use rand::prelude::IteratorRandom; use serde::de::Unexpected; use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; -use serde_json::Value; -use std::borrow::Cow; use std::cmp::Ordering; use std::collections::{HashMap, HashSet, VecDeque}; use std::fmt::{Display, Formatter}; @@ -65,6 +54,33 @@ pub mod public_oplog; pub mod regions; pub mod trim_date; +#[cfg(feature = "poem")] +mod poem; + +#[cfg(feature = "protobuf")] +pub mod protobuf; + +#[cfg(feature = "poem")] +pub trait PoemTypeRequirements: + poem_openapi::types::Type + poem_openapi::types::ParseFromJSON + poem_openapi::types::ToJSON +{ +} + +#[cfg(not(feature = "poem"))] +pub trait PoemTypeRequirements {} + +#[cfg(feature = "poem")] +impl< + T: poem_openapi::types::Type + + poem_openapi::types::ParseFromJSON + + poem_openapi::types::ToJSON, + > PoemTypeRequirements for T +{ +} + +#[cfg(not(feature = "poem"))] +impl PoemTypeRequirements for T {} + newtype_uuid!( ComponentId, golem_api_grpc::proto::golem::component::ComponentId @@ -99,57 +115,6 @@ impl Display for Timestamp { } } -impl ToJSON for Timestamp { - fn to_json(&self) -> Option { - Some(Value::String(self.0.to_string())) - } -} - -impl poem_openapi::types::Type for Timestamp { - const IS_REQUIRED: bool = true; - type RawValueType = Self; - type RawElementValueType = Self; - - fn name() -> Cow<'static, str> { - Cow::from("string(timestamp)") - } - - fn schema_ref() -> MetaSchemaRef { - MetaSchemaRef::Inline(Box::new(MetaSchema::new_with_format("string", "date-time"))) - } - - fn as_raw_value(&self) -> Option<&Self::RawValueType> { - Some(self) - } - - fn raw_element_iter<'a>( - &'a self, - ) -> Box + 'a> { - Box::new(self.as_raw_value().into_iter()) - } -} - -impl ParseFromParameter for Timestamp { - fn parse_from_parameter(value: &str) -> ParseResult { - value.parse().map_err(|_| { - poem_openapi::types::ParseError::::custom( - "Unexpected representation of timestamp".to_string(), - ) - }) - } -} - -impl ParseFromJSON for Timestamp { - fn parse_from_json(value: Option) -> ParseResult { - match value { - Some(Value::String(s)) => Timestamp::parse_from_parameter(&s), - _ => Err(poem_openapi::types::ParseError::::custom( - "Unexpected representation of timestamp".to_string(), - )), - } - } -} - impl FromStr for Timestamp { type Err = String; @@ -216,27 +181,6 @@ impl<'de> bincode::BorrowDecode<'de> for Timestamp { } } -impl From for prost_types::Timestamp { - fn from(value: Timestamp) -> Self { - let d = value - .0 - .duration_since(iso8601_timestamp::Timestamp::UNIX_EPOCH); - Self { - seconds: d.whole_seconds(), - nanos: d.subsec_nanoseconds(), - } - } -} - -impl From for Timestamp { - fn from(value: prost_types::Timestamp) -> Self { - Timestamp( - iso8601_timestamp::Timestamp::UNIX_EPOCH - .add(Duration::new(value.seconds as u64, value.nanos as u32)), - ) - } -} - impl From for Timestamp { fn from(value: u64) -> Self { Timestamp(iso8601_timestamp::Timestamp::UNIX_EPOCH.add(Duration::from_millis(value))) @@ -261,9 +205,10 @@ impl IntoValue for Timestamp { pub type ComponentVersion = u64; -#[derive(Clone, Debug, Eq, PartialEq, Hash, Encode, Decode, Serialize, Deserialize, Object)] +#[derive(Clone, Debug, Eq, PartialEq, Hash, Encode, Decode, Serialize, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] +#[cfg_attr(feature = "poem", oai(rename_all = "camelCase"))] #[serde(rename_all = "camelCase")] -#[oai(rename_all = "camelCase")] pub struct WorkerId { pub component_id: ComponentId, pub worker_name: String, @@ -318,28 +263,6 @@ impl Display for WorkerId { } } -impl From for golem_api_grpc::proto::golem::worker::WorkerId { - fn from(value: WorkerId) -> Self { - Self { - component_id: Some(value.component_id.into()), - name: value.worker_name, - } - } -} - -impl TryFrom for WorkerId { - type Error = String; - - fn try_from( - value: golem_api_grpc::proto::golem::worker::WorkerId, - ) -> Result { - Ok(Self { - component_id: value.component_id.unwrap().try_into()?, - worker_name: value.name, - }) - } -} - impl IntoValue for WorkerId { fn into_value(self) -> golem_wasm_rpc::Value { golem_wasm_rpc::Value::Record(vec![ @@ -481,32 +404,10 @@ impl From<&WorkerId> for TargetWorkerId { } } -impl TryFrom for TargetWorkerId { - type Error = String; - - fn try_from(value: golem::worker::TargetWorkerId) -> Result { - Ok(Self { - component_id: value - .component_id - .ok_or("Missing component_id")? - .try_into()?, - worker_name: value.name, - }) - } -} - -impl From for golem::worker::TargetWorkerId { - fn from(value: TargetWorkerId) -> Self { - Self { - component_id: Some(value.component_id.into()), - name: value.worker_name, - } - } -} - -#[derive(Clone, Debug, Eq, PartialEq, Hash, Encode, Decode, Serialize, Deserialize, Object)] +#[derive(Clone, Debug, Eq, PartialEq, Hash, Encode, Decode, Serialize, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] +#[cfg_attr(feature = "poem", oai(rename_all = "camelCase"))] #[serde(rename_all = "camelCase")] -#[oai(rename_all = "camelCase")] pub struct PromiseId { pub worker_id: WorkerId, pub oplog_idx: OplogIndex, @@ -518,28 +419,6 @@ impl PromiseId { } } -impl From for golem_api_grpc::proto::golem::worker::PromiseId { - fn from(value: PromiseId) -> Self { - Self { - worker_id: Some(value.worker_id.into()), - oplog_idx: value.oplog_idx.into(), - } - } -} - -impl TryFrom for PromiseId { - type Error = String; - - fn try_from( - value: golem_api_grpc::proto::golem::worker::PromiseId, - ) -> Result { - Ok(Self { - worker_id: value.worker_id.ok_or("Missing worker_id")?.try_into()?, - oplog_idx: OplogIndex::from_u64(value.oplog_idx), - }) - } -} - impl Display for PromiseId { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}/{}", self.worker_id, self.oplog_idx) @@ -622,20 +501,11 @@ impl Display for ScheduleId { } #[derive( - Clone, - Copy, - Debug, - Eq, - PartialEq, - PartialOrd, - Ord, - Hash, - Serialize, - Deserialize, - Encode, - Decode, - Object, + Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize, Encode, Decode, )] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] +#[cfg_attr(feature = "poem", oai(rename_all = "camelCase"))] +#[serde(rename_all = "camelCase")] pub struct ShardId { value: i64, } @@ -684,18 +554,6 @@ impl Display for ShardId { } } -impl From for golem_api_grpc::proto::golem::shardmanager::ShardId { - fn from(value: ShardId) -> golem_api_grpc::proto::golem::shardmanager::ShardId { - golem_api_grpc::proto::golem::shardmanager::ShardId { value: value.value } - } -} - -impl From for ShardId { - fn from(proto: golem_api_grpc::proto::golem::shardmanager::ShardId) -> Self { - Self { value: proto.value } - } -} - impl IntoValue for ShardId { fn into_value(self) -> golem_wasm_rpc::Value { golem_wasm_rpc::Value::S64(self.value) @@ -728,15 +586,6 @@ impl Pod { } } -impl From for Pod { - fn from(value: GrpcPod) -> Self { - Self { - host: value.host, - port: value.port as u16, - } - } -} - #[derive(Clone)] pub struct RoutingTable { pub number_of_shards: NumberOfShards, @@ -766,36 +615,12 @@ impl RoutingTable { } } -impl From for RoutingTable { - fn from(value: GrpcRoutingTable) -> Self { - Self { - number_of_shards: NumberOfShards { - value: value.number_of_shards as usize, - }, - shard_assignments: value - .shard_assignments - .into_iter() - .map(RoutingTableEntry::from) - .map(|routing_table_entry| (routing_table_entry.shard_id, routing_table_entry.pod)) - .collect(), - } - } -} - +#[allow(dead_code)] pub struct RoutingTableEntry { shard_id: ShardId, pod: Pod, } -impl From for RoutingTableEntry { - fn from(value: GrpcRoutingTableEntry) -> Self { - Self { - shard_id: value.shard_id.unwrap().into(), - pod: value.pod.unwrap().into(), - } - } -} - #[derive(Clone, Debug, Default)] pub struct ShardAssignment { pub number_of_shards: usize, @@ -907,18 +732,6 @@ impl<'de> Deserialize<'de> for IdempotencyKey { } } -impl From for IdempotencyKey { - fn from(proto: golem_api_grpc::proto::golem::worker::IdempotencyKey) -> Self { - Self { value: proto.value } - } -} - -impl From for golem_api_grpc::proto::golem::worker::IdempotencyKey { - fn from(value: IdempotencyKey) -> Self { - Self { value: value.value } - } -} - impl IntoValue for IdempotencyKey { fn into_value(self) -> golem_wasm_rpc::Value { golem_wasm_rpc::Value::String(self.value) @@ -929,55 +742,6 @@ impl IntoValue for IdempotencyKey { } } -impl poem_openapi::types::Type for IdempotencyKey { - const IS_REQUIRED: bool = true; - type RawValueType = Self; - type RawElementValueType = Self; - - fn name() -> Cow<'static, str> { - Cow::from(format!("string({})", stringify!(InvocationKey))) - } - - fn schema_ref() -> MetaSchemaRef { - MetaSchemaRef::Inline(Box::new(MetaSchema::new("string"))) - } - - fn as_raw_value(&self) -> Option<&Self::RawValueType> { - Some(self) - } - - fn raw_element_iter<'a>( - &'a self, - ) -> Box + 'a> { - Box::new(self.as_raw_value().into_iter()) - } -} - -impl ParseFromParameter for IdempotencyKey { - fn parse_from_parameter(value: &str) -> ParseResult { - Ok(Self { - value: value.to_string(), - }) - } -} - -impl ParseFromJSON for IdempotencyKey { - fn parse_from_json(value: Option) -> ParseResult { - match value { - Some(Value::String(s)) => Ok(Self { value: s }), - _ => Err(poem_openapi::types::ParseError::::custom( - format!("Unexpected representation of {}", stringify!(InvocationKey)), - )), - } - } -} - -impl ToJSON for IdempotencyKey { - fn to_json(&self) -> Option { - Some(Value::String(self.value.clone())) - } -} - impl Display for IdempotencyKey { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.value) @@ -1043,6 +807,17 @@ pub struct WorkerResourceDescription { pub indexed_resource_key: Option, } +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Encode, Decode)] +pub struct RetryConfig { + pub max_attempts: u32, + #[serde(with = "humantime_serde")] + pub min_delay: Duration, + #[serde(with = "humantime_serde")] + pub max_delay: Duration, + pub multiplier: f64, + pub max_jitter_factor: Option, +} + /// Contains status information about a worker according to a given oplog index. /// /// This status is just cached information, all fields must be computable by the oplog alone. @@ -1188,7 +963,8 @@ pub struct SuccessfulUpdateRecord { /// /// This is always recorded together with the current oplog index, and it can only be used /// as a source of truth if there are no newer oplog entries since the record. -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Encode, Decode, Enum)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Encode, Decode)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Enum))] pub enum WorkerStatus { /// The worker is running an invoked function Running, @@ -1251,24 +1027,6 @@ impl Display for WorkerStatus { } } -impl From for golem_api_grpc::proto::golem::worker::WorkerStatus { - fn from(value: WorkerStatus) -> Self { - match value { - WorkerStatus::Running => golem_api_grpc::proto::golem::worker::WorkerStatus::Running, - WorkerStatus::Idle => golem_api_grpc::proto::golem::worker::WorkerStatus::Idle, - WorkerStatus::Suspended => { - golem_api_grpc::proto::golem::worker::WorkerStatus::Suspended - } - WorkerStatus::Interrupted => { - golem_api_grpc::proto::golem::worker::WorkerStatus::Interrupted - } - WorkerStatus::Retrying => golem_api_grpc::proto::golem::worker::WorkerStatus::Retrying, - WorkerStatus::Failed => golem_api_grpc::proto::golem::worker::WorkerStatus::Failed, - WorkerStatus::Exited => golem_api_grpc::proto::golem::worker::WorkerStatus::Exited, - } - } -} - impl TryFrom for WorkerStatus { type Error = String; @@ -1405,67 +1163,6 @@ impl From<&str> for AccountId { } } -impl From for AccountId { - fn from(proto: golem_api_grpc::proto::golem::common::AccountId) -> Self { - Self { value: proto.name } - } -} - -impl From for golem_api_grpc::proto::golem::common::AccountId { - fn from(value: AccountId) -> Self { - golem_api_grpc::proto::golem::common::AccountId { name: value.value } - } -} - -impl poem_openapi::types::Type for AccountId { - const IS_REQUIRED: bool = true; - type RawValueType = Self; - type RawElementValueType = Self; - - fn name() -> Cow<'static, str> { - Cow::from("string(account_id)") - } - - fn schema_ref() -> MetaSchemaRef { - MetaSchemaRef::Inline(Box::new(MetaSchema::new("string"))) - } - - fn as_raw_value(&self) -> Option<&Self::RawValueType> { - Some(self) - } - - fn raw_element_iter<'a>( - &'a self, - ) -> Box + 'a> { - Box::new(self.as_raw_value().into_iter()) - } -} - -impl ParseFromParameter for AccountId { - fn parse_from_parameter(value: &str) -> ParseResult { - Ok(Self { - value: value.to_string(), - }) - } -} - -impl ParseFromJSON for AccountId { - fn parse_from_json(value: Option) -> ParseResult { - match value { - Some(Value::String(s)) => Ok(Self { value: s }), - _ => Err(poem_openapi::types::ParseError::::custom( - "Unexpected representation of AccountId".to_string(), - )), - } - } -} - -impl ToJSON for AccountId { - fn to_json(&self) -> Option { - Some(Value::String(self.value.clone())) - } -} - impl Display for AccountId { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}", &self.value) @@ -1486,7 +1183,10 @@ pub trait HasAccountId { fn account_id(&self) -> AccountId; } -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Encode, Decode, Object)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Encode, Decode)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] +#[cfg_attr(feature = "poem", oai(rename_all = "camelCase"))] +#[serde(rename_all = "camelCase")] pub struct WorkerNameFilter { pub comparator: StringFilterComparator, pub value: String, @@ -1504,7 +1204,10 @@ impl Display for WorkerNameFilter { } } -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Encode, Decode, Object)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Encode, Decode)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] +#[cfg_attr(feature = "poem", oai(rename_all = "camelCase"))] +#[serde(rename_all = "camelCase")] pub struct WorkerStatusFilter { pub comparator: FilterComparator, pub value: WorkerStatus, @@ -1522,7 +1225,10 @@ impl Display for WorkerStatusFilter { } } -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Encode, Decode, Object)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Encode, Decode)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] +#[cfg_attr(feature = "poem", oai(rename_all = "camelCase"))] +#[serde(rename_all = "camelCase")] pub struct WorkerVersionFilter { pub comparator: FilterComparator, pub value: ComponentVersion, @@ -1540,7 +1246,10 @@ impl Display for WorkerVersionFilter { } } -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Encode, Decode, Object)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Encode, Decode)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] +#[cfg_attr(feature = "poem", oai(rename_all = "camelCase"))] +#[serde(rename_all = "camelCase")] pub struct WorkerCreatedAtFilter { pub comparator: FilterComparator, pub value: Timestamp, @@ -1558,7 +1267,10 @@ impl Display for WorkerCreatedAtFilter { } } -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Encode, Decode, Object)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Encode, Decode)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] +#[cfg_attr(feature = "poem", oai(rename_all = "camelCase"))] +#[serde(rename_all = "camelCase")] pub struct WorkerEnvFilter { pub name: String, pub comparator: StringFilterComparator, @@ -1581,7 +1293,10 @@ impl Display for WorkerEnvFilter { } } -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Encode, Decode, Object)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Encode, Decode)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] +#[cfg_attr(feature = "poem", oai(rename_all = "camelCase"))] +#[serde(rename_all = "camelCase")] pub struct WorkerAndFilter { pub filters: Vec, } @@ -1606,7 +1321,10 @@ impl Display for WorkerAndFilter { } } -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Encode, Decode, Object)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Encode, Decode)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] +#[cfg_attr(feature = "poem", oai(rename_all = "camelCase"))] +#[serde(rename_all = "camelCase")] pub struct WorkerOrFilter { pub filters: Vec, } @@ -1631,7 +1349,10 @@ impl Display for WorkerOrFilter { } } -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Encode, Decode, Object)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Encode, Decode)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] +#[cfg_attr(feature = "poem", oai(rename_all = "camelCase"))] +#[serde(rename_all = "camelCase")] pub struct WorkerNotFilter { filter: Box, } @@ -1650,8 +1371,9 @@ impl Display for WorkerNotFilter { } } -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Encode, Decode, Union)] -#[oai(discriminator_name = "type", one_of = true)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Encode, Decode)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Union))] +#[cfg_attr(feature = "poem", oai(discriminator_name = "type", one_of = true))] #[serde(tag = "type")] pub enum WorkerFilter { Name(WorkerNameFilter), @@ -1862,148 +1584,8 @@ impl FromStr for WorkerFilter { } } -impl TryFrom for WorkerFilter { - type Error = String; - - fn try_from( - value: golem_api_grpc::proto::golem::worker::WorkerFilter, - ) -> Result { - match value.filter { - Some(filter) => match filter { - golem_api_grpc::proto::golem::worker::worker_filter::Filter::Name(filter) => Ok( - WorkerFilter::new_name(filter.comparator.try_into()?, filter.value), - ), - golem_api_grpc::proto::golem::worker::worker_filter::Filter::Version(filter) => Ok( - WorkerFilter::new_version(filter.comparator.try_into()?, filter.value), - ), - golem_api_grpc::proto::golem::worker::worker_filter::Filter::Status(filter) => { - Ok(WorkerFilter::new_status( - filter.comparator.try_into()?, - filter.value.try_into()?, - )) - } - golem_api_grpc::proto::golem::worker::worker_filter::Filter::CreatedAt(filter) => { - let value = filter - .value - .map(|t| t.into()) - .ok_or_else(|| "Missing value".to_string())?; - Ok(WorkerFilter::new_created_at( - filter.comparator.try_into()?, - value, - )) - } - golem_api_grpc::proto::golem::worker::worker_filter::Filter::Env(filter) => Ok( - WorkerFilter::new_env(filter.name, filter.comparator.try_into()?, filter.value), - ), - golem_api_grpc::proto::golem::worker::worker_filter::Filter::Not(filter) => { - let filter = *filter.filter.ok_or_else(|| "Missing filter".to_string())?; - Ok(WorkerFilter::new_not(filter.try_into()?)) - } - golem_api_grpc::proto::golem::worker::worker_filter::Filter::And( - golem_api_grpc::proto::golem::worker::WorkerAndFilter { filters }, - ) => { - let filters = filters.into_iter().map(|f| f.try_into()).collect::, - String, - >>( - )?; - - Ok(WorkerFilter::new_and(filters)) - } - golem_api_grpc::proto::golem::worker::worker_filter::Filter::Or( - golem_api_grpc::proto::golem::worker::WorkerOrFilter { filters }, - ) => { - let filters = filters.into_iter().map(|f| f.try_into()).collect::, - String, - >>( - )?; - - Ok(WorkerFilter::new_or(filters)) - } - }, - None => Err("Missing filter".to_string()), - } - } -} - -impl From for golem_api_grpc::proto::golem::worker::WorkerFilter { - fn from(value: WorkerFilter) -> Self { - let filter = match value { - WorkerFilter::Name(WorkerNameFilter { comparator, value }) => { - golem_api_grpc::proto::golem::worker::worker_filter::Filter::Name( - golem_api_grpc::proto::golem::worker::WorkerNameFilter { - comparator: comparator.into(), - value, - }, - ) - } - WorkerFilter::Version(WorkerVersionFilter { comparator, value }) => { - golem_api_grpc::proto::golem::worker::worker_filter::Filter::Version( - golem_api_grpc::proto::golem::worker::WorkerVersionFilter { - comparator: comparator.into(), - value, - }, - ) - } - WorkerFilter::Env(WorkerEnvFilter { - name, - comparator, - value, - }) => golem_api_grpc::proto::golem::worker::worker_filter::Filter::Env( - golem_api_grpc::proto::golem::worker::WorkerEnvFilter { - name, - comparator: comparator.into(), - value, - }, - ), - WorkerFilter::Status(WorkerStatusFilter { comparator, value }) => { - golem_api_grpc::proto::golem::worker::worker_filter::Filter::Status( - golem_api_grpc::proto::golem::worker::WorkerStatusFilter { - comparator: comparator.into(), - value: value.into(), - }, - ) - } - WorkerFilter::CreatedAt(WorkerCreatedAtFilter { comparator, value }) => { - golem_api_grpc::proto::golem::worker::worker_filter::Filter::CreatedAt( - golem_api_grpc::proto::golem::worker::WorkerCreatedAtFilter { - value: Some(value.into()), - comparator: comparator.into(), - }, - ) - } - WorkerFilter::Not(WorkerNotFilter { filter }) => { - let f: golem_api_grpc::proto::golem::worker::WorkerFilter = (*filter).into(); - golem_api_grpc::proto::golem::worker::worker_filter::Filter::Not(Box::new( - golem_api_grpc::proto::golem::worker::WorkerNotFilter { - filter: Some(Box::new(f)), - }, - )) - } - WorkerFilter::And(filter) => { - golem_api_grpc::proto::golem::worker::worker_filter::Filter::And( - golem_api_grpc::proto::golem::worker::WorkerAndFilter { - filters: filter.filters.into_iter().map(|f| f.into()).collect(), - }, - ) - } - WorkerFilter::Or(filter) => { - golem_api_grpc::proto::golem::worker::worker_filter::Filter::Or( - golem_api_grpc::proto::golem::worker::WorkerOrFilter { - filters: filter.filters.into_iter().map(|f| f.into()).collect(), - }, - ) - } - }; - - golem_api_grpc::proto::golem::worker::WorkerFilter { - filter: Some(filter), - } - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Encode, Decode, Enum)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Encode, Decode)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Enum))] pub enum StringFilterComparator { Equal, NotEqual, @@ -2026,25 +1608,6 @@ impl StringFilterComparator { } } -impl From for golem_api_grpc::proto::golem::common::StringFilterComparator { - fn from(value: StringFilterComparator) -> Self { - match value { - StringFilterComparator::Equal => { - golem_api_grpc::proto::golem::common::StringFilterComparator::StringEqual - } - StringFilterComparator::NotEqual => { - golem_api_grpc::proto::golem::common::StringFilterComparator::StringNotEqual - } - StringFilterComparator::Like => { - golem_api_grpc::proto::golem::common::StringFilterComparator::StringLike - } - StringFilterComparator::NotLike => { - golem_api_grpc::proto::golem::common::StringFilterComparator::StringNotLike - } - } - } -} - impl FromStr for StringFilterComparator { type Err = String; @@ -2096,7 +1659,8 @@ impl Display for StringFilterComparator { } } -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Encode, Decode, Enum)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Encode, Decode)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Enum))] pub enum FilterComparator { Equal, NotEqual, @@ -2148,29 +1712,6 @@ impl FromStr for FilterComparator { } } -impl From for golem_api_grpc::proto::golem::common::FilterComparator { - fn from(value: FilterComparator) -> Self { - match value { - FilterComparator::Equal => { - golem_api_grpc::proto::golem::common::FilterComparator::Equal - } - FilterComparator::NotEqual => { - golem_api_grpc::proto::golem::common::FilterComparator::NotEqual - } - FilterComparator::Less => golem_api_grpc::proto::golem::common::FilterComparator::Less, - FilterComparator::LessEqual => { - golem_api_grpc::proto::golem::common::FilterComparator::LessEqual - } - FilterComparator::Greater => { - golem_api_grpc::proto::golem::common::FilterComparator::Greater - } - FilterComparator::GreaterEqual => { - golem_api_grpc::proto::golem::common::FilterComparator::GreaterEqual - } - } - } -} - impl TryFrom for FilterComparator { type Error = String; @@ -2200,7 +1741,10 @@ impl From for i32 { } } -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Encode, Decode, Object, Default)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Encode, Decode, Default)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] +#[cfg_attr(feature = "poem", oai(rename_all = "camelCase"))] +#[serde(rename_all = "camelCase")] pub struct ScanCursor { pub cursor: u64, pub layer: usize, @@ -2250,24 +1794,6 @@ impl FromStr for ScanCursor { } } -impl From for ScanCursor { - fn from(value: Cursor) -> Self { - Self { - cursor: value.cursor, - layer: value.layer as usize, - } - } -} - -impl From for Cursor { - fn from(value: ScanCursor) -> Self { - Self { - cursor: value.cursor, - layer: value.layer as u64, - } - } -} - #[derive(Debug, Clone, PartialEq, Eq, Hash, Encode, Decode, Serialize, Deserialize)] pub enum LogLevel { Trace, @@ -2278,32 +1804,6 @@ pub enum LogLevel { Critical, } -impl From for LogLevel { - fn from(value: golem_api_grpc::proto::golem::worker::Level) -> Self { - match value { - golem_api_grpc::proto::golem::worker::Level::Trace => LogLevel::Trace, - golem_api_grpc::proto::golem::worker::Level::Debug => LogLevel::Debug, - golem_api_grpc::proto::golem::worker::Level::Info => LogLevel::Info, - golem_api_grpc::proto::golem::worker::Level::Warn => LogLevel::Warn, - golem_api_grpc::proto::golem::worker::Level::Error => LogLevel::Error, - golem_api_grpc::proto::golem::worker::Level::Critical => LogLevel::Critical, - } - } -} - -impl From for golem_api_grpc::proto::golem::worker::Level { - fn from(value: LogLevel) -> Self { - match value { - LogLevel::Trace => golem_api_grpc::proto::golem::worker::Level::Trace, - LogLevel::Debug => golem_api_grpc::proto::golem::worker::Level::Debug, - LogLevel::Info => golem_api_grpc::proto::golem::worker::Level::Info, - LogLevel::Warn => golem_api_grpc::proto::golem::worker::Level::Warn, - LogLevel::Error => golem_api_grpc::proto::golem::worker::Level::Error, - LogLevel::Critical => golem_api_grpc::proto::golem::worker::Level::Critical, - } - } -} - #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum WorkerEvent { StdOut { @@ -2458,135 +1958,8 @@ impl Display for WorkerEvent { } } -impl TryFrom for WorkerEvent { - type Error = String; - - fn try_from( - value: golem_api_grpc::proto::golem::worker::LogEvent, - ) -> Result { - match value.event { - Some(event) => match event { - golem_api_grpc::proto::golem::worker::log_event::Event::Stdout(event) => { - Ok(WorkerEvent::StdOut { - timestamp: event.timestamp.ok_or("Missing timestamp")?.into(), - bytes: event.message.into_bytes(), - }) - } - golem_api_grpc::proto::golem::worker::log_event::Event::Stderr(event) => { - Ok(WorkerEvent::StdErr { - timestamp: event.timestamp.ok_or("Missing timestamp")?.into(), - bytes: event.message.into_bytes(), - }) - } - golem_api_grpc::proto::golem::worker::log_event::Event::Log(event) => { - Ok(WorkerEvent::Log { - timestamp: event.timestamp.ok_or("Missing timestamp")?.into(), - level: event.level().into(), - context: event.context, - message: event.message, - }) - } - golem_api_grpc::proto::golem::worker::log_event::Event::InvocationStarted( - event, - ) => Ok(WorkerEvent::InvocationStart { - timestamp: event.timestamp.ok_or("Missing timestamp")?.into(), - function: event.function, - idempotency_key: event - .idempotency_key - .ok_or("Missing idempotency key")? - .into(), - }), - golem_api_grpc::proto::golem::worker::log_event::Event::InvocationFinished( - event, - ) => Ok(WorkerEvent::InvocationFinished { - timestamp: event.timestamp.ok_or("Missing timestamp")?.into(), - function: event.function, - idempotency_key: event - .idempotency_key - .ok_or("Missing idempotency key")? - .into(), - }), - }, - None => Err("Missing event".to_string()), - } - } -} - -impl TryFrom for golem_api_grpc::proto::golem::worker::LogEvent { - type Error = String; - - fn try_from(value: WorkerEvent) -> Result { - match value { - WorkerEvent::StdOut { timestamp, bytes } => Ok(golem::worker::LogEvent { - event: Some(golem::worker::log_event::Event::Stdout( - golem::worker::StdOutLog { - message: String::from_utf8_lossy(&bytes).to_string(), - timestamp: Some(timestamp.into()), - }, - )), - }), - WorkerEvent::StdErr { timestamp, bytes } => Ok(golem::worker::LogEvent { - event: Some( - golem_api_grpc::proto::golem::worker::log_event::Event::Stderr( - golem::worker::StdErrLog { - message: String::from_utf8_lossy(&bytes).to_string(), - timestamp: Some(timestamp.into()), - }, - ), - ), - }), - WorkerEvent::Log { - timestamp, - level, - context, - message, - } => Ok(golem::worker::LogEvent { - event: Some(golem::worker::log_event::Event::Log(golem::worker::Log { - level: match level { - LogLevel::Trace => golem::worker::Level::Trace.into(), - LogLevel::Debug => golem::worker::Level::Debug.into(), - LogLevel::Info => golem::worker::Level::Info.into(), - LogLevel::Warn => golem::worker::Level::Warn.into(), - LogLevel::Error => golem::worker::Level::Error.into(), - LogLevel::Critical => golem::worker::Level::Critical.into(), - }, - context, - message, - timestamp: Some(timestamp.into()), - })), - }), - WorkerEvent::InvocationStart { - timestamp, - function, - idempotency_key, - } => Ok(golem::worker::LogEvent { - event: Some(golem::worker::log_event::Event::InvocationStarted( - golem::worker::InvocationStarted { - function, - idempotency_key: Some(idempotency_key.into()), - timestamp: Some(timestamp.into()), - }, - )), - }), - WorkerEvent::InvocationFinished { - timestamp, - function, - idempotency_key, - } => Ok(golem::worker::LogEvent { - event: Some(golem::worker::log_event::Event::InvocationFinished( - golem::worker::InvocationFinished { - function, - idempotency_key: Some(idempotency_key.into()), - timestamp: Some(timestamp.into()), - }, - )), - }), - WorkerEvent::Close => Err("Close event is not supported via protobuf".to_string()), - } - } -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Enum)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Enum))] #[repr(i32)] pub enum ComponentType { Durable = 0, @@ -2605,32 +1978,6 @@ impl TryFrom for ComponentType { } } -impl From for ComponentType { - fn from(value: golem_api_grpc::proto::golem::component::ComponentType) -> Self { - match value { - golem_api_grpc::proto::golem::component::ComponentType::Durable => { - ComponentType::Durable - } - golem_api_grpc::proto::golem::component::ComponentType::Ephemeral => { - ComponentType::Ephemeral - } - } - } -} - -impl From for golem_api_grpc::proto::golem::component::ComponentType { - fn from(value: ComponentType) -> Self { - match value { - ComponentType::Durable => { - golem_api_grpc::proto::golem::component::ComponentType::Durable - } - ComponentType::Ephemeral => { - golem_api_grpc::proto::golem::component::ComponentType::Ephemeral - } - } - } -} - impl Display for ComponentType { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let s = match self { @@ -2653,12 +2000,16 @@ impl FromStr for ComponentType { } } -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Object)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] +#[cfg_attr(feature = "poem", oai(rename_all = "camelCase"))] +#[serde(rename_all = "camelCase")] pub struct Empty {} /// Key that can be used to identify a component file. /// All files with the same content will have the same key. -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, NewType)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::NewType))] pub struct InitialComponentFileKey(pub String); impl Display for InitialComponentFileKey { @@ -2716,56 +2067,6 @@ impl Display for ComponentFilePath { } } -impl poem_openapi::types::Type for ComponentFilePath { - const IS_REQUIRED: bool = true; - - type RawValueType = Self; - - type RawElementValueType = Self; - - fn name() -> Cow<'static, str> { - "string".into() - } - - fn schema_ref() -> MetaSchemaRef { - MetaSchemaRef::Inline(Box::new(MetaSchema { - description: Some("Path inside a component filesystem. Must be absolute."), - ..MetaSchema::new("string") - })) - } - - fn as_raw_value(&self) -> Option<&Self::RawValueType> { - Some(self) - } - - fn raw_element_iter<'a>( - &'a self, - ) -> Box + 'a> { - Box::new(self.as_raw_value().into_iter()) - } -} - -impl poem_openapi::types::ToJSON for ComponentFilePath { - fn to_json(&self) -> Option { - Some(serde_json::Value::String(self.to_string())) - } -} - -impl poem_openapi::types::ParseFromJSON for ComponentFilePath { - fn parse_from_json( - value: Option, - ) -> Result> { - match value { - None => Err(poem_openapi::types::ParseError::custom( - "Missing value for ComponentFilePath", - )), - Some(value) => { - serde_json::from_value(value).map_err(poem_openapi::types::ParseError::custom) - } - } - } -} - impl Serialize for ComponentFilePath { fn serialize(&self, serializer: S) -> Result where @@ -2785,9 +2086,10 @@ impl<'de> Deserialize<'de> for ComponentFilePath { } } -#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize, Enum)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Enum))] #[serde(rename_all = "kebab-case")] -#[oai(rename_all = "kebab-case")] +#[cfg_attr(feature = "poem", oai(rename_all = "kebab-case"))] pub enum ComponentFilePermissions { ReadOnly, ReadWrite, @@ -2809,39 +2111,10 @@ impl ComponentFilePermissions { } } -impl From - for ComponentFilePermissions -{ - fn from(value: golem_api_grpc::proto::golem::component::ComponentFilePermissions) -> Self { - match value { - golem_api_grpc::proto::golem::component::ComponentFilePermissions::ReadOnly => { - ComponentFilePermissions::ReadOnly - } - golem_api_grpc::proto::golem::component::ComponentFilePermissions::ReadWrite => { - ComponentFilePermissions::ReadWrite - } - } - } -} - -impl From - for golem_api_grpc::proto::golem::component::ComponentFilePermissions -{ - fn from(value: ComponentFilePermissions) -> Self { - match value { - ComponentFilePermissions::ReadOnly => { - golem_api_grpc::proto::golem::component::ComponentFilePermissions::ReadOnly - } - ComponentFilePermissions::ReadWrite => { - golem_api_grpc::proto::golem::component::ComponentFilePermissions::ReadWrite - } - } - } -} - -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Object)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] +#[cfg_attr(feature = "poem", oai(rename_all = "camelCase"))] #[serde(rename_all = "camelCase")] -#[oai(rename_all = "camelCase")] pub struct InitialComponentFile { pub key: InitialComponentFileKey, pub path: ComponentFilePath, @@ -2854,42 +2127,10 @@ impl InitialComponentFile { } } -impl From for golem_api_grpc::proto::golem::component::InitialComponentFile { - fn from(value: InitialComponentFile) -> Self { - let permissions: golem_api_grpc::proto::golem::component::ComponentFilePermissions = - value.permissions.into(); - Self { - key: value.key.0, - path: value.path.to_string(), - permissions: permissions.into(), - } - } -} - -impl TryFrom - for InitialComponentFile -{ - type Error = String; - - fn try_from( - value: golem_api_grpc::proto::golem::component::InitialComponentFile, - ) -> Result { - let permissions: golem_api_grpc::proto::golem::component::ComponentFilePermissions = value - .permissions - .try_into() - .map_err(|e| format!("Failed converting permissions {e}"))?; - let permissions: ComponentFilePermissions = permissions.into(); - let path = ComponentFilePath::from_abs_str(&value.path).map_err(|e| e.to_string())?; - let key = InitialComponentFileKey(value.key); - Ok(Self { - key, - path, - permissions, - }) - } -} - -#[derive(Clone, Debug, Serialize, Deserialize, Object)] +#[derive(Clone, Debug, Serialize, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] +#[cfg_attr(feature = "poem", oai(rename_all = "camelCase"))] +#[serde(rename_all = "camelCase")] pub struct ComponentFilePathWithPermissions { pub path: ComponentFilePath, pub permissions: ComponentFilePermissions, @@ -2907,7 +2148,10 @@ impl Display for ComponentFilePathWithPermissions { } } -#[derive(Clone, Debug, Serialize, Deserialize, Object)] +#[derive(Clone, Debug, Serialize, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] +#[cfg_attr(feature = "poem", oai(rename_all = "camelCase"))] +#[serde(rename_all = "camelCase")] pub struct ComponentFilePathWithPermissionsList { pub values: Vec, } @@ -2918,15 +2162,6 @@ impl Display for ComponentFilePathWithPermissionsList { } } -impl poem_openapi::types::ParseFromMultipartField for ComponentFilePathWithPermissionsList { - async fn parse_from_multipart(field: Option) -> ParseResult { - String::parse_from_multipart(field) - .await - .map_err(|err| err.propagate::()) - .and_then(|s| serde_json::from_str(&s).map_err(poem_openapi::types::ParseError::custom)) - } -} - #[derive(Clone, Debug, PartialEq)] pub enum ComponentFileSystemNodeDetails { File { @@ -2943,83 +2178,10 @@ pub struct ComponentFileSystemNode { pub details: ComponentFileSystemNodeDetails, } -impl From for golem_api_grpc::proto::golem::worker::FileSystemNode { - fn from(value: ComponentFileSystemNode) -> Self { - let last_modified = value - .last_modified - .duration_since(SystemTime::UNIX_EPOCH) - .unwrap() - .as_secs(); - - match value.details { - ComponentFileSystemNodeDetails::File { permissions, size } => - golem_api_grpc::proto::golem::worker::FileSystemNode { - value: Some(golem_api_grpc::proto::golem::worker::file_system_node::Value::File( - golem_api_grpc::proto::golem::worker::FileFileSystemNode { - name: value.name, - last_modified, - size, - permissions: - golem_api_grpc::proto::golem::component::ComponentFilePermissions::from(permissions).into(), - } - )) - }, - ComponentFileSystemNodeDetails::Directory => - golem_api_grpc::proto::golem::worker::FileSystemNode { - value: Some(golem_api_grpc::proto::golem::worker::file_system_node::Value::Directory( - golem_api_grpc::proto::golem::worker::DirectoryFileSystemNode { - name: value.name, - last_modified, - } - )) - } - } - } -} - -impl TryFrom for ComponentFileSystemNode { - type Error = anyhow::Error; - - fn try_from( - value: golem_api_grpc::proto::golem::worker::FileSystemNode, - ) -> Result { - match value.value { - Some(golem_api_grpc::proto::golem::worker::file_system_node::Value::Directory( - golem_api_grpc::proto::golem::worker::DirectoryFileSystemNode { - name, - last_modified, - }, - )) => Ok(ComponentFileSystemNode { - name, - last_modified: SystemTime::UNIX_EPOCH + Duration::from_secs(last_modified), - details: ComponentFileSystemNodeDetails::Directory, - }), - Some(golem_api_grpc::proto::golem::worker::file_system_node::Value::File( - golem_api_grpc::proto::golem::worker::FileFileSystemNode { - name, - last_modified, - size, - permissions, - }, - )) => Ok(ComponentFileSystemNode { - name, - last_modified: SystemTime::UNIX_EPOCH + Duration::from_secs(last_modified), - details: ComponentFileSystemNodeDetails::File { - permissions: - golem_api_grpc::proto::golem::component::ComponentFilePermissions::try_from( - permissions, - )? - .into(), - size, - }, - }), - None => Err(anyhow::anyhow!("Missing value")), - } - } -} -#[derive(Debug, Clone, PartialEq, Serialize, Encode, Decode, Enum, Default)] +#[derive(Debug, Clone, PartialEq, Serialize, Encode, Decode, Default)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Enum))] #[serde(rename_all = "kebab-case")] -#[oai(rename_all = "kebab-case")] +#[cfg_attr(feature = "poem", oai(rename_all = "kebab-case"))] pub enum GatewayBindingType { #[default] Default, @@ -3071,41 +2233,6 @@ impl TryFrom for GatewayBindingType { } } -impl From for GatewayBindingType { - fn from(value: golem_api_grpc::proto::golem::apidefinition::GatewayBindingType) -> Self { - match value { - golem_api_grpc::proto::golem::apidefinition::GatewayBindingType::Default => { - GatewayBindingType::Default - } - golem_api_grpc::proto::golem::apidefinition::GatewayBindingType::FileServer => { - GatewayBindingType::FileServer - } - golem_api_grpc::proto::golem::apidefinition::GatewayBindingType::CorsPreflight => { - GatewayBindingType::CorsPreflight - } - golem_api_grpc::proto::golem::apidefinition::GatewayBindingType::AuthCallBack => { - GatewayBindingType::CorsPreflight - } - } - } -} - -impl From for golem_api_grpc::proto::golem::apidefinition::GatewayBindingType { - fn from(value: GatewayBindingType) -> Self { - match value { - GatewayBindingType::Default => { - golem_api_grpc::proto::golem::apidefinition::GatewayBindingType::Default - } - GatewayBindingType::FileServer => { - golem_api_grpc::proto::golem::apidefinition::GatewayBindingType::FileServer - } - GatewayBindingType::CorsPreflight => { - golem_api_grpc::proto::golem::apidefinition::GatewayBindingType::CorsPreflight - } - } - } -} - #[cfg(test)] mod tests { use test_r::test; @@ -3118,14 +2245,12 @@ mod tests { use crate::model::oplog::OplogIndex; use crate::model::{ - AccountId, ComponentFilePath, ComponentFilePermissions, ComponentId, Empty, - FilterComparator, IdempotencyKey, InitialComponentFile, InitialComponentFileKey, ShardId, + AccountId, ComponentFilePath, ComponentId, FilterComparator, IdempotencyKey, ShardId, StringFilterComparator, TargetWorkerId, Timestamp, WorkerFilter, WorkerId, WorkerMetadata, WorkerStatus, WorkerStatusRecord, }; use bincode::{Decode, Encode}; - use poem_openapi::types::ToJSON; use rand::{thread_rng, Rng}; use serde::{Deserialize, Serialize}; @@ -3445,22 +2570,6 @@ mod tests { assert_ne!(derived31, derived32); } - #[test] - fn worker_status_serialization_poem_serde_equivalence() { - let status = WorkerStatus::Retrying; - let serialized = status.to_json_string(); - let deserialized: WorkerStatus = serde_json::from_str(&serialized).unwrap(); - assert_eq!(status, deserialized); - } - - #[test] - fn idempotency_key_serialization_poem_serde_equivalence() { - let key = IdempotencyKey::fresh(); - let serialized = key.to_json_string(); - let deserialized: IdempotencyKey = serde_json::from_str(&serialized).unwrap(); - assert_eq!(key, deserialized); - } - #[test] fn initial_component_file_path_from_absolute() { let path = ComponentFilePath::from_abs_str("/a/b/c").unwrap(); @@ -3472,23 +2581,4 @@ mod tests { let path = ComponentFilePath::from_abs_str("a/b/c"); assert!(path.is_err()); } - - #[test] - fn empty_poem_serde_equivalence() { - let serialized = Empty {}.to_json_string(); - let deserialized: Empty = serde_json::from_str(&serialized).unwrap(); - assert_eq!(Empty {}, deserialized); - } - - #[test] - fn initial_component_file_serde_equivalence() { - let file = InitialComponentFile { - key: InitialComponentFileKey("key".to_string()), - path: ComponentFilePath::from_rel_str("hello").unwrap(), - permissions: ComponentFilePermissions::ReadWrite, - }; - let serialized = file.to_json_string(); - let deserialized: InitialComponentFile = serde_json::from_str(&serialized).unwrap(); - assert_eq!(file, deserialized); - } } diff --git a/golem-common/src/model/oplog.rs b/golem-common/src/model/oplog.rs index 7dadc0e5d..2be2f0d89 100644 --- a/golem-common/src/model/oplog.rs +++ b/golem-common/src/model/oplog.rs @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::config::RetryConfig; use crate::model::regions::OplogRegion; +use crate::model::RetryConfig; use crate::model::{ AccountId, ComponentVersion, IdempotencyKey, PluginInstallationId, Timestamp, WorkerId, WorkerInvocation, @@ -27,7 +27,6 @@ use bincode::{BorrowDecode, Decode, Encode}; use golem_wasm_ast::analysis::analysed_type::{r#enum, u64}; use golem_wasm_ast::analysis::AnalysedType; use golem_wasm_rpc::{IntoValue, Value}; -use poem_openapi::{Enum, NewType}; use serde::{Deserialize, Serialize}; use std::collections::HashSet; use std::fmt::{Display, Formatter}; @@ -49,8 +48,8 @@ use uuid::Uuid; Encode, Decode, Default, - NewType, )] +#[cfg_attr(feature = "poem", derive(poem_openapi::NewType))] pub struct OplogIndex(u64); impl OplogIndex { @@ -200,20 +199,9 @@ impl<'de> BorrowDecode<'de> for PayloadId { } #[derive( - Debug, - Clone, - Copy, - PartialOrd, - Ord, - PartialEq, - Eq, - Hash, - Encode, - Decode, - Serialize, - Deserialize, - NewType, + Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash, Encode, Decode, Serialize, Deserialize, )] +#[cfg_attr(feature = "poem", derive(poem_openapi::NewType))] pub struct WorkerResourceId(pub u64); impl WorkerResourceId { @@ -246,26 +234,9 @@ pub struct IndexedResourceKey { pub resource_params: Vec, } -impl From for golem_api_grpc::proto::golem::worker::IndexedResourceMetadata { - fn from(value: IndexedResourceKey) -> Self { - golem_api_grpc::proto::golem::worker::IndexedResourceMetadata { - resource_name: value.resource_name, - resource_params: value.resource_params, - } - } -} - -impl From for IndexedResourceKey { - fn from(value: golem_api_grpc::proto::golem::worker::IndexedResourceMetadata) -> Self { - IndexedResourceKey { - resource_name: value.resource_name, - resource_params: value.resource_params, - } - } -} - /// Worker log levels including the special stdout and stderr channels -#[derive(Copy, Clone, Debug, PartialEq, Encode, Decode, Serialize, Deserialize, Enum)] +#[derive(Copy, Clone, Debug, PartialEq, Encode, Decode, Serialize, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Enum))] #[repr(u8)] pub enum LogLevel { Stdout, @@ -852,3 +823,26 @@ impl WorkerError { } } } + +#[cfg(feature = "protobuf")] +mod protobuf { + use crate::model::oplog::IndexedResourceKey; + + impl From for golem_api_grpc::proto::golem::worker::IndexedResourceMetadata { + fn from(value: IndexedResourceKey) -> Self { + golem_api_grpc::proto::golem::worker::IndexedResourceMetadata { + resource_name: value.resource_name, + resource_params: value.resource_params, + } + } + } + + impl From for IndexedResourceKey { + fn from(value: golem_api_grpc::proto::golem::worker::IndexedResourceMetadata) -> Self { + IndexedResourceKey { + resource_name: value.resource_name, + resource_params: value.resource_params, + } + } + } +} diff --git a/golem-common/src/model/plugin.rs b/golem-common/src/model/plugin.rs index ed2eb7acd..dcac7fd0a 100644 --- a/golem-common/src/model/plugin.rs +++ b/golem-common/src/model/plugin.rs @@ -1,29 +1,24 @@ use crate::model::{ AccountId, ComponentId, ComponentVersion, Empty, HasAccountId, PluginInstallationId, + PoemTypeRequirements, }; -use crate::repo::RowMeta; use async_trait::async_trait; -use poem_openapi::types::{ - ParseError, ParseFromJSON, ParseFromParameter, ParseResult, ToJSON, Type, -}; -use poem_openapi::{Enum, Object, Union}; use serde::{Deserialize, Serialize}; -use sqlx::postgres::PgRow; -use sqlx::sqlite::SqliteRow; -use sqlx::{Postgres, Sqlite}; use std::collections::HashMap; use std::fmt::{Debug, Display, Formatter}; use std::str::FromStr; -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Object)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] +#[cfg_attr(feature = "poem", oai(rename_all = "camelCase"))] #[serde(rename_all = "camelCase")] -#[oai(rename_all = "camelCase")] pub struct ComponentPluginScope { pub component_id: ComponentId, } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Union)] -#[oai(discriminator_name = "type", one_of = true)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Union))] +#[cfg_attr(feature = "poem", oai(discriminator_name = "type", one_of = true))] #[serde(tag = "type")] pub enum DefaultPluginScope { Global(Empty), @@ -62,69 +57,27 @@ impl Display for DefaultPluginScope { } } -impl ParseFromParameter for DefaultPluginScope { - fn parse_from_parameter(value: &str) -> ParseResult { +#[cfg(feature = "poem")] +impl poem_openapi::types::ParseFromParameter for DefaultPluginScope { + fn parse_from_parameter(value: &str) -> poem_openapi::types::ParseResult { if value == "global" { Ok(Self::global()) } else if let Some(id_part) = value.strip_prefix("component:") { let component_id = ComponentId::try_from(id_part); match component_id { Ok(component_id) => Ok(Self::component(component_id)), - Err(err) => Err(ParseError::::custom(err)), + Err(err) => Err(poem_openapi::types::ParseError::::custom(err)), } } else { - Err(ParseError::::custom("Unexpected representation of plugin scope - must be 'global' or 'component:'".to_string())) - } - } -} - -impl From for golem_api_grpc::proto::golem::component::DefaultPluginScope { - fn from(scope: DefaultPluginScope) -> Self { - match scope { - DefaultPluginScope::Global(_) => golem_api_grpc::proto::golem::component::DefaultPluginScope { - scope: Some(golem_api_grpc::proto::golem::component::default_plugin_scope::Scope::Global( - golem_api_grpc::proto::golem::common::Empty {}, - )), - }, - DefaultPluginScope::Component(scope) => golem_api_grpc::proto::golem::component::DefaultPluginScope { - scope: Some(golem_api_grpc::proto::golem::component::default_plugin_scope::Scope::Component( - golem_api_grpc::proto::golem::component::ComponentPluginScope { - component_id: Some(scope.component_id.into()), - }, - )), - }, + Err(poem_openapi::types::ParseError::::custom("Unexpected representation of plugin scope - must be 'global' or 'component:'".to_string())) } } } -impl TryFrom for DefaultPluginScope { - type Error = String; - - fn try_from( - proto: golem_api_grpc::proto::golem::component::DefaultPluginScope, - ) -> Result { - match proto.scope { - Some(golem_api_grpc::proto::golem::component::default_plugin_scope::Scope::Global( - _, - )) => Ok(Self::global()), - Some( - golem_api_grpc::proto::golem::component::default_plugin_scope::Scope::Component( - proto, - ), - ) => Ok(Self::component( - proto - .component_id - .ok_or("Missing component_id".to_string())? - .try_into()?, - )), - None => Err("Missing scope".to_string()), - } - } -} - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Object)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] +#[cfg_attr(feature = "poem", oai(rename_all = "camelCase"))] #[serde(rename_all = "camelCase")] -#[oai(rename_all = "camelCase")] pub struct PluginInstallation { pub id: PluginInstallationId, pub name: String, @@ -133,37 +86,10 @@ pub struct PluginInstallation { pub parameters: HashMap, } -impl From for golem_api_grpc::proto::golem::component::PluginInstallation { - fn from(plugin_installation: PluginInstallation) -> Self { - golem_api_grpc::proto::golem::component::PluginInstallation { - id: Some(plugin_installation.id.into()), - name: plugin_installation.name, - version: plugin_installation.version, - priority: plugin_installation.priority, - parameters: plugin_installation.parameters, - } - } -} - -impl TryFrom for PluginInstallation { - type Error = String; - - fn try_from( - proto: golem_api_grpc::proto::golem::component::PluginInstallation, - ) -> Result { - Ok(PluginInstallation { - id: proto.id.ok_or("Missing id")?.try_into()?, - name: proto.name, - version: proto.version, - priority: proto.priority, - parameters: proto.parameters, - }) - } -} - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Object)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] +#[cfg_attr(feature = "poem", oai(rename_all = "camelCase"))] #[serde(rename_all = "camelCase")] -#[oai(rename_all = "camelCase")] pub struct PluginInstallationCreation { pub name: String, pub version: String, @@ -183,7 +109,10 @@ impl PluginInstallationCreation { } } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Object)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] +#[cfg_attr(feature = "poem", oai(rename_all = "camelCase"))] +#[serde(rename_all = "camelCase")] pub struct PluginInstallationUpdate { pub priority: i32, pub parameters: HashMap, @@ -196,17 +125,16 @@ pub trait PluginInstallationTarget: + PartialEq + Serialize + for<'de> Deserialize<'de> - + Type - + ParseFromJSON - + ToJSON + + PoemTypeRequirements + Send + Sync + 'static { - type Row: RowMeta - + RowMeta - + for<'r> sqlx::FromRow<'r, SqliteRow> - + for<'r> sqlx::FromRow<'r, PgRow> + #[cfg(feature = "sql")] + type Row: crate::repo::RowMeta + + crate::repo::RowMeta + + for<'r> sqlx::FromRow<'r, sqlx::sqlite::SqliteRow> + + for<'r> sqlx::FromRow<'r, sqlx::postgres::PgRow> + From + TryInto + Clone @@ -216,6 +144,7 @@ pub trait PluginInstallationTarget: + Unpin + 'static; + #[cfg(feature = "sql")] fn table_name() -> &'static str; } @@ -228,17 +157,16 @@ pub trait PluginOwner: + PartialEq + Serialize + for<'de> Deserialize<'de> - + Type - + ParseFromJSON - + ToJSON + + PoemTypeRequirements + Send + Sync + 'static { - type Row: RowMeta - + RowMeta - + for<'r> sqlx::FromRow<'r, SqliteRow> - + for<'r> sqlx::FromRow<'r, PgRow> + #[cfg(feature = "sql")] + type Row: crate::repo::RowMeta + + crate::repo::RowMeta + + for<'r> sqlx::FromRow<'r, sqlx::sqlite::SqliteRow> + + for<'r> sqlx::FromRow<'r, sqlx::postgres::PgRow> + From + TryInto + Clone @@ -250,9 +178,10 @@ pub trait PluginOwner: + 'static; } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Object)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] +#[cfg_attr(feature = "poem", oai(rename_all = "camelCase"))] #[serde(rename_all = "camelCase")] -#[oai(rename_all = "camelCase")] pub struct DefaultPluginOwner; impl Display for DefaultPluginOwner { @@ -280,12 +209,14 @@ impl HasAccountId for DefaultPluginOwner { } impl PluginOwner for DefaultPluginOwner { + #[cfg(feature = "sql")] type Row = crate::repo::plugin::DefaultPluginOwnerRow; } -#[derive(Debug, Clone, PartialEq, Serialize, Object)] +#[derive(Debug, Clone, PartialEq, Serialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] +#[cfg_attr(feature = "poem", oai(rename_all = "camelCase"))] #[serde(rename_all = "camelCase")] -#[oai(rename_all = "camelCase")] pub struct PluginDefinition { pub name: String, pub version: String, @@ -297,46 +228,10 @@ pub struct PluginDefinition { pub owner: Owner, } -impl From> - for golem_api_grpc::proto::golem::component::PluginDefinition -{ - fn from(value: PluginDefinition) -> Self { - golem_api_grpc::proto::golem::component::PluginDefinition { - name: value.name, - version: value.version, - description: value.description, - icon: value.icon, - homepage: value.homepage, - specs: Some(value.specs.into()), - scope: Some(value.scope.into()), - } - } -} - -impl TryFrom - for PluginDefinition -{ - type Error = String; - - fn try_from( - value: golem_api_grpc::proto::golem::component::PluginDefinition, - ) -> Result { - Ok(PluginDefinition { - name: value.name, - version: value.version, - description: value.description, - icon: value.icon, - homepage: value.homepage, - specs: value.specs.ok_or("Missing plugin specs")?.try_into()?, - scope: value.scope.ok_or("Missing plugin scope")?.try_into()?, - owner: DefaultPluginOwner, - }) - } -} - -#[derive(Debug, Clone, PartialEq, Serialize, Object)] +#[derive(Debug, Clone, PartialEq, Serialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] +#[cfg_attr(feature = "poem", oai(rename_all = "camelCase"))] #[serde(rename_all = "camelCase")] -#[oai(rename_all = "camelCase")] pub struct PluginDefinitionWithoutOwner { pub name: String, pub version: String, @@ -362,15 +257,17 @@ impl PluginDefinitionWithoutOwner { } } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Enum)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Enum))] #[repr(i8)] pub enum PluginType { ComponentTransformer = 0, OplogProcessor = 1, } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Union)] -#[oai(discriminator_name = "type", one_of = true)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Union))] +#[cfg_attr(feature = "poem", oai(discriminator_name = "type", one_of = true))] #[serde(tag = "type")] pub enum PluginTypeSpecificDefinition { ComponentTransformer(ComponentTransformerDefinition), @@ -388,39 +285,10 @@ impl PluginTypeSpecificDefinition { } } -impl From - for golem_api_grpc::proto::golem::component::PluginTypeSpecificDefinition -{ - fn from(value: PluginTypeSpecificDefinition) -> Self { - match value { - PluginTypeSpecificDefinition::ComponentTransformer(value) => golem_api_grpc::proto::golem::component::PluginTypeSpecificDefinition { - definition: Some(golem_api_grpc::proto::golem::component::plugin_type_specific_definition::Definition::ComponentTransformer(value.into())) - }, - PluginTypeSpecificDefinition::OplogProcessor(value) => golem_api_grpc::proto::golem::component::PluginTypeSpecificDefinition { - definition: Some(golem_api_grpc::proto::golem::component::plugin_type_specific_definition::Definition::OplogProcessor(value.into())) - } - } - } -} - -impl TryFrom - for PluginTypeSpecificDefinition -{ - type Error = String; - - fn try_from( - value: golem_api_grpc::proto::golem::component::PluginTypeSpecificDefinition, - ) -> Result { - match value.definition.ok_or("Missing plugin type specific definition")? { - golem_api_grpc::proto::golem::component::plugin_type_specific_definition::Definition::ComponentTransformer(value) => Ok(PluginTypeSpecificDefinition::ComponentTransformer(value.try_into()?)), - golem_api_grpc::proto::golem::component::plugin_type_specific_definition::Definition::OplogProcessor(value) => Ok(PluginTypeSpecificDefinition::OplogProcessor(value.try_into()?)), - } - } -} - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Object)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] +#[cfg_attr(feature = "poem", oai(rename_all = "camelCase"))] #[serde(rename_all = "camelCase")] -#[oai(rename_all = "camelCase")] pub struct ComponentTransformerDefinition { pub provided_wit_package: Option, pub json_schema: Option, @@ -428,73 +296,15 @@ pub struct ComponentTransformerDefinition { pub transform_url: String, } -impl From - for golem_api_grpc::proto::golem::component::ComponentTransformerDefinition -{ - fn from(value: ComponentTransformerDefinition) -> Self { - golem_api_grpc::proto::golem::component::ComponentTransformerDefinition { - provided_wit_package: value.provided_wit_package, - json_schema: value.json_schema, - validate_url: value.validate_url, - transform_url: value.transform_url, - } - } -} - -impl TryFrom - for ComponentTransformerDefinition -{ - type Error = String; - - fn try_from( - value: golem_api_grpc::proto::golem::component::ComponentTransformerDefinition, - ) -> Result { - Ok(ComponentTransformerDefinition { - provided_wit_package: value.provided_wit_package, - json_schema: value.json_schema, - validate_url: value.validate_url, - transform_url: value.transform_url, - }) - } -} - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Object)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] +#[cfg_attr(feature = "poem", oai(rename_all = "camelCase"))] #[serde(rename_all = "camelCase")] -#[oai(rename_all = "camelCase")] pub struct OplogProcessorDefinition { pub component_id: ComponentId, pub component_version: ComponentVersion, } -impl From - for golem_api_grpc::proto::golem::component::OplogProcessorDefinition -{ - fn from(value: OplogProcessorDefinition) -> Self { - golem_api_grpc::proto::golem::component::OplogProcessorDefinition { - component_id: Some(value.component_id.into()), - component_version: value.component_version, - } - } -} - -impl TryFrom - for OplogProcessorDefinition -{ - type Error = String; - - fn try_from( - value: golem_api_grpc::proto::golem::component::OplogProcessorDefinition, - ) -> Result { - Ok(OplogProcessorDefinition { - component_id: value - .component_id - .ok_or("Missing component_id")? - .try_into()?, - component_version: value.component_version, - }) - } -} - #[async_trait] pub trait PluginScope: Debug @@ -502,17 +312,16 @@ pub trait PluginScope: + PartialEq + Serialize + for<'de> Deserialize<'de> - + Type - + ParseFromJSON - + ToJSON + + PoemTypeRequirements + Send + Sync + 'static { - type Row: RowMeta - + RowMeta - + for<'r> sqlx::FromRow<'r, SqliteRow> - + for<'r> sqlx::FromRow<'r, PgRow> + #[cfg(feature = "sql")] + type Row: crate::repo::RowMeta + + crate::repo::RowMeta + + for<'r> sqlx::FromRow<'r, sqlx::sqlite::SqliteRow> + + for<'r> sqlx::FromRow<'r, sqlx::postgres::PgRow> + From + TryInto + Send @@ -529,6 +338,7 @@ pub trait PluginScope: #[async_trait] impl PluginScope for DefaultPluginScope { + #[cfg(feature = "sql")] type Row = crate::repo::plugin::DefaultPluginScopeRow; type RequestContext = (); @@ -541,9 +351,10 @@ impl PluginScope for DefaultPluginScope { } } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Object)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] +#[cfg_attr(feature = "poem", oai(rename_all = "camelCase"))] #[serde(rename_all = "camelCase")] -#[oai(rename_all = "camelCase")] pub struct ComponentPluginInstallationTarget { pub component_id: ComponentId, pub component_version: ComponentVersion, @@ -556,9 +367,218 @@ impl Display for ComponentPluginInstallationTarget { } impl PluginInstallationTarget for ComponentPluginInstallationTarget { + #[cfg(feature = "sql")] type Row = crate::repo::plugin_installation::ComponentPluginInstallationRow; + #[cfg(feature = "sql")] fn table_name() -> &'static str { "component_plugin_installation" } } + +#[cfg(feature = "protobuf")] +mod protobuf { + use crate::model::plugin::{ + ComponentTransformerDefinition, DefaultPluginOwner, DefaultPluginScope, + OplogProcessorDefinition, PluginDefinition, PluginInstallation, + PluginTypeSpecificDefinition, + }; + + impl From for golem_api_grpc::proto::golem::component::DefaultPluginScope { + fn from(scope: DefaultPluginScope) -> Self { + match scope { + DefaultPluginScope::Global(_) => golem_api_grpc::proto::golem::component::DefaultPluginScope { + scope: Some(golem_api_grpc::proto::golem::component::default_plugin_scope::Scope::Global( + golem_api_grpc::proto::golem::common::Empty {}, + )), + }, + DefaultPluginScope::Component(scope) => golem_api_grpc::proto::golem::component::DefaultPluginScope { + scope: Some(golem_api_grpc::proto::golem::component::default_plugin_scope::Scope::Component( + golem_api_grpc::proto::golem::component::ComponentPluginScope { + component_id: Some(scope.component_id.into()), + }, + )), + }, + } + } + } + + impl TryFrom for DefaultPluginScope { + type Error = String; + + fn try_from( + proto: golem_api_grpc::proto::golem::component::DefaultPluginScope, + ) -> Result { + match proto.scope { + Some( + golem_api_grpc::proto::golem::component::default_plugin_scope::Scope::Global(_), + ) => Ok(Self::global()), + Some( + golem_api_grpc::proto::golem::component::default_plugin_scope::Scope::Component( + proto, + ), + ) => Ok(Self::component( + proto + .component_id + .ok_or("Missing component_id".to_string())? + .try_into()?, + )), + None => Err("Missing scope".to_string()), + } + } + } + + impl From> + for golem_api_grpc::proto::golem::component::PluginDefinition + { + fn from(value: PluginDefinition) -> Self { + golem_api_grpc::proto::golem::component::PluginDefinition { + name: value.name, + version: value.version, + description: value.description, + icon: value.icon, + homepage: value.homepage, + specs: Some(value.specs.into()), + scope: Some(value.scope.into()), + } + } + } + + impl TryFrom + for PluginDefinition + { + type Error = String; + + fn try_from( + value: golem_api_grpc::proto::golem::component::PluginDefinition, + ) -> Result { + Ok(PluginDefinition { + name: value.name, + version: value.version, + description: value.description, + icon: value.icon, + homepage: value.homepage, + specs: value.specs.ok_or("Missing plugin specs")?.try_into()?, + scope: value.scope.ok_or("Missing plugin scope")?.try_into()?, + owner: DefaultPluginOwner, + }) + } + } + + impl From for golem_api_grpc::proto::golem::component::PluginInstallation { + fn from(plugin_installation: PluginInstallation) -> Self { + golem_api_grpc::proto::golem::component::PluginInstallation { + id: Some(plugin_installation.id.into()), + name: plugin_installation.name, + version: plugin_installation.version, + priority: plugin_installation.priority, + parameters: plugin_installation.parameters, + } + } + } + + impl TryFrom for PluginInstallation { + type Error = String; + + fn try_from( + proto: golem_api_grpc::proto::golem::component::PluginInstallation, + ) -> Result { + Ok(PluginInstallation { + id: proto.id.ok_or("Missing id")?.try_into()?, + name: proto.name, + version: proto.version, + priority: proto.priority, + parameters: proto.parameters, + }) + } + } + + impl From + for golem_api_grpc::proto::golem::component::PluginTypeSpecificDefinition + { + fn from(value: PluginTypeSpecificDefinition) -> Self { + match value { + PluginTypeSpecificDefinition::ComponentTransformer(value) => golem_api_grpc::proto::golem::component::PluginTypeSpecificDefinition { + definition: Some(golem_api_grpc::proto::golem::component::plugin_type_specific_definition::Definition::ComponentTransformer(value.into())) + }, + PluginTypeSpecificDefinition::OplogProcessor(value) => golem_api_grpc::proto::golem::component::PluginTypeSpecificDefinition { + definition: Some(golem_api_grpc::proto::golem::component::plugin_type_specific_definition::Definition::OplogProcessor(value.into())) + } + } + } + } + + impl TryFrom + for PluginTypeSpecificDefinition + { + type Error = String; + + fn try_from( + value: golem_api_grpc::proto::golem::component::PluginTypeSpecificDefinition, + ) -> Result { + match value.definition.ok_or("Missing plugin type specific definition")? { + golem_api_grpc::proto::golem::component::plugin_type_specific_definition::Definition::ComponentTransformer(value) => Ok(PluginTypeSpecificDefinition::ComponentTransformer(value.try_into()?)), + golem_api_grpc::proto::golem::component::plugin_type_specific_definition::Definition::OplogProcessor(value) => Ok(PluginTypeSpecificDefinition::OplogProcessor(value.try_into()?)), + } + } + } + + impl From + for golem_api_grpc::proto::golem::component::ComponentTransformerDefinition + { + fn from(value: ComponentTransformerDefinition) -> Self { + golem_api_grpc::proto::golem::component::ComponentTransformerDefinition { + provided_wit_package: value.provided_wit_package, + json_schema: value.json_schema, + validate_url: value.validate_url, + transform_url: value.transform_url, + } + } + } + + impl TryFrom + for ComponentTransformerDefinition + { + type Error = String; + + fn try_from( + value: golem_api_grpc::proto::golem::component::ComponentTransformerDefinition, + ) -> Result { + Ok(ComponentTransformerDefinition { + provided_wit_package: value.provided_wit_package, + json_schema: value.json_schema, + validate_url: value.validate_url, + transform_url: value.transform_url, + }) + } + } + + impl From + for golem_api_grpc::proto::golem::component::OplogProcessorDefinition + { + fn from(value: OplogProcessorDefinition) -> Self { + golem_api_grpc::proto::golem::component::OplogProcessorDefinition { + component_id: Some(value.component_id.into()), + component_version: value.component_version, + } + } + } + + impl TryFrom + for OplogProcessorDefinition + { + type Error = String; + + fn try_from( + value: golem_api_grpc::proto::golem::component::OplogProcessorDefinition, + ) -> Result { + Ok(OplogProcessorDefinition { + component_id: value + .component_id + .ok_or("Missing component_id")? + .try_into()?, + component_version: value.component_version, + }) + } + } +} diff --git a/golem-common/src/model/poem.rs b/golem-common/src/model/poem.rs new file mode 100644 index 000000000..c31f42de6 --- /dev/null +++ b/golem-common/src/model/poem.rs @@ -0,0 +1,275 @@ +// Copyright 2024 Golem Cloud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::model::{ + AccountId, ComponentFilePath, ComponentFilePathWithPermissionsList, IdempotencyKey, Timestamp, +}; +use poem_openapi::registry::{MetaSchema, MetaSchemaRef}; +use poem_openapi::types::{ParseFromJSON, ParseFromParameter, ParseResult, ToJSON}; +use serde_json::Value; +use std::borrow::Cow; + +impl poem_openapi::types::Type for Timestamp { + const IS_REQUIRED: bool = true; + type RawValueType = Self; + type RawElementValueType = Self; + + fn name() -> Cow<'static, str> { + Cow::from("string(timestamp)") + } + + fn schema_ref() -> MetaSchemaRef { + MetaSchemaRef::Inline(Box::new(MetaSchema::new_with_format("string", "date-time"))) + } + + fn as_raw_value(&self) -> Option<&Self::RawValueType> { + Some(self) + } + + fn raw_element_iter<'a>( + &'a self, + ) -> Box + 'a> { + Box::new(self.as_raw_value().into_iter()) + } +} + +impl ToJSON for Timestamp { + fn to_json(&self) -> Option { + Some(Value::String(self.0.to_string())) + } +} + +impl ParseFromParameter for Timestamp { + fn parse_from_parameter(value: &str) -> ParseResult { + value.parse().map_err(|_| { + poem_openapi::types::ParseError::::custom( + "Unexpected representation of timestamp".to_string(), + ) + }) + } +} + +impl ParseFromJSON for Timestamp { + fn parse_from_json(value: Option) -> ParseResult { + match value { + Some(Value::String(s)) => Timestamp::parse_from_parameter(&s), + _ => Err(poem_openapi::types::ParseError::::custom( + "Unexpected representation of timestamp".to_string(), + )), + } + } +} + +impl poem_openapi::types::Type for IdempotencyKey { + const IS_REQUIRED: bool = true; + type RawValueType = Self; + type RawElementValueType = Self; + + fn name() -> Cow<'static, str> { + Cow::from(format!("string({})", stringify!(InvocationKey))) + } + + fn schema_ref() -> MetaSchemaRef { + MetaSchemaRef::Inline(Box::new(MetaSchema::new("string"))) + } + + fn as_raw_value(&self) -> Option<&Self::RawValueType> { + Some(self) + } + + fn raw_element_iter<'a>( + &'a self, + ) -> Box + 'a> { + Box::new(self.as_raw_value().into_iter()) + } +} + +impl ParseFromParameter for IdempotencyKey { + fn parse_from_parameter(value: &str) -> ParseResult { + Ok(Self { + value: value.to_string(), + }) + } +} + +impl ParseFromJSON for IdempotencyKey { + fn parse_from_json(value: Option) -> ParseResult { + match value { + Some(Value::String(s)) => Ok(Self { value: s }), + _ => Err(poem_openapi::types::ParseError::::custom( + format!("Unexpected representation of {}", stringify!(InvocationKey)), + )), + } + } +} + +impl ToJSON for IdempotencyKey { + fn to_json(&self) -> Option { + Some(Value::String(self.value.clone())) + } +} + +impl poem_openapi::types::Type for AccountId { + const IS_REQUIRED: bool = true; + type RawValueType = Self; + type RawElementValueType = Self; + + fn name() -> Cow<'static, str> { + Cow::from("string(account_id)") + } + + fn schema_ref() -> MetaSchemaRef { + MetaSchemaRef::Inline(Box::new(MetaSchema::new("string"))) + } + + fn as_raw_value(&self) -> Option<&Self::RawValueType> { + Some(self) + } + + fn raw_element_iter<'a>( + &'a self, + ) -> Box + 'a> { + Box::new(self.as_raw_value().into_iter()) + } +} + +impl ParseFromParameter for AccountId { + fn parse_from_parameter(value: &str) -> ParseResult { + Ok(Self { + value: value.to_string(), + }) + } +} + +impl ParseFromJSON for AccountId { + fn parse_from_json(value: Option) -> ParseResult { + match value { + Some(Value::String(s)) => Ok(Self { value: s }), + _ => Err(poem_openapi::types::ParseError::::custom( + "Unexpected representation of AccountId".to_string(), + )), + } + } +} + +impl ToJSON for AccountId { + fn to_json(&self) -> Option { + Some(Value::String(self.value.clone())) + } +} + +impl poem_openapi::types::Type for ComponentFilePath { + const IS_REQUIRED: bool = true; + + type RawValueType = Self; + + type RawElementValueType = Self; + + fn name() -> Cow<'static, str> { + "string".into() + } + + fn schema_ref() -> MetaSchemaRef { + MetaSchemaRef::Inline(Box::new(MetaSchema { + description: Some("Path inside a component filesystem. Must be absolute."), + ..MetaSchema::new("string") + })) + } + + fn as_raw_value(&self) -> Option<&Self::RawValueType> { + Some(self) + } + + fn raw_element_iter<'a>( + &'a self, + ) -> Box + 'a> { + Box::new(self.as_raw_value().into_iter()) + } +} + +impl poem_openapi::types::ToJSON for ComponentFilePath { + fn to_json(&self) -> Option { + Some(serde_json::Value::String(self.to_string())) + } +} + +impl poem_openapi::types::ParseFromJSON for ComponentFilePath { + fn parse_from_json( + value: Option, + ) -> Result> { + match value { + None => Err(poem_openapi::types::ParseError::custom( + "Missing value for ComponentFilePath", + )), + Some(value) => { + serde_json::from_value(value).map_err(poem_openapi::types::ParseError::custom) + } + } + } +} + +impl poem_openapi::types::ParseFromMultipartField for ComponentFilePathWithPermissionsList { + async fn parse_from_multipart(field: Option) -> ParseResult { + String::parse_from_multipart(field) + .await + .map_err(|err| err.propagate::()) + .and_then(|s| serde_json::from_str(&s).map_err(poem_openapi::types::ParseError::custom)) + } +} + +#[cfg(test)] +mod tests { + use test_r::test; + + use crate::model::{ + ComponentFilePath, ComponentFilePermissions, Empty, IdempotencyKey, InitialComponentFile, + InitialComponentFileKey, WorkerStatus, + }; + use poem_openapi::types::ToJSON; + + #[test] + fn worker_status_serialization_poem_serde_equivalence() { + let status = WorkerStatus::Retrying; + let serialized = status.to_json_string(); + let deserialized: WorkerStatus = serde_json::from_str(&serialized).unwrap(); + assert_eq!(status, deserialized); + } + + #[test] + fn idempotency_key_serialization_poem_serde_equivalence() { + let key = IdempotencyKey::fresh(); + let serialized = key.to_json_string(); + let deserialized: IdempotencyKey = serde_json::from_str(&serialized).unwrap(); + assert_eq!(key, deserialized); + } + + #[test] + fn empty_poem_serde_equivalence() { + let serialized = Empty {}.to_json_string(); + let deserialized: Empty = serde_json::from_str(&serialized).unwrap(); + assert_eq!(Empty {}, deserialized); + } + + #[test] + fn initial_component_file_serde_equivalence() { + let file = InitialComponentFile { + key: InitialComponentFileKey("key".to_string()), + path: ComponentFilePath::from_rel_str("hello").unwrap(), + permissions: ComponentFilePermissions::ReadWrite, + }; + let serialized = file.to_json_string(); + let deserialized: InitialComponentFile = serde_json::from_str(&serialized).unwrap(); + assert_eq!(file, deserialized); + } +} diff --git a/golem-common/src/model/protobuf.rs b/golem-common/src/model/protobuf.rs new file mode 100644 index 000000000..417b42a77 --- /dev/null +++ b/golem-common/src/model/protobuf.rs @@ -0,0 +1,763 @@ +// Copyright 2024 Golem Cloud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::model::oplog::OplogIndex; +use crate::model::{ + AccountId, ComponentFilePath, ComponentFilePermissions, ComponentFileSystemNode, + ComponentFileSystemNodeDetails, ComponentType, FilterComparator, GatewayBindingType, + IdempotencyKey, InitialComponentFile, InitialComponentFileKey, LogLevel, NumberOfShards, Pod, + PromiseId, RoutingTable, RoutingTableEntry, ScanCursor, ShardId, StringFilterComparator, + TargetWorkerId, Timestamp, WorkerCreatedAtFilter, WorkerEnvFilter, WorkerEvent, WorkerFilter, + WorkerId, WorkerNameFilter, WorkerNotFilter, WorkerStatus, WorkerStatusFilter, + WorkerVersionFilter, +}; +use golem_api_grpc::proto::golem; +use golem_api_grpc::proto::golem::shardmanager::{ + Pod as GrpcPod, RoutingTable as GrpcRoutingTable, RoutingTableEntry as GrpcRoutingTableEntry, +}; +use golem_api_grpc::proto::golem::worker::Cursor; +use std::ops::Add; +use std::time::{Duration, SystemTime}; + +impl From for prost_types::Timestamp { + fn from(value: Timestamp) -> Self { + let d = value + .0 + .duration_since(iso8601_timestamp::Timestamp::UNIX_EPOCH); + Self { + seconds: d.whole_seconds(), + nanos: d.subsec_nanoseconds(), + } + } +} + +impl From for Timestamp { + fn from(value: prost_types::Timestamp) -> Self { + Timestamp( + iso8601_timestamp::Timestamp::UNIX_EPOCH + .add(Duration::new(value.seconds as u64, value.nanos as u32)), + ) + } +} + +impl From for golem_api_grpc::proto::golem::worker::WorkerId { + fn from(value: WorkerId) -> Self { + Self { + component_id: Some(value.component_id.into()), + name: value.worker_name, + } + } +} + +impl TryFrom for WorkerId { + type Error = String; + + fn try_from( + value: golem_api_grpc::proto::golem::worker::WorkerId, + ) -> Result { + Ok(Self { + component_id: value.component_id.unwrap().try_into()?, + worker_name: value.name, + }) + } +} + +impl TryFrom for TargetWorkerId { + type Error = String; + + fn try_from(value: golem::worker::TargetWorkerId) -> Result { + Ok(Self { + component_id: value + .component_id + .ok_or("Missing component_id")? + .try_into()?, + worker_name: value.name, + }) + } +} + +impl From for golem::worker::TargetWorkerId { + fn from(value: TargetWorkerId) -> Self { + Self { + component_id: Some(value.component_id.into()), + name: value.worker_name, + } + } +} + +impl From for golem_api_grpc::proto::golem::worker::PromiseId { + fn from(value: PromiseId) -> Self { + Self { + worker_id: Some(value.worker_id.into()), + oplog_idx: value.oplog_idx.into(), + } + } +} + +impl TryFrom for PromiseId { + type Error = String; + + fn try_from( + value: golem_api_grpc::proto::golem::worker::PromiseId, + ) -> Result { + Ok(Self { + worker_id: value.worker_id.ok_or("Missing worker_id")?.try_into()?, + oplog_idx: OplogIndex::from_u64(value.oplog_idx), + }) + } +} + +impl From for golem_api_grpc::proto::golem::shardmanager::ShardId { + fn from(value: ShardId) -> golem_api_grpc::proto::golem::shardmanager::ShardId { + golem_api_grpc::proto::golem::shardmanager::ShardId { value: value.value } + } +} + +impl From for ShardId { + fn from(proto: golem_api_grpc::proto::golem::shardmanager::ShardId) -> Self { + Self { value: proto.value } + } +} + +impl From for Pod { + fn from(value: GrpcPod) -> Self { + Self { + host: value.host, + port: value.port as u16, + } + } +} + +impl From for RoutingTableEntry { + fn from(value: GrpcRoutingTableEntry) -> Self { + Self { + shard_id: value.shard_id.unwrap().into(), + pod: value.pod.unwrap().into(), + } + } +} + +impl From for RoutingTable { + fn from(value: GrpcRoutingTable) -> Self { + Self { + number_of_shards: NumberOfShards { + value: value.number_of_shards as usize, + }, + shard_assignments: value + .shard_assignments + .into_iter() + .map(RoutingTableEntry::from) + .map(|routing_table_entry| (routing_table_entry.shard_id, routing_table_entry.pod)) + .collect(), + } + } +} + +impl From for IdempotencyKey { + fn from(proto: golem_api_grpc::proto::golem::worker::IdempotencyKey) -> Self { + Self { value: proto.value } + } +} + +impl From for golem_api_grpc::proto::golem::worker::IdempotencyKey { + fn from(value: IdempotencyKey) -> Self { + Self { value: value.value } + } +} + +impl From for golem_api_grpc::proto::golem::worker::WorkerStatus { + fn from(value: WorkerStatus) -> Self { + match value { + WorkerStatus::Running => golem_api_grpc::proto::golem::worker::WorkerStatus::Running, + WorkerStatus::Idle => golem_api_grpc::proto::golem::worker::WorkerStatus::Idle, + WorkerStatus::Suspended => { + golem_api_grpc::proto::golem::worker::WorkerStatus::Suspended + } + WorkerStatus::Interrupted => { + golem_api_grpc::proto::golem::worker::WorkerStatus::Interrupted + } + WorkerStatus::Retrying => golem_api_grpc::proto::golem::worker::WorkerStatus::Retrying, + WorkerStatus::Failed => golem_api_grpc::proto::golem::worker::WorkerStatus::Failed, + WorkerStatus::Exited => golem_api_grpc::proto::golem::worker::WorkerStatus::Exited, + } + } +} + +impl From for AccountId { + fn from(proto: golem_api_grpc::proto::golem::common::AccountId) -> Self { + Self { value: proto.name } + } +} + +impl From for golem_api_grpc::proto::golem::common::AccountId { + fn from(value: AccountId) -> Self { + golem_api_grpc::proto::golem::common::AccountId { name: value.value } + } +} + +impl TryFrom for WorkerFilter { + type Error = String; + + fn try_from( + value: golem_api_grpc::proto::golem::worker::WorkerFilter, + ) -> Result { + match value.filter { + Some(filter) => match filter { + golem_api_grpc::proto::golem::worker::worker_filter::Filter::Name(filter) => Ok( + WorkerFilter::new_name(filter.comparator.try_into()?, filter.value), + ), + golem_api_grpc::proto::golem::worker::worker_filter::Filter::Version(filter) => Ok( + WorkerFilter::new_version(filter.comparator.try_into()?, filter.value), + ), + golem_api_grpc::proto::golem::worker::worker_filter::Filter::Status(filter) => { + Ok(WorkerFilter::new_status( + filter.comparator.try_into()?, + filter.value.try_into()?, + )) + } + golem_api_grpc::proto::golem::worker::worker_filter::Filter::CreatedAt(filter) => { + let value = filter + .value + .map(|t| t.into()) + .ok_or_else(|| "Missing value".to_string())?; + Ok(WorkerFilter::new_created_at( + filter.comparator.try_into()?, + value, + )) + } + golem_api_grpc::proto::golem::worker::worker_filter::Filter::Env(filter) => Ok( + WorkerFilter::new_env(filter.name, filter.comparator.try_into()?, filter.value), + ), + golem_api_grpc::proto::golem::worker::worker_filter::Filter::Not(filter) => { + let filter = *filter.filter.ok_or_else(|| "Missing filter".to_string())?; + Ok(WorkerFilter::new_not(filter.try_into()?)) + } + golem_api_grpc::proto::golem::worker::worker_filter::Filter::And( + golem_api_grpc::proto::golem::worker::WorkerAndFilter { filters }, + ) => { + let filters = filters.into_iter().map(|f| f.try_into()).collect::, + String, + >>( + )?; + + Ok(WorkerFilter::new_and(filters)) + } + golem_api_grpc::proto::golem::worker::worker_filter::Filter::Or( + golem_api_grpc::proto::golem::worker::WorkerOrFilter { filters }, + ) => { + let filters = filters.into_iter().map(|f| f.try_into()).collect::, + String, + >>( + )?; + + Ok(WorkerFilter::new_or(filters)) + } + }, + None => Err("Missing filter".to_string()), + } + } +} + +impl From for golem_api_grpc::proto::golem::worker::WorkerFilter { + fn from(value: WorkerFilter) -> Self { + let filter = match value { + WorkerFilter::Name(WorkerNameFilter { comparator, value }) => { + golem_api_grpc::proto::golem::worker::worker_filter::Filter::Name( + golem_api_grpc::proto::golem::worker::WorkerNameFilter { + comparator: comparator.into(), + value, + }, + ) + } + WorkerFilter::Version(WorkerVersionFilter { comparator, value }) => { + golem_api_grpc::proto::golem::worker::worker_filter::Filter::Version( + golem_api_grpc::proto::golem::worker::WorkerVersionFilter { + comparator: comparator.into(), + value, + }, + ) + } + WorkerFilter::Env(WorkerEnvFilter { + name, + comparator, + value, + }) => golem_api_grpc::proto::golem::worker::worker_filter::Filter::Env( + golem_api_grpc::proto::golem::worker::WorkerEnvFilter { + name, + comparator: comparator.into(), + value, + }, + ), + WorkerFilter::Status(WorkerStatusFilter { comparator, value }) => { + golem_api_grpc::proto::golem::worker::worker_filter::Filter::Status( + golem_api_grpc::proto::golem::worker::WorkerStatusFilter { + comparator: comparator.into(), + value: value.into(), + }, + ) + } + WorkerFilter::CreatedAt(WorkerCreatedAtFilter { comparator, value }) => { + golem_api_grpc::proto::golem::worker::worker_filter::Filter::CreatedAt( + golem_api_grpc::proto::golem::worker::WorkerCreatedAtFilter { + value: Some(value.into()), + comparator: comparator.into(), + }, + ) + } + WorkerFilter::Not(WorkerNotFilter { filter }) => { + let f: golem_api_grpc::proto::golem::worker::WorkerFilter = (*filter).into(); + golem_api_grpc::proto::golem::worker::worker_filter::Filter::Not(Box::new( + golem_api_grpc::proto::golem::worker::WorkerNotFilter { + filter: Some(Box::new(f)), + }, + )) + } + WorkerFilter::And(filter) => { + golem_api_grpc::proto::golem::worker::worker_filter::Filter::And( + golem_api_grpc::proto::golem::worker::WorkerAndFilter { + filters: filter.filters.into_iter().map(|f| f.into()).collect(), + }, + ) + } + WorkerFilter::Or(filter) => { + golem_api_grpc::proto::golem::worker::worker_filter::Filter::Or( + golem_api_grpc::proto::golem::worker::WorkerOrFilter { + filters: filter.filters.into_iter().map(|f| f.into()).collect(), + }, + ) + } + }; + + golem_api_grpc::proto::golem::worker::WorkerFilter { + filter: Some(filter), + } + } +} + +impl From for golem_api_grpc::proto::golem::common::StringFilterComparator { + fn from(value: StringFilterComparator) -> Self { + match value { + StringFilterComparator::Equal => { + golem_api_grpc::proto::golem::common::StringFilterComparator::StringEqual + } + StringFilterComparator::NotEqual => { + golem_api_grpc::proto::golem::common::StringFilterComparator::StringNotEqual + } + StringFilterComparator::Like => { + golem_api_grpc::proto::golem::common::StringFilterComparator::StringLike + } + StringFilterComparator::NotLike => { + golem_api_grpc::proto::golem::common::StringFilterComparator::StringNotLike + } + } + } +} + +impl From for golem_api_grpc::proto::golem::common::FilterComparator { + fn from(value: FilterComparator) -> Self { + match value { + FilterComparator::Equal => { + golem_api_grpc::proto::golem::common::FilterComparator::Equal + } + FilterComparator::NotEqual => { + golem_api_grpc::proto::golem::common::FilterComparator::NotEqual + } + FilterComparator::Less => golem_api_grpc::proto::golem::common::FilterComparator::Less, + FilterComparator::LessEqual => { + golem_api_grpc::proto::golem::common::FilterComparator::LessEqual + } + FilterComparator::Greater => { + golem_api_grpc::proto::golem::common::FilterComparator::Greater + } + FilterComparator::GreaterEqual => { + golem_api_grpc::proto::golem::common::FilterComparator::GreaterEqual + } + } + } +} + +impl From for ScanCursor { + fn from(value: Cursor) -> Self { + Self { + cursor: value.cursor, + layer: value.layer as usize, + } + } +} + +impl From for Cursor { + fn from(value: ScanCursor) -> Self { + Self { + cursor: value.cursor, + layer: value.layer as u64, + } + } +} + +impl From for LogLevel { + fn from(value: golem_api_grpc::proto::golem::worker::Level) -> Self { + match value { + golem_api_grpc::proto::golem::worker::Level::Trace => LogLevel::Trace, + golem_api_grpc::proto::golem::worker::Level::Debug => LogLevel::Debug, + golem_api_grpc::proto::golem::worker::Level::Info => LogLevel::Info, + golem_api_grpc::proto::golem::worker::Level::Warn => LogLevel::Warn, + golem_api_grpc::proto::golem::worker::Level::Error => LogLevel::Error, + golem_api_grpc::proto::golem::worker::Level::Critical => LogLevel::Critical, + } + } +} + +impl From for golem_api_grpc::proto::golem::worker::Level { + fn from(value: LogLevel) -> Self { + match value { + LogLevel::Trace => golem_api_grpc::proto::golem::worker::Level::Trace, + LogLevel::Debug => golem_api_grpc::proto::golem::worker::Level::Debug, + LogLevel::Info => golem_api_grpc::proto::golem::worker::Level::Info, + LogLevel::Warn => golem_api_grpc::proto::golem::worker::Level::Warn, + LogLevel::Error => golem_api_grpc::proto::golem::worker::Level::Error, + LogLevel::Critical => golem_api_grpc::proto::golem::worker::Level::Critical, + } + } +} + +impl TryFrom for WorkerEvent { + type Error = String; + + fn try_from( + value: golem_api_grpc::proto::golem::worker::LogEvent, + ) -> Result { + match value.event { + Some(event) => match event { + golem_api_grpc::proto::golem::worker::log_event::Event::Stdout(event) => { + Ok(WorkerEvent::StdOut { + timestamp: event.timestamp.ok_or("Missing timestamp")?.into(), + bytes: event.message.into_bytes(), + }) + } + golem_api_grpc::proto::golem::worker::log_event::Event::Stderr(event) => { + Ok(WorkerEvent::StdErr { + timestamp: event.timestamp.ok_or("Missing timestamp")?.into(), + bytes: event.message.into_bytes(), + }) + } + golem_api_grpc::proto::golem::worker::log_event::Event::Log(event) => { + Ok(WorkerEvent::Log { + timestamp: event.timestamp.ok_or("Missing timestamp")?.into(), + level: event.level().into(), + context: event.context, + message: event.message, + }) + } + golem_api_grpc::proto::golem::worker::log_event::Event::InvocationStarted( + event, + ) => Ok(WorkerEvent::InvocationStart { + timestamp: event.timestamp.ok_or("Missing timestamp")?.into(), + function: event.function, + idempotency_key: event + .idempotency_key + .ok_or("Missing idempotency key")? + .into(), + }), + golem_api_grpc::proto::golem::worker::log_event::Event::InvocationFinished( + event, + ) => Ok(WorkerEvent::InvocationFinished { + timestamp: event.timestamp.ok_or("Missing timestamp")?.into(), + function: event.function, + idempotency_key: event + .idempotency_key + .ok_or("Missing idempotency key")? + .into(), + }), + }, + None => Err("Missing event".to_string()), + } + } +} + +impl TryFrom for golem_api_grpc::proto::golem::worker::LogEvent { + type Error = String; + + fn try_from(value: WorkerEvent) -> Result { + match value { + WorkerEvent::StdOut { timestamp, bytes } => Ok(golem::worker::LogEvent { + event: Some(golem::worker::log_event::Event::Stdout( + golem::worker::StdOutLog { + message: String::from_utf8_lossy(&bytes).to_string(), + timestamp: Some(timestamp.into()), + }, + )), + }), + WorkerEvent::StdErr { timestamp, bytes } => Ok(golem::worker::LogEvent { + event: Some( + golem_api_grpc::proto::golem::worker::log_event::Event::Stderr( + golem::worker::StdErrLog { + message: String::from_utf8_lossy(&bytes).to_string(), + timestamp: Some(timestamp.into()), + }, + ), + ), + }), + WorkerEvent::Log { + timestamp, + level, + context, + message, + } => Ok(golem::worker::LogEvent { + event: Some(golem::worker::log_event::Event::Log(golem::worker::Log { + level: match level { + LogLevel::Trace => golem::worker::Level::Trace.into(), + LogLevel::Debug => golem::worker::Level::Debug.into(), + LogLevel::Info => golem::worker::Level::Info.into(), + LogLevel::Warn => golem::worker::Level::Warn.into(), + LogLevel::Error => golem::worker::Level::Error.into(), + LogLevel::Critical => golem::worker::Level::Critical.into(), + }, + context, + message, + timestamp: Some(timestamp.into()), + })), + }), + WorkerEvent::InvocationStart { + timestamp, + function, + idempotency_key, + } => Ok(golem::worker::LogEvent { + event: Some(golem::worker::log_event::Event::InvocationStarted( + golem::worker::InvocationStarted { + function, + idempotency_key: Some(idempotency_key.into()), + timestamp: Some(timestamp.into()), + }, + )), + }), + WorkerEvent::InvocationFinished { + timestamp, + function, + idempotency_key, + } => Ok(golem::worker::LogEvent { + event: Some(golem::worker::log_event::Event::InvocationFinished( + golem::worker::InvocationFinished { + function, + idempotency_key: Some(idempotency_key.into()), + timestamp: Some(timestamp.into()), + }, + )), + }), + WorkerEvent::Close => Err("Close event is not supported via protobuf".to_string()), + } + } +} + +impl From for ComponentType { + fn from(value: golem_api_grpc::proto::golem::component::ComponentType) -> Self { + match value { + golem_api_grpc::proto::golem::component::ComponentType::Durable => { + ComponentType::Durable + } + golem_api_grpc::proto::golem::component::ComponentType::Ephemeral => { + ComponentType::Ephemeral + } + } + } +} + +impl From for golem_api_grpc::proto::golem::component::ComponentType { + fn from(value: ComponentType) -> Self { + match value { + ComponentType::Durable => { + golem_api_grpc::proto::golem::component::ComponentType::Durable + } + ComponentType::Ephemeral => { + golem_api_grpc::proto::golem::component::ComponentType::Ephemeral + } + } + } +} + +impl From + for ComponentFilePermissions +{ + fn from(value: golem_api_grpc::proto::golem::component::ComponentFilePermissions) -> Self { + match value { + golem_api_grpc::proto::golem::component::ComponentFilePermissions::ReadOnly => { + ComponentFilePermissions::ReadOnly + } + golem_api_grpc::proto::golem::component::ComponentFilePermissions::ReadWrite => { + ComponentFilePermissions::ReadWrite + } + } + } +} + +impl From + for golem_api_grpc::proto::golem::component::ComponentFilePermissions +{ + fn from(value: ComponentFilePermissions) -> Self { + match value { + ComponentFilePermissions::ReadOnly => { + golem_api_grpc::proto::golem::component::ComponentFilePermissions::ReadOnly + } + ComponentFilePermissions::ReadWrite => { + golem_api_grpc::proto::golem::component::ComponentFilePermissions::ReadWrite + } + } + } +} + +impl From for golem_api_grpc::proto::golem::component::InitialComponentFile { + fn from(value: InitialComponentFile) -> Self { + let permissions: golem_api_grpc::proto::golem::component::ComponentFilePermissions = + value.permissions.into(); + Self { + key: value.key.0, + path: value.path.to_string(), + permissions: permissions.into(), + } + } +} + +impl TryFrom + for InitialComponentFile +{ + type Error = String; + + fn try_from( + value: golem_api_grpc::proto::golem::component::InitialComponentFile, + ) -> Result { + let permissions: golem_api_grpc::proto::golem::component::ComponentFilePermissions = value + .permissions + .try_into() + .map_err(|e| format!("Failed converting permissions {e}"))?; + let permissions: ComponentFilePermissions = permissions.into(); + let path = ComponentFilePath::from_abs_str(&value.path).map_err(|e| e.to_string())?; + let key = InitialComponentFileKey(value.key); + Ok(Self { + key, + path, + permissions, + }) + } +} + +impl From for golem_api_grpc::proto::golem::worker::FileSystemNode { + fn from(value: ComponentFileSystemNode) -> Self { + let last_modified = value + .last_modified + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap() + .as_secs(); + + match value.details { + ComponentFileSystemNodeDetails::File { permissions, size } => + golem_api_grpc::proto::golem::worker::FileSystemNode { + value: Some(golem_api_grpc::proto::golem::worker::file_system_node::Value::File( + golem_api_grpc::proto::golem::worker::FileFileSystemNode { + name: value.name, + last_modified, + size, + permissions: + golem_api_grpc::proto::golem::component::ComponentFilePermissions::from(permissions).into(), + } + )) + }, + ComponentFileSystemNodeDetails::Directory => + golem_api_grpc::proto::golem::worker::FileSystemNode { + value: Some(golem_api_grpc::proto::golem::worker::file_system_node::Value::Directory( + golem_api_grpc::proto::golem::worker::DirectoryFileSystemNode { + name: value.name, + last_modified, + } + )) + } + } + } +} + +impl TryFrom for ComponentFileSystemNode { + type Error = anyhow::Error; + + fn try_from( + value: golem_api_grpc::proto::golem::worker::FileSystemNode, + ) -> Result { + match value.value { + Some(golem_api_grpc::proto::golem::worker::file_system_node::Value::Directory( + golem_api_grpc::proto::golem::worker::DirectoryFileSystemNode { + name, + last_modified, + }, + )) => Ok(ComponentFileSystemNode { + name, + last_modified: SystemTime::UNIX_EPOCH + Duration::from_secs(last_modified), + details: ComponentFileSystemNodeDetails::Directory, + }), + Some(golem_api_grpc::proto::golem::worker::file_system_node::Value::File( + golem_api_grpc::proto::golem::worker::FileFileSystemNode { + name, + last_modified, + size, + permissions, + }, + )) => Ok(ComponentFileSystemNode { + name, + last_modified: SystemTime::UNIX_EPOCH + Duration::from_secs(last_modified), + details: ComponentFileSystemNodeDetails::File { + permissions: + golem_api_grpc::proto::golem::component::ComponentFilePermissions::try_from( + permissions, + )? + .into(), + size, + }, + }), + None => Err(anyhow::anyhow!("Missing value")), + } + } +} + +impl From for GatewayBindingType { + fn from(value: golem_api_grpc::proto::golem::apidefinition::GatewayBindingType) -> Self { + match value { + golem_api_grpc::proto::golem::apidefinition::GatewayBindingType::Default => { + GatewayBindingType::Default + } + golem_api_grpc::proto::golem::apidefinition::GatewayBindingType::FileServer => { + GatewayBindingType::FileServer + } + golem_api_grpc::proto::golem::apidefinition::GatewayBindingType::CorsPreflight => { + GatewayBindingType::CorsPreflight + } + golem_api_grpc::proto::golem::apidefinition::GatewayBindingType::AuthCallBack => { + GatewayBindingType::CorsPreflight + } + } + } +} + +impl From for golem_api_grpc::proto::golem::apidefinition::GatewayBindingType { + fn from(value: GatewayBindingType) -> Self { + match value { + GatewayBindingType::Default => { + golem_api_grpc::proto::golem::apidefinition::GatewayBindingType::Default + } + GatewayBindingType::FileServer => { + golem_api_grpc::proto::golem::apidefinition::GatewayBindingType::FileServer + } + GatewayBindingType::CorsPreflight => { + golem_api_grpc::proto::golem::apidefinition::GatewayBindingType::CorsPreflight + } + } + } +} diff --git a/golem-common/src/model/public_oplog.rs b/golem-common/src/model/public_oplog.rs index 86983e357..fb093a46a 100644 --- a/golem-common/src/model/public_oplog.rs +++ b/golem-common/src/model/public_oplog.rs @@ -12,35 +12,34 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::config::RetryConfig; use crate::model::lucene::{LeafQuery, Query}; use crate::model::oplog::{LogLevel, OplogIndex, WorkerResourceId, WrappedFunctionType}; use crate::model::plugin::PluginInstallation; use crate::model::regions::OplogRegion; +use crate::model::RetryConfig; use crate::model::{ AccountId, ComponentVersion, Empty, IdempotencyKey, PluginInstallationId, Timestamp, WorkerId, }; -use golem_api_grpc::proto::golem::worker::{oplog_entry, worker_invocation, wrapped_function_type}; use golem_wasm_ast::analysis::analysed_type::{ case, f64, field, list, option, record, s64, str, tuple, u32, u64, u8, unit_case, variant, }; use golem_wasm_ast::analysis::{AnalysedType, NameOptionTypePair}; use golem_wasm_rpc::{IntoValue, Value, ValueAndType, WitValue}; -use poem_openapi::types::{ParseFromParameter, ParseResult}; -use poem_openapi::{Object, Union}; use serde::{Deserialize, Serialize}; -use std::collections::{BTreeMap, BTreeSet, HashMap}; +use std::collections::{BTreeMap, BTreeSet}; use std::fmt; use std::fmt::{Display, Formatter}; use std::time::Duration; -#[derive(Clone, Debug, Serialize, PartialEq, Deserialize, Object)] +#[derive(Clone, Debug, Serialize, PartialEq, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] pub struct SnapshotBasedUpdateParameters { pub payload: Vec, } -#[derive(Clone, Debug, Serialize, PartialEq, Deserialize, Union)] -#[oai(discriminator_name = "type", one_of = true)] +#[derive(Clone, Debug, Serialize, PartialEq, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Union))] +#[cfg_attr(feature = "poem", oai(discriminator_name = "type", one_of = true))] #[serde(tag = "type")] pub enum PublicUpdateDescription { Automatic(Empty), @@ -69,13 +68,15 @@ impl IntoValue for PublicUpdateDescription { } } -#[derive(Clone, Debug, Serialize, PartialEq, Deserialize, Object)] +#[derive(Clone, Debug, Serialize, PartialEq, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] pub struct WriteRemoteBatchedParameters { pub index: Option, } -#[derive(Clone, Debug, Serialize, PartialEq, Deserialize, Union)] -#[oai(discriminator_name = "type", one_of = true)] +#[derive(Clone, Debug, Serialize, PartialEq, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Union))] +#[cfg_attr(feature = "poem", oai(discriminator_name = "type", one_of = true))] #[serde(tag = "type")] pub enum PublicWrappedFunctionType { /// The side-effect reads from the worker's local state (for example local file system, @@ -150,12 +151,16 @@ impl IntoValue for PublicWrappedFunctionType { } } -#[derive(Clone, Debug, Serialize, PartialEq, Deserialize, Object)] +#[derive(Clone, Debug, Serialize, PartialEq, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] +#[cfg_attr(feature = "poem", oai(rename_all = "camelCase"))] +#[serde(rename_all = "camelCase")] pub struct DetailsParameter { pub details: String, } -#[derive(Clone, Debug, Serialize, PartialEq, Deserialize, Object)] +#[derive(Clone, Debug, Serialize, PartialEq, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] pub struct PublicRetryConfig { pub max_attempts: u32, #[serde(with = "humantime_serde")] @@ -200,7 +205,8 @@ impl IntoValue for PublicRetryConfig { } } -#[derive(Clone, Debug, Serialize, PartialEq, Deserialize, Object)] +#[derive(Clone, Debug, Serialize, PartialEq, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] pub struct ExportedFunctionParameters { pub idempotency_key: IdempotencyKey, pub full_function_name: String, @@ -228,13 +234,15 @@ impl IntoValue for ExportedFunctionParameters { } } -#[derive(Clone, Debug, Serialize, PartialEq, Deserialize, Object)] +#[derive(Clone, Debug, Serialize, PartialEq, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] pub struct ManualUpdateParameters { pub target_version: ComponentVersion, } -#[derive(Clone, Debug, Serialize, PartialEq, Deserialize, Union)] -#[oai(discriminator_name = "type", one_of = true)] +#[derive(Clone, Debug, Serialize, PartialEq, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Union))] +#[cfg_attr(feature = "poem", oai(discriminator_name = "type", one_of = true))] #[serde(tag = "type")] pub enum PublicWorkerInvocation { ExportedFunction(ExportedFunctionParameters), @@ -263,7 +271,8 @@ impl IntoValue for PublicWorkerInvocation { } } -#[derive(Clone, Debug, Serialize, PartialEq, Eq, PartialOrd, Ord, Deserialize, Object)] +#[derive(Clone, Debug, Serialize, PartialEq, Eq, PartialOrd, Ord, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] pub struct PluginInstallationDescription { pub installation_id: PluginInstallationId, pub plugin_name: String, @@ -307,40 +316,8 @@ impl From for PluginInstallationDescription { } } -impl From - for golem_api_grpc::proto::golem::worker::PluginInstallationDescription -{ - fn from(plugin_installation_description: PluginInstallationDescription) -> Self { - golem_api_grpc::proto::golem::worker::PluginInstallationDescription { - installation_id: Some(plugin_installation_description.installation_id.into()), - plugin_name: plugin_installation_description.plugin_name, - plugin_version: plugin_installation_description.plugin_version, - parameters: HashMap::from_iter(plugin_installation_description.parameters), - } - } -} - -impl TryFrom - for PluginInstallationDescription -{ - type Error = String; - - fn try_from( - value: golem_api_grpc::proto::golem::worker::PluginInstallationDescription, - ) -> Result { - Ok(PluginInstallationDescription { - installation_id: value - .installation_id - .ok_or("Missing installation_id".to_string())? - .try_into()?, - plugin_name: value.plugin_name, - plugin_version: value.plugin_version, - parameters: BTreeMap::from_iter(value.parameters), - }) - } -} - -#[derive(Clone, Debug, Serialize, PartialEq, Deserialize, Object)] +#[derive(Clone, Debug, Serialize, PartialEq, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] pub struct CreateParameters { pub timestamp: Timestamp, pub worker_id: WorkerId, @@ -397,7 +374,8 @@ impl IntoValue for CreateParameters { } } -#[derive(Clone, Debug, Serialize, PartialEq, Deserialize, Object)] +#[derive(Clone, Debug, Serialize, PartialEq, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] pub struct ImportedFunctionInvokedParameters { pub timestamp: Timestamp, pub function_name: String, @@ -433,7 +411,8 @@ impl IntoValue for ImportedFunctionInvokedParameters { } } -#[derive(Clone, Debug, Serialize, PartialEq, Deserialize, Object)] +#[derive(Clone, Debug, Serialize, PartialEq, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] pub struct ExportedFunctionInvokedParameters { pub timestamp: Timestamp, pub function_name: String, @@ -464,7 +443,8 @@ impl IntoValue for ExportedFunctionInvokedParameters { } } -#[derive(Clone, Debug, Serialize, PartialEq, Deserialize, Object)] +#[derive(Clone, Debug, Serialize, PartialEq, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] pub struct ExportedFunctionCompletedParameters { pub timestamp: Timestamp, pub response: ValueAndType, @@ -490,12 +470,14 @@ impl IntoValue for ExportedFunctionCompletedParameters { } } -#[derive(Clone, Debug, Serialize, PartialEq, Deserialize, Object)] +#[derive(Clone, Debug, Serialize, PartialEq, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] pub struct TimestampParameter { pub timestamp: Timestamp, } -#[derive(Clone, Debug, Serialize, PartialEq, Deserialize, Object)] +#[derive(Clone, Debug, Serialize, PartialEq, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] pub struct ErrorParameters { pub timestamp: Timestamp, pub error: String, @@ -514,7 +496,8 @@ impl IntoValue for ErrorParameters { } } -#[derive(Clone, Debug, Serialize, PartialEq, Deserialize, Object)] +#[derive(Clone, Debug, Serialize, PartialEq, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] pub struct JumpParameters { pub timestamp: Timestamp, pub jump: OplogRegion, @@ -538,7 +521,8 @@ impl IntoValue for JumpParameters { } } -#[derive(Clone, Debug, Serialize, PartialEq, Deserialize, Object)] +#[derive(Clone, Debug, Serialize, PartialEq, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] pub struct ChangeRetryPolicyParameters { pub timestamp: Timestamp, pub new_policy: PublicRetryConfig, @@ -560,7 +544,8 @@ impl IntoValue for ChangeRetryPolicyParameters { } } -#[derive(Clone, Debug, Serialize, PartialEq, Deserialize, Object)] +#[derive(Clone, Debug, Serialize, PartialEq, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] pub struct EndRegionParameters { pub timestamp: Timestamp, pub begin_index: OplogIndex, @@ -582,7 +567,8 @@ impl IntoValue for EndRegionParameters { } } -#[derive(Clone, Debug, Serialize, PartialEq, Deserialize, Object)] +#[derive(Clone, Debug, Serialize, PartialEq, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] pub struct PendingWorkerInvocationParameters { pub timestamp: Timestamp, pub invocation: PublicWorkerInvocation, @@ -604,7 +590,8 @@ impl IntoValue for PendingWorkerInvocationParameters { } } -#[derive(Clone, Debug, Serialize, PartialEq, Deserialize, Object)] +#[derive(Clone, Debug, Serialize, PartialEq, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] pub struct PendingUpdateParameters { pub timestamp: Timestamp, pub target_version: ComponentVersion, @@ -629,7 +616,8 @@ impl IntoValue for PendingUpdateParameters { } } -#[derive(Clone, Debug, Serialize, PartialEq, Deserialize, Object)] +#[derive(Clone, Debug, Serialize, PartialEq, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] pub struct SuccessfulUpdateParameters { pub timestamp: Timestamp, pub target_version: ComponentVersion, @@ -663,7 +651,8 @@ impl IntoValue for SuccessfulUpdateParameters { } } -#[derive(Clone, Debug, Serialize, PartialEq, Deserialize, Object)] +#[derive(Clone, Debug, Serialize, PartialEq, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] pub struct FailedUpdateParameters { pub timestamp: Timestamp, pub target_version: ComponentVersion, @@ -688,7 +677,8 @@ impl IntoValue for FailedUpdateParameters { } } -#[derive(Clone, Debug, Serialize, PartialEq, Deserialize, Object)] +#[derive(Clone, Debug, Serialize, PartialEq, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] pub struct GrowMemoryParameters { pub timestamp: Timestamp, pub delta: u64, @@ -707,7 +697,8 @@ impl IntoValue for GrowMemoryParameters { } } -#[derive(Clone, Debug, Serialize, PartialEq, Deserialize, Object)] +#[derive(Clone, Debug, Serialize, PartialEq, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] pub struct ResourceParameters { pub timestamp: Timestamp, pub id: WorkerResourceId, @@ -726,7 +717,8 @@ impl IntoValue for ResourceParameters { } } -#[derive(Clone, Debug, Serialize, PartialEq, Deserialize, Object)] +#[derive(Clone, Debug, Serialize, PartialEq, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] pub struct DescribeResourceParameters { pub timestamp: Timestamp, pub id: WorkerResourceId, @@ -758,7 +750,8 @@ impl IntoValue for DescribeResourceParameters { } } -#[derive(Clone, Debug, Serialize, PartialEq, Deserialize, Object)] +#[derive(Clone, Debug, Serialize, PartialEq, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] pub struct LogParameters { pub timestamp: Timestamp, pub level: LogLevel, @@ -786,7 +779,8 @@ impl IntoValue for LogParameters { } } -#[derive(Clone, Debug, Serialize, PartialEq, Deserialize, Object)] +#[derive(Clone, Debug, Serialize, PartialEq, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] pub struct ActivatePluginParameters { pub timestamp: Timestamp, pub plugin: PluginInstallationDescription, @@ -805,7 +799,8 @@ impl IntoValue for ActivatePluginParameters { } } -#[derive(Clone, Debug, Serialize, PartialEq, Deserialize, Object)] +#[derive(Clone, Debug, Serialize, PartialEq, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] pub struct DeactivatePluginParameters { pub timestamp: Timestamp, pub plugin: PluginInstallationDescription, @@ -832,8 +827,9 @@ impl IntoValue for DeactivatePluginParameters { /// The rest of the system will always use `OplogEntry` internally - the only point where the /// oplog payloads are decoded and re-encoded as `Value` is in this module, and it should only be used /// before exposing an oplog entry through a public API. -#[derive(Clone, Debug, Serialize, PartialEq, Deserialize, Union)] -#[oai(discriminator_name = "type", one_of = true)] +#[derive(Clone, Debug, Serialize, PartialEq, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Union))] +#[cfg_attr(feature = "poem", oai(discriminator_name = "type", one_of = true))] #[serde(tag = "type")] pub enum PublicOplogEntry { Create(CreateParameters), @@ -1461,918 +1457,993 @@ impl IntoValue for PublicOplogEntry { } } -impl TryFrom for PublicOplogEntry { - type Error = String; +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] +pub struct OplogCursor { + pub next_oplog_index: u64, + pub current_component_version: u64, +} - fn try_from(value: golem_api_grpc::proto::golem::worker::OplogEntry) -> Result { - match value.entry.ok_or("Oplog entry is empty")? { - oplog_entry::Entry::Create(create) => Ok(PublicOplogEntry::Create(CreateParameters { - timestamp: create.timestamp.ok_or("Missing timestamp field")?.into(), - worker_id: create - .worker_id - .ok_or("Missing worker_id field")? - .try_into()?, - component_version: create.component_version, - args: create.args, - env: create.env.into_iter().collect(), - account_id: create.account_id.ok_or("Missing account_id field")?.into(), - parent: match create.parent { - Some(parent) => Some(parent.try_into()?), - None => None, - }, - component_size: create.component_size, - initial_total_linear_memory_size: create.initial_total_linear_memory_size, - initial_active_plugins: BTreeSet::from_iter( - create - .initial_active_plugins - .into_iter() - .map(|pr| pr.try_into()) - .collect::, _>>()?, - ), - })), - oplog_entry::Entry::ImportedFunctionInvoked(imported_function_invoked) => Ok( - PublicOplogEntry::ImportedFunctionInvoked(ImportedFunctionInvokedParameters { - timestamp: imported_function_invoked - .timestamp - .ok_or("Missing timestamp field")? - .into(), - function_name: imported_function_invoked.function_name, - request: imported_function_invoked - .request - .ok_or("Missing request field")? - .try_into()?, - response: imported_function_invoked - .response - .ok_or("Missing response field")? - .try_into()?, - wrapped_function_type: imported_function_invoked - .wrapped_function_type - .ok_or("Missing wrapped_function_type field")? - .try_into()?, - }), - ), - oplog_entry::Entry::ExportedFunctionInvoked(exported_function_invoked) => Ok( - PublicOplogEntry::ExportedFunctionInvoked(ExportedFunctionInvokedParameters { - timestamp: exported_function_invoked - .timestamp - .ok_or("Missing timestamp field")? - .into(), - function_name: exported_function_invoked.function_name, - request: exported_function_invoked - .request - .into_iter() - .map(TryInto::try_into) - .collect::, String>>()?, - idempotency_key: exported_function_invoked - .idempotency_key - .ok_or("Missing idempotency_key field")? - .into(), - }), - ), - oplog_entry::Entry::ExportedFunctionCompleted(exported_function_completed) => Ok( - PublicOplogEntry::ExportedFunctionCompleted(ExportedFunctionCompletedParameters { - timestamp: exported_function_completed - .timestamp - .ok_or("Missing timestamp field")? - .into(), - response: exported_function_completed - .response - .ok_or("Missing response field")? - .try_into()?, - consumed_fuel: exported_function_completed.consumed_fuel, - }), - ), - oplog_entry::Entry::Suspend(suspend) => { - Ok(PublicOplogEntry::Suspend(TimestampParameter { - timestamp: suspend.timestamp.ok_or("Missing timestamp field")?.into(), - })) - } - oplog_entry::Entry::Error(error) => Ok(PublicOplogEntry::Error(ErrorParameters { - timestamp: error.timestamp.ok_or("Missing timestamp field")?.into(), - error: error.error, - })), - oplog_entry::Entry::NoOp(no_op) => Ok(PublicOplogEntry::NoOp(TimestampParameter { - timestamp: no_op.timestamp.ok_or("Missing timestamp field")?.into(), - })), - oplog_entry::Entry::Jump(jump) => Ok(PublicOplogEntry::Jump(JumpParameters { - timestamp: jump.timestamp.ok_or("Missing timestamp field")?.into(), - jump: OplogRegion { - start: OplogIndex::from_u64(jump.start), - end: OplogIndex::from_u64(jump.end), - }, - })), - oplog_entry::Entry::Interrupted(interrupted) => { - Ok(PublicOplogEntry::Interrupted(TimestampParameter { - timestamp: interrupted - .timestamp - .ok_or("Missing timestamp field")? - .into(), - })) - } - oplog_entry::Entry::Exited(exited) => { - Ok(PublicOplogEntry::Exited(TimestampParameter { - timestamp: exited.timestamp.ok_or("Missing timestamp field")?.into(), - })) - } - oplog_entry::Entry::ChangeRetryPolicy(change_retry_policy) => Ok( - PublicOplogEntry::ChangeRetryPolicy(ChangeRetryPolicyParameters { - timestamp: change_retry_policy - .timestamp - .ok_or("Missing timestamp field")? - .into(), - new_policy: change_retry_policy - .retry_policy - .ok_or("Missing retry_policy field")? - .try_into()?, - }), - ), - oplog_entry::Entry::BeginAtomicRegion(begin_atomic_region) => { - Ok(PublicOplogEntry::BeginAtomicRegion(TimestampParameter { - timestamp: begin_atomic_region - .timestamp - .ok_or("Missing timestamp field")? - .into(), - })) - } - oplog_entry::Entry::EndAtomicRegion(end_atomic_region) => { - Ok(PublicOplogEntry::EndAtomicRegion(EndRegionParameters { - timestamp: end_atomic_region - .timestamp - .ok_or("Missing timestamp field")? - .into(), - begin_index: OplogIndex::from_u64(end_atomic_region.begin_index), - })) - } - oplog_entry::Entry::BeginRemoteWrite(begin_remote_write) => { - Ok(PublicOplogEntry::BeginRemoteWrite(TimestampParameter { - timestamp: begin_remote_write - .timestamp - .ok_or("Missing timestamp field")? - .into(), - })) - } - oplog_entry::Entry::EndRemoteWrite(end_remote_write) => { - Ok(PublicOplogEntry::EndRemoteWrite(EndRegionParameters { - timestamp: end_remote_write - .timestamp - .ok_or("Missing timestamp field")? - .into(), - begin_index: OplogIndex::from_u64(end_remote_write.begin_index), - })) - } - oplog_entry::Entry::PendingWorkerInvocation(pending_worker_invocation) => Ok( - PublicOplogEntry::PendingWorkerInvocation(PendingWorkerInvocationParameters { - timestamp: pending_worker_invocation - .timestamp - .ok_or("Missing timestamp field")? - .into(), - invocation: pending_worker_invocation - .invocation - .ok_or("Missing invocation field")? - .try_into()?, - }), - ), - oplog_entry::Entry::PendingUpdate(pending_update) => { - Ok(PublicOplogEntry::PendingUpdate(PendingUpdateParameters { - timestamp: pending_update - .timestamp - .ok_or("Missing timestamp field")? - .into(), - target_version: pending_update.target_version, - description: pending_update - .update_description - .ok_or("Missing update_description field")? - .try_into()?, - })) - } - oplog_entry::Entry::SuccessfulUpdate(successful_update) => Ok( - PublicOplogEntry::SuccessfulUpdate(SuccessfulUpdateParameters { - timestamp: successful_update - .timestamp - .ok_or("Missing timestamp field")? - .into(), - target_version: successful_update.target_version, - new_component_size: successful_update.new_component_size, - new_active_plugins: BTreeSet::from_iter( - successful_update - .new_active_plugins - .into_iter() - .map(|pr| pr.try_into()) - .collect::, _>>()?, - ), - }), - ), - oplog_entry::Entry::FailedUpdate(failed_update) => { - Ok(PublicOplogEntry::FailedUpdate(FailedUpdateParameters { - timestamp: failed_update - .timestamp - .ok_or("Missing timestamp field")? - .into(), - target_version: failed_update.target_version, - details: failed_update.details, - })) - } - oplog_entry::Entry::GrowMemory(grow_memory) => { - Ok(PublicOplogEntry::GrowMemory(GrowMemoryParameters { - timestamp: grow_memory - .timestamp - .ok_or("Missing timestamp field")? - .into(), - delta: grow_memory.delta, - })) - } - oplog_entry::Entry::CreateResource(create_resource) => { - Ok(PublicOplogEntry::CreateResource(ResourceParameters { - timestamp: create_resource - .timestamp - .ok_or("Missing timestamp field")? - .into(), - id: WorkerResourceId(create_resource.resource_id), - })) - } - oplog_entry::Entry::DropResource(drop_resource) => { - Ok(PublicOplogEntry::DropResource(ResourceParameters { - timestamp: drop_resource - .timestamp - .ok_or("Missing timestamp field")? - .into(), - id: WorkerResourceId(drop_resource.resource_id), - })) +#[cfg(feature = "poem")] +impl poem_openapi::types::ParseFromParameter for OplogCursor { + fn parse_from_parameter(value: &str) -> poem_openapi::types::ParseResult { + let parts: Vec<&str> = value.split('-').collect(); + if parts.len() != 2 { + return Err("Invalid oplog cursor".into()); + } + let next_oplog_index = parts[0] + .parse() + .map_err(|_| "Invalid index in the oplog cursor")?; + let current_component_version = parts[1] + .parse() + .map_err(|_| "Invalid component version in the oplog cursor")?; + Ok(OplogCursor { + next_oplog_index, + current_component_version, + }) + } +} + +impl Display for OplogCursor { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!( + f, + "{}-{}", + self.next_oplog_index, self.current_component_version + ) + } +} + +#[cfg(feature = "protobuf")] +mod protobuf { + use crate::model::oplog::{LogLevel, OplogIndex, WorkerResourceId}; + use crate::model::public_oplog::{ + ActivatePluginParameters, ChangeRetryPolicyParameters, CreateParameters, + DeactivatePluginParameters, DescribeResourceParameters, EndRegionParameters, + ErrorParameters, ExportedFunctionCompletedParameters, ExportedFunctionInvokedParameters, + ExportedFunctionParameters, FailedUpdateParameters, GrowMemoryParameters, + ImportedFunctionInvokedParameters, JumpParameters, LogParameters, ManualUpdateParameters, + OplogCursor, PendingUpdateParameters, PendingWorkerInvocationParameters, + PluginInstallationDescription, PublicOplogEntry, PublicRetryConfig, + PublicUpdateDescription, PublicWorkerInvocation, PublicWrappedFunctionType, + ResourceParameters, SnapshotBasedUpdateParameters, SuccessfulUpdateParameters, + TimestampParameter, WriteRemoteBatchedParameters, + }; + use crate::model::regions::OplogRegion; + use crate::model::Empty; + use golem_api_grpc::proto::golem::worker::{ + oplog_entry, worker_invocation, wrapped_function_type, + }; + use golem_wasm_rpc::ValueAndType; + use std::collections::{BTreeMap, BTreeSet, HashMap}; + use std::time::Duration; + + impl From for OplogCursor { + fn from(value: golem_api_grpc::proto::golem::worker::OplogCursor) -> Self { + Self { + next_oplog_index: value.next_oplog_index, + current_component_version: value.current_component_version, } - oplog_entry::Entry::DescribeResource(describe_resource) => Ok( - PublicOplogEntry::DescribeResource(DescribeResourceParameters { - timestamp: describe_resource - .timestamp - .ok_or("Missing timestamp field")? - .into(), - id: WorkerResourceId(describe_resource.resource_id), - resource_name: describe_resource.resource_name, - resource_params: describe_resource - .resource_params - .into_iter() - .map(TryInto::try_into) - .collect::, String>>()?, - }), - ), - oplog_entry::Entry::Log(log) => Ok(PublicOplogEntry::Log(LogParameters { - level: log.level().into(), - timestamp: log.timestamp.ok_or("Missing timestamp field")?.into(), - context: log.context, - message: log.message, - })), - oplog_entry::Entry::Restart(restart) => { - Ok(PublicOplogEntry::Restart(TimestampParameter { - timestamp: restart.timestamp.ok_or("Missing timestamp field")?.into(), - })) + } + } + + impl From for golem_api_grpc::proto::golem::worker::OplogCursor { + fn from(value: OplogCursor) -> Self { + Self { + next_oplog_index: value.next_oplog_index, + current_component_version: value.current_component_version, } - oplog_entry::Entry::ActivatePlugin(activate) => { - Ok(PublicOplogEntry::ActivatePlugin(ActivatePluginParameters { - timestamp: activate.timestamp.ok_or("Missing timestamp field")?.into(), - plugin: activate.plugin.ok_or("Missing plugin field")?.try_into()?, - })) + } + } + + impl From + for golem_api_grpc::proto::golem::worker::PluginInstallationDescription + { + fn from(plugin_installation_description: PluginInstallationDescription) -> Self { + golem_api_grpc::proto::golem::worker::PluginInstallationDescription { + installation_id: Some(plugin_installation_description.installation_id.into()), + plugin_name: plugin_installation_description.plugin_name, + plugin_version: plugin_installation_description.plugin_version, + parameters: HashMap::from_iter(plugin_installation_description.parameters), } - oplog_entry::Entry::DeactivatePlugin(deactivate) => Ok( - PublicOplogEntry::DeactivatePlugin(DeactivatePluginParameters { - timestamp: deactivate - .timestamp - .ok_or("Missing timestamp field")? - .into(), - plugin: deactivate - .plugin - .ok_or("Missing plugin field")? - .try_into()?, - }), - ), } } -} -impl TryFrom for golem_api_grpc::proto::golem::worker::OplogEntry { - type Error = String; + impl TryFrom + for PluginInstallationDescription + { + type Error = String; - fn try_from(value: PublicOplogEntry) -> Result { - Ok(match value { - PublicOplogEntry::Create(create) => golem_api_grpc::proto::golem::worker::OplogEntry { - entry: Some(oplog_entry::Entry::Create( - golem_api_grpc::proto::golem::worker::CreateParameters { - timestamp: Some(create.timestamp.into()), - worker_id: Some(create.worker_id.into()), + fn try_from( + value: golem_api_grpc::proto::golem::worker::PluginInstallationDescription, + ) -> Result { + Ok(PluginInstallationDescription { + installation_id: value + .installation_id + .ok_or("Missing installation_id".to_string())? + .try_into()?, + plugin_name: value.plugin_name, + plugin_version: value.plugin_version, + parameters: BTreeMap::from_iter(value.parameters), + }) + } + } + impl TryFrom for PublicOplogEntry { + type Error = String; + + fn try_from( + value: golem_api_grpc::proto::golem::worker::OplogEntry, + ) -> Result { + match value.entry.ok_or("Oplog entry is empty")? { + oplog_entry::Entry::Create(create) => { + Ok(PublicOplogEntry::Create(CreateParameters { + timestamp: create.timestamp.ok_or("Missing timestamp field")?.into(), + worker_id: create + .worker_id + .ok_or("Missing worker_id field")? + .try_into()?, component_version: create.component_version, args: create.args, env: create.env.into_iter().collect(), - account_id: Some(create.account_id.into()), - parent: create.parent.map(Into::into), + account_id: create.account_id.ok_or("Missing account_id field")?.into(), + parent: match create.parent { + Some(parent) => Some(parent.try_into()?), + None => None, + }, component_size: create.component_size, initial_total_linear_memory_size: create.initial_total_linear_memory_size, - initial_active_plugins: create - .initial_active_plugins - .into_iter() - .map(Into::into) - .collect(), - }, - )), - }, - PublicOplogEntry::ImportedFunctionInvoked(imported_function_invoked) => { - golem_api_grpc::proto::golem::worker::OplogEntry { - entry: Some(oplog_entry::Entry::ImportedFunctionInvoked( - golem_api_grpc::proto::golem::worker::ImportedFunctionInvokedParameters { - timestamp: Some(imported_function_invoked.timestamp.into()), - function_name: imported_function_invoked.function_name, - request: Some(imported_function_invoked.request.try_into().map_err( - |errors: Vec| { - format!("Failed to convert request: {}", errors.join(", ")) - }, - )?), - response: Some(imported_function_invoked.response.try_into().map_err( - |errors: Vec| { - format!("Failed to convert response: {}", errors.join(", ")) - }, - )?), - wrapped_function_type: Some( - imported_function_invoked.wrapped_function_type.into(), - ), - }, - )), - } - } - PublicOplogEntry::ExportedFunctionInvoked(exported_function_invoked) => { - golem_api_grpc::proto::golem::worker::OplogEntry { - entry: Some(oplog_entry::Entry::ExportedFunctionInvoked( - golem_api_grpc::proto::golem::worker::ExportedFunctionInvokedParameters { - timestamp: Some(exported_function_invoked.timestamp.into()), - function_name: exported_function_invoked.function_name, - request: exported_function_invoked - .request + initial_active_plugins: BTreeSet::from_iter( + create + .initial_active_plugins .into_iter() - .map(|value| { - value.try_into().map_err(|errors: Vec| { - format!("Failed to convert request: {}", errors.join(", ")) - }) - }) + .map(|pr| pr.try_into()) .collect::, _>>()?, - idempotency_key: Some(exported_function_invoked.idempotency_key.into()), - }, - )), + ), + })) } - } - PublicOplogEntry::ExportedFunctionCompleted(exported_function_completed) => { - golem_api_grpc::proto::golem::worker::OplogEntry { - entry: Some(oplog_entry::Entry::ExportedFunctionCompleted( - golem_api_grpc::proto::golem::worker::ExportedFunctionCompletedParameters { - timestamp: Some(exported_function_completed.timestamp.into()), - response: Some( - exported_function_completed.response.try_into().map_err( - |errors: Vec| { - format!("Failed to convert response: {}", errors.join(", ")) - }, - )?, - ), + oplog_entry::Entry::ImportedFunctionInvoked(imported_function_invoked) => Ok( + PublicOplogEntry::ImportedFunctionInvoked(ImportedFunctionInvokedParameters { + timestamp: imported_function_invoked + .timestamp + .ok_or("Missing timestamp field")? + .into(), + function_name: imported_function_invoked.function_name, + request: imported_function_invoked + .request + .ok_or("Missing request field")? + .try_into()?, + response: imported_function_invoked + .response + .ok_or("Missing response field")? + .try_into()?, + wrapped_function_type: imported_function_invoked + .wrapped_function_type + .ok_or("Missing wrapped_function_type field")? + .try_into()?, + }), + ), + oplog_entry::Entry::ExportedFunctionInvoked(exported_function_invoked) => Ok( + PublicOplogEntry::ExportedFunctionInvoked(ExportedFunctionInvokedParameters { + timestamp: exported_function_invoked + .timestamp + .ok_or("Missing timestamp field")? + .into(), + function_name: exported_function_invoked.function_name, + request: exported_function_invoked + .request + .into_iter() + .map(TryInto::try_into) + .collect::, String>>()?, + idempotency_key: exported_function_invoked + .idempotency_key + .ok_or("Missing idempotency_key field")? + .into(), + }), + ), + oplog_entry::Entry::ExportedFunctionCompleted(exported_function_completed) => { + Ok(PublicOplogEntry::ExportedFunctionCompleted( + ExportedFunctionCompletedParameters { + timestamp: exported_function_completed + .timestamp + .ok_or("Missing timestamp field")? + .into(), + response: exported_function_completed + .response + .ok_or("Missing response field")? + .try_into()?, consumed_fuel: exported_function_completed.consumed_fuel, }, - )), + )) } - } - PublicOplogEntry::Suspend(suspend) => { - golem_api_grpc::proto::golem::worker::OplogEntry { - entry: Some(oplog_entry::Entry::Suspend( - golem_api_grpc::proto::golem::worker::TimestampParameter { - timestamp: Some(suspend.timestamp.into()), - }, - )), + oplog_entry::Entry::Suspend(suspend) => { + Ok(PublicOplogEntry::Suspend(TimestampParameter { + timestamp: suspend.timestamp.ok_or("Missing timestamp field")?.into(), + })) } - } - PublicOplogEntry::Error(error) => golem_api_grpc::proto::golem::worker::OplogEntry { - entry: Some(oplog_entry::Entry::Error( - golem_api_grpc::proto::golem::worker::ErrorParameters { - timestamp: Some(error.timestamp.into()), - error: error.error, + oplog_entry::Entry::Error(error) => Ok(PublicOplogEntry::Error(ErrorParameters { + timestamp: error.timestamp.ok_or("Missing timestamp field")?.into(), + error: error.error, + })), + oplog_entry::Entry::NoOp(no_op) => Ok(PublicOplogEntry::NoOp(TimestampParameter { + timestamp: no_op.timestamp.ok_or("Missing timestamp field")?.into(), + })), + oplog_entry::Entry::Jump(jump) => Ok(PublicOplogEntry::Jump(JumpParameters { + timestamp: jump.timestamp.ok_or("Missing timestamp field")?.into(), + jump: OplogRegion { + start: OplogIndex::from_u64(jump.start), + end: OplogIndex::from_u64(jump.end), }, - )), - }, - PublicOplogEntry::NoOp(no_op) => golem_api_grpc::proto::golem::worker::OplogEntry { - entry: Some(oplog_entry::Entry::NoOp( - golem_api_grpc::proto::golem::worker::TimestampParameter { - timestamp: Some(no_op.timestamp.into()), - }, - )), - }, - PublicOplogEntry::Jump(jump) => golem_api_grpc::proto::golem::worker::OplogEntry { - entry: Some(oplog_entry::Entry::Jump( - golem_api_grpc::proto::golem::worker::JumpParameters { - timestamp: Some(jump.timestamp.into()), - start: jump.jump.start.into(), - end: jump.jump.end.into(), - }, - )), - }, - PublicOplogEntry::Interrupted(interrupted) => { - golem_api_grpc::proto::golem::worker::OplogEntry { - entry: Some(oplog_entry::Entry::Interrupted( - golem_api_grpc::proto::golem::worker::TimestampParameter { - timestamp: Some(interrupted.timestamp.into()), - }, - )), + })), + oplog_entry::Entry::Interrupted(interrupted) => { + Ok(PublicOplogEntry::Interrupted(TimestampParameter { + timestamp: interrupted + .timestamp + .ok_or("Missing timestamp field")? + .into(), + })) } - } - PublicOplogEntry::Exited(exited) => golem_api_grpc::proto::golem::worker::OplogEntry { - entry: Some(oplog_entry::Entry::Exited( - golem_api_grpc::proto::golem::worker::TimestampParameter { - timestamp: Some(exited.timestamp.into()), - }, - )), - }, - PublicOplogEntry::ChangeRetryPolicy(change_retry_policy) => { - golem_api_grpc::proto::golem::worker::OplogEntry { - entry: Some(oplog_entry::Entry::ChangeRetryPolicy( - golem_api_grpc::proto::golem::worker::ChangeRetryPolicyParameters { - timestamp: Some(change_retry_policy.timestamp.into()), - retry_policy: Some(change_retry_policy.new_policy.into()), - }, - )), + oplog_entry::Entry::Exited(exited) => { + Ok(PublicOplogEntry::Exited(TimestampParameter { + timestamp: exited.timestamp.ok_or("Missing timestamp field")?.into(), + })) } - } - PublicOplogEntry::BeginAtomicRegion(begin_atomic_region) => { - golem_api_grpc::proto::golem::worker::OplogEntry { - entry: Some(oplog_entry::Entry::BeginAtomicRegion( - golem_api_grpc::proto::golem::worker::TimestampParameter { - timestamp: Some(begin_atomic_region.timestamp.into()), - }, - )), + oplog_entry::Entry::ChangeRetryPolicy(change_retry_policy) => Ok( + PublicOplogEntry::ChangeRetryPolicy(ChangeRetryPolicyParameters { + timestamp: change_retry_policy + .timestamp + .ok_or("Missing timestamp field")? + .into(), + new_policy: change_retry_policy + .retry_policy + .ok_or("Missing retry_policy field")? + .try_into()?, + }), + ), + oplog_entry::Entry::BeginAtomicRegion(begin_atomic_region) => { + Ok(PublicOplogEntry::BeginAtomicRegion(TimestampParameter { + timestamp: begin_atomic_region + .timestamp + .ok_or("Missing timestamp field")? + .into(), + })) } - } - PublicOplogEntry::EndAtomicRegion(end_atomic_region) => { - golem_api_grpc::proto::golem::worker::OplogEntry { - entry: Some(oplog_entry::Entry::EndAtomicRegion( - golem_api_grpc::proto::golem::worker::EndAtomicRegionParameters { - timestamp: Some(end_atomic_region.timestamp.into()), - begin_index: end_atomic_region.begin_index.into(), - }, - )), + oplog_entry::Entry::EndAtomicRegion(end_atomic_region) => { + Ok(PublicOplogEntry::EndAtomicRegion(EndRegionParameters { + timestamp: end_atomic_region + .timestamp + .ok_or("Missing timestamp field")? + .into(), + begin_index: OplogIndex::from_u64(end_atomic_region.begin_index), + })) } - } - PublicOplogEntry::BeginRemoteWrite(begin_remote_write) => { - golem_api_grpc::proto::golem::worker::OplogEntry { - entry: Some(oplog_entry::Entry::BeginRemoteWrite( - golem_api_grpc::proto::golem::worker::TimestampParameter { - timestamp: Some(begin_remote_write.timestamp.into()), - }, - )), + oplog_entry::Entry::BeginRemoteWrite(begin_remote_write) => { + Ok(PublicOplogEntry::BeginRemoteWrite(TimestampParameter { + timestamp: begin_remote_write + .timestamp + .ok_or("Missing timestamp field")? + .into(), + })) } - } - PublicOplogEntry::EndRemoteWrite(end_remote_write) => { - golem_api_grpc::proto::golem::worker::OplogEntry { - entry: Some(oplog_entry::Entry::EndRemoteWrite( - golem_api_grpc::proto::golem::worker::EndRemoteWriteParameters { - timestamp: Some(end_remote_write.timestamp.into()), - begin_index: end_remote_write.begin_index.into(), - }, - )), + oplog_entry::Entry::EndRemoteWrite(end_remote_write) => { + Ok(PublicOplogEntry::EndRemoteWrite(EndRegionParameters { + timestamp: end_remote_write + .timestamp + .ok_or("Missing timestamp field")? + .into(), + begin_index: OplogIndex::from_u64(end_remote_write.begin_index), + })) } - } - PublicOplogEntry::PendingWorkerInvocation(pending_worker_invocation) => { - golem_api_grpc::proto::golem::worker::OplogEntry { - entry: Some(oplog_entry::Entry::PendingWorkerInvocation( - golem_api_grpc::proto::golem::worker::PendingWorkerInvocationParameters { - timestamp: Some(pending_worker_invocation.timestamp.into()), - invocation: Some(pending_worker_invocation.invocation.try_into()?), - }, - )), + oplog_entry::Entry::PendingWorkerInvocation(pending_worker_invocation) => Ok( + PublicOplogEntry::PendingWorkerInvocation(PendingWorkerInvocationParameters { + timestamp: pending_worker_invocation + .timestamp + .ok_or("Missing timestamp field")? + .into(), + invocation: pending_worker_invocation + .invocation + .ok_or("Missing invocation field")? + .try_into()?, + }), + ), + oplog_entry::Entry::PendingUpdate(pending_update) => { + Ok(PublicOplogEntry::PendingUpdate(PendingUpdateParameters { + timestamp: pending_update + .timestamp + .ok_or("Missing timestamp field")? + .into(), + target_version: pending_update.target_version, + description: pending_update + .update_description + .ok_or("Missing update_description field")? + .try_into()?, + })) } - } - PublicOplogEntry::PendingUpdate(pending_update) => { - golem_api_grpc::proto::golem::worker::OplogEntry { - entry: Some(oplog_entry::Entry::PendingUpdate( - golem_api_grpc::proto::golem::worker::PendingUpdateParameters { - timestamp: Some(pending_update.timestamp.into()), - target_version: pending_update.target_version, - update_description: Some(pending_update.description.into()), - }, - )), + oplog_entry::Entry::SuccessfulUpdate(successful_update) => Ok( + PublicOplogEntry::SuccessfulUpdate(SuccessfulUpdateParameters { + timestamp: successful_update + .timestamp + .ok_or("Missing timestamp field")? + .into(), + target_version: successful_update.target_version, + new_component_size: successful_update.new_component_size, + new_active_plugins: BTreeSet::from_iter( + successful_update + .new_active_plugins + .into_iter() + .map(|pr| pr.try_into()) + .collect::, _>>()?, + ), + }), + ), + oplog_entry::Entry::FailedUpdate(failed_update) => { + Ok(PublicOplogEntry::FailedUpdate(FailedUpdateParameters { + timestamp: failed_update + .timestamp + .ok_or("Missing timestamp field")? + .into(), + target_version: failed_update.target_version, + details: failed_update.details, + })) + } + oplog_entry::Entry::GrowMemory(grow_memory) => { + Ok(PublicOplogEntry::GrowMemory(GrowMemoryParameters { + timestamp: grow_memory + .timestamp + .ok_or("Missing timestamp field")? + .into(), + delta: grow_memory.delta, + })) + } + oplog_entry::Entry::CreateResource(create_resource) => { + Ok(PublicOplogEntry::CreateResource(ResourceParameters { + timestamp: create_resource + .timestamp + .ok_or("Missing timestamp field")? + .into(), + id: WorkerResourceId(create_resource.resource_id), + })) + } + oplog_entry::Entry::DropResource(drop_resource) => { + Ok(PublicOplogEntry::DropResource(ResourceParameters { + timestamp: drop_resource + .timestamp + .ok_or("Missing timestamp field")? + .into(), + id: WorkerResourceId(drop_resource.resource_id), + })) } + oplog_entry::Entry::DescribeResource(describe_resource) => Ok( + PublicOplogEntry::DescribeResource(DescribeResourceParameters { + timestamp: describe_resource + .timestamp + .ok_or("Missing timestamp field")? + .into(), + id: WorkerResourceId(describe_resource.resource_id), + resource_name: describe_resource.resource_name, + resource_params: describe_resource + .resource_params + .into_iter() + .map(TryInto::try_into) + .collect::, String>>()?, + }), + ), + oplog_entry::Entry::Log(log) => Ok(PublicOplogEntry::Log(LogParameters { + level: log.level().into(), + timestamp: log.timestamp.ok_or("Missing timestamp field")?.into(), + context: log.context, + message: log.message, + })), + oplog_entry::Entry::Restart(restart) => { + Ok(PublicOplogEntry::Restart(TimestampParameter { + timestamp: restart.timestamp.ok_or("Missing timestamp field")?.into(), + })) + } + oplog_entry::Entry::ActivatePlugin(activate) => { + Ok(PublicOplogEntry::ActivatePlugin(ActivatePluginParameters { + timestamp: activate.timestamp.ok_or("Missing timestamp field")?.into(), + plugin: activate.plugin.ok_or("Missing plugin field")?.try_into()?, + })) + } + oplog_entry::Entry::DeactivatePlugin(deactivate) => Ok( + PublicOplogEntry::DeactivatePlugin(DeactivatePluginParameters { + timestamp: deactivate + .timestamp + .ok_or("Missing timestamp field")? + .into(), + plugin: deactivate + .plugin + .ok_or("Missing plugin field")? + .try_into()?, + }), + ), } - PublicOplogEntry::SuccessfulUpdate(successful_update) => { - golem_api_grpc::proto::golem::worker::OplogEntry { - entry: Some(oplog_entry::Entry::SuccessfulUpdate( - golem_api_grpc::proto::golem::worker::SuccessfulUpdateParameters { - timestamp: Some(successful_update.timestamp.into()), - target_version: successful_update.target_version, - new_component_size: successful_update.new_component_size, - new_active_plugins: successful_update - .new_active_plugins + } + } + + impl TryFrom for golem_api_grpc::proto::golem::worker::OplogEntry { + type Error = String; + + fn try_from(value: PublicOplogEntry) -> Result { + Ok(match value { + PublicOplogEntry::Create(create) => golem_api_grpc::proto::golem::worker::OplogEntry { + entry: Some(oplog_entry::Entry::Create( + golem_api_grpc::proto::golem::worker::CreateParameters { + timestamp: Some(create.timestamp.into()), + worker_id: Some(create.worker_id.into()), + component_version: create.component_version, + args: create.args, + env: create.env.into_iter().collect(), + account_id: Some(create.account_id.into()), + parent: create.parent.map(Into::into), + component_size: create.component_size, + initial_total_linear_memory_size: create.initial_total_linear_memory_size, + initial_active_plugins: create + .initial_active_plugins .into_iter() .map(Into::into) .collect(), }, )), + }, + PublicOplogEntry::ImportedFunctionInvoked(imported_function_invoked) => { + golem_api_grpc::proto::golem::worker::OplogEntry { + entry: Some(oplog_entry::Entry::ImportedFunctionInvoked( + golem_api_grpc::proto::golem::worker::ImportedFunctionInvokedParameters { + timestamp: Some(imported_function_invoked.timestamp.into()), + function_name: imported_function_invoked.function_name, + request: Some(imported_function_invoked.request.try_into().map_err( + |errors: Vec| { + format!("Failed to convert request: {}", errors.join(", ")) + }, + )?), + response: Some(imported_function_invoked.response.try_into().map_err( + |errors: Vec| { + format!("Failed to convert response: {}", errors.join(", ")) + }, + )?), + wrapped_function_type: Some( + imported_function_invoked.wrapped_function_type.into(), + ), + }, + )), + } } - } - PublicOplogEntry::FailedUpdate(failed_update) => { - golem_api_grpc::proto::golem::worker::OplogEntry { - entry: Some(oplog_entry::Entry::FailedUpdate( - golem_api_grpc::proto::golem::worker::FailedUpdateParameters { - timestamp: Some(failed_update.timestamp.into()), - target_version: failed_update.target_version, - details: failed_update.details, - }, - )), + PublicOplogEntry::ExportedFunctionInvoked(exported_function_invoked) => { + golem_api_grpc::proto::golem::worker::OplogEntry { + entry: Some(oplog_entry::Entry::ExportedFunctionInvoked( + golem_api_grpc::proto::golem::worker::ExportedFunctionInvokedParameters { + timestamp: Some(exported_function_invoked.timestamp.into()), + function_name: exported_function_invoked.function_name, + request: exported_function_invoked + .request + .into_iter() + .map(|value| { + value.try_into().map_err(|errors: Vec| { + format!("Failed to convert request: {}", errors.join(", ")) + }) + }) + .collect::, _>>()?, + idempotency_key: Some(exported_function_invoked.idempotency_key.into()), + }, + )), + } } - } - PublicOplogEntry::GrowMemory(grow_memory) => { - golem_api_grpc::proto::golem::worker::OplogEntry { - entry: Some(oplog_entry::Entry::GrowMemory( - golem_api_grpc::proto::golem::worker::GrowMemoryParameters { - timestamp: Some(grow_memory.timestamp.into()), - delta: grow_memory.delta, - }, - )), + PublicOplogEntry::ExportedFunctionCompleted(exported_function_completed) => { + golem_api_grpc::proto::golem::worker::OplogEntry { + entry: Some(oplog_entry::Entry::ExportedFunctionCompleted( + golem_api_grpc::proto::golem::worker::ExportedFunctionCompletedParameters { + timestamp: Some(exported_function_completed.timestamp.into()), + response: Some( + exported_function_completed.response.try_into().map_err( + |errors: Vec| { + format!("Failed to convert response: {}", errors.join(", ")) + }, + )?, + ), + consumed_fuel: exported_function_completed.consumed_fuel, + }, + )), + } } - } - PublicOplogEntry::CreateResource(create_resource) => { - golem_api_grpc::proto::golem::worker::OplogEntry { - entry: Some(oplog_entry::Entry::CreateResource( - golem_api_grpc::proto::golem::worker::CreateResourceParameters { - timestamp: Some(create_resource.timestamp.into()), - resource_id: create_resource.id.0, + PublicOplogEntry::Suspend(suspend) => { + golem_api_grpc::proto::golem::worker::OplogEntry { + entry: Some(oplog_entry::Entry::Suspend( + golem_api_grpc::proto::golem::worker::TimestampParameter { + timestamp: Some(suspend.timestamp.into()), + }, + )), + } + } + PublicOplogEntry::Error(error) => golem_api_grpc::proto::golem::worker::OplogEntry { + entry: Some(oplog_entry::Entry::Error( + golem_api_grpc::proto::golem::worker::ErrorParameters { + timestamp: Some(error.timestamp.into()), + error: error.error, }, )), - } - } - PublicOplogEntry::DropResource(drop_resource) => { - golem_api_grpc::proto::golem::worker::OplogEntry { - entry: Some(oplog_entry::Entry::DropResource( - golem_api_grpc::proto::golem::worker::DropResourceParameters { - timestamp: Some(drop_resource.timestamp.into()), - resource_id: drop_resource.id.0, + }, + PublicOplogEntry::NoOp(no_op) => golem_api_grpc::proto::golem::worker::OplogEntry { + entry: Some(oplog_entry::Entry::NoOp( + golem_api_grpc::proto::golem::worker::TimestampParameter { + timestamp: Some(no_op.timestamp.into()), }, )), - } - } - PublicOplogEntry::DescribeResource(describe_resource) => { - golem_api_grpc::proto::golem::worker::OplogEntry { - entry: Some(oplog_entry::Entry::DescribeResource( - golem_api_grpc::proto::golem::worker::DescribeResourceParameters { - timestamp: Some(describe_resource.timestamp.into()), - resource_id: describe_resource.id.0, - resource_name: describe_resource.resource_name, - resource_params: describe_resource - .resource_params - .into_iter() - .map(|value| { - value.try_into().map_err(|errors: Vec| { - format!("Failed to convert request: {}", errors.join(", ")) - }) - }) - .collect::, _>>()?, + }, + PublicOplogEntry::Jump(jump) => golem_api_grpc::proto::golem::worker::OplogEntry { + entry: Some(oplog_entry::Entry::Jump( + golem_api_grpc::proto::golem::worker::JumpParameters { + timestamp: Some(jump.timestamp.into()), + start: jump.jump.start.into(), + end: jump.jump.end.into(), }, )), + }, + PublicOplogEntry::Interrupted(interrupted) => { + golem_api_grpc::proto::golem::worker::OplogEntry { + entry: Some(oplog_entry::Entry::Interrupted( + golem_api_grpc::proto::golem::worker::TimestampParameter { + timestamp: Some(interrupted.timestamp.into()), + }, + )), + } } - } - PublicOplogEntry::Log(log) => golem_api_grpc::proto::golem::worker::OplogEntry { - entry: Some(oplog_entry::Entry::Log( - golem_api_grpc::proto::golem::worker::LogParameters { - timestamp: Some(log.timestamp.into()), - level: Into::::into( - log.level, - ) as i32, - context: log.context, - message: log.message, - }, - )), - }, - PublicOplogEntry::Restart(restart) => { - golem_api_grpc::proto::golem::worker::OplogEntry { - entry: Some(oplog_entry::Entry::Restart( + PublicOplogEntry::Exited(exited) => golem_api_grpc::proto::golem::worker::OplogEntry { + entry: Some(oplog_entry::Entry::Exited( golem_api_grpc::proto::golem::worker::TimestampParameter { - timestamp: Some(restart.timestamp.into()), + timestamp: Some(exited.timestamp.into()), }, )), + }, + PublicOplogEntry::ChangeRetryPolicy(change_retry_policy) => { + golem_api_grpc::proto::golem::worker::OplogEntry { + entry: Some(oplog_entry::Entry::ChangeRetryPolicy( + golem_api_grpc::proto::golem::worker::ChangeRetryPolicyParameters { + timestamp: Some(change_retry_policy.timestamp.into()), + retry_policy: Some(change_retry_policy.new_policy.into()), + }, + )), + } } - } - PublicOplogEntry::ActivatePlugin(activate) => { - golem_api_grpc::proto::golem::worker::OplogEntry { - entry: Some(oplog_entry::Entry::ActivatePlugin( - golem_api_grpc::proto::golem::worker::ActivatePluginParameters { - timestamp: Some(activate.timestamp.into()), - plugin: Some(activate.plugin.into()), - }, - )), + PublicOplogEntry::BeginAtomicRegion(begin_atomic_region) => { + golem_api_grpc::proto::golem::worker::OplogEntry { + entry: Some(oplog_entry::Entry::BeginAtomicRegion( + golem_api_grpc::proto::golem::worker::TimestampParameter { + timestamp: Some(begin_atomic_region.timestamp.into()), + }, + )), + } } - } - PublicOplogEntry::DeactivatePlugin(deactivate) => { - golem_api_grpc::proto::golem::worker::OplogEntry { - entry: Some(oplog_entry::Entry::DeactivatePlugin( - golem_api_grpc::proto::golem::worker::DeactivatePluginParameters { - timestamp: Some(deactivate.timestamp.into()), - plugin: Some(deactivate.plugin.into()), + PublicOplogEntry::EndAtomicRegion(end_atomic_region) => { + golem_api_grpc::proto::golem::worker::OplogEntry { + entry: Some(oplog_entry::Entry::EndAtomicRegion( + golem_api_grpc::proto::golem::worker::EndAtomicRegionParameters { + timestamp: Some(end_atomic_region.timestamp.into()), + begin_index: end_atomic_region.begin_index.into(), + }, + )), + } + } + PublicOplogEntry::BeginRemoteWrite(begin_remote_write) => { + golem_api_grpc::proto::golem::worker::OplogEntry { + entry: Some(oplog_entry::Entry::BeginRemoteWrite( + golem_api_grpc::proto::golem::worker::TimestampParameter { + timestamp: Some(begin_remote_write.timestamp.into()), + }, + )), + } + } + PublicOplogEntry::EndRemoteWrite(end_remote_write) => { + golem_api_grpc::proto::golem::worker::OplogEntry { + entry: Some(oplog_entry::Entry::EndRemoteWrite( + golem_api_grpc::proto::golem::worker::EndRemoteWriteParameters { + timestamp: Some(end_remote_write.timestamp.into()), + begin_index: end_remote_write.begin_index.into(), + }, + )), + } + } + PublicOplogEntry::PendingWorkerInvocation(pending_worker_invocation) => { + golem_api_grpc::proto::golem::worker::OplogEntry { + entry: Some(oplog_entry::Entry::PendingWorkerInvocation( + golem_api_grpc::proto::golem::worker::PendingWorkerInvocationParameters { + timestamp: Some(pending_worker_invocation.timestamp.into()), + invocation: Some(pending_worker_invocation.invocation.try_into()?), + }, + )), + } + } + PublicOplogEntry::PendingUpdate(pending_update) => { + golem_api_grpc::proto::golem::worker::OplogEntry { + entry: Some(oplog_entry::Entry::PendingUpdate( + golem_api_grpc::proto::golem::worker::PendingUpdateParameters { + timestamp: Some(pending_update.timestamp.into()), + target_version: pending_update.target_version, + update_description: Some(pending_update.description.into()), + }, + )), + } + } + PublicOplogEntry::SuccessfulUpdate(successful_update) => { + golem_api_grpc::proto::golem::worker::OplogEntry { + entry: Some(oplog_entry::Entry::SuccessfulUpdate( + golem_api_grpc::proto::golem::worker::SuccessfulUpdateParameters { + timestamp: Some(successful_update.timestamp.into()), + target_version: successful_update.target_version, + new_component_size: successful_update.new_component_size, + new_active_plugins: successful_update + .new_active_plugins + .into_iter() + .map(Into::into) + .collect(), + }, + )), + } + } + PublicOplogEntry::FailedUpdate(failed_update) => { + golem_api_grpc::proto::golem::worker::OplogEntry { + entry: Some(oplog_entry::Entry::FailedUpdate( + golem_api_grpc::proto::golem::worker::FailedUpdateParameters { + timestamp: Some(failed_update.timestamp.into()), + target_version: failed_update.target_version, + details: failed_update.details, + }, + )), + } + } + PublicOplogEntry::GrowMemory(grow_memory) => { + golem_api_grpc::proto::golem::worker::OplogEntry { + entry: Some(oplog_entry::Entry::GrowMemory( + golem_api_grpc::proto::golem::worker::GrowMemoryParameters { + timestamp: Some(grow_memory.timestamp.into()), + delta: grow_memory.delta, + }, + )), + } + } + PublicOplogEntry::CreateResource(create_resource) => { + golem_api_grpc::proto::golem::worker::OplogEntry { + entry: Some(oplog_entry::Entry::CreateResource( + golem_api_grpc::proto::golem::worker::CreateResourceParameters { + timestamp: Some(create_resource.timestamp.into()), + resource_id: create_resource.id.0, + }, + )), + } + } + PublicOplogEntry::DropResource(drop_resource) => { + golem_api_grpc::proto::golem::worker::OplogEntry { + entry: Some(oplog_entry::Entry::DropResource( + golem_api_grpc::proto::golem::worker::DropResourceParameters { + timestamp: Some(drop_resource.timestamp.into()), + resource_id: drop_resource.id.0, + }, + )), + } + } + PublicOplogEntry::DescribeResource(describe_resource) => { + golem_api_grpc::proto::golem::worker::OplogEntry { + entry: Some(oplog_entry::Entry::DescribeResource( + golem_api_grpc::proto::golem::worker::DescribeResourceParameters { + timestamp: Some(describe_resource.timestamp.into()), + resource_id: describe_resource.id.0, + resource_name: describe_resource.resource_name, + resource_params: describe_resource + .resource_params + .into_iter() + .map(|value| { + value.try_into().map_err(|errors: Vec| { + format!("Failed to convert request: {}", errors.join(", ")) + }) + }) + .collect::, _>>()?, + }, + )), + } + } + PublicOplogEntry::Log(log) => golem_api_grpc::proto::golem::worker::OplogEntry { + entry: Some(oplog_entry::Entry::Log( + golem_api_grpc::proto::golem::worker::LogParameters { + timestamp: Some(log.timestamp.into()), + level: Into::::into( + log.level, + ) as i32, + context: log.context, + message: log.message, }, )), + }, + PublicOplogEntry::Restart(restart) => { + golem_api_grpc::proto::golem::worker::OplogEntry { + entry: Some(oplog_entry::Entry::Restart( + golem_api_grpc::proto::golem::worker::TimestampParameter { + timestamp: Some(restart.timestamp.into()), + }, + )), + } } - } - }) + PublicOplogEntry::ActivatePlugin(activate) => { + golem_api_grpc::proto::golem::worker::OplogEntry { + entry: Some(oplog_entry::Entry::ActivatePlugin( + golem_api_grpc::proto::golem::worker::ActivatePluginParameters { + timestamp: Some(activate.timestamp.into()), + plugin: Some(activate.plugin.into()), + }, + )), + } + } + PublicOplogEntry::DeactivatePlugin(deactivate) => { + golem_api_grpc::proto::golem::worker::OplogEntry { + entry: Some(oplog_entry::Entry::DeactivatePlugin( + golem_api_grpc::proto::golem::worker::DeactivatePluginParameters { + timestamp: Some(deactivate.timestamp.into()), + plugin: Some(deactivate.plugin.into()), + }, + )), + } + } + }) + } } -} -impl TryFrom - for PublicWrappedFunctionType -{ - type Error = String; + impl TryFrom + for PublicWrappedFunctionType + { + type Error = String; - fn try_from( - value: golem_api_grpc::proto::golem::worker::WrappedFunctionType, - ) -> Result { - match value.r#type() { - wrapped_function_type::Type::ReadLocal => { - Ok(PublicWrappedFunctionType::ReadLocal(Empty {})) - } - wrapped_function_type::Type::WriteLocal => { - Ok(PublicWrappedFunctionType::WriteLocal(Empty {})) - } - wrapped_function_type::Type::ReadRemote => { - Ok(PublicWrappedFunctionType::ReadRemote(Empty {})) - } - wrapped_function_type::Type::WriteRemote => { - Ok(PublicWrappedFunctionType::WriteRemote(Empty {})) + fn try_from( + value: golem_api_grpc::proto::golem::worker::WrappedFunctionType, + ) -> Result { + match value.r#type() { + wrapped_function_type::Type::ReadLocal => { + Ok(PublicWrappedFunctionType::ReadLocal(Empty {})) + } + wrapped_function_type::Type::WriteLocal => { + Ok(PublicWrappedFunctionType::WriteLocal(Empty {})) + } + wrapped_function_type::Type::ReadRemote => { + Ok(PublicWrappedFunctionType::ReadRemote(Empty {})) + } + wrapped_function_type::Type::WriteRemote => { + Ok(PublicWrappedFunctionType::WriteRemote(Empty {})) + } + wrapped_function_type::Type::WriteRemoteBatched => Ok( + PublicWrappedFunctionType::WriteRemoteBatched(WriteRemoteBatchedParameters { + index: value.oplog_index.map(OplogIndex::from_u64), + }), + ), } - wrapped_function_type::Type::WriteRemoteBatched => Ok( - PublicWrappedFunctionType::WriteRemoteBatched(WriteRemoteBatchedParameters { - index: value.oplog_index.map(OplogIndex::from_u64), - }), - ), } } -} -impl From for golem_api_grpc::proto::golem::worker::WrappedFunctionType { - fn from(value: PublicWrappedFunctionType) -> Self { - match value { - PublicWrappedFunctionType::ReadLocal(_) => { - golem_api_grpc::proto::golem::worker::WrappedFunctionType { - r#type: wrapped_function_type::Type::ReadLocal as i32, - oplog_index: None, + impl From for golem_api_grpc::proto::golem::worker::WrappedFunctionType { + fn from(value: PublicWrappedFunctionType) -> Self { + match value { + PublicWrappedFunctionType::ReadLocal(_) => { + golem_api_grpc::proto::golem::worker::WrappedFunctionType { + r#type: wrapped_function_type::Type::ReadLocal as i32, + oplog_index: None, + } } - } - PublicWrappedFunctionType::WriteLocal(_) => { - golem_api_grpc::proto::golem::worker::WrappedFunctionType { - r#type: wrapped_function_type::Type::WriteLocal as i32, - oplog_index: None, + PublicWrappedFunctionType::WriteLocal(_) => { + golem_api_grpc::proto::golem::worker::WrappedFunctionType { + r#type: wrapped_function_type::Type::WriteLocal as i32, + oplog_index: None, + } } - } - PublicWrappedFunctionType::ReadRemote(_) => { - golem_api_grpc::proto::golem::worker::WrappedFunctionType { - r#type: wrapped_function_type::Type::ReadRemote as i32, - oplog_index: None, + PublicWrappedFunctionType::ReadRemote(_) => { + golem_api_grpc::proto::golem::worker::WrappedFunctionType { + r#type: wrapped_function_type::Type::ReadRemote as i32, + oplog_index: None, + } } - } - PublicWrappedFunctionType::WriteRemote(_) => { - golem_api_grpc::proto::golem::worker::WrappedFunctionType { - r#type: wrapped_function_type::Type::WriteRemote as i32, - oplog_index: None, + PublicWrappedFunctionType::WriteRemote(_) => { + golem_api_grpc::proto::golem::worker::WrappedFunctionType { + r#type: wrapped_function_type::Type::WriteRemote as i32, + oplog_index: None, + } } - } - PublicWrappedFunctionType::WriteRemoteBatched(parameters) => { - golem_api_grpc::proto::golem::worker::WrappedFunctionType { - r#type: wrapped_function_type::Type::WriteRemoteBatched as i32, - oplog_index: parameters.index.map(|index| index.into()), + PublicWrappedFunctionType::WriteRemoteBatched(parameters) => { + golem_api_grpc::proto::golem::worker::WrappedFunctionType { + r#type: wrapped_function_type::Type::WriteRemoteBatched as i32, + oplog_index: parameters.index.map(|index| index.into()), + } } } } } -} -impl TryFrom for PublicRetryConfig { - type Error = String; + impl TryFrom for PublicRetryConfig { + type Error = String; - fn try_from( - value: golem_api_grpc::proto::golem::worker::RetryPolicy, - ) -> Result { - Ok(PublicRetryConfig { - max_attempts: value.max_attempts, - min_delay: Duration::from_millis(value.min_delay), - max_delay: Duration::from_millis(value.max_delay), - multiplier: value.multiplier, - max_jitter_factor: value.max_jitter_factor, - }) + fn try_from( + value: golem_api_grpc::proto::golem::worker::RetryPolicy, + ) -> Result { + Ok(PublicRetryConfig { + max_attempts: value.max_attempts, + min_delay: Duration::from_millis(value.min_delay), + max_delay: Duration::from_millis(value.max_delay), + multiplier: value.multiplier, + max_jitter_factor: value.max_jitter_factor, + }) + } } -} -impl From for golem_api_grpc::proto::golem::worker::RetryPolicy { - fn from(value: PublicRetryConfig) -> Self { - golem_api_grpc::proto::golem::worker::RetryPolicy { - max_attempts: value.max_attempts, - min_delay: value.min_delay.as_millis() as u64, - max_delay: value.max_delay.as_millis() as u64, - multiplier: value.multiplier, - max_jitter_factor: value.max_jitter_factor, + impl From for golem_api_grpc::proto::golem::worker::RetryPolicy { + fn from(value: PublicRetryConfig) -> Self { + golem_api_grpc::proto::golem::worker::RetryPolicy { + max_attempts: value.max_attempts, + min_delay: value.min_delay.as_millis() as u64, + max_delay: value.max_delay.as_millis() as u64, + multiplier: value.multiplier, + max_jitter_factor: value.max_jitter_factor, + } } } -} -impl From for LogLevel { - fn from(value: golem_api_grpc::proto::golem::worker::OplogLogLevel) -> Self { - match value { - golem_api_grpc::proto::golem::worker::OplogLogLevel::OplogTrace => LogLevel::Trace, - golem_api_grpc::proto::golem::worker::OplogLogLevel::OplogDebug => LogLevel::Debug, - golem_api_grpc::proto::golem::worker::OplogLogLevel::OplogInfo => LogLevel::Info, - golem_api_grpc::proto::golem::worker::OplogLogLevel::OplogWarn => LogLevel::Warn, - golem_api_grpc::proto::golem::worker::OplogLogLevel::OplogError => LogLevel::Error, - golem_api_grpc::proto::golem::worker::OplogLogLevel::OplogCritical => { - LogLevel::Critical + impl From for LogLevel { + fn from(value: golem_api_grpc::proto::golem::worker::OplogLogLevel) -> Self { + match value { + golem_api_grpc::proto::golem::worker::OplogLogLevel::OplogTrace => LogLevel::Trace, + golem_api_grpc::proto::golem::worker::OplogLogLevel::OplogDebug => LogLevel::Debug, + golem_api_grpc::proto::golem::worker::OplogLogLevel::OplogInfo => LogLevel::Info, + golem_api_grpc::proto::golem::worker::OplogLogLevel::OplogWarn => LogLevel::Warn, + golem_api_grpc::proto::golem::worker::OplogLogLevel::OplogError => LogLevel::Error, + golem_api_grpc::proto::golem::worker::OplogLogLevel::OplogCritical => { + LogLevel::Critical + } + golem_api_grpc::proto::golem::worker::OplogLogLevel::OplogStderr => { + LogLevel::Stderr + } + golem_api_grpc::proto::golem::worker::OplogLogLevel::OplogStdout => { + LogLevel::Stdout + } } - golem_api_grpc::proto::golem::worker::OplogLogLevel::OplogStderr => LogLevel::Stderr, - golem_api_grpc::proto::golem::worker::OplogLogLevel::OplogStdout => LogLevel::Stdout, } } -} -impl From for golem_api_grpc::proto::golem::worker::OplogLogLevel { - fn from(value: LogLevel) -> Self { - match value { - LogLevel::Trace => golem_api_grpc::proto::golem::worker::OplogLogLevel::OplogTrace, - LogLevel::Debug => golem_api_grpc::proto::golem::worker::OplogLogLevel::OplogDebug, - LogLevel::Info => golem_api_grpc::proto::golem::worker::OplogLogLevel::OplogInfo, - LogLevel::Warn => golem_api_grpc::proto::golem::worker::OplogLogLevel::OplogWarn, - LogLevel::Error => golem_api_grpc::proto::golem::worker::OplogLogLevel::OplogError, - LogLevel::Critical => { - golem_api_grpc::proto::golem::worker::OplogLogLevel::OplogCritical + impl From for golem_api_grpc::proto::golem::worker::OplogLogLevel { + fn from(value: LogLevel) -> Self { + match value { + LogLevel::Trace => golem_api_grpc::proto::golem::worker::OplogLogLevel::OplogTrace, + LogLevel::Debug => golem_api_grpc::proto::golem::worker::OplogLogLevel::OplogDebug, + LogLevel::Info => golem_api_grpc::proto::golem::worker::OplogLogLevel::OplogInfo, + LogLevel::Warn => golem_api_grpc::proto::golem::worker::OplogLogLevel::OplogWarn, + LogLevel::Error => golem_api_grpc::proto::golem::worker::OplogLogLevel::OplogError, + LogLevel::Critical => { + golem_api_grpc::proto::golem::worker::OplogLogLevel::OplogCritical + } + LogLevel::Stderr => { + golem_api_grpc::proto::golem::worker::OplogLogLevel::OplogStderr + } + LogLevel::Stdout => { + golem_api_grpc::proto::golem::worker::OplogLogLevel::OplogStdout + } } - LogLevel::Stderr => golem_api_grpc::proto::golem::worker::OplogLogLevel::OplogStderr, - LogLevel::Stdout => golem_api_grpc::proto::golem::worker::OplogLogLevel::OplogStdout, } } -} -impl TryFrom for PublicWorkerInvocation { - type Error = String; - - fn try_from( - value: golem_api_grpc::proto::golem::worker::WorkerInvocation, - ) -> Result { - match value.invocation.ok_or("Missing invocation field")? { - worker_invocation::Invocation::ExportedFunction(exported_function) => Ok( - PublicWorkerInvocation::ExportedFunction(ExportedFunctionParameters { - idempotency_key: exported_function - .idempotency_key - .ok_or("Missing idempotency_key field")? - .into(), - full_function_name: exported_function.function_name, - function_input: if exported_function.valid_input { - Some( - exported_function - .input - .into_iter() - .map(TryInto::try_into) - .collect::, String>>()?, - ) - } else { - None - }, - }), - ), - worker_invocation::Invocation::ManualUpdate(manual_update) => Ok( - PublicWorkerInvocation::ManualUpdate(ManualUpdateParameters { - target_version: manual_update, - }), - ), + impl TryFrom for PublicWorkerInvocation { + type Error = String; + + fn try_from( + value: golem_api_grpc::proto::golem::worker::WorkerInvocation, + ) -> Result { + match value.invocation.ok_or("Missing invocation field")? { + worker_invocation::Invocation::ExportedFunction(exported_function) => Ok( + PublicWorkerInvocation::ExportedFunction(ExportedFunctionParameters { + idempotency_key: exported_function + .idempotency_key + .ok_or("Missing idempotency_key field")? + .into(), + full_function_name: exported_function.function_name, + function_input: if exported_function.valid_input { + Some( + exported_function + .input + .into_iter() + .map(TryInto::try_into) + .collect::, String>>()?, + ) + } else { + None + }, + }), + ), + worker_invocation::Invocation::ManualUpdate(manual_update) => Ok( + PublicWorkerInvocation::ManualUpdate(ManualUpdateParameters { + target_version: manual_update, + }), + ), + } } } -} -impl TryFrom for golem_api_grpc::proto::golem::worker::WorkerInvocation { - type Error = String; + impl TryFrom for golem_api_grpc::proto::golem::worker::WorkerInvocation { + type Error = String; - fn try_from(value: PublicWorkerInvocation) -> Result { - Ok(match value { - PublicWorkerInvocation::ExportedFunction(exported_function) => { - golem_api_grpc::proto::golem::worker::WorkerInvocation { - invocation: Some(worker_invocation::Invocation::ExportedFunction( - golem_api_grpc::proto::golem::worker::ExportedFunctionInvocationParameters { - idempotency_key: Some(exported_function.idempotency_key.into()), - function_name: exported_function.full_function_name, - valid_input: exported_function.function_input.is_some(), - input: exported_function - .function_input - .unwrap_or_default() - .into_iter() - .map(|input| input.try_into().map_err( - |errors: Vec| { - format!("Failed to convert request: {}", errors.join(", ")) - }, - )).collect::, _>>()?, - }, - )), + fn try_from(value: PublicWorkerInvocation) -> Result { + Ok(match value { + PublicWorkerInvocation::ExportedFunction(exported_function) => { + golem_api_grpc::proto::golem::worker::WorkerInvocation { + invocation: Some(worker_invocation::Invocation::ExportedFunction( + golem_api_grpc::proto::golem::worker::ExportedFunctionInvocationParameters { + idempotency_key: Some(exported_function.idempotency_key.into()), + function_name: exported_function.full_function_name, + valid_input: exported_function.function_input.is_some(), + input: exported_function + .function_input + .unwrap_or_default() + .into_iter() + .map(|input| input.try_into().map_err( + |errors: Vec| { + format!("Failed to convert request: {}", errors.join(", ")) + }, + )).collect::, _>>()?, + }, + )), + } } - } - PublicWorkerInvocation::ManualUpdate(manual_update) => { - golem_api_grpc::proto::golem::worker::WorkerInvocation { - invocation: Some(worker_invocation::Invocation::ManualUpdate( - manual_update.target_version, - )), + PublicWorkerInvocation::ManualUpdate(manual_update) => { + golem_api_grpc::proto::golem::worker::WorkerInvocation { + invocation: Some(worker_invocation::Invocation::ManualUpdate( + manual_update.target_version, + )), + } } - } - }) + }) + } } -} -impl TryFrom for PublicUpdateDescription { - type Error = String; + impl TryFrom for PublicUpdateDescription { + type Error = String; - fn try_from( - value: golem_api_grpc::proto::golem::worker::UpdateDescription, - ) -> Result { - match value.description.ok_or("Missing description field")? { - golem_api_grpc::proto::golem::worker::update_description::Description::AutoUpdate(_) => { - Ok(PublicUpdateDescription::Automatic(Empty {})) + fn try_from( + value: golem_api_grpc::proto::golem::worker::UpdateDescription, + ) -> Result { + match value.description.ok_or("Missing description field")? { + golem_api_grpc::proto::golem::worker::update_description::Description::AutoUpdate(_) => { + Ok(PublicUpdateDescription::Automatic(Empty {})) + } + golem_api_grpc::proto::golem::worker::update_description::Description::SnapshotBased( + snapshot_based, + ) => Ok(PublicUpdateDescription::SnapshotBased(SnapshotBasedUpdateParameters { + payload: snapshot_based.payload, + })), } - golem_api_grpc::proto::golem::worker::update_description::Description::SnapshotBased( - snapshot_based, - ) => Ok(PublicUpdateDescription::SnapshotBased(SnapshotBasedUpdateParameters { - payload: snapshot_based.payload, - })), } } -} -impl From for golem_api_grpc::proto::golem::worker::UpdateDescription { - fn from(value: PublicUpdateDescription) -> Self { - match value { - PublicUpdateDescription::Automatic(_) => golem_api_grpc::proto::golem::worker::UpdateDescription { - description: Some( - golem_api_grpc::proto::golem::worker::update_description::Description::AutoUpdate( - golem_api_grpc::proto::golem::common::Empty {}, - ), - ), - }, - PublicUpdateDescription::SnapshotBased(snapshot_based) => { - golem_api_grpc::proto::golem::worker::UpdateDescription { + impl From for golem_api_grpc::proto::golem::worker::UpdateDescription { + fn from(value: PublicUpdateDescription) -> Self { + match value { + PublicUpdateDescription::Automatic(_) => golem_api_grpc::proto::golem::worker::UpdateDescription { description: Some( - golem_api_grpc::proto::golem::worker::update_description::Description::SnapshotBased( - golem_api_grpc::proto::golem::worker::SnapshotBasedUpdateParameters { - payload: snapshot_based.payload - } + golem_api_grpc::proto::golem::worker::update_description::Description::AutoUpdate( + golem_api_grpc::proto::golem::common::Empty {}, ), ), + }, + PublicUpdateDescription::SnapshotBased(snapshot_based) => { + golem_api_grpc::proto::golem::worker::UpdateDescription { + description: Some( + golem_api_grpc::proto::golem::worker::update_description::Description::SnapshotBased( + golem_api_grpc::proto::golem::worker::SnapshotBasedUpdateParameters { + payload: snapshot_based.payload + } + ), + ), + } } } } } } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Object)] -pub struct OplogCursor { - pub next_oplog_index: u64, - pub current_component_version: u64, -} - -impl ParseFromParameter for OplogCursor { - fn parse_from_parameter(value: &str) -> ParseResult { - let parts: Vec<&str> = value.split('-').collect(); - if parts.len() != 2 { - return Err("Invalid oplog cursor".into()); - } - let next_oplog_index = parts[0] - .parse() - .map_err(|_| "Invalid index in the oplog cursor")?; - let current_component_version = parts[1] - .parse() - .map_err(|_| "Invalid component version in the oplog cursor")?; - Ok(OplogCursor { - next_oplog_index, - current_component_version, - }) - } -} - -impl Display for OplogCursor { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!( - f, - "{}-{}", - self.next_oplog_index, self.current_component_version - ) - } -} - -impl From for OplogCursor { - fn from(value: golem_api_grpc::proto::golem::worker::OplogCursor) -> Self { - Self { - next_oplog_index: value.next_oplog_index, - current_component_version: value.current_component_version, - } - } -} - -impl From for golem_api_grpc::proto::golem::worker::OplogCursor { - fn from(value: OplogCursor) -> Self { - Self { - next_oplog_index: value.next_oplog_index, - current_component_version: value.current_component_version, - } - } -} - #[cfg(test)] mod tests { - use super::{ + use test_r::test; + + use crate::model::public_oplog::{ ChangeRetryPolicyParameters, CreateParameters, DescribeResourceParameters, EndRegionParameters, ErrorParameters, ExportedFunctionCompletedParameters, ExportedFunctionInvokedParameters, ExportedFunctionParameters, FailedUpdateParameters, @@ -2382,23 +2453,25 @@ mod tests { PublicWrappedFunctionType, ResourceParameters, SnapshotBasedUpdateParameters, SuccessfulUpdateParameters, TimestampParameter, }; - use crate::model::oplog::{LogLevel, OplogIndex, WorkerResourceId}; - use crate::model::regions::OplogRegion; use crate::model::{ AccountId, ComponentId, Empty, IdempotencyKey, PluginInstallationId, Timestamp, WorkerId, }; + use std::collections::{BTreeMap, BTreeSet}; + use uuid::Uuid; + + use crate::model::oplog::{LogLevel, OplogIndex, WorkerResourceId}; + use crate::model::regions::OplogRegion; use golem_wasm_ast::analysis::analysed_type::{field, list, r#enum, record, s16, str, u64}; use golem_wasm_rpc::{Value, ValueAndType}; + #[cfg(feature = "poem")] use poem_openapi::types::ToJSON; - use std::collections::{BTreeMap, BTreeSet}; - use test_r::test; - use uuid::Uuid; fn rounded_ts(ts: Timestamp) -> Timestamp { Timestamp::from(ts.to_millis()) } #[test] + #[cfg(feature = "poem")] fn create_serialization_poem_serde_equivalence() { let entry = PublicOplogEntry::Create(CreateParameters { timestamp: rounded_ts(Timestamp::now_utc()), @@ -2439,6 +2512,7 @@ mod tests { } #[test] + #[cfg(feature = "poem")] fn imported_function_invoked_serialization_poem_serde_equivalence() { let entry = PublicOplogEntry::ImportedFunctionInvoked(ImportedFunctionInvokedParameters { timestamp: rounded_ts(Timestamp::now_utc()), @@ -2459,6 +2533,7 @@ mod tests { } #[test] + #[cfg(feature = "poem")] fn exported_function_invoked_serialization_poem_serde_equivalence() { let entry = PublicOplogEntry::ExportedFunctionInvoked(ExportedFunctionInvokedParameters { timestamp: rounded_ts(Timestamp::now_utc()), @@ -2481,6 +2556,7 @@ mod tests { } #[test] + #[cfg(feature = "poem")] fn exported_function_completed_serialization_poem_serde_equivalence() { let entry = PublicOplogEntry::ExportedFunctionCompleted(ExportedFunctionCompletedParameters { @@ -2497,6 +2573,7 @@ mod tests { } #[test] + #[cfg(feature = "poem")] fn suspend_serialization_poem_serde_equivalence() { let entry = PublicOplogEntry::Suspend(TimestampParameter { timestamp: rounded_ts(Timestamp::now_utc()), @@ -2507,6 +2584,7 @@ mod tests { } #[test] + #[cfg(feature = "poem")] fn error_serialization_poem_serde_equivalence() { let entry = PublicOplogEntry::Error(ErrorParameters { timestamp: rounded_ts(Timestamp::now_utc()), @@ -2518,6 +2596,7 @@ mod tests { } #[test] + #[cfg(feature = "poem")] fn no_op_serialization_poem_serde_equivalence() { let entry = PublicOplogEntry::NoOp(TimestampParameter { timestamp: rounded_ts(Timestamp::now_utc()), @@ -2528,6 +2607,7 @@ mod tests { } #[test] + #[cfg(feature = "poem")] fn jump_serialization_poem_serde_equivalence() { let entry = PublicOplogEntry::Jump(JumpParameters { timestamp: rounded_ts(Timestamp::now_utc()), @@ -2542,6 +2622,7 @@ mod tests { } #[test] + #[cfg(feature = "poem")] fn interrupted_serialization_poem_serde_equivalence() { let entry = PublicOplogEntry::Interrupted(TimestampParameter { timestamp: rounded_ts(Timestamp::now_utc()), @@ -2552,6 +2633,7 @@ mod tests { } #[test] + #[cfg(feature = "poem")] fn exited_serialization_poem_serde_equivalence() { let entry = PublicOplogEntry::Exited(TimestampParameter { timestamp: rounded_ts(Timestamp::now_utc()), @@ -2562,6 +2644,7 @@ mod tests { } #[test] + #[cfg(feature = "poem")] fn change_retry_policy_serialization_poem_serde_equivalence() { let entry = PublicOplogEntry::ChangeRetryPolicy(ChangeRetryPolicyParameters { timestamp: rounded_ts(Timestamp::now_utc()), @@ -2579,6 +2662,7 @@ mod tests { } #[test] + #[cfg(feature = "poem")] fn begin_atomic_region_serialization_poem_serde_equivalence() { let entry = PublicOplogEntry::BeginAtomicRegion(TimestampParameter { timestamp: rounded_ts(Timestamp::now_utc()), @@ -2589,6 +2673,7 @@ mod tests { } #[test] + #[cfg(feature = "poem")] fn end_atomic_region_serialization_poem_serde_equivalence() { let entry = PublicOplogEntry::EndAtomicRegion(EndRegionParameters { timestamp: rounded_ts(Timestamp::now_utc()), @@ -2600,6 +2685,7 @@ mod tests { } #[test] + #[cfg(feature = "poem")] fn begin_remote_write_serialization_poem_serde_equivalence() { let entry = PublicOplogEntry::BeginRemoteWrite(TimestampParameter { timestamp: rounded_ts(Timestamp::now_utc()), @@ -2610,6 +2696,7 @@ mod tests { } #[test] + #[cfg(feature = "poem")] fn end_remote_write_serialization_poem_serde_equivalence() { let entry = PublicOplogEntry::EndRemoteWrite(EndRegionParameters { timestamp: rounded_ts(Timestamp::now_utc()), @@ -2621,6 +2708,7 @@ mod tests { } #[test] + #[cfg(feature = "poem")] fn pending_worker_invocation_serialization_poem_serde_equivalence() { let entry = PublicOplogEntry::PendingWorkerInvocation(PendingWorkerInvocationParameters { timestamp: rounded_ts(Timestamp::now_utc()), @@ -2645,6 +2733,7 @@ mod tests { } #[test] + #[cfg(feature = "poem")] fn pending_update_serialization_poem_serde_equivalence_1() { let entry = PublicOplogEntry::PendingUpdate(PendingUpdateParameters { timestamp: rounded_ts(Timestamp::now_utc()), @@ -2659,6 +2748,7 @@ mod tests { } #[test] + #[cfg(feature = "poem")] fn pending_update_serialization_poem_serde_equivalence_2() { let entry = PublicOplogEntry::PendingUpdate(PendingUpdateParameters { timestamp: rounded_ts(Timestamp::now_utc()), @@ -2671,6 +2761,7 @@ mod tests { } #[test] + #[cfg(feature = "poem")] fn successful_update_serialization_poem_serde_equivalence() { let entry = PublicOplogEntry::SuccessfulUpdate(SuccessfulUpdateParameters { timestamp: rounded_ts(Timestamp::now_utc()), @@ -2691,6 +2782,7 @@ mod tests { } #[test] + #[cfg(feature = "poem")] fn failed_update_serialization_poem_serde_equivalence_1() { let entry = PublicOplogEntry::FailedUpdate(FailedUpdateParameters { timestamp: rounded_ts(Timestamp::now_utc()), @@ -2703,6 +2795,7 @@ mod tests { } #[test] + #[cfg(feature = "poem")] fn failed_update_serialization_poem_serde_equivalence_2() { let entry = PublicOplogEntry::FailedUpdate(FailedUpdateParameters { timestamp: rounded_ts(Timestamp::now_utc()), @@ -2715,6 +2808,7 @@ mod tests { } #[test] + #[cfg(feature = "poem")] fn grow_memory_serialization_poem_serde_equivalence() { let entry = PublicOplogEntry::GrowMemory(GrowMemoryParameters { timestamp: rounded_ts(Timestamp::now_utc()), @@ -2726,6 +2820,7 @@ mod tests { } #[test] + #[cfg(feature = "poem")] fn create_resource_serialization_poem_serde_equivalence() { let entry = PublicOplogEntry::CreateResource(ResourceParameters { timestamp: rounded_ts(Timestamp::now_utc()), @@ -2738,6 +2833,7 @@ mod tests { } #[test] + #[cfg(feature = "poem")] fn drop_resource_serialization_poem_serde_equivalence() { let entry = PublicOplogEntry::DropResource(ResourceParameters { timestamp: rounded_ts(Timestamp::now_utc()), @@ -2750,6 +2846,7 @@ mod tests { } #[test] + #[cfg(feature = "poem")] fn describe_resource_serialization_poem_serde_equivalence() { let entry = PublicOplogEntry::DescribeResource(DescribeResourceParameters { timestamp: rounded_ts(Timestamp::now_utc()), @@ -2773,6 +2870,7 @@ mod tests { } #[test] + #[cfg(feature = "poem")] fn log_serialization_poem_serde_equivalence() { let entry = PublicOplogEntry::Log(LogParameters { timestamp: rounded_ts(Timestamp::now_utc()), @@ -2786,6 +2884,7 @@ mod tests { } #[test] + #[cfg(feature = "poem")] fn restart_serialization_poem_serde_equivalence() { let entry = PublicOplogEntry::Restart(TimestampParameter { timestamp: rounded_ts(Timestamp::now_utc()), diff --git a/golem-common/src/model/regions.rs b/golem-common/src/model/regions.rs index 9a6c979a7..992cbc550 100644 --- a/golem-common/src/model/regions.rs +++ b/golem-common/src/model/regions.rs @@ -20,11 +20,11 @@ use std::ops::RangeInclusive; use crate::model::oplog::OplogIndex; use bincode::{Decode, Encode}; -use poem_openapi::Object; use range_set_blaze::RangeSetBlaze; use serde::{Deserialize, Serialize}; -#[derive(Clone, Debug, Eq, PartialEq, Encode, Decode, Serialize, Deserialize, Object)] +#[derive(Clone, Debug, Eq, PartialEq, Encode, Decode, Serialize, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] pub struct OplogRegion { pub start: OplogIndex, pub end: OplogIndex, diff --git a/golem-common/src/newtype.rs b/golem-common/src/newtype.rs index 6a9332e3d..7962a0937 100644 --- a/golem-common/src/newtype.rs +++ b/golem-common/src/newtype.rs @@ -68,6 +68,7 @@ macro_rules! newtype_uuid { } } + #[cfg(feature = "protobuf")] impl TryFrom<$proto_type> for $name { type Error = String; @@ -81,6 +82,7 @@ macro_rules! newtype_uuid { } } + #[cfg(feature = "protobuf")] impl From<$name> for $proto_type { fn from(value: $name) -> Self { $proto_type { @@ -89,17 +91,20 @@ macro_rules! newtype_uuid { } } + #[cfg(feature = "poem")] impl poem_openapi::types::Type for $name { const IS_REQUIRED: bool = true; type RawValueType = Self; type RawElementValueType = Self; - fn name() -> Cow<'static, str> { - Cow::from(format!("string({})", stringify!($name))) + fn name() -> std::borrow::Cow<'static, str> { + std::borrow::Cow::from(format!("string({})", stringify!($name))) } - fn schema_ref() -> MetaSchemaRef { - MetaSchemaRef::Inline(Box::new(MetaSchema::new_with_format("string", "uuid"))) + fn schema_ref() -> poem_openapi::registry::MetaSchemaRef { + poem_openapi::registry::MetaSchemaRef::Inline(Box::new( + poem_openapi::registry::MetaSchema::new_with_format("string", "uuid"), + )) } fn as_raw_value(&self) -> Option<&Self::RawValueType> { @@ -113,16 +118,20 @@ macro_rules! newtype_uuid { } } - impl ParseFromParameter for $name { - fn parse_from_parameter(value: &str) -> ParseResult { + #[cfg(feature = "poem")] + impl poem_openapi::types::ParseFromParameter for $name { + fn parse_from_parameter(value: &str) -> poem_openapi::types::ParseResult { Ok(Self(value.try_into()?)) } } - impl ParseFromJSON for $name { - fn parse_from_json(value: Option) -> ParseResult { + #[cfg(feature = "poem")] + impl poem_openapi::types::ParseFromJSON for $name { + fn parse_from_json( + value: Option, + ) -> poem_openapi::types::ParseResult { match value { - Some(Value::String(s)) => Ok(Self(Uuid::from_str(&s)?)), + Some(serde_json::Value::String(s)) => Ok(Self(Uuid::from_str(&s)?)), _ => Err(poem_openapi::types::ParseError::<$name>::custom(format!( "Unexpected representation of {}", stringify!($name) @@ -131,9 +140,10 @@ macro_rules! newtype_uuid { } } - impl ToJSON for $name { - fn to_json(&self) -> Option { - Some(Value::String(self.0.to_string())) + #[cfg(feature = "poem")] + impl poem_openapi::types::ToJSON for $name { + fn to_json(&self) -> Option { + Some(serde_json::Value::String(self.0.to_string())) } } diff --git a/golem-common/src/retriable_error.rs b/golem-common/src/retriable_error.rs index 82375b5e9..008e24091 100644 --- a/golem-common/src/retriable_error.rs +++ b/golem-common/src/retriable_error.rs @@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -use tonic::{Code, Status}; - pub trait IsRetriableError { /// Returns true if the error is retriable. fn is_retriable(&self) -> bool; @@ -26,8 +24,11 @@ pub trait IsRetriableError { fn as_loggable(&self) -> Option; } -impl IsRetriableError for Status { +#[cfg(feature = "protobuf")] +impl IsRetriableError for tonic::Status { fn is_retriable(&self) -> bool { + use tonic::Code; + match self.code() { Code::Ok | Code::Cancelled diff --git a/golem-common/src/retries.rs b/golem-common/src/retries.rs index dba0093a7..fc610af2f 100644 --- a/golem-common/src/retries.rs +++ b/golem-common/src/retries.rs @@ -18,10 +18,10 @@ use std::pin::Pin; use std::time::{Duration, Instant}; use tracing::{error, info, warn, Level}; -use crate::config::RetryConfig; use crate::metrics::external_calls::{ record_external_call_failure, record_external_call_retry, record_external_call_success, }; +use crate::model::RetryConfig; use crate::retriable_error::IsRetriableError; /// Returns the delay to be waited before the next retry attempt. @@ -221,7 +221,7 @@ where mod tests { use test_r::test; - use crate::config::RetryConfig; + use crate::model::RetryConfig; use std::time::Duration; #[test] diff --git a/golem-common/src/serialization.rs b/golem-common/src/serialization.rs index bc861a841..24b9f39ba 100644 --- a/golem-common/src/serialization.rs +++ b/golem-common/src/serialization.rs @@ -14,7 +14,6 @@ use bincode::{Decode, Encode}; use bytes::{BufMut, Bytes, BytesMut}; -use tracing::error; /// serde_json - no longer supported pub const SERIALIZATION_VERSION_V1: u8 = 1u8; @@ -53,7 +52,8 @@ pub fn deserialize_with_version(data: &[u8], version: u8) -> Result Ok(value), None => { - error!( + #[cfg(feature = "observability")] + tracing::error!( version, data = format!("{:?}", data), "invalid serialization version" diff --git a/golem-component-compilation-service/src/config.rs b/golem-component-compilation-service/src/config.rs index e90a22813..202ed5b92 100644 --- a/golem-component-compilation-service/src/config.rs +++ b/golem-component-compilation-service/src/config.rs @@ -19,7 +19,8 @@ use std::net::{Ipv4Addr, SocketAddrV4}; use std::path::Path; use uuid::Uuid; -use golem_common::config::{ConfigExample, ConfigLoader, HasConfigExamples, RetryConfig}; +use golem_common::config::{ConfigExample, ConfigLoader, HasConfigExamples}; +use golem_common::model::RetryConfig; use golem_common::tracing::TracingConfig; use golem_service_base::config::BlobStorageConfig; use golem_worker_executor_base::services::golem_config::CompiledComponentServiceConfig; diff --git a/golem-component-compilation-service/src/service/compile_worker.rs b/golem-component-compilation-service/src/service/compile_worker.rs index 2a08d6754..2cc7c6b6b 100644 --- a/golem-component-compilation-service/src/service/compile_worker.rs +++ b/golem-component-compilation-service/src/service/compile_worker.rs @@ -20,9 +20,9 @@ use golem_api_grpc::proto::golem::component::v1::download_component_response; use golem_api_grpc::proto::golem::component::v1::ComponentError; use golem_api_grpc::proto::golem::component::v1::DownloadComponentRequest; use golem_common::client::{GrpcClient, GrpcClientConfig}; -use golem_common::config::RetryConfig; use golem_common::metrics::external_calls::record_external_call_response_size_bytes; use golem_common::model::ComponentId; +use golem_common::model::RetryConfig; use golem_common::retries::with_retries; use golem_worker_executor_base::grpc::authorised_grpc_request; use golem_worker_executor_base::grpc::is_grpc_retriable; diff --git a/golem-component-service-base/src/service/component.rs b/golem-component-service-base/src/service/component.rs index 2fbea25ee..ac324e06d 100644 --- a/golem-component-service-base/src/service/component.rs +++ b/golem-component-service-base/src/service/component.rs @@ -26,7 +26,6 @@ use bytes::Bytes; use futures::TryStreamExt; use golem_api_grpc::proto::golem::common::{ErrorBody, ErrorsBody}; use golem_api_grpc::proto::golem::component::v1::component_error; -use golem_common::config::RetryConfig; use golem_common::model::component::ComponentOwner; use golem_common::model::component_constraint::FunctionConstraintCollection; use golem_common::model::component_metadata::{ComponentMetadata, ComponentProcessingError}; @@ -35,6 +34,7 @@ use golem_common::model::plugin::{ PluginInstallationUpdate, PluginScope, PluginTypeSpecificDefinition, }; use golem_common::model::ComponentVersion; +use golem_common::model::RetryConfig; use golem_common::model::{AccountId, PluginInstallationId}; use golem_common::model::{ ComponentFilePath, ComponentFilePermissions, ComponentId, ComponentType, InitialComponentFile, diff --git a/golem-rib/Cargo.toml b/golem-rib/Cargo.toml index e3be2edda..454bfda74 100644 --- a/golem-rib/Cargo.toml +++ b/golem-rib/Cargo.toml @@ -7,21 +7,24 @@ homepage = "https://golem.cloud" repository = "https://github.com/golemcloud/golem" description = "Parser for Golem's Rib language" +[features] +default = ["json_in_errors", "protobuf", "poem"] +json_in_errors = ["protobuf", "golem-wasm-rpc/json"] +protobuf = ["dep:golem-api-grpc", "golem-wasm-ast/protobuf", "golem-wasm-rpc/protobuf"] +poem = ["dep:poem-openapi", "golem-wasm-ast/poem_openapi", "golem-wasm-ast/poem_openapi"] + [dependencies] -golem-api-grpc = { path = "../golem-api-grpc", version = "0.0.0" } -golem-wasm-ast = { path = "../wasm-ast", version = "0.0.0" } -golem-wasm-rpc = { path = "../wasm-rpc", version = "0.0.0", default-features = false, features = ["host"] } +golem-api-grpc = { path = "../golem-api-grpc", version = "0.0.0", optional = true } # TODO: remove this dependency +golem-wasm-ast = { path = "../wasm-ast", version = "0.0.0", default-features = false, features = ["analysis", "bincode"] } +golem-wasm-rpc = { path = "../wasm-rpc", version = "0.0.0", default-features = false, features = ["bincode", "typeinfo", "text"] } -async-trait = { workspace = true } -bigdecimal = {workspace = true } +bigdecimal = { workspace = true } bincode = { workspace = true } combine = { workspace = true } -poem-openapi = { workspace = true } +poem-openapi = { workspace = true, optional = true } semver = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } -tokio = {workspace = true} -wasm-wave = { workspace = true } [dev-dependencies] test-r = { workspace = true } diff --git a/golem-rib/src/call_type.rs b/golem-rib/src/call_type.rs index a162decd0..4bace2f6b 100644 --- a/golem-rib/src/call_type.rs +++ b/golem-rib/src/call_type.rs @@ -12,8 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::{DynamicParsedFunctionName, ParsedFunctionName}; -use std::convert::TryFrom; +use crate::DynamicParsedFunctionName; use std::fmt::Display; #[derive(Debug, PartialEq, Eq, Clone)] @@ -46,67 +45,77 @@ impl Display for CallType { } } -impl TryFrom for CallType { - type Error = String; - fn try_from(value: golem_api_grpc::proto::golem::rib::CallType) -> Result { - let invocation = value.name.ok_or("Missing name of invocation")?; - match invocation { - golem_api_grpc::proto::golem::rib::call_type::Name::Parsed(name) => Ok( - CallType::Function(DynamicParsedFunctionName::try_from(name)?), - ), - golem_api_grpc::proto::golem::rib::call_type::Name::VariantConstructor(name) => { - Ok(CallType::VariantConstructor(name)) - } - golem_api_grpc::proto::golem::rib::call_type::Name::EnumConstructor(name) => { - Ok(CallType::EnumConstructor(name)) +#[cfg(feature = "protobuf")] +mod protobuf { + use crate::call_type::CallType; + use crate::{DynamicParsedFunctionName, ParsedFunctionName}; + + impl TryFrom for CallType { + type Error = String; + fn try_from( + value: golem_api_grpc::proto::golem::rib::CallType, + ) -> Result { + let invocation = value.name.ok_or("Missing name of invocation")?; + match invocation { + golem_api_grpc::proto::golem::rib::call_type::Name::Parsed(name) => Ok( + CallType::Function(DynamicParsedFunctionName::try_from(name)?), + ), + golem_api_grpc::proto::golem::rib::call_type::Name::VariantConstructor(name) => { + Ok(CallType::VariantConstructor(name)) + } + golem_api_grpc::proto::golem::rib::call_type::Name::EnumConstructor(name) => { + Ok(CallType::EnumConstructor(name)) + } } } } -} -impl From for golem_api_grpc::proto::golem::rib::CallType { - fn from(value: CallType) -> Self { - match value { - CallType::Function(parsed_name) => golem_api_grpc::proto::golem::rib::CallType { - name: Some(golem_api_grpc::proto::golem::rib::call_type::Name::Parsed( - parsed_name.into(), - )), - }, - CallType::VariantConstructor(name) => golem_api_grpc::proto::golem::rib::CallType { - name: Some( - golem_api_grpc::proto::golem::rib::call_type::Name::VariantConstructor(name), - ), - }, - CallType::EnumConstructor(name) => golem_api_grpc::proto::golem::rib::CallType { - name: Some( - golem_api_grpc::proto::golem::rib::call_type::Name::EnumConstructor(name), - ), - }, + impl From for golem_api_grpc::proto::golem::rib::CallType { + fn from(value: CallType) -> Self { + match value { + CallType::Function(parsed_name) => golem_api_grpc::proto::golem::rib::CallType { + name: Some(golem_api_grpc::proto::golem::rib::call_type::Name::Parsed( + parsed_name.into(), + )), + }, + CallType::VariantConstructor(name) => golem_api_grpc::proto::golem::rib::CallType { + name: Some( + golem_api_grpc::proto::golem::rib::call_type::Name::VariantConstructor( + name, + ), + ), + }, + CallType::EnumConstructor(name) => golem_api_grpc::proto::golem::rib::CallType { + name: Some( + golem_api_grpc::proto::golem::rib::call_type::Name::EnumConstructor(name), + ), + }, + } } } -} -// InvocationName is a legacy structure to keep the backward compatibility. -// InvocationName is corresponding to the new CallType and the difference here is, -// InvocationName::Function will always hold a static function name and not a dynamic one -// with Expr representing resource construction parameters -impl TryFrom for CallType { - type Error = String; - fn try_from( - value: golem_api_grpc::proto::golem::rib::InvocationName, - ) -> Result { - let invocation = value.name.ok_or("Missing name of invocation")?; - match invocation { - golem_api_grpc::proto::golem::rib::invocation_name::Name::Parsed(name) => { - Ok(CallType::Function(DynamicParsedFunctionName::parse( - ParsedFunctionName::try_from(name)?.to_string(), - )?)) - } - golem_api_grpc::proto::golem::rib::invocation_name::Name::VariantConstructor(name) => { - Ok(CallType::VariantConstructor(name)) - } - golem_api_grpc::proto::golem::rib::invocation_name::Name::EnumConstructor(name) => { - Ok(CallType::EnumConstructor(name)) + // InvocationName is a legacy structure to keep the backward compatibility. + // InvocationName is corresponding to the new CallType and the difference here is, + // InvocationName::Function will always hold a static function name and not a dynamic one + // with Expr representing resource construction parameters + impl TryFrom for CallType { + type Error = String; + fn try_from( + value: golem_api_grpc::proto::golem::rib::InvocationName, + ) -> Result { + let invocation = value.name.ok_or("Missing name of invocation")?; + match invocation { + golem_api_grpc::proto::golem::rib::invocation_name::Name::Parsed(name) => { + Ok(CallType::Function(DynamicParsedFunctionName::parse( + ParsedFunctionName::try_from(name)?.to_string(), + )?)) + } + golem_api_grpc::proto::golem::rib::invocation_name::Name::VariantConstructor( + name, + ) => Ok(CallType::VariantConstructor(name)), + golem_api_grpc::proto::golem::rib::invocation_name::Name::EnumConstructor(name) => { + Ok(CallType::EnumConstructor(name)) + } } } } diff --git a/golem-rib/src/compiler/byte_code.rs b/golem-rib/src/compiler/byte_code.rs index 578797849..8ba3f5d71 100644 --- a/golem-rib/src/compiler/byte_code.rs +++ b/golem-rib/src/compiler/byte_code.rs @@ -16,7 +16,6 @@ use crate::compiler::byte_code::internal::ExprState; use crate::compiler::ir::RibIR; use crate::{Expr, InferredExpr, InstructionId}; use bincode::{Decode, Encode}; -use golem_api_grpc::proto::golem::rib::RibByteCode as ProtoRibByteCode; #[derive(Debug, Clone, PartialEq, Encode, Decode)] pub struct RibByteCode { @@ -56,29 +55,37 @@ impl RibByteCode { } } -impl TryFrom for RibByteCode { - type Error = String; +#[cfg(feature = "protobuf")] +mod protobuf { + use crate::RibByteCode; + use golem_api_grpc::proto::golem::rib::RibByteCode as ProtoRibByteCode; - fn try_from(value: ProtoRibByteCode) -> Result { - let proto_instructions = value.instructions; - let mut instructions = Vec::new(); + impl TryFrom for RibByteCode { + type Error = String; - for proto_instruction in proto_instructions { - instructions.push(proto_instruction.try_into()?); - } + fn try_from(value: ProtoRibByteCode) -> Result { + let proto_instructions = value.instructions; + let mut instructions = Vec::new(); - Ok(RibByteCode { instructions }) - } -} + for proto_instruction in proto_instructions { + instructions.push(proto_instruction.try_into()?); + } -impl From for ProtoRibByteCode { - fn from(value: RibByteCode) -> Self { - let mut instructions = Vec::new(); - for instruction in value.instructions { - instructions.push(instruction.into()); + Ok(RibByteCode { instructions }) } + } - ProtoRibByteCode { instructions } + impl TryFrom for ProtoRibByteCode { + type Error = String; + + fn try_from(value: RibByteCode) -> Result { + let mut instructions = Vec::new(); + for instruction in value.instructions { + instructions.push(instruction.try_into()?); + } + + Ok(ProtoRibByteCode { instructions }) + } } } @@ -88,11 +95,11 @@ mod internal { AnalysedTypeWithUnit, DynamicParsedFunctionReference, Expr, FunctionReferenceType, InferredType, InstructionId, RibIR, VariableId, }; - use golem_wasm_ast::analysis::AnalysedType; - use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; + use golem_wasm_ast::analysis::{AnalysedType, TypeFlags}; + use std::collections::HashSet; use crate::call_type::CallType; - use golem_wasm_rpc::protobuf::TypedFlags; + use golem_wasm_rpc::{IntoValueAndType, Value, ValueAndType}; use std::ops::Deref; pub(crate) fn process_expr( @@ -113,7 +120,7 @@ mod internal { instructions.push(RibIR::LoadVar(variable_id.clone())); } Expr::Literal(str, _) => { - let type_annotated_value = TypeAnnotatedValue::Str(str.clone()); + let type_annotated_value = str.clone().into_value_and_type(); instructions.push(RibIR::PushLit(type_annotated_value)); } Expr::Number(num, _, inferred_type) => { @@ -449,10 +456,17 @@ mod internal { Expr::Flags(flag_values, inferred_type) => match inferred_type { InferredType::Flags(all_flags) => { - instructions.push(RibIR::PushFlag(TypeAnnotatedValue::Flags(TypedFlags { - typ: all_flags.clone(), - values: flag_values.clone(), - }))); + let mut bitmap = Vec::new(); + let flag_values_set: HashSet<&String> = HashSet::from_iter(flag_values.iter()); + for flag in all_flags.iter() { + bitmap.push(flag_values_set.contains(flag)); + } + instructions.push(RibIR::PushFlag(ValueAndType { + value: Value::Flags(bitmap), + typ: AnalysedType::Flags(TypeFlags { + names: all_flags.iter().map(|n| n.to_string()).collect(), + }), + })); } inferred_type => { return Err(format!( @@ -462,7 +476,7 @@ mod internal { } }, Expr::Boolean(bool, _) => { - instructions.push(RibIR::PushLit(TypeAnnotatedValue::Bool(*bool))); + instructions.push(RibIR::PushLit(bool.into_value_and_type())); } Expr::GetTag(expr, _) => { stack.push(ExprState::from_expr(expr.deref())); @@ -686,7 +700,7 @@ mod compiler_tests { use crate::{ArmPattern, FunctionTypeRegistry, InferredType, MatchArm, Number, VariableId}; use golem_wasm_ast::analysis::analysed_type::{list, str}; use golem_wasm_ast::analysis::{AnalysedType, NameTypePair, TypeRecord, TypeStr}; - use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; + use golem_wasm_rpc::IntoValueAndType; #[test] fn test_instructions_for_literal() { @@ -696,7 +710,7 @@ mod compiler_tests { let instructions = RibByteCode::from_expr(&inferred_expr).unwrap(); - let instruction_set = vec![RibIR::PushLit(TypeAnnotatedValue::Str("hello".to_string()))]; + let instruction_set = vec![RibIR::PushLit("hello".into_value_and_type())]; let expected_instructions = RibByteCode { instructions: instruction_set, @@ -743,7 +757,7 @@ mod compiler_tests { let instructions = RibByteCode::from_expr(&inferred_expr).unwrap(); let instruction_set = vec![ - RibIR::PushLit(TypeAnnotatedValue::Str("hello".to_string())), + RibIR::PushLit("hello".into_value_and_type()), RibIR::AssignVar(variable_id), ]; @@ -777,8 +791,8 @@ mod compiler_tests { let instructions = RibByteCode::from_expr(&inferred_expr).unwrap(); - let type_annotated_value1 = TypeAnnotatedValue::F32(1.0); - let type_annotated_value2 = TypeAnnotatedValue::U32(1); + let type_annotated_value1 = 1.0f32.into_value_and_type(); + let type_annotated_value2 = 1u32.into_value_and_type(); let instruction_set = vec![ RibIR::PushLit(type_annotated_value2), @@ -816,8 +830,8 @@ mod compiler_tests { let instructions = RibByteCode::from_expr(&inferred_expr).unwrap(); - let type_annotated_value1 = TypeAnnotatedValue::F32(1.0); - let type_annotated_value2 = TypeAnnotatedValue::U32(2); + let type_annotated_value1 = 1.0f32.into_value_and_type(); + let type_annotated_value2 = 2u32.into_value_and_type(); let instruction_set = vec![ RibIR::PushLit(type_annotated_value2), @@ -855,8 +869,8 @@ mod compiler_tests { let instructions = RibByteCode::from_expr(&inferred_expr).unwrap(); - let type_annotated_value1 = TypeAnnotatedValue::F32(1.0); - let type_annotated_value2 = TypeAnnotatedValue::U32(1); + let type_annotated_value1 = 1.0f32.into_value_and_type(); + let type_annotated_value2 = 1u32.into_value_and_type(); let instruction_set = vec![ RibIR::PushLit(type_annotated_value2), @@ -894,8 +908,8 @@ mod compiler_tests { let instructions = RibByteCode::from_expr(&inferred_expr).unwrap(); - let type_annotated_value1 = TypeAnnotatedValue::F32(1.0); - let type_annotated_value2 = TypeAnnotatedValue::U32(1); + let type_annotated_value1 = 1.0f32.into_value_and_type(); + let type_annotated_value2 = 1u32.into_value_and_type(); let instruction_set = vec![ RibIR::PushLit(type_annotated_value2), @@ -933,8 +947,8 @@ mod compiler_tests { let instructions = RibByteCode::from_expr(&inferred_expr).unwrap(); - let type_annotated_value1 = TypeAnnotatedValue::F32(1.0); - let type_annotated_value2 = TypeAnnotatedValue::U32(1); + let type_annotated_value1 = 1.0f32.into_value_and_type(); + let type_annotated_value2 = 1u32.into_value_and_type(); let instruction_set = vec![ RibIR::PushLit(type_annotated_value2), @@ -973,8 +987,8 @@ mod compiler_tests { let instructions = RibByteCode::from_expr(&inferred_expr).unwrap(); - let bar_value = TypeAnnotatedValue::Str("bar_value".to_string()); - let foo_value = TypeAnnotatedValue::Str("foo_value".to_string()); + let bar_value = "bar_value".into_value_and_type(); + let foo_value = "foo_value".into_value_and_type(); let instruction_set = vec![ RibIR::PushLit(bar_value), @@ -1018,8 +1032,8 @@ mod compiler_tests { let instructions = RibByteCode::from_expr(&inferred_expr).unwrap(); let instruction_set = vec![ - RibIR::PushLit(TypeAnnotatedValue::Str("foo".to_string())), - RibIR::PushLit(TypeAnnotatedValue::Str("bar".to_string())), + RibIR::PushLit("foo".into_value_and_type()), + RibIR::PushLit("bar".into_value_and_type()), ]; let expected_instructions = RibByteCode { @@ -1048,12 +1062,12 @@ mod compiler_tests { let instructions = RibByteCode::from_expr(&inferred_expr).unwrap(); let instruction_set = vec![ - RibIR::PushLit(TypeAnnotatedValue::Str("pred".to_string())), + RibIR::PushLit("pred".into_value_and_type()), RibIR::JumpIfFalse(InstructionId { index: 1 }), // jumps to the next label having Id 1 (which is else block) - RibIR::PushLit(TypeAnnotatedValue::Str("then".to_string())), + RibIR::PushLit("then".into_value_and_type()), RibIR::Jump(InstructionId { index: 2 }), // Once if is executed then jump to the end of the else block with id 2 RibIR::Label(InstructionId { index: 1 }), - RibIR::PushLit(TypeAnnotatedValue::Str("else".to_string())), + RibIR::PushLit("else".into_value_and_type()), RibIR::Label(InstructionId { index: 2 }), ]; @@ -1089,17 +1103,17 @@ mod compiler_tests { let instruction_set = vec![ // if case - RibIR::PushLit(TypeAnnotatedValue::Str("if-pred1".to_string())), + RibIR::PushLit("if-pred1".into_value_and_type()), RibIR::JumpIfFalse(InstructionId { index: 1 }), // jumps to the next label having Id 1 (which is else block) - RibIR::PushLit(TypeAnnotatedValue::Str("then1".to_string())), + RibIR::PushLit("then1".into_value_and_type()), RibIR::Jump(InstructionId { index: 2 }), // Once if is executed then jump to the end of the else block with id 3 RibIR::Label(InstructionId { index: 1 }), - RibIR::PushLit(TypeAnnotatedValue::Str("else-pred2".to_string())), + RibIR::PushLit("else-pred2".into_value_and_type()), RibIR::JumpIfFalse(InstructionId { index: 3 }), // jumps to the next label having Id 2 (which is else block) - RibIR::PushLit(TypeAnnotatedValue::Str("else-then2".to_string())), + RibIR::PushLit("else-then2".into_value_and_type()), RibIR::Jump(InstructionId { index: 4 }), // Once if is executed then jump to the end of the else block with id 3 RibIR::Label(InstructionId { index: 3 }), - RibIR::PushLit(TypeAnnotatedValue::Str("else-else2".to_string())), + RibIR::PushLit("else-else2".into_value_and_type()), RibIR::Label(InstructionId { index: 4 }), RibIR::Label(InstructionId { index: 2 }), ]; @@ -1137,8 +1151,8 @@ mod compiler_tests { let instructions = RibByteCode::from_expr(&inferred_expr).unwrap(); - let bar_value = TypeAnnotatedValue::Str("bar_value".to_string()); - let foo_value = TypeAnnotatedValue::Str("foo_value".to_string()); + let bar_value = "bar_value".into_value_and_type(); + let foo_value = "foo_value".into_value_and_type(); let instruction_set = vec![ RibIR::PushLit(bar_value), @@ -1185,8 +1199,8 @@ mod compiler_tests { let instructions = RibByteCode::from_expr(&inferred_expr).unwrap(); let instruction_set = vec![ - RibIR::PushLit(TypeAnnotatedValue::Str("bar".to_string())), - RibIR::PushLit(TypeAnnotatedValue::Str("foo".to_string())), + RibIR::PushLit("bar".into_value_and_type()), + RibIR::PushLit("foo".into_value_and_type()), RibIR::PushList(list(str()), 2), RibIR::SelectIndex(1), ]; @@ -1235,25 +1249,25 @@ mod compiler_tests { // instructions will correspond to an if-else statement let instruction_set = vec![ - RibIR::PushLit(TypeAnnotatedValue::Str("arm1_pattern_expr".to_string())), - RibIR::PushLit(TypeAnnotatedValue::Str("pred".to_string())), + RibIR::PushLit("arm1_pattern_expr".into_value_and_type()), + RibIR::PushLit("pred".into_value_and_type()), RibIR::EqualTo, RibIR::JumpIfFalse(InstructionId { index: 1 }), - RibIR::PushLit(TypeAnnotatedValue::Str("arm1_resolution_expr".to_string())), + RibIR::PushLit("arm1_resolution_expr".into_value_and_type()), RibIR::Jump(InstructionId { index: 2 }), RibIR::Label(InstructionId { index: 1 }), - RibIR::PushLit(TypeAnnotatedValue::Str("arm2_pattern_expr".to_string())), - RibIR::PushLit(TypeAnnotatedValue::Str("pred".to_string())), + RibIR::PushLit("arm2_pattern_expr".into_value_and_type()), + RibIR::PushLit("pred".into_value_and_type()), RibIR::EqualTo, RibIR::JumpIfFalse(InstructionId { index: 3 }), - RibIR::PushLit(TypeAnnotatedValue::Str("arm2_resolution_expr".to_string())), + RibIR::PushLit("arm2_resolution_expr".into_value_and_type()), RibIR::Jump(InstructionId { index: 4 }), RibIR::Label(InstructionId { index: 3 }), - RibIR::PushLit(TypeAnnotatedValue::Str("arm3_pattern_expr".to_string())), - RibIR::PushLit(TypeAnnotatedValue::Str("pred".to_string())), + RibIR::PushLit("arm3_pattern_expr".into_value_and_type()), + RibIR::PushLit("pred".into_value_and_type()), RibIR::EqualTo, RibIR::JumpIfFalse(InstructionId { index: 5 }), - RibIR::PushLit(TypeAnnotatedValue::Str("arm3_resolution_expr".to_string())), + RibIR::PushLit("arm3_resolution_expr".into_value_and_type()), RibIR::Jump(InstructionId { index: 6 }), RibIR::Label(InstructionId { index: 5 }), RibIR::Throw("No match found".to_string()), diff --git a/golem-rib/src/compiler/compiler_output.rs b/golem-rib/src/compiler/compiler_output.rs index 10c39dfab..4b535aa70 100644 --- a/golem-rib/src/compiler/compiler_output.rs +++ b/golem-rib/src/compiler/compiler_output.rs @@ -14,8 +14,6 @@ use crate::compiler::worker_functions_in_rib::WorkerFunctionsInRib; use crate::{RibByteCode, RibInputTypeInfo, RibOutputTypeInfo}; -use golem_api_grpc::proto::golem::rib::CompilerOutput as ProtoCompilerOutput; -use std::convert::TryFrom; #[derive(Debug, Clone)] pub struct CompilerOutput { @@ -30,50 +28,60 @@ pub struct CompilerOutput { pub rib_output_type_info: Option, } -impl TryFrom for CompilerOutput { - type Error = String; +#[cfg(feature = "protobuf")] +mod protobuf { + use crate::{ + CompilerOutput, RibByteCode, RibInputTypeInfo, RibOutputTypeInfo, WorkerFunctionsInRib, + }; + use golem_api_grpc::proto::golem::rib::CompilerOutput as ProtoCompilerOutput; - fn try_from(value: ProtoCompilerOutput) -> Result { - let proto_rib_input = value.rib_input.ok_or("Missing rib_input")?; - let proto_byte_code = value.byte_code.ok_or("Missing byte_code")?; - let rib_input = RibInputTypeInfo::try_from(proto_rib_input)?; - let byte_code = RibByteCode::try_from(proto_byte_code)?; - let worker_invoke_calls = if let Some(value) = value.worker_invoke_calls { - Some(WorkerFunctionsInRib::try_from(value)?) - } else { - None - }; + impl TryFrom for CompilerOutput { + type Error = String; - let rib_output_type_info = value - .rib_output - .map(RibOutputTypeInfo::try_from) - .transpose()?; + fn try_from(value: ProtoCompilerOutput) -> Result { + let proto_rib_input = value.rib_input.ok_or("Missing rib_input")?; + let proto_byte_code = value.byte_code.ok_or("Missing byte_code")?; + let rib_input = RibInputTypeInfo::try_from(proto_rib_input)?; + let byte_code = RibByteCode::try_from(proto_byte_code)?; + let worker_invoke_calls = if let Some(value) = value.worker_invoke_calls { + Some(WorkerFunctionsInRib::try_from(value)?) + } else { + None + }; - Ok(CompilerOutput { - worker_invoke_calls, - byte_code, - rib_input_type_info: rib_input, - rib_output_type_info, - }) + let rib_output_type_info = value + .rib_output + .map(RibOutputTypeInfo::try_from) + .transpose()?; + + Ok(CompilerOutput { + worker_invoke_calls, + byte_code, + rib_input_type_info: rib_input, + rib_output_type_info, + }) + } } -} -impl From for ProtoCompilerOutput { - fn from(value: CompilerOutput) -> Self { - ProtoCompilerOutput { - byte_code: Some(golem_api_grpc::proto::golem::rib::RibByteCode::from( - value.byte_code, - )), - rib_input: Some(golem_api_grpc::proto::golem::rib::RibInputType::from( - value.rib_input_type_info, - )), - worker_invoke_calls: value - .worker_invoke_calls - .map(golem_api_grpc::proto::golem::rib::WorkerFunctionsInRib::from), + impl TryFrom for ProtoCompilerOutput { + type Error = String; + + fn try_from(value: CompilerOutput) -> Result { + Ok(ProtoCompilerOutput { + byte_code: Some(golem_api_grpc::proto::golem::rib::RibByteCode::try_from( + value.byte_code, + )?), + rib_input: Some(golem_api_grpc::proto::golem::rib::RibInputType::from( + value.rib_input_type_info, + )), + worker_invoke_calls: value + .worker_invoke_calls + .map(golem_api_grpc::proto::golem::rib::WorkerFunctionsInRib::from), - rib_output: value - .rib_output_type_info - .map(golem_api_grpc::proto::golem::rib::RibOutputType::from), + rib_output: value + .rib_output_type_info + .map(golem_api_grpc::proto::golem::rib::RibOutputType::from), + }) } } } diff --git a/golem-rib/src/compiler/ir.rs b/golem-rib/src/compiler/ir.rs index e94e3239b..f8ae17106 100644 --- a/golem-rib/src/compiler/ir.rs +++ b/golem-rib/src/compiler/ir.rs @@ -14,21 +14,14 @@ use crate::{AnalysedTypeWithUnit, ParsedFunctionSite, VariableId}; use bincode::{Decode, Encode}; -use golem_api_grpc::proto::golem::rib::rib_ir::Instruction; -use golem_api_grpc::proto::golem::rib::{ - And, CallInstruction, ConcatInstruction, CreateFunctionNameInstruction, EqualTo, GetTag, - GreaterThan, GreaterThanOrEqualTo, IsEmpty, JumpInstruction, LessThan, LessThanOrEqualTo, - Negate, Or, PushListInstruction, PushNoneInstruction, PushTupleInstruction, - RibIr as ProtoRibIR, -}; -use golem_wasm_ast::analysis::{AnalysedType, TypeStr}; -use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; +use golem_wasm_ast::analysis::AnalysedType; +use golem_wasm_rpc::ValueAndType; use serde::{Deserialize, Serialize}; // To create any type, example, CreateOption, you have to feed a fully formed AnalysedType #[derive(Debug, Clone, PartialEq, Encode, Decode)] pub enum RibIR { - PushLit(TypeAnnotatedValue), + PushLit(ValueAndType), AssignVar(VariableId), LoadVar(VariableId), CreateAndPushRecord(AnalysedType), @@ -39,7 +32,7 @@ pub enum RibIR { PushNone(Option), // In certain cases, we don't need the type info PushOkResult(AnalysedType), PushErrResult(AnalysedType), - PushFlag(TypeAnnotatedValue), // More or less like a literal, compiler can form the value directly + PushFlag(ValueAndType), // More or less like a literal, compiler can form the value directly SelectField(String), SelectIndex(usize), EqualTo, @@ -121,121 +114,6 @@ pub enum FunctionReferenceType { }, } -impl TryFrom for FunctionReferenceType { - type Error = String; - fn try_from( - value: golem_api_grpc::proto::golem::rib::FunctionReferenceType, - ) -> Result { - let value = value.r#type.ok_or("Missing type".to_string())?; - let function_reference_type = match value { - golem_api_grpc::proto::golem::rib::function_reference_type::Type::Function(name) => FunctionReferenceType::Function { - function: name.name - }, - golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceConstructor(name) => - FunctionReferenceType::RawResourceConstructor { - resource: name.resource_name - }, - golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceDrop(name) => FunctionReferenceType::RawResourceDrop { - resource: name.resource_name - }, - golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceMethod(raw_resource_method) =>{ - let resource = raw_resource_method.resource_name; - let method = raw_resource_method.method_name; - FunctionReferenceType::RawResourceMethod { resource, method } - } - golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceStaticMethod(raw_resource_static_method) => { - let resource = raw_resource_static_method.resource_name; - let method = raw_resource_static_method.method_name; - FunctionReferenceType::RawResourceStaticMethod{ resource, method } - } - golem_api_grpc::proto::golem::rib::function_reference_type::Type::IndexedResourceConstructor(indexed_resource_constructor) => { - let resource = indexed_resource_constructor.resource_name; - let arg_size = indexed_resource_constructor.arg_size; - FunctionReferenceType::IndexedResourceConstructor { resource, arg_size: arg_size as usize } - } - golem_api_grpc::proto::golem::rib::function_reference_type::Type::IndexedResourceMethod(indexed_resource_method) => { - let resource = indexed_resource_method.resource_name; - let arg_size = indexed_resource_method.arg_size; - let method = indexed_resource_method.method_name; - FunctionReferenceType::IndexedResourceMethod { resource, arg_size: arg_size as usize, method } - } - golem_api_grpc::proto::golem::rib::function_reference_type::Type::IndexedResourceStaticMethod(indexed_resource_static_method) => { - let resource = indexed_resource_static_method.resource_name; - let arg_size = indexed_resource_static_method.arg_size; - let method = indexed_resource_static_method.method_name; - FunctionReferenceType::IndexedResourceStaticMethod { resource, arg_size: arg_size as usize, method } - } - golem_api_grpc::proto::golem::rib::function_reference_type::Type::IndexedResourceDrop(indexed_resource_drop) => { - let resource = indexed_resource_drop.resource_name; - let arg_size = indexed_resource_drop.arg_size; - FunctionReferenceType::IndexedResourceDrop { resource, arg_size: arg_size as usize } - } - }; - Ok(function_reference_type) - } -} - -impl From for golem_api_grpc::proto::golem::rib::FunctionReferenceType { - fn from(value: FunctionReferenceType) -> Self { - match value { - FunctionReferenceType::Function { function } => golem_api_grpc::proto::golem::rib::FunctionReferenceType { - r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::Function(golem_api_grpc::proto::golem::rib::Function { - name: function - })) - }, - FunctionReferenceType::RawResourceConstructor{ resource } => golem_api_grpc::proto::golem::rib::FunctionReferenceType { - r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceConstructor(golem_api_grpc::proto::golem::rib::RawResourceConstructor { - resource_name: resource - })) - }, - FunctionReferenceType::RawResourceDrop { resource } => golem_api_grpc::proto::golem::rib::FunctionReferenceType { - r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceDrop(golem_api_grpc::proto::golem::rib::RawResourceDrop { - resource_name: resource - })) - }, - FunctionReferenceType::RawResourceMethod { resource, method } => golem_api_grpc::proto::golem::rib::FunctionReferenceType { - r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceMethod(golem_api_grpc::proto::golem::rib::RawResourceMethod { - resource_name: resource, - method_name: method - })) - }, - FunctionReferenceType::RawResourceStaticMethod { resource, method } => golem_api_grpc::proto::golem::rib::FunctionReferenceType { - r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceStaticMethod(golem_api_grpc::proto::golem::rib::RawResourceStaticMethod { - resource_name: resource, - method_name: method - })) - }, - FunctionReferenceType::IndexedResourceConstructor { resource, arg_size } => golem_api_grpc::proto::golem::rib::FunctionReferenceType { - r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::IndexedResourceConstructor(golem_api_grpc::proto::golem::rib::IndexedResourceConstructor { - resource_name: resource, - arg_size: arg_size as u32 - })) - }, - FunctionReferenceType::IndexedResourceMethod { resource, arg_size, method } => golem_api_grpc::proto::golem::rib::FunctionReferenceType { - r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::IndexedResourceMethod(golem_api_grpc::proto::golem::rib::IndexedResourceMethod { - resource_name: resource, - arg_size: arg_size as u32, - method_name: method - })) - }, - FunctionReferenceType::IndexedResourceStaticMethod { resource, arg_size, method } => golem_api_grpc::proto::golem::rib::FunctionReferenceType { - r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::IndexedResourceStaticMethod(golem_api_grpc::proto::golem::rib::IndexedResourceStaticMethod { - resource_name: resource, - arg_size: arg_size as u32, - method_name: method - })) - }, - FunctionReferenceType::IndexedResourceDrop { resource, arg_size } => golem_api_grpc::proto::golem::rib::FunctionReferenceType { - r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::IndexedResourceDrop(golem_api_grpc::proto::golem::rib::IndexedResourceDrop { - resource_name: resource, - arg_size: arg_size as u32 - })) - } - - } - } -} - // Every instruction can have a unique ID, and the compiler // can assign this and label the start and end of byte code blocks. // This is more efficient than assigning index to every instruction and incrementing it @@ -267,345 +145,488 @@ impl InstructionId { } } -impl TryFrom for RibIR { - type Error = String; - - fn try_from(value: ProtoRibIR) -> Result { - let instruction = value - .instruction - .ok_or_else(|| "Missing instruction".to_string())?; - - match instruction { - Instruction::PushLit(value) => Ok(RibIR::PushLit( - value - .type_annotated_value - .ok_or("Missing type_annotated_value".to_string())?, - )), - Instruction::AssignVar(value) => Ok(RibIR::AssignVar( - value - .try_into() - .map_err(|_| "Failed to convert AssignVar".to_string())?, - )), - Instruction::LoadVar(value) => Ok(RibIR::LoadVar( - value - .try_into() - .map_err(|_| "Failed to convert LoadVar".to_string())?, - )), - Instruction::CreateAndPushRecord(value) => { - Ok(RibIR::CreateAndPushRecord((&value).try_into().map_err( - |_| "Failed to convert CreateAndPushRecord".to_string(), - )?)) - } - Instruction::Plus(value) => { - Ok(RibIR::Plus((&value).try_into().map_err(|_| { - "Failed to convert CreateAndPushRecord".to_string() - })?)) - } - Instruction::Multiply(value) => { - Ok(RibIR::Multiply((&value).try_into().map_err(|_| { - "Failed to convert CreateAndPushRecord".to_string() - })?)) - } - Instruction::Minus(value) => { - Ok(RibIR::Minus((&value).try_into().map_err(|_| { - "Failed to convert CreateAndPushRecord".to_string() - })?)) - } - Instruction::Divide(value) => { - Ok(RibIR::Divide((&value).try_into().map_err(|_| { - "Failed to convert CreateAndPushRecord".to_string() - })?)) +#[cfg(feature = "protobuf")] +mod protobuf { + use crate::{ + AnalysedTypeWithUnit, FunctionReferenceType, InstructionId, ParsedFunctionSite, RibIR, + }; + use golem_api_grpc::proto::golem::rib::rib_ir::Instruction; + use golem_api_grpc::proto::golem::rib::{ + And, CallInstruction, ConcatInstruction, CreateFunctionNameInstruction, EqualTo, GetTag, + GreaterThan, GreaterThanOrEqualTo, IsEmpty, JumpInstruction, LessThan, LessThanOrEqualTo, + Negate, Or, PushListInstruction, PushNoneInstruction, PushTupleInstruction, + RibIr as ProtoRibIR, + }; + use golem_wasm_ast::analysis::{AnalysedType, TypeStr}; + use golem_wasm_rpc::ValueAndType; + + impl TryFrom for FunctionReferenceType { + type Error = String; + fn try_from( + value: golem_api_grpc::proto::golem::rib::FunctionReferenceType, + ) -> Result { + let value = value.r#type.ok_or("Missing type".to_string())?; + let function_reference_type = match value { + golem_api_grpc::proto::golem::rib::function_reference_type::Type::Function(name) => FunctionReferenceType::Function { + function: name.name + }, + golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceConstructor(name) => + FunctionReferenceType::RawResourceConstructor { + resource: name.resource_name + }, + golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceDrop(name) => FunctionReferenceType::RawResourceDrop { + resource: name.resource_name + }, + golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceMethod(raw_resource_method) => { + let resource = raw_resource_method.resource_name; + let method = raw_resource_method.method_name; + FunctionReferenceType::RawResourceMethod { resource, method } + } + golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceStaticMethod(raw_resource_static_method) => { + let resource = raw_resource_static_method.resource_name; + let method = raw_resource_static_method.method_name; + FunctionReferenceType::RawResourceStaticMethod { resource, method } + } + golem_api_grpc::proto::golem::rib::function_reference_type::Type::IndexedResourceConstructor(indexed_resource_constructor) => { + let resource = indexed_resource_constructor.resource_name; + let arg_size = indexed_resource_constructor.arg_size; + FunctionReferenceType::IndexedResourceConstructor { resource, arg_size: arg_size as usize } + } + golem_api_grpc::proto::golem::rib::function_reference_type::Type::IndexedResourceMethod(indexed_resource_method) => { + let resource = indexed_resource_method.resource_name; + let arg_size = indexed_resource_method.arg_size; + let method = indexed_resource_method.method_name; + FunctionReferenceType::IndexedResourceMethod { resource, arg_size: arg_size as usize, method } + } + golem_api_grpc::proto::golem::rib::function_reference_type::Type::IndexedResourceStaticMethod(indexed_resource_static_method) => { + let resource = indexed_resource_static_method.resource_name; + let arg_size = indexed_resource_static_method.arg_size; + let method = indexed_resource_static_method.method_name; + FunctionReferenceType::IndexedResourceStaticMethod { resource, arg_size: arg_size as usize, method } + } + golem_api_grpc::proto::golem::rib::function_reference_type::Type::IndexedResourceDrop(indexed_resource_drop) => { + let resource = indexed_resource_drop.resource_name; + let arg_size = indexed_resource_drop.arg_size; + FunctionReferenceType::IndexedResourceDrop { resource, arg_size: arg_size as usize } + } + }; + Ok(function_reference_type) + } + } + + impl From for golem_api_grpc::proto::golem::rib::FunctionReferenceType { + fn from(value: FunctionReferenceType) -> Self { + match value { + FunctionReferenceType::Function { function } => golem_api_grpc::proto::golem::rib::FunctionReferenceType { + r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::Function(golem_api_grpc::proto::golem::rib::Function { + name: function + })) + }, + FunctionReferenceType::RawResourceConstructor { resource } => golem_api_grpc::proto::golem::rib::FunctionReferenceType { + r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceConstructor(golem_api_grpc::proto::golem::rib::RawResourceConstructor { + resource_name: resource + })) + }, + FunctionReferenceType::RawResourceDrop { resource } => golem_api_grpc::proto::golem::rib::FunctionReferenceType { + r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceDrop(golem_api_grpc::proto::golem::rib::RawResourceDrop { + resource_name: resource + })) + }, + FunctionReferenceType::RawResourceMethod { resource, method } => golem_api_grpc::proto::golem::rib::FunctionReferenceType { + r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceMethod(golem_api_grpc::proto::golem::rib::RawResourceMethod { + resource_name: resource, + method_name: method, + })) + }, + FunctionReferenceType::RawResourceStaticMethod { resource, method } => golem_api_grpc::proto::golem::rib::FunctionReferenceType { + r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::RawResourceStaticMethod(golem_api_grpc::proto::golem::rib::RawResourceStaticMethod { + resource_name: resource, + method_name: method, + })) + }, + FunctionReferenceType::IndexedResourceConstructor { resource, arg_size } => golem_api_grpc::proto::golem::rib::FunctionReferenceType { + r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::IndexedResourceConstructor(golem_api_grpc::proto::golem::rib::IndexedResourceConstructor { + resource_name: resource, + arg_size: arg_size as u32, + })) + }, + FunctionReferenceType::IndexedResourceMethod { resource, arg_size, method } => golem_api_grpc::proto::golem::rib::FunctionReferenceType { + r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::IndexedResourceMethod(golem_api_grpc::proto::golem::rib::IndexedResourceMethod { + resource_name: resource, + arg_size: arg_size as u32, + method_name: method, + })) + }, + FunctionReferenceType::IndexedResourceStaticMethod { resource, arg_size, method } => golem_api_grpc::proto::golem::rib::FunctionReferenceType { + r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::IndexedResourceStaticMethod(golem_api_grpc::proto::golem::rib::IndexedResourceStaticMethod { + resource_name: resource, + arg_size: arg_size as u32, + method_name: method, + })) + }, + FunctionReferenceType::IndexedResourceDrop { resource, arg_size } => golem_api_grpc::proto::golem::rib::FunctionReferenceType { + r#type: Some(golem_api_grpc::proto::golem::rib::function_reference_type::Type::IndexedResourceDrop(golem_api_grpc::proto::golem::rib::IndexedResourceDrop { + resource_name: resource, + arg_size: arg_size as u32, + })) + } } + } + } + + impl TryFrom for RibIR { + type Error = String; + + fn try_from(value: ProtoRibIR) -> Result { + let instruction = value + .instruction + .ok_or_else(|| "Missing instruction".to_string())?; - Instruction::UpdateRecord(value) => Ok(RibIR::UpdateRecord(value)), - Instruction::PushList(value) => Ok(RibIR::PushList( - value - .list_type - .ok_or("List type not present".to_string()) - .and_then(|t| { - (&t).try_into() - .map_err(|_| "Failed to convert AnalysedType".to_string()) - })?, - value.list_size as usize, - )), - Instruction::CreateSome(value) => Ok(RibIR::PushSome( - (&value) - .try_into() - .map_err(|_| "Failed to convert CreateSome".to_string())?, - )), - Instruction::CreateNone(value) => match value.none_type { - Some(v) => { - let optional_type = (&v) + match instruction { + Instruction::PushLit(value) => { + let value: ValueAndType = value.try_into()?; + Ok(RibIR::PushLit(value)) + } + Instruction::AssignVar(value) => Ok(RibIR::AssignVar( + value .try_into() - .map_err(|_| "Failed to convert AnalysedType".to_string()); - Ok(RibIR::PushNone(Some(optional_type?))) - } - None => Ok(RibIR::PushNone(None)), - }, - Instruction::CreateOkResult(value) => { - Ok(RibIR::PushOkResult((&value).try_into().map_err(|_| { - "Failed to convert CreateOkResult".to_string() - })?)) - } - Instruction::CreateErrResult(value) => { - Ok(RibIR::PushErrResult((&value).try_into().map_err(|_| { - "Failed to convert CreateErrResult".to_string() - })?)) - } - Instruction::SelectField(value) => Ok(RibIR::SelectField(value)), - Instruction::SelectIndex(value) => Ok(RibIR::SelectIndex(value as usize)), - Instruction::EqualTo(_) => Ok(RibIR::EqualTo), - Instruction::GreaterThan(_) => Ok(RibIR::GreaterThan), - Instruction::LessThan(_) => Ok(RibIR::LessThan), - Instruction::GreaterThanOrEqualTo(_) => Ok(RibIR::GreaterThanOrEqualTo), - Instruction::LessThanOrEqualTo(_) => Ok(RibIR::LessThanOrEqualTo), - Instruction::And(_) => Ok(RibIR::And), - Instruction::IsEmpty(_) => Ok(RibIR::IsEmpty), - Instruction::Or(_) => Ok(RibIR::Or), - Instruction::JumpIfFalse(value) => Ok(RibIR::JumpIfFalse(InstructionId::from( - value.instruction_id as usize, - ))), - Instruction::Jump(value) => Ok(RibIR::Jump(InstructionId::from( - value.instruction_id as usize, - ))), - Instruction::Label(value) => Ok(RibIR::Label(InstructionId::from( - value.instruction_id as usize, - ))), - Instruction::Deconstruct(_) => Ok(RibIR::Deconstruct), - Instruction::Call(call_instruction) => { - let return_type = match call_instruction.return_type { - Some(return_type) => { - let analysed_type = (&return_type) - .try_into() - .map_err(|_| "Failed to convert AnalysedType".to_string())?; + .map_err(|_| "Failed to convert AssignVar".to_string())?, + )), + Instruction::LoadVar(value) => Ok(RibIR::LoadVar( + value + .try_into() + .map_err(|_| "Failed to convert LoadVar".to_string())?, + )), + Instruction::CreateAndPushRecord(value) => { + Ok(RibIR::CreateAndPushRecord((&value).try_into().map_err( + |_| "Failed to convert CreateAndPushRecord".to_string(), + )?)) + } + Instruction::Plus(value) => { + Ok(RibIR::Plus((&value).try_into().map_err(|_| { + "Failed to convert CreateAndPushRecord".to_string() + })?)) + } + Instruction::Multiply(value) => { + Ok(RibIR::Multiply((&value).try_into().map_err(|_| { + "Failed to convert CreateAndPushRecord".to_string() + })?)) + } + Instruction::Minus(value) => { + Ok(RibIR::Minus((&value).try_into().map_err(|_| { + "Failed to convert CreateAndPushRecord".to_string() + })?)) + } + Instruction::Divide(value) => { + Ok(RibIR::Divide((&value).try_into().map_err(|_| { + "Failed to convert CreateAndPushRecord".to_string() + })?)) + } - AnalysedTypeWithUnit::Type(analysed_type) + Instruction::UpdateRecord(value) => Ok(RibIR::UpdateRecord(value)), + Instruction::PushList(value) => Ok(RibIR::PushList( + value + .list_type + .ok_or("List type not present".to_string()) + .and_then(|t| { + (&t).try_into() + .map_err(|_| "Failed to convert AnalysedType".to_string()) + })?, + value.list_size as usize, + )), + Instruction::CreateSome(value) => Ok(RibIR::PushSome( + (&value) + .try_into() + .map_err(|_| "Failed to convert CreateSome".to_string())?, + )), + Instruction::CreateNone(value) => match value.none_type { + Some(v) => { + let optional_type = (&v) + .try_into() + .map_err(|_| "Failed to convert AnalysedType".to_string()); + Ok(RibIR::PushNone(Some(optional_type?))) } - None => AnalysedTypeWithUnit::Unit, - }; + None => Ok(RibIR::PushNone(None)), + }, + Instruction::CreateOkResult(value) => { + Ok(RibIR::PushOkResult((&value).try_into().map_err(|_| { + "Failed to convert CreateOkResult".to_string() + })?)) + } + Instruction::CreateErrResult(value) => { + Ok(RibIR::PushErrResult((&value).try_into().map_err(|_| { + "Failed to convert CreateErrResult".to_string() + })?)) + } + Instruction::SelectField(value) => Ok(RibIR::SelectField(value)), + Instruction::SelectIndex(value) => Ok(RibIR::SelectIndex(value as usize)), + Instruction::EqualTo(_) => Ok(RibIR::EqualTo), + Instruction::GreaterThan(_) => Ok(RibIR::GreaterThan), + Instruction::LessThan(_) => Ok(RibIR::LessThan), + Instruction::GreaterThanOrEqualTo(_) => Ok(RibIR::GreaterThanOrEqualTo), + Instruction::LessThanOrEqualTo(_) => Ok(RibIR::LessThanOrEqualTo), + Instruction::And(_) => Ok(RibIR::And), + Instruction::IsEmpty(_) => Ok(RibIR::IsEmpty), + Instruction::Or(_) => Ok(RibIR::Or), + Instruction::JumpIfFalse(value) => Ok(RibIR::JumpIfFalse(InstructionId::from( + value.instruction_id as usize, + ))), + Instruction::Jump(value) => Ok(RibIR::Jump(InstructionId::from( + value.instruction_id as usize, + ))), + Instruction::Label(value) => Ok(RibIR::Label(InstructionId::from( + value.instruction_id as usize, + ))), + Instruction::Deconstruct(_) => Ok(RibIR::Deconstruct), + Instruction::Call(call_instruction) => { + let return_type = match call_instruction.return_type { + Some(return_type) => { + let analysed_type = (&return_type) + .try_into() + .map_err(|_| "Failed to convert AnalysedType".to_string())?; + + AnalysedTypeWithUnit::Type(analysed_type) + } + None => AnalysedTypeWithUnit::Unit, + }; + + Ok(RibIR::InvokeFunction( + call_instruction.argument_count as usize, + return_type, + )) + } + Instruction::VariantConstruction(variant_construction) => { + let variant_type = variant_construction + .return_type + .ok_or("Missing return_type for variant construction".to_string())?; - Ok(RibIR::InvokeFunction( - call_instruction.argument_count as usize, - return_type, - )) - } - Instruction::VariantConstruction(variant_construction) => { - let variant_type = variant_construction - .return_type - .ok_or("Missing return_type for variant construction".to_string())?; - - let analysed_variant_type = (&variant_type) - .try_into() - .map_err(|_| "Failed to convert AnalysedType".to_string())?; - - Ok(RibIR::PushVariant( - variant_construction.variant_name, - analysed_variant_type, - )) - } - Instruction::EnumConstruction(enum_construction) => { - let enum_type = enum_construction - .return_type - .ok_or("Missing return_type for enum construction".to_string())?; - - let analysed_enum_type = (&enum_type) - .try_into() - .map_err(|_| "Failed to convert AnalysedType".to_string())?; - - Ok(RibIR::PushEnum( - enum_construction.enum_name, - analysed_enum_type, - )) - } - Instruction::Throw(value) => Ok(RibIR::Throw(value)), - Instruction::PushFlag(flag) => Ok(RibIR::PushFlag( - flag.type_annotated_value - .ok_or("Missing flag".to_string())?, - )), - Instruction::GetTag(_) => Ok(RibIR::GetTag), - Instruction::PushTuple(tuple_instruction) => { - let tuple_type = tuple_instruction - .tuple_type - .ok_or("Missing tuple_type".to_string()) - .and_then(|t| { - (&t).try_into() - .map_err(|_| "Failed to convert AnalysedType".to_string()) - })?; - - Ok(RibIR::PushTuple( - tuple_type, - tuple_instruction.tuple_size as usize, - )) - } - Instruction::Negate(_) => Ok(RibIR::Negate), - Instruction::Concat(concat_instruction) => { - Ok(RibIR::Concat(concat_instruction.arg_size as usize)) - } - Instruction::CreateFunctionName(instruction) => { - let parsed_site = instruction.site.ok_or("Missing site".to_string())?; - let parsed_function_site = ParsedFunctionSite::try_from(parsed_site)?; - - let reference_type = instruction - .function_reference_details - .ok_or("Missing reference_type".to_string())?; - let function_reference_type = reference_type.try_into()?; - - Ok(RibIR::CreateFunctionName( - parsed_function_site, - function_reference_type, - )) - } - Instruction::ListToIterator(_) => Ok(RibIR::ListToIterator), - Instruction::CreateSink(create_sink) => { - let result = create_sink - .list_type - .ok_or("Sink list type not present".to_string()) - .and_then(|t| { - (&t).try_into() - .map_err(|_| "Failed to convert AnalysedType".to_string()) - })?; - - Ok(RibIR::CreateSink(result)) - } - Instruction::AdvanceIterator(_) => Ok(RibIR::AdvanceIterator), - Instruction::SinkToList(_) => Ok(RibIR::SinkToList), - Instruction::PushToSink(_) => Ok(RibIR::PushToSink), - } - } -} + let analysed_variant_type = (&variant_type) + .try_into() + .map_err(|_| "Failed to convert AnalysedType".to_string())?; -impl From for ProtoRibIR { - fn from(value: RibIR) -> Self { - let instruction = match value { - RibIR::PushLit(value) => { - Instruction::PushLit(golem_wasm_rpc::protobuf::TypeAnnotatedValue { - type_annotated_value: Some(value), - }) - } - RibIR::And => Instruction::And(And {}), - RibIR::IsEmpty => Instruction::IsEmpty(IsEmpty {}), - RibIR::Or => Instruction::Or(Or {}), - RibIR::AssignVar(value) => Instruction::AssignVar(value.into()), - RibIR::LoadVar(value) => Instruction::LoadVar(value.into()), - RibIR::CreateAndPushRecord(value) => Instruction::CreateAndPushRecord((&value).into()), - RibIR::Plus(value) => Instruction::Plus((&value).into()), - RibIR::Minus(value) => Instruction::Minus((&value).into()), - RibIR::Multiply(value) => Instruction::Multiply((&value).into()), - RibIR::Divide(value) => Instruction::Divide((&value).into()), - RibIR::UpdateRecord(value) => Instruction::UpdateRecord(value), - RibIR::PushList(value, arg_size) => Instruction::PushList(PushListInstruction { - list_type: Some((&value).into()), - list_size: arg_size as u64, - }), - RibIR::PushSome(value) => Instruction::CreateSome((&value).into()), - RibIR::PushNone(value) => { - let push_none_instruction = PushNoneInstruction { - none_type: value.map(|t| (&t).into()), - }; - Instruction::CreateNone(push_none_instruction) - } - RibIR::PushOkResult(value) => Instruction::CreateOkResult((&value).into()), - RibIR::PushErrResult(value) => Instruction::CreateErrResult((&value).into()), - RibIR::SelectField(value) => Instruction::SelectField(value), - RibIR::SelectIndex(value) => Instruction::SelectIndex(value as u64), - RibIR::EqualTo => Instruction::EqualTo(EqualTo {}), - RibIR::GreaterThan => Instruction::GreaterThan(GreaterThan {}), - RibIR::LessThan => Instruction::LessThan(LessThan {}), - RibIR::GreaterThanOrEqualTo => { - Instruction::GreaterThanOrEqualTo(GreaterThanOrEqualTo {}) - } - RibIR::LessThanOrEqualTo => Instruction::LessThanOrEqualTo(LessThanOrEqualTo {}), - RibIR::JumpIfFalse(value) => Instruction::JumpIfFalse(JumpInstruction { - instruction_id: value.index as u64, - }), - RibIR::Jump(value) => Instruction::Jump(JumpInstruction { - instruction_id: value.index as u64, - }), - RibIR::Label(value) => Instruction::Label(JumpInstruction { - instruction_id: value.index as u64, - }), - RibIR::Deconstruct => Instruction::Deconstruct((&AnalysedType::Str(TypeStr)).into()), //TODO; remove type in deconstruct from protobuf - RibIR::InvokeFunction(arg_count, return_type) => { - let typ = match return_type { - AnalysedTypeWithUnit::Unit => None, - AnalysedTypeWithUnit::Type(analysed_type) => { - let typ = golem_wasm_ast::analysis::protobuf::Type::from(&analysed_type); - Some(typ) - } - }; + Ok(RibIR::PushVariant( + variant_construction.variant_name, + analysed_variant_type, + )) + } + Instruction::EnumConstruction(enum_construction) => { + let enum_type = enum_construction + .return_type + .ok_or("Missing return_type for enum construction".to_string())?; - Instruction::Call(CallInstruction { - argument_count: arg_count as u64, - return_type: typ, - }) - } - RibIR::PushVariant(name, return_type) => { - let typ = golem_wasm_ast::analysis::protobuf::Type::from(&return_type); + let analysed_enum_type = (&enum_type) + .try_into() + .map_err(|_| "Failed to convert AnalysedType".to_string())?; - Instruction::VariantConstruction( - golem_api_grpc::proto::golem::rib::VariantConstructionInstruction { - variant_name: name, - return_type: Some(typ), - }, - ) + Ok(RibIR::PushEnum( + enum_construction.enum_name, + analysed_enum_type, + )) + } + Instruction::Throw(value) => Ok(RibIR::Throw(value)), + Instruction::PushFlag(flag) => { + let flag: ValueAndType = flag.try_into()?; + Ok(RibIR::PushFlag(flag)) + } + Instruction::GetTag(_) => Ok(RibIR::GetTag), + Instruction::PushTuple(tuple_instruction) => { + let tuple_type = tuple_instruction + .tuple_type + .ok_or("Missing tuple_type".to_string()) + .and_then(|t| { + (&t).try_into() + .map_err(|_| "Failed to convert AnalysedType".to_string()) + })?; + + Ok(RibIR::PushTuple( + tuple_type, + tuple_instruction.tuple_size as usize, + )) + } + Instruction::Negate(_) => Ok(RibIR::Negate), + Instruction::Concat(concat_instruction) => { + Ok(RibIR::Concat(concat_instruction.arg_size as usize)) + } + Instruction::CreateFunctionName(instruction) => { + let parsed_site = instruction.site.ok_or("Missing site".to_string())?; + let parsed_function_site = ParsedFunctionSite::try_from(parsed_site)?; + + let reference_type = instruction + .function_reference_details + .ok_or("Missing reference_type".to_string())?; + let function_reference_type = reference_type.try_into()?; + + Ok(RibIR::CreateFunctionName( + parsed_function_site, + function_reference_type, + )) + } + Instruction::ListToIterator(_) => Ok(RibIR::ListToIterator), + Instruction::CreateSink(create_sink) => { + let result = create_sink + .list_type + .ok_or("Sink list type not present".to_string()) + .and_then(|t| { + (&t).try_into() + .map_err(|_| "Failed to convert AnalysedType".to_string()) + })?; + + Ok(RibIR::CreateSink(result)) + } + Instruction::AdvanceIterator(_) => Ok(RibIR::AdvanceIterator), + Instruction::SinkToList(_) => Ok(RibIR::SinkToList), + Instruction::PushToSink(_) => Ok(RibIR::PushToSink), } - RibIR::PushEnum(name, return_type) => { - let typ = golem_wasm_ast::analysis::protobuf::Type::from(&return_type); + } + } - Instruction::EnumConstruction( - golem_api_grpc::proto::golem::rib::EnumConstructionInstruction { - enum_name: name, - return_type: Some(typ), - }, - ) - } - RibIR::Throw(msg) => Instruction::Throw(msg), - RibIR::PushFlag(flag) => { - Instruction::PushFlag(golem_wasm_rpc::protobuf::TypeAnnotatedValue { - type_annotated_value: Some(flag), - }) - } - RibIR::GetTag => Instruction::GetTag(GetTag {}), - RibIR::PushTuple(analysed_type, size) => { - let typ = golem_wasm_ast::analysis::protobuf::Type::from(&analysed_type); - - Instruction::PushTuple(PushTupleInstruction { - tuple_type: Some(typ), - tuple_size: size as u64, - }) - } - RibIR::Concat(concat) => Instruction::Concat(ConcatInstruction { - arg_size: concat as u64, - }), - RibIR::Negate => Instruction::Negate(Negate {}), - RibIR::CreateFunctionName(site, reference_type) => { - Instruction::CreateFunctionName(CreateFunctionNameInstruction { - site: Some(site.into()), - function_reference_details: Some(reference_type.into()), - }) - } + impl TryFrom for ProtoRibIR { + type Error = String; + + fn try_from(value: RibIR) -> Result { + let instruction = match value { + RibIR::PushLit(value) => { + Instruction::PushLit(golem_wasm_rpc::protobuf::TypeAnnotatedValue { + type_annotated_value: Some( + value + .try_into() + .map_err(|errs: Vec| errs.join(", "))?, + ), + }) + } + RibIR::And => Instruction::And(And {}), + RibIR::IsEmpty => Instruction::IsEmpty(IsEmpty {}), + RibIR::Or => Instruction::Or(Or {}), + RibIR::AssignVar(value) => Instruction::AssignVar(value.into()), + RibIR::LoadVar(value) => Instruction::LoadVar(value.into()), + RibIR::CreateAndPushRecord(value) => { + Instruction::CreateAndPushRecord((&value).into()) + } + RibIR::Plus(value) => Instruction::Plus((&value).into()), + RibIR::Minus(value) => Instruction::Minus((&value).into()), + RibIR::Multiply(value) => Instruction::Multiply((&value).into()), + RibIR::Divide(value) => Instruction::Divide((&value).into()), + RibIR::UpdateRecord(value) => Instruction::UpdateRecord(value), + RibIR::PushList(value, arg_size) => Instruction::PushList(PushListInstruction { + list_type: Some((&value).into()), + list_size: arg_size as u64, + }), + RibIR::PushSome(value) => Instruction::CreateSome((&value).into()), + RibIR::PushNone(value) => { + let push_none_instruction = PushNoneInstruction { + none_type: value.map(|t| (&t).into()), + }; + Instruction::CreateNone(push_none_instruction) + } + RibIR::PushOkResult(value) => Instruction::CreateOkResult((&value).into()), + RibIR::PushErrResult(value) => Instruction::CreateErrResult((&value).into()), + RibIR::SelectField(value) => Instruction::SelectField(value), + RibIR::SelectIndex(value) => Instruction::SelectIndex(value as u64), + RibIR::EqualTo => Instruction::EqualTo(EqualTo {}), + RibIR::GreaterThan => Instruction::GreaterThan(GreaterThan {}), + RibIR::LessThan => Instruction::LessThan(LessThan {}), + RibIR::GreaterThanOrEqualTo => { + Instruction::GreaterThanOrEqualTo(GreaterThanOrEqualTo {}) + } + RibIR::LessThanOrEqualTo => Instruction::LessThanOrEqualTo(LessThanOrEqualTo {}), + RibIR::JumpIfFalse(value) => Instruction::JumpIfFalse(JumpInstruction { + instruction_id: value.index as u64, + }), + RibIR::Jump(value) => Instruction::Jump(JumpInstruction { + instruction_id: value.index as u64, + }), + RibIR::Label(value) => Instruction::Label(JumpInstruction { + instruction_id: value.index as u64, + }), + RibIR::Deconstruct => { + Instruction::Deconstruct((&AnalysedType::Str(TypeStr)).into()) + } //TODO; remove type in deconstruct from protobuf + RibIR::InvokeFunction(arg_count, return_type) => { + let typ = match return_type { + AnalysedTypeWithUnit::Unit => None, + AnalysedTypeWithUnit::Type(analysed_type) => { + let typ = + golem_wasm_ast::analysis::protobuf::Type::from(&analysed_type); + Some(typ) + } + }; + + Instruction::Call(CallInstruction { + argument_count: arg_count as u64, + return_type: typ, + }) + } + RibIR::PushVariant(name, return_type) => { + let typ = golem_wasm_ast::analysis::protobuf::Type::from(&return_type); + + Instruction::VariantConstruction( + golem_api_grpc::proto::golem::rib::VariantConstructionInstruction { + variant_name: name, + return_type: Some(typ), + }, + ) + } + RibIR::PushEnum(name, return_type) => { + let typ = golem_wasm_ast::analysis::protobuf::Type::from(&return_type); + + Instruction::EnumConstruction( + golem_api_grpc::proto::golem::rib::EnumConstructionInstruction { + enum_name: name, + return_type: Some(typ), + }, + ) + } + RibIR::Throw(msg) => Instruction::Throw(msg), + RibIR::PushFlag(flag) => { + Instruction::PushFlag(golem_wasm_rpc::protobuf::TypeAnnotatedValue { + type_annotated_value: Some( + flag.try_into() + .map_err(|errs: Vec| errs.join(", "))?, + ), + }) + } + RibIR::GetTag => Instruction::GetTag(GetTag {}), + RibIR::PushTuple(analysed_type, size) => { + let typ = golem_wasm_ast::analysis::protobuf::Type::from(&analysed_type); + + Instruction::PushTuple(PushTupleInstruction { + tuple_type: Some(typ), + tuple_size: size as u64, + }) + } + RibIR::Concat(concat) => Instruction::Concat(ConcatInstruction { + arg_size: concat as u64, + }), + RibIR::Negate => Instruction::Negate(Negate {}), + RibIR::CreateFunctionName(site, reference_type) => { + Instruction::CreateFunctionName(CreateFunctionNameInstruction { + site: Some(site.into()), + function_reference_details: Some(reference_type.into()), + }) + } - RibIR::ListToIterator => { - Instruction::ListToIterator(golem_api_grpc::proto::golem::rib::ListToIterator {}) - } - RibIR::CreateSink(analysed_type) => { - Instruction::CreateSink(golem_api_grpc::proto::golem::rib::CreateSink { - list_type: Some((&analysed_type).into()), - }) - } - RibIR::AdvanceIterator => { - Instruction::AdvanceIterator(golem_api_grpc::proto::golem::rib::AdvanceIterator {}) - } - RibIR::PushToSink => { - Instruction::PushToSink(golem_api_grpc::proto::golem::rib::PushToSink {}) - } - RibIR::SinkToList => { - Instruction::SinkToList(golem_api_grpc::proto::golem::rib::SinkToList {}) - } - }; + RibIR::ListToIterator => Instruction::ListToIterator( + golem_api_grpc::proto::golem::rib::ListToIterator {}, + ), + RibIR::CreateSink(analysed_type) => { + Instruction::CreateSink(golem_api_grpc::proto::golem::rib::CreateSink { + list_type: Some((&analysed_type).into()), + }) + } + RibIR::AdvanceIterator => Instruction::AdvanceIterator( + golem_api_grpc::proto::golem::rib::AdvanceIterator {}, + ), + RibIR::PushToSink => { + Instruction::PushToSink(golem_api_grpc::proto::golem::rib::PushToSink {}) + } + RibIR::SinkToList => { + Instruction::SinkToList(golem_api_grpc::proto::golem::rib::SinkToList {}) + } + }; - ProtoRibIR { - instruction: Some(instruction), + Ok(ProtoRibIR { + instruction: Some(instruction), + }) } } } diff --git a/golem-rib/src/compiler/worker_functions_in_rib.rs b/golem-rib/src/compiler/worker_functions_in_rib.rs index 4b46b872e..8ad4d6c56 100644 --- a/golem-rib/src/compiler/worker_functions_in_rib.rs +++ b/golem-rib/src/compiler/worker_functions_in_rib.rs @@ -13,8 +13,6 @@ // limitations under the License. use crate::{FunctionTypeRegistry, InferredExpr, RegistryKey, RegistryValue}; -use golem_api_grpc::proto::golem::rib::WorkerFunctionType as WorkerFunctionTypeProto; -use golem_api_grpc::proto::golem::rib::WorkerFunctionsInRib as WorkerFunctionsInRibProto; use golem_wasm_ast::analysis::AnalysedType; // An easier data type that focus just on the side effecting function calls in Rib script. @@ -67,33 +65,6 @@ impl WorkerFunctionsInRib { } } -impl TryFrom for WorkerFunctionsInRib { - type Error = String; - - fn try_from(value: WorkerFunctionsInRibProto) -> Result { - let function_calls_proto = value.function_calls; - let function_calls = function_calls_proto - .iter() - .map(|worker_function_type_proto| { - WorkerFunctionType::try_from(worker_function_type_proto.clone()) - }) - .collect::>()?; - Ok(Self { function_calls }) - } -} - -impl From for WorkerFunctionsInRibProto { - fn from(value: WorkerFunctionsInRib) -> Self { - WorkerFunctionsInRibProto { - function_calls: value - .function_calls - .iter() - .map(|x| WorkerFunctionTypeProto::from(x.clone())) - .collect(), - } - } -} - #[derive(Debug, Clone, PartialEq, Eq)] pub struct WorkerFunctionType { pub function_key: RegistryKey, @@ -101,49 +72,84 @@ pub struct WorkerFunctionType { pub return_types: Vec, } -impl TryFrom for WorkerFunctionType { - type Error = String; - - fn try_from(value: WorkerFunctionTypeProto) -> Result { - let return_types = value - .return_types - .iter() - .map(AnalysedType::try_from) - .collect::>()?; - - let parameter_types = value - .parameter_types - .iter() - .map(AnalysedType::try_from) - .collect::>()?; - - let registry_key_proto = value.function_key.ok_or("Function key missing")?; - let function_key = RegistryKey::try_from(registry_key_proto)?; - - Ok(Self { - function_key, - return_types, - parameter_types, - }) - } -} +#[cfg(feature = "protobuf")] +mod protobuf { + use crate::{RegistryKey, WorkerFunctionType, WorkerFunctionsInRib}; + use golem_api_grpc::proto::golem::rib::WorkerFunctionType as WorkerFunctionTypeProto; + use golem_api_grpc::proto::golem::rib::WorkerFunctionsInRib as WorkerFunctionsInRibProto; + use golem_wasm_ast::analysis::AnalysedType; -impl From for WorkerFunctionTypeProto { - fn from(value: WorkerFunctionType) -> Self { - let registry_key = value.function_key.into(); + impl TryFrom for WorkerFunctionsInRib { + type Error = String; - WorkerFunctionTypeProto { - function_key: Some(registry_key), - parameter_types: value - .parameter_types + fn try_from(value: WorkerFunctionsInRibProto) -> Result { + let function_calls_proto = value.function_calls; + let function_calls = function_calls_proto .iter() - .map(|analysed_type| analysed_type.into()) - .collect(), - return_types: value + .map(|worker_function_type_proto| { + WorkerFunctionType::try_from(worker_function_type_proto.clone()) + }) + .collect::>()?; + Ok(Self { function_calls }) + } + } + + impl From for WorkerFunctionsInRibProto { + fn from(value: WorkerFunctionsInRib) -> Self { + WorkerFunctionsInRibProto { + function_calls: value + .function_calls + .iter() + .map(|x| WorkerFunctionTypeProto::from(x.clone())) + .collect(), + } + } + } + + impl TryFrom for WorkerFunctionType { + type Error = String; + + fn try_from(value: WorkerFunctionTypeProto) -> Result { + let return_types = value .return_types .iter() - .map(|analysed_type| analysed_type.into()) - .collect(), + .map(AnalysedType::try_from) + .collect::>()?; + + let parameter_types = value + .parameter_types + .iter() + .map(AnalysedType::try_from) + .collect::>()?; + + let registry_key_proto = value.function_key.ok_or("Function key missing")?; + let function_key = RegistryKey::try_from(registry_key_proto)?; + + Ok(Self { + function_key, + return_types, + parameter_types, + }) + } + } + + impl From for WorkerFunctionTypeProto { + fn from(value: WorkerFunctionType) -> Self { + let registry_key = value.function_key.into(); + + WorkerFunctionTypeProto { + function_key: Some(registry_key), + parameter_types: value + .parameter_types + .iter() + .map(|analysed_type| analysed_type.into()) + .collect(), + return_types: value + .return_types + .iter() + .map(|analysed_type| analysed_type.into()) + .collect(), + } } } } diff --git a/golem-rib/src/expr.rs b/golem-rib/src/expr.rs index 03faed293..e7eb6d73d 100644 --- a/golem-rib/src/expr.rs +++ b/golem-rib/src/expr.rs @@ -25,9 +25,8 @@ use combine::parser::char::spaces; use combine::stream::position; use combine::Parser; use combine::{eof, EasyParser}; -use golem_api_grpc::proto::golem::rib::RecordFieldArmPattern; use golem_wasm_ast::analysis::AnalysedType; -use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; +use golem_wasm_rpc::{IntoValueAndType, ValueAndType}; use serde::{Deserialize, Serialize, Serializer}; use serde_json::Value; use std::collections::VecDeque; @@ -35,7 +34,6 @@ use std::fmt::Display; use std::ops::Deref; use std::str::FromStr; -// https://github.com/golemcloud/golem/issues/1035 #[derive(Debug, Clone, PartialEq, Eq)] pub enum Expr { Let(VariableId, Option, Box, InferredType), @@ -795,18 +793,18 @@ pub struct Number { impl Eq for Number {} impl Number { - pub fn to_val(&self, analysed_type: &AnalysedType) -> Option { + pub fn to_val(&self, analysed_type: &AnalysedType) -> Option { match analysed_type { - AnalysedType::F64(_) => self.value.to_f64().map(TypeAnnotatedValue::F64), // This will result in precision loss again - AnalysedType::U64(_) => self.value.to_u64().map(TypeAnnotatedValue::U64), - AnalysedType::F32(_) => self.value.to_f32().map(TypeAnnotatedValue::F32), - AnalysedType::U32(_) => self.value.to_u32().map(TypeAnnotatedValue::U32), - AnalysedType::S32(_) => self.value.to_i32().map(TypeAnnotatedValue::S32), - AnalysedType::S64(_) => self.value.to_i64().map(TypeAnnotatedValue::S64), - AnalysedType::U8(_) => self.value.to_u32().map(TypeAnnotatedValue::U8), - AnalysedType::S8(_) => self.value.to_i32().map(TypeAnnotatedValue::S8), - AnalysedType::U16(_) => self.value.to_u32().map(TypeAnnotatedValue::U16), - AnalysedType::S16(_) => self.value.to_i32().map(TypeAnnotatedValue::S16), + AnalysedType::F64(_) => self.value.to_f64().map(|v| v.into_value_and_type()), + AnalysedType::U64(_) => self.value.to_u64().map(|v| v.into_value_and_type()), + AnalysedType::F32(_) => self.value.to_f32().map(|v| v.into_value_and_type()), + AnalysedType::U32(_) => self.value.to_u32().map(|v| v.into_value_and_type()), + AnalysedType::S32(_) => self.value.to_i32().map(|v| v.into_value_and_type()), + AnalysedType::S64(_) => self.value.to_i64().map(|v| v.into_value_and_type()), + AnalysedType::U8(_) => self.value.to_u8().map(|v| v.into_value_and_type()), + AnalysedType::S8(_) => self.value.to_i32().map(|v| v.into_value_and_type()), + AnalysedType::U16(_) => self.value.to_u16().map(|v| v.into_value_and_type()), + AnalysedType::S16(_) => self.value.to_i32().map(|v| v.into_value_and_type()), _ => None, } } @@ -985,6 +983,7 @@ impl ArmPattern { } } +#[cfg(feature = "protobuf")] impl TryFrom for Expr { type Error = String; @@ -1306,507 +1305,538 @@ impl TryFrom for Expr { } } -impl From for golem_api_grpc::proto::golem::rib::Expr { - fn from(value: Expr) -> Self { - let expr = match value { - Expr::Let(variable_id, type_name, expr, _) => { - Some(golem_api_grpc::proto::golem::rib::expr::Expr::Let( - Box::new(golem_api_grpc::proto::golem::rib::LetExpr { - name: variable_id.name().to_string(), - expr: Some(Box::new((*expr).into())), - type_name: type_name.map(|t| t.into()), - }), - )) - } - Expr::SelectField(expr, field, _) => { - Some(golem_api_grpc::proto::golem::rib::expr::Expr::SelectField( - Box::new(golem_api_grpc::proto::golem::rib::SelectFieldExpr { - expr: Some(Box::new((*expr).into())), - field, - }), - )) - } - Expr::SelectIndex(expr, index, _) => { - Some(golem_api_grpc::proto::golem::rib::expr::Expr::SelectIndex( - Box::new(golem_api_grpc::proto::golem::rib::SelectIndexExpr { +impl Display for Expr { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", text::to_string(self).unwrap()) + } +} + +impl Display for ArmPattern { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", text::to_string_arm_pattern(self).unwrap()) + } +} + +impl<'de> Deserialize<'de> for Expr { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let value = serde_json::Value::deserialize(deserializer)?; + match value { + Value::String(expr_string) => match from_string(expr_string.as_str()) { + Ok(expr) => Ok(expr), + Err(message) => Err(serde::de::Error::custom(message.to_string())), + }, + + e => Err(serde::de::Error::custom(format!( + "Failed to deserialize expression {}", + e + ))), + } + } +} + +impl Serialize for Expr { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match text::to_string(self) { + Ok(value) => serde_json::Value::serialize(&Value::String(value), serializer), + Err(error) => Err(serde::ser::Error::custom(error.to_string())), + } + } +} + +#[cfg(feature = "protobuf")] +mod protobuf { + use crate::{ArmPattern, Expr, MatchArm}; + + impl From for golem_api_grpc::proto::golem::rib::Expr { + fn from(value: Expr) -> Self { + let expr = match value { + Expr::Let(variable_id, type_name, expr, _) => { + Some(golem_api_grpc::proto::golem::rib::expr::Expr::Let( + Box::new(golem_api_grpc::proto::golem::rib::LetExpr { + name: variable_id.name().to_string(), + expr: Some(Box::new((*expr).into())), + type_name: type_name.map(|t| t.into()), + }), + )) + } + Expr::SelectField(expr, field, _) => { + Some(golem_api_grpc::proto::golem::rib::expr::Expr::SelectField( + Box::new(golem_api_grpc::proto::golem::rib::SelectFieldExpr { + expr: Some(Box::new((*expr).into())), + field, + }), + )) + } + Expr::SelectIndex(expr, index, _) => { + Some(golem_api_grpc::proto::golem::rib::expr::Expr::SelectIndex( + Box::new(golem_api_grpc::proto::golem::rib::SelectIndexExpr { + expr: Some(Box::new((*expr).into())), + index: index as u64, + }), + )) + } + Expr::Sequence(exprs, _) => { + Some(golem_api_grpc::proto::golem::rib::expr::Expr::Sequence( + golem_api_grpc::proto::golem::rib::SequenceExpr { + exprs: exprs.into_iter().map(|expr| expr.into()).collect(), + }, + )) + } + Expr::Record(fields, _) => { + Some(golem_api_grpc::proto::golem::rib::expr::Expr::Record( + golem_api_grpc::proto::golem::rib::RecordExpr { + fields: fields + .into_iter() + .map(|(name, expr)| { + golem_api_grpc::proto::golem::rib::RecordFieldExpr { + name, + expr: Some((*expr).into()), + } + }) + .collect(), + }, + )) + } + Expr::Tuple(exprs, _) => { + Some(golem_api_grpc::proto::golem::rib::expr::Expr::Tuple( + golem_api_grpc::proto::golem::rib::TupleExpr { + exprs: exprs.into_iter().map(|expr| expr.into()).collect(), + }, + )) + } + Expr::Literal(value, _) => { + Some(golem_api_grpc::proto::golem::rib::expr::Expr::Literal( + golem_api_grpc::proto::golem::rib::LiteralExpr { value }, + )) + } + Expr::Number(number, type_name, _) => { + Some(golem_api_grpc::proto::golem::rib::expr::Expr::Number( + golem_api_grpc::proto::golem::rib::NumberExpr { + number: Some(number.value.to_string()), + float: None, + type_name: type_name.map(|t| t.into()), + }, + )) + } + Expr::Flags(values, _) => { + Some(golem_api_grpc::proto::golem::rib::expr::Expr::Flags( + golem_api_grpc::proto::golem::rib::FlagsExpr { values }, + )) + } + Expr::Identifier(variable_id, _) => { + Some(golem_api_grpc::proto::golem::rib::expr::Expr::Identifier( + golem_api_grpc::proto::golem::rib::IdentifierExpr { + name: variable_id.name(), + }, + )) + } + Expr::Boolean(value, _) => { + Some(golem_api_grpc::proto::golem::rib::expr::Expr::Boolean( + golem_api_grpc::proto::golem::rib::BooleanExpr { value }, + )) + } + Expr::Concat(exprs, _) => { + Some(golem_api_grpc::proto::golem::rib::expr::Expr::Concat( + golem_api_grpc::proto::golem::rib::ConcatExpr { + exprs: exprs.into_iter().map(|expr| expr.into()).collect(), + }, + )) + } + Expr::ExprBlock(exprs, _) => { + Some(golem_api_grpc::proto::golem::rib::expr::Expr::Multiple( + golem_api_grpc::proto::golem::rib::MultipleExpr { + exprs: exprs.into_iter().map(|expr| expr.into()).collect(), + }, + )) + } + Expr::Not(expr, _) => Some(golem_api_grpc::proto::golem::rib::expr::Expr::Not( + Box::new(golem_api_grpc::proto::golem::rib::NotExpr { expr: Some(Box::new((*expr).into())), - index: index as u64, }), - )) - } - Expr::Sequence(exprs, _) => { - Some(golem_api_grpc::proto::golem::rib::expr::Expr::Sequence( - golem_api_grpc::proto::golem::rib::SequenceExpr { - exprs: exprs.into_iter().map(|expr| expr.into()).collect(), - }, - )) - } - Expr::Record(fields, _) => Some(golem_api_grpc::proto::golem::rib::expr::Expr::Record( - golem_api_grpc::proto::golem::rib::RecordExpr { - fields: fields - .into_iter() - .map( - |(name, expr)| golem_api_grpc::proto::golem::rib::RecordFieldExpr { - name, - expr: Some((*expr).into()), - }, - ) - .collect(), - }, - )), - Expr::Tuple(exprs, _) => Some(golem_api_grpc::proto::golem::rib::expr::Expr::Tuple( - golem_api_grpc::proto::golem::rib::TupleExpr { - exprs: exprs.into_iter().map(|expr| expr.into()).collect(), - }, - )), - Expr::Literal(value, _) => { - Some(golem_api_grpc::proto::golem::rib::expr::Expr::Literal( - golem_api_grpc::proto::golem::rib::LiteralExpr { value }, - )) - } - Expr::Number(number, type_name, _) => { - Some(golem_api_grpc::proto::golem::rib::expr::Expr::Number( - golem_api_grpc::proto::golem::rib::NumberExpr { - number: Some(number.value.to_string()), - float: None, - type_name: type_name.map(|t| t.into()), - }, - )) - } - Expr::Flags(values, _) => Some(golem_api_grpc::proto::golem::rib::expr::Expr::Flags( - golem_api_grpc::proto::golem::rib::FlagsExpr { values }, - )), - Expr::Identifier(variable_id, _) => { - Some(golem_api_grpc::proto::golem::rib::expr::Expr::Identifier( - golem_api_grpc::proto::golem::rib::IdentifierExpr { - name: variable_id.name(), - }, - )) - } - Expr::Boolean(value, _) => { - Some(golem_api_grpc::proto::golem::rib::expr::Expr::Boolean( - golem_api_grpc::proto::golem::rib::BooleanExpr { value }, - )) - } - Expr::Concat(exprs, _) => Some(golem_api_grpc::proto::golem::rib::expr::Expr::Concat( - golem_api_grpc::proto::golem::rib::ConcatExpr { - exprs: exprs.into_iter().map(|expr| expr.into()).collect(), - }, - )), - Expr::ExprBlock(exprs, _) => { - Some(golem_api_grpc::proto::golem::rib::expr::Expr::Multiple( - golem_api_grpc::proto::golem::rib::MultipleExpr { - exprs: exprs.into_iter().map(|expr| expr.into()).collect(), - }, - )) - } - Expr::Not(expr, _) => Some(golem_api_grpc::proto::golem::rib::expr::Expr::Not( - Box::new(golem_api_grpc::proto::golem::rib::NotExpr { - expr: Some(Box::new((*expr).into())), - }), - )), - Expr::GreaterThan(left, right, _) => { - Some(golem_api_grpc::proto::golem::rib::expr::Expr::GreaterThan( - Box::new(golem_api_grpc::proto::golem::rib::GreaterThanExpr { - left: Some(Box::new((*left).into())), - right: Some(Box::new((*right).into())), - }), - )) - } - Expr::GreaterThanOrEqualTo(left, right, _) => Some( - golem_api_grpc::proto::golem::rib::expr::Expr::GreaterThanOrEqual(Box::new( - golem_api_grpc::proto::golem::rib::GreaterThanOrEqualToExpr { - left: Some(Box::new((*left).into())), - right: Some(Box::new((*right).into())), - }, )), - ), - Expr::LessThan(left, right, _) => { - Some(golem_api_grpc::proto::golem::rib::expr::Expr::LessThan( - Box::new(golem_api_grpc::proto::golem::rib::LessThanExpr { - left: Some(Box::new((*left).into())), - right: Some(Box::new((*right).into())), - }), - )) - } - Expr::Plus(left, right, _) => Some(golem_api_grpc::proto::golem::rib::expr::Expr::Add( - Box::new(golem_api_grpc::proto::golem::rib::AddExpr { - left: Some(Box::new((*left).into())), - right: Some(Box::new((*right).into())), - }), - )), - Expr::Minus(left, right, _) => { - Some(golem_api_grpc::proto::golem::rib::expr::Expr::Subtract( - Box::new(golem_api_grpc::proto::golem::rib::SubtractExpr { - left: Some(Box::new((*left).into())), - right: Some(Box::new((*right).into())), - }), - )) - } - Expr::Divide(left, right, _) => { - Some(golem_api_grpc::proto::golem::rib::expr::Expr::Divide( - Box::new(golem_api_grpc::proto::golem::rib::DivideExpr { - left: Some(Box::new((*left).into())), - right: Some(Box::new((*right).into())), - }), - )) - } - Expr::Multiply(left, right, _) => { - Some(golem_api_grpc::proto::golem::rib::expr::Expr::Multiply( - Box::new(golem_api_grpc::proto::golem::rib::MultiplyExpr { - left: Some(Box::new((*left).into())), - right: Some(Box::new((*right).into())), - }), - )) - } - Expr::LessThanOrEqualTo(left, right, _) => Some( - golem_api_grpc::proto::golem::rib::expr::Expr::LessThanOrEqual(Box::new( - golem_api_grpc::proto::golem::rib::LessThanOrEqualToExpr { - left: Some(Box::new((*left).into())), - right: Some(Box::new((*right).into())), - }, - )), - ), - Expr::EqualTo(left, right, _) => { - Some(golem_api_grpc::proto::golem::rib::expr::Expr::EqualTo( - Box::new(golem_api_grpc::proto::golem::rib::EqualToExpr { - left: Some(Box::new((*left).into())), - right: Some(Box::new((*right).into())), - }), - )) - } - Expr::Cond(left, cond, right, _) => { - Some(golem_api_grpc::proto::golem::rib::expr::Expr::Cond( - Box::new(golem_api_grpc::proto::golem::rib::CondExpr { - left: Some(Box::new((*left).into())), - cond: Some(Box::new((*cond).into())), - right: Some(Box::new((*right).into())), - }), - )) - } - Expr::PatternMatch(expr, arms, _) => { - Some(golem_api_grpc::proto::golem::rib::expr::Expr::PatternMatch( - Box::new(golem_api_grpc::proto::golem::rib::PatternMatchExpr { + Expr::GreaterThan(left, right, _) => { + Some(golem_api_grpc::proto::golem::rib::expr::Expr::GreaterThan( + Box::new(golem_api_grpc::proto::golem::rib::GreaterThanExpr { + left: Some(Box::new((*left).into())), + right: Some(Box::new((*right).into())), + }), + )) + } + Expr::GreaterThanOrEqualTo(left, right, _) => Some( + golem_api_grpc::proto::golem::rib::expr::Expr::GreaterThanOrEqual(Box::new( + golem_api_grpc::proto::golem::rib::GreaterThanOrEqualToExpr { + left: Some(Box::new((*left).into())), + right: Some(Box::new((*right).into())), + }, + )), + ), + Expr::LessThan(left, right, _) => { + Some(golem_api_grpc::proto::golem::rib::expr::Expr::LessThan( + Box::new(golem_api_grpc::proto::golem::rib::LessThanExpr { + left: Some(Box::new((*left).into())), + right: Some(Box::new((*right).into())), + }), + )) + } + Expr::Plus(left, right, _) => { + Some(golem_api_grpc::proto::golem::rib::expr::Expr::Add( + Box::new(golem_api_grpc::proto::golem::rib::AddExpr { + left: Some(Box::new((*left).into())), + right: Some(Box::new((*right).into())), + }), + )) + } + Expr::Minus(left, right, _) => { + Some(golem_api_grpc::proto::golem::rib::expr::Expr::Subtract( + Box::new(golem_api_grpc::proto::golem::rib::SubtractExpr { + left: Some(Box::new((*left).into())), + right: Some(Box::new((*right).into())), + }), + )) + } + Expr::Divide(left, right, _) => { + Some(golem_api_grpc::proto::golem::rib::expr::Expr::Divide( + Box::new(golem_api_grpc::proto::golem::rib::DivideExpr { + left: Some(Box::new((*left).into())), + right: Some(Box::new((*right).into())), + }), + )) + } + Expr::Multiply(left, right, _) => { + Some(golem_api_grpc::proto::golem::rib::expr::Expr::Multiply( + Box::new(golem_api_grpc::proto::golem::rib::MultiplyExpr { + left: Some(Box::new((*left).into())), + right: Some(Box::new((*right).into())), + }), + )) + } + Expr::LessThanOrEqualTo(left, right, _) => Some( + golem_api_grpc::proto::golem::rib::expr::Expr::LessThanOrEqual(Box::new( + golem_api_grpc::proto::golem::rib::LessThanOrEqualToExpr { + left: Some(Box::new((*left).into())), + right: Some(Box::new((*right).into())), + }, + )), + ), + Expr::EqualTo(left, right, _) => { + Some(golem_api_grpc::proto::golem::rib::expr::Expr::EqualTo( + Box::new(golem_api_grpc::proto::golem::rib::EqualToExpr { + left: Some(Box::new((*left).into())), + right: Some(Box::new((*right).into())), + }), + )) + } + Expr::Cond(left, cond, right, _) => { + Some(golem_api_grpc::proto::golem::rib::expr::Expr::Cond( + Box::new(golem_api_grpc::proto::golem::rib::CondExpr { + left: Some(Box::new((*left).into())), + cond: Some(Box::new((*cond).into())), + right: Some(Box::new((*right).into())), + }), + )) + } + Expr::PatternMatch(expr, arms, _) => { + Some(golem_api_grpc::proto::golem::rib::expr::Expr::PatternMatch( + Box::new(golem_api_grpc::proto::golem::rib::PatternMatchExpr { + expr: Some(Box::new((*expr).into())), + patterns: arms.into_iter().map(|a| a.into()).collect(), + }), + )) + } + Expr::Option(expr, _) => { + Some(golem_api_grpc::proto::golem::rib::expr::Expr::Option( + Box::new(golem_api_grpc::proto::golem::rib::OptionExpr { + expr: expr.map(|expr| Box::new((*expr).into())), + }), + )) + } + Expr::Result(expr, _) => { + let result = match expr { + Ok(expr) => golem_api_grpc::proto::golem::rib::result_expr::Result::Ok( + Box::new((*expr).into()), + ), + Err(expr) => golem_api_grpc::proto::golem::rib::result_expr::Result::Err( + Box::new((*expr).into()), + ), + }; + + Some(golem_api_grpc::proto::golem::rib::expr::Expr::Result( + Box::new(golem_api_grpc::proto::golem::rib::ResultExpr { + result: Some(result), + }), + )) + } + Expr::Call(function_name, args, _) => { + Some(golem_api_grpc::proto::golem::rib::expr::Expr::Call( + golem_api_grpc::proto::golem::rib::CallExpr { + name: None, + params: args.into_iter().map(|expr| expr.into()).collect(), + call_type: Some(function_name.into()), + }, + )) + } + Expr::Unwrap(expr, _) => { + Some(golem_api_grpc::proto::golem::rib::expr::Expr::Unwrap( + Box::new(golem_api_grpc::proto::golem::rib::UnwrapExpr { + expr: Some(Box::new((*expr).into())), + }), + )) + } + Expr::Throw(message, _) => { + Some(golem_api_grpc::proto::golem::rib::expr::Expr::Throw( + golem_api_grpc::proto::golem::rib::ThrowExpr { message }, + )) + } + Expr::GetTag(expr, _) => Some(golem_api_grpc::proto::golem::rib::expr::Expr::Tag( + Box::new(golem_api_grpc::proto::golem::rib::GetTagExpr { expr: Some(Box::new((*expr).into())), - patterns: arms.into_iter().map(|a| a.into()).collect(), }), - )) - } - Expr::Option(expr, _) => Some(golem_api_grpc::proto::golem::rib::expr::Expr::Option( - Box::new(golem_api_grpc::proto::golem::rib::OptionExpr { - expr: expr.map(|expr| Box::new((*expr).into())), - }), - )), - Expr::Result(expr, _) => { - let result = match expr { - Ok(expr) => golem_api_grpc::proto::golem::rib::result_expr::Result::Ok( - Box::new((*expr).into()), - ), - Err(expr) => golem_api_grpc::proto::golem::rib::result_expr::Result::Err( - Box::new((*expr).into()), - ), - }; + )), + Expr::And(left, right, _) => { + Some(golem_api_grpc::proto::golem::rib::expr::Expr::And( + Box::new(golem_api_grpc::proto::golem::rib::AndExpr { + left: Some(Box::new((*left).into())), + right: Some(Box::new((*right).into())), + }), + )) + } - Some(golem_api_grpc::proto::golem::rib::expr::Expr::Result( - Box::new(golem_api_grpc::proto::golem::rib::ResultExpr { - result: Some(result), - }), - )) - } - Expr::Call(function_name, args, _) => { - Some(golem_api_grpc::proto::golem::rib::expr::Expr::Call( - golem_api_grpc::proto::golem::rib::CallExpr { - name: None, - params: args.into_iter().map(|expr| expr.into()).collect(), - call_type: Some(function_name.into()), - }, - )) - } - Expr::Unwrap(expr, _) => Some(golem_api_grpc::proto::golem::rib::expr::Expr::Unwrap( - Box::new(golem_api_grpc::proto::golem::rib::UnwrapExpr { - expr: Some(Box::new((*expr).into())), - }), - )), - Expr::Throw(message, _) => Some(golem_api_grpc::proto::golem::rib::expr::Expr::Throw( - golem_api_grpc::proto::golem::rib::ThrowExpr { message }, - )), - Expr::GetTag(expr, _) => Some(golem_api_grpc::proto::golem::rib::expr::Expr::Tag( - Box::new(golem_api_grpc::proto::golem::rib::GetTagExpr { - expr: Some(Box::new((*expr).into())), - }), - )), - Expr::And(left, right, _) => Some(golem_api_grpc::proto::golem::rib::expr::Expr::And( - Box::new(golem_api_grpc::proto::golem::rib::AndExpr { - left: Some(Box::new((*left).into())), - right: Some(Box::new((*right).into())), - }), - )), - - Expr::Or(left, right, _) => Some(golem_api_grpc::proto::golem::rib::expr::Expr::Or( - Box::new(golem_api_grpc::proto::golem::rib::OrExpr { - left: Some(Box::new((*left).into())), - right: Some(Box::new((*right).into())), - }), - )), - Expr::ListComprehension { - iterated_variable, - iterable_expr, - yield_expr, - .. - } => Some( - golem_api_grpc::proto::golem::rib::expr::Expr::ListComprehension(Box::new( - golem_api_grpc::proto::golem::rib::ListComprehensionExpr { + Expr::Or(left, right, _) => { + Some(golem_api_grpc::proto::golem::rib::expr::Expr::Or(Box::new( + golem_api_grpc::proto::golem::rib::OrExpr { + left: Some(Box::new((*left).into())), + right: Some(Box::new((*right).into())), + }, + ))) + } + Expr::ListComprehension { + iterated_variable, + iterable_expr, + yield_expr, + .. + } => Some( + golem_api_grpc::proto::golem::rib::expr::Expr::ListComprehension(Box::new( + golem_api_grpc::proto::golem::rib::ListComprehensionExpr { + iterated_variable: iterated_variable.name(), + iterable_expr: Some(Box::new((*iterable_expr).into())), + yield_expr: Some(Box::new((*yield_expr).into())), + }, + )), + ), + + Expr::ListReduce { + reduce_variable, + iterated_variable, + iterable_expr, + yield_expr, + init_value_expr, + .. + } => Some(golem_api_grpc::proto::golem::rib::expr::Expr::ListReduce( + Box::new(golem_api_grpc::proto::golem::rib::ListReduceExpr { + reduce_variable: reduce_variable.name(), iterated_variable: iterated_variable.name(), iterable_expr: Some(Box::new((*iterable_expr).into())), + init_value_expr: Some(Box::new((*init_value_expr).into())), yield_expr: Some(Box::new((*yield_expr).into())), - }, + }), )), - ), - - Expr::ListReduce { - reduce_variable, - iterated_variable, - iterable_expr, - yield_expr, - init_value_expr, - .. - } => Some(golem_api_grpc::proto::golem::rib::expr::Expr::ListReduce( - Box::new(golem_api_grpc::proto::golem::rib::ListReduceExpr { - reduce_variable: reduce_variable.name(), - iterated_variable: iterated_variable.name(), - iterable_expr: Some(Box::new((*iterable_expr).into())), - init_value_expr: Some(Box::new((*init_value_expr).into())), - yield_expr: Some(Box::new((*yield_expr).into())), - }), - )), - }; + }; - golem_api_grpc::proto::golem::rib::Expr { expr } + golem_api_grpc::proto::golem::rib::Expr { expr } + } } -} -impl TryFrom for ArmPattern { - type Error = String; + impl TryFrom for ArmPattern { + type Error = String; - fn try_from(value: golem_api_grpc::proto::golem::rib::ArmPattern) -> Result { - let pattern = value.pattern.ok_or("Missing pattern")?; - match pattern { - golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::WildCard(_) => { - Ok(ArmPattern::WildCard) - } - golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::As(asp) => { - let name = asp.name; - let pattern = asp.pattern.ok_or("Missing pattern")?; - Ok(ArmPattern::As(name, Box::new((*pattern).try_into()?))) - } - golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::Constructor( - golem_api_grpc::proto::golem::rib::ConstructorArmPattern { name, patterns }, - ) => { - let patterns = patterns - .into_iter() - .map(ArmPattern::try_from) - .collect::, _>>()?; - Ok(ArmPattern::Constructor(name, patterns)) - } - golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::TupleConstructor( - golem_api_grpc::proto::golem::rib::TupleConstructorArmPattern { patterns }, - ) => { - let patterns = patterns - .into_iter() - .map(ArmPattern::try_from) - .collect::, _>>()?; - Ok(ArmPattern::TupleConstructor(patterns)) - } - golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::Literal( - golem_api_grpc::proto::golem::rib::LiteralArmPattern { expr }, - ) => { - let inner = expr.ok_or("Missing expr")?; - Ok(ArmPattern::Literal(Box::new(inner.try_into()?))) - } - golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::RecordConstructor( - golem_api_grpc::proto::golem::rib::RecordConstructorArmPattern { fields }, - ) => { - let fields = fields - .into_iter() - .map(|field| { - let name = field.name; - let proto_pattern = field.pattern.ok_or("Missing pattern")?; - let arm_pattern = ArmPattern::try_from(proto_pattern)?; - Ok((name, arm_pattern)) - }) - .collect::, String>>()?; - Ok(ArmPattern::RecordConstructor(fields)) - } - golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::ListConstructor( - golem_api_grpc::proto::golem::rib::ListConstructorArmPattern { patterns }, - ) => { - let patterns = patterns - .into_iter() - .map(ArmPattern::try_from) - .collect::, _>>()?; - Ok(ArmPattern::ListConstructor(patterns)) + fn try_from( + value: golem_api_grpc::proto::golem::rib::ArmPattern, + ) -> Result { + let pattern = value.pattern.ok_or("Missing pattern")?; + match pattern { + golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::WildCard(_) => { + Ok(ArmPattern::WildCard) + } + golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::As(asp) => { + let name = asp.name; + let pattern = asp.pattern.ok_or("Missing pattern")?; + Ok(ArmPattern::As(name, Box::new((*pattern).try_into()?))) + } + golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::Constructor( + golem_api_grpc::proto::golem::rib::ConstructorArmPattern { name, patterns }, + ) => { + let patterns = patterns + .into_iter() + .map(ArmPattern::try_from) + .collect::, _>>()?; + Ok(ArmPattern::Constructor(name, patterns)) + } + golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::TupleConstructor( + golem_api_grpc::proto::golem::rib::TupleConstructorArmPattern { patterns }, + ) => { + let patterns = patterns + .into_iter() + .map(ArmPattern::try_from) + .collect::, _>>()?; + Ok(ArmPattern::TupleConstructor(patterns)) + } + golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::Literal( + golem_api_grpc::proto::golem::rib::LiteralArmPattern { expr }, + ) => { + let inner = expr.ok_or("Missing expr")?; + Ok(ArmPattern::Literal(Box::new(inner.try_into()?))) + } + golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::RecordConstructor( + golem_api_grpc::proto::golem::rib::RecordConstructorArmPattern { fields }, + ) => { + let fields = fields + .into_iter() + .map(|field| { + let name = field.name; + let proto_pattern = field.pattern.ok_or("Missing pattern")?; + let arm_pattern = ArmPattern::try_from(proto_pattern)?; + Ok((name, arm_pattern)) + }) + .collect::, String>>()?; + Ok(ArmPattern::RecordConstructor(fields)) + } + golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::ListConstructor( + golem_api_grpc::proto::golem::rib::ListConstructorArmPattern { patterns }, + ) => { + let patterns = patterns + .into_iter() + .map(ArmPattern::try_from) + .collect::, _>>()?; + Ok(ArmPattern::ListConstructor(patterns)) + } } } } -} -impl From for golem_api_grpc::proto::golem::rib::ArmPattern { - fn from(value: ArmPattern) -> Self { - match value { - ArmPattern::WildCard => golem_api_grpc::proto::golem::rib::ArmPattern { - pattern: Some( - golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::WildCard( - golem_api_grpc::proto::golem::rib::WildCardArmPattern {}, - ), - ), - }, - ArmPattern::As(name, pattern) => golem_api_grpc::proto::golem::rib::ArmPattern { - pattern: Some(golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::As( - Box::new(golem_api_grpc::proto::golem::rib::AsArmPattern { - name, - pattern: Some(Box::new((*pattern).into())), - }), - )), - }, - ArmPattern::Constructor(name, patterns) => { - golem_api_grpc::proto::golem::rib::ArmPattern { + impl From for golem_api_grpc::proto::golem::rib::ArmPattern { + fn from(value: ArmPattern) -> Self { + match value { + ArmPattern::WildCard => golem_api_grpc::proto::golem::rib::ArmPattern { pattern: Some( - golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::Constructor( - golem_api_grpc::proto::golem::rib::ConstructorArmPattern { - name, - patterns: patterns - .into_iter() - .map(golem_api_grpc::proto::golem::rib::ArmPattern::from) - .collect(), - }, + golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::WildCard( + golem_api_grpc::proto::golem::rib::WildCardArmPattern {}, ), ), + }, + ArmPattern::As(name, pattern) => golem_api_grpc::proto::golem::rib::ArmPattern { + pattern: Some(golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::As( + Box::new(golem_api_grpc::proto::golem::rib::AsArmPattern { + name, + pattern: Some(Box::new((*pattern).into())), + }), + )), + }, + ArmPattern::Constructor(name, patterns) => { + golem_api_grpc::proto::golem::rib::ArmPattern { + pattern: Some( + golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::Constructor( + golem_api_grpc::proto::golem::rib::ConstructorArmPattern { + name, + patterns: patterns + .into_iter() + .map(golem_api_grpc::proto::golem::rib::ArmPattern::from) + .collect(), + }, + ), + ), + } } - } - ArmPattern::Literal(expr) => golem_api_grpc::proto::golem::rib::ArmPattern { - pattern: Some( - golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::Literal( - golem_api_grpc::proto::golem::rib::LiteralArmPattern { - expr: Some((*expr).into()), - }, - ), - ), - }, - - ArmPattern::TupleConstructor(patterns) => { - golem_api_grpc::proto::golem::rib::ArmPattern { + ArmPattern::Literal(expr) => golem_api_grpc::proto::golem::rib::ArmPattern { pattern: Some( - golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::TupleConstructor( - golem_api_grpc::proto::golem::rib::TupleConstructorArmPattern { - patterns: patterns - .into_iter() - .map(golem_api_grpc::proto::golem::rib::ArmPattern::from) - .collect(), + golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::Literal( + golem_api_grpc::proto::golem::rib::LiteralArmPattern { + expr: Some((*expr).into()), }, ), ), + }, + + ArmPattern::TupleConstructor(patterns) => { + golem_api_grpc::proto::golem::rib::ArmPattern { + pattern: Some( + golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::TupleConstructor( + golem_api_grpc::proto::golem::rib::TupleConstructorArmPattern { + patterns: patterns + .into_iter() + .map(golem_api_grpc::proto::golem::rib::ArmPattern::from) + .collect(), + }, + ), + ), + } } - } - ArmPattern::RecordConstructor(fields) => { - golem_api_grpc::proto::golem::rib::ArmPattern { - pattern: Some( - golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::RecordConstructor( - golem_api_grpc::proto::golem::rib::RecordConstructorArmPattern { - fields: fields - .into_iter() - .map(|(name, pattern)| RecordFieldArmPattern { - name, - pattern: Some(pattern.into()), - }) - .collect(), - }, + ArmPattern::RecordConstructor(fields) => { + golem_api_grpc::proto::golem::rib::ArmPattern { + pattern: Some( + golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::RecordConstructor( + golem_api_grpc::proto::golem::rib::RecordConstructorArmPattern { + fields: fields + .into_iter() + .map(|(name, pattern)| { + golem_api_grpc::proto::golem::rib::RecordFieldArmPattern { + name, + pattern: Some(pattern.into()), + } + }) + .collect(), + }, + ), ), - ), + } } - } - ArmPattern::ListConstructor(patterns) => { - golem_api_grpc::proto::golem::rib::ArmPattern { - pattern: Some( - golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::ListConstructor( - golem_api_grpc::proto::golem::rib::ListConstructorArmPattern { - patterns: patterns - .into_iter() - .map(golem_api_grpc::proto::golem::rib::ArmPattern::from) - .collect(), - }, + ArmPattern::ListConstructor(patterns) => { + golem_api_grpc::proto::golem::rib::ArmPattern { + pattern: Some( + golem_api_grpc::proto::golem::rib::arm_pattern::Pattern::ListConstructor( + golem_api_grpc::proto::golem::rib::ListConstructorArmPattern { + patterns: patterns + .into_iter() + .map(golem_api_grpc::proto::golem::rib::ArmPattern::from) + .collect(), + }, + ), ), - ), + } } } } } -} - -impl TryFrom for MatchArm { - type Error = String; - - fn try_from(value: golem_api_grpc::proto::golem::rib::MatchArm) -> Result { - let pattern = value.pattern.ok_or("Missing pattern")?; - let expr = value.expr.ok_or("Missing expr")?; - Ok(MatchArm::new(pattern.try_into()?, expr.try_into()?)) - } -} - -impl From for golem_api_grpc::proto::golem::rib::MatchArm { - fn from(value: MatchArm) -> Self { - let MatchArm { - arm_pattern, - arm_resolution_expr, - } = value; - golem_api_grpc::proto::golem::rib::MatchArm { - pattern: Some(arm_pattern.into()), - expr: Some((*arm_resolution_expr).into()), - } - } -} - -impl Display for Expr { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", text::to_string(self).unwrap()) - } -} -impl Display for ArmPattern { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", text::to_string_arm_pattern(self).unwrap()) - } -} + impl TryFrom for MatchArm { + type Error = String; -impl<'de> Deserialize<'de> for Expr { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let value = serde_json::Value::deserialize(deserializer)?; - match value { - Value::String(expr_string) => match from_string(expr_string.as_str()) { - Ok(expr) => Ok(expr), - Err(message) => Err(serde::de::Error::custom(message.to_string())), - }, - - e => Err(serde::de::Error::custom(format!( - "Failed to deserialize expression {}", - e - ))), + fn try_from( + value: golem_api_grpc::proto::golem::rib::MatchArm, + ) -> Result { + let pattern = value.pattern.ok_or("Missing pattern")?; + let expr = value.expr.ok_or("Missing expr")?; + Ok(MatchArm::new(pattern.try_into()?, expr.try_into()?)) } } -} -impl Serialize for Expr { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - match text::to_string(self) { - Ok(value) => serde_json::Value::serialize(&Value::String(value), serializer), - Err(error) => Err(serde::ser::Error::custom(error.to_string())), + impl From for golem_api_grpc::proto::golem::rib::MatchArm { + fn from(value: MatchArm) -> Self { + let MatchArm { + arm_pattern, + arm_resolution_expr, + } = value; + golem_api_grpc::proto::golem::rib::MatchArm { + pattern: Some(arm_pattern.into()), + expr: Some((*arm_resolution_expr).into()), + } } } } diff --git a/golem-rib/src/function_name.rs b/golem-rib/src/function_name.rs index 9b66d201e..41f1b09c4 100644 --- a/golem-rib/src/function_name.rs +++ b/golem-rib/src/function_name.rs @@ -16,11 +16,7 @@ use crate::Expr; use bincode::{BorrowDecode, Decode, Encode}; use combine::stream::easy; use combine::EasyParser; -use golem_api_grpc::proto::golem::rib::dynamic_parsed_function_reference::FunctionReference as ProtoDynamicFunctionReference; -use golem_wasm_ast::analysis::AnalysedType; -use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; -use golem_wasm_rpc::type_annotated_value_from_str; -use golem_wasm_rpc::Value; +use golem_wasm_rpc::{parse_value_and_type, ValueAndType}; use semver::{BuildMetadata, Prerelease}; use serde::{Deserialize, Serialize}; use std::borrow::Cow; @@ -112,33 +108,6 @@ impl<'de> BorrowDecode<'de> for SemVer { } } -impl TryFrom for SemVer { - type Error = String; - - fn try_from(value: golem_api_grpc::proto::golem::rib::SemVersion) -> Result { - Ok(SemVer(semver::Version { - major: value.major, - minor: value.minor, - patch: value.patch, - pre: Prerelease::new(&value.pre).map_err(|_| "Invalid prerelease".to_string())?, - build: BuildMetadata::new(&value.build) - .map_err(|_| "Invalid build metadata".to_string())?, - })) - } -} - -impl From for golem_api_grpc::proto::golem::rib::SemVersion { - fn from(value: SemVer) -> Self { - golem_api_grpc::proto::golem::rib::SemVersion { - major: value.0.major, - minor: value.0.minor, - patch: value.0.patch, - pre: value.0.pre.to_string(), - build: value.0.build.to_string(), - } - } -} - impl ParsedFunctionSite { pub fn interface_name(&self) -> Option { match self { @@ -160,75 +129,6 @@ impl ParsedFunctionSite { } } -impl TryFrom for ParsedFunctionSite { - type Error = String; - - fn try_from( - value: golem_api_grpc::proto::golem::rib::ParsedFunctionSite, - ) -> Result { - let site = value.site.ok_or("Missing site".to_string())?; - match site { - golem_api_grpc::proto::golem::rib::parsed_function_site::Site::Global(_) => { - Ok(Self::Global) - } - golem_api_grpc::proto::golem::rib::parsed_function_site::Site::Interface( - golem_api_grpc::proto::golem::rib::InterfaceFunctionSite { name }, - ) => Ok(Self::Interface { name }), - golem_api_grpc::proto::golem::rib::parsed_function_site::Site::PackageInterface( - golem_api_grpc::proto::golem::rib::PackageInterfaceFunctionSite { - namespace, - package, - interface, - version, - }, - ) => { - let version = match version { - Some(version) => Some(version.try_into()?), - None => None, - }; - - Ok(Self::PackagedInterface { - namespace, - package, - interface, - version, - }) - } - } - } -} - -impl From for golem_api_grpc::proto::golem::rib::ParsedFunctionSite { - fn from(value: ParsedFunctionSite) -> Self { - let site = match value { - ParsedFunctionSite::Global => { - golem_api_grpc::proto::golem::rib::parsed_function_site::Site::Global( - golem_api_grpc::proto::golem::rib::GlobalFunctionSite {}, - ) - } - ParsedFunctionSite::Interface { name } => { - golem_api_grpc::proto::golem::rib::parsed_function_site::Site::Interface( - golem_api_grpc::proto::golem::rib::InterfaceFunctionSite { name }, - ) - } - ParsedFunctionSite::PackagedInterface { - namespace, - package, - interface, - version, - } => golem_api_grpc::proto::golem::rib::parsed_function_site::Site::PackageInterface( - golem_api_grpc::proto::golem::rib::PackageInterfaceFunctionSite { - namespace, - package, - interface, - version: version.map(|v| v.into()), - }, - ), - }; - golem_api_grpc::proto::golem::rib::ParsedFunctionSite { site: Some(site) } - } -} - #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] pub enum ParsedFunctionReference { Function { @@ -566,7 +466,10 @@ impl ParsedFunctionReference { } } - pub fn resource_params(&self, types: &[AnalysedType]) -> Result>, String> { + pub fn resource_params( + &self, + types: &[golem_wasm_ast::analysis::AnalysedType], + ) -> Result>, String> { if let Some(raw_params) = self.raw_resource_params() { if raw_params.len() != types.len() { Err(format!( @@ -577,10 +480,8 @@ impl ParsedFunctionReference { } else { let mut result = Vec::new(); for (raw_param, param_type) in raw_params.iter().zip(types.iter()) { - let type_annotated_value: TypeAnnotatedValue = - type_annotated_value_from_str(param_type, raw_param)?; - let value = type_annotated_value.try_into()?; - result.push(value); + let value_and_type: ValueAndType = parse_value_and_type(param_type, raw_param)?; + result.push(value_and_type); } Ok(Some(result)) } @@ -590,304 +491,6 @@ impl ParsedFunctionReference { } } -impl From - for golem_api_grpc::proto::golem::rib::DynamicParsedFunctionReference -{ - fn from(value: DynamicParsedFunctionReference) -> Self { - let function = match value { - DynamicParsedFunctionReference::Function { function } => ProtoDynamicFunctionReference::Function( - golem_api_grpc::proto::golem::rib::FunctionFunctionReference { function }, - ), - DynamicParsedFunctionReference::RawResourceConstructor { resource } => ProtoDynamicFunctionReference::RawResourceConstructor( - golem_api_grpc::proto::golem::rib::RawResourceConstructorFunctionReference { resource }, - ), - DynamicParsedFunctionReference::RawResourceMethod { resource, method } => ProtoDynamicFunctionReference::RawResourceMethod( - golem_api_grpc::proto::golem::rib::RawResourceMethodFunctionReference { resource, method }, - ), - DynamicParsedFunctionReference::RawResourceStaticMethod { resource, method } => ProtoDynamicFunctionReference::RawResourceStaticMethod( - golem_api_grpc::proto::golem::rib::RawResourceStaticMethodFunctionReference { resource, method }, - ), - DynamicParsedFunctionReference::RawResourceDrop { resource } => ProtoDynamicFunctionReference::RawResourceDrop( - golem_api_grpc::proto::golem::rib::RawResourceDropFunctionReference { resource }, - ), - DynamicParsedFunctionReference::IndexedResourceConstructor { resource, resource_params } => ProtoDynamicFunctionReference::IndexedResourceConstructor( - golem_api_grpc::proto::golem::rib::DynamicIndexedResourceConstructorFunctionReference { - resource, - resource_params: resource_params.into_iter().map(|x| x.into()).collect(), - }, - ), - DynamicParsedFunctionReference::IndexedResourceMethod { resource, resource_params, method } => ProtoDynamicFunctionReference::IndexedResourceMethod( - golem_api_grpc::proto::golem::rib::DynamicIndexedResourceMethodFunctionReference { - resource, - resource_params: resource_params.into_iter().map(|x| x.into()).collect(), - method, - }, - ), - DynamicParsedFunctionReference::IndexedResourceStaticMethod { resource, resource_params, method } => ProtoDynamicFunctionReference::IndexedResourceStaticMethod( - golem_api_grpc::proto::golem::rib::DynamicIndexedResourceStaticMethodFunctionReference { - resource, - resource_params: resource_params.into_iter().map(|x| x.into()).collect(), - method, - }, - ), - DynamicParsedFunctionReference::IndexedResourceDrop { resource, resource_params } => ProtoDynamicFunctionReference::IndexedResourceDrop( - golem_api_grpc::proto::golem::rib::DynamicIndexedResourceDropFunctionReference { - resource, - resource_params: resource_params.into_iter().map(|x| x.into()).collect(), - }, - ), - }; - - golem_api_grpc::proto::golem::rib::DynamicParsedFunctionReference { - function_reference: Some(function), - } - } -} - -impl TryFrom - for DynamicParsedFunctionReference -{ - type Error = String; - - fn try_from( - value: golem_api_grpc::proto::golem::rib::DynamicParsedFunctionReference, - ) -> Result { - let function = value - .function_reference - .ok_or("Missing function reference".to_string())?; - - match function { - ProtoDynamicFunctionReference::Function(golem_api_grpc::proto::golem::rib::FunctionFunctionReference { - function - }) => { - Ok(Self::Function { function }) - } - ProtoDynamicFunctionReference::RawResourceConstructor(golem_api_grpc::proto::golem::rib::RawResourceConstructorFunctionReference { - resource - }) => { - Ok(Self::RawResourceConstructor { resource }) - } - ProtoDynamicFunctionReference::RawResourceMethod(golem_api_grpc::proto::golem::rib::RawResourceMethodFunctionReference { - resource, - method - }) => { - Ok(Self::RawResourceMethod { resource, method }) - } - ProtoDynamicFunctionReference::RawResourceStaticMethod(golem_api_grpc::proto::golem::rib::RawResourceStaticMethodFunctionReference { - resource, - method - }) => { - Ok(Self::RawResourceStaticMethod { resource, method }) - } - ProtoDynamicFunctionReference::RawResourceDrop(golem_api_grpc::proto::golem::rib::RawResourceDropFunctionReference { - resource - }) => { - Ok(Self::RawResourceDrop { resource }) - } - ProtoDynamicFunctionReference::IndexedResourceConstructor(golem_api_grpc::proto::golem::rib::DynamicIndexedResourceConstructorFunctionReference { - resource, - resource_params - }) => { - let resource_params: Vec = - resource_params.into_iter().map(Expr::try_from).collect::, String>>()?; - - Ok(Self::IndexedResourceConstructor { resource, resource_params }) - } - ProtoDynamicFunctionReference::IndexedResourceMethod(golem_api_grpc::proto::golem::rib::DynamicIndexedResourceMethodFunctionReference { - resource, - resource_params, - method - }) => { - let resource_params: Vec = - resource_params.into_iter().map(Expr::try_from).collect::, String>>()?; - - Ok(Self::IndexedResourceMethod { resource, resource_params, method }) - } - ProtoDynamicFunctionReference::IndexedResourceStaticMethod(golem_api_grpc::proto::golem::rib::DynamicIndexedResourceStaticMethodFunctionReference { - resource, - resource_params, - method - }) => { - let resource_params: Vec = - resource_params.into_iter().map(Expr::try_from).collect::, String>>()?; - - Ok(Self::IndexedResourceStaticMethod { resource, resource_params, method }) - } - ProtoDynamicFunctionReference::IndexedResourceDrop(golem_api_grpc::proto::golem::rib::DynamicIndexedResourceDropFunctionReference { - resource, - resource_params - }) => { - let resource_params: Vec = - resource_params.into_iter().map(Expr::try_from).collect::, String>>()?; - - Ok(Self::IndexedResourceDrop { resource, resource_params }) - } - } - } -} - -impl TryFrom - for ParsedFunctionReference -{ - type Error = String; - - fn try_from( - value: golem_api_grpc::proto::golem::rib::ParsedFunctionReference, - ) -> Result { - let function = value - .function_reference - .ok_or("Missing function".to_string())?; - match function { - golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::Function(golem_api_grpc::proto::golem::rib::FunctionFunctionReference { - function - }) => { - Ok(Self::Function { function }) - } - golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::RawResourceConstructor(golem_api_grpc::proto::golem::rib::RawResourceConstructorFunctionReference { - resource - }) => { - Ok(Self::RawResourceConstructor { resource }) - } - golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::RawResourceMethod(golem_api_grpc::proto::golem::rib::RawResourceMethodFunctionReference { - resource, - method - }) => { - Ok(Self::RawResourceMethod { resource, method }) - } - golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::RawResourceStaticMethod(golem_api_grpc::proto::golem::rib::RawResourceStaticMethodFunctionReference { - resource, - method - }) => { - Ok(Self::RawResourceStaticMethod { resource, method }) - } - golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::RawResourceDrop(golem_api_grpc::proto::golem::rib::RawResourceDropFunctionReference { - resource - }) => { - Ok(Self::RawResourceDrop { resource }) - } - golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::IndexedResourceConstructor(golem_api_grpc::proto::golem::rib::IndexedResourceConstructorFunctionReference { - resource, - resource_params - }) => { - Ok(Self::IndexedResourceConstructor { - resource, - resource_params, - }) - } - golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::IndexedResourceMethod(golem_api_grpc::proto::golem::rib::IndexedResourceMethodFunctionReference { - resource, - resource_params, - method - }) => { - Ok(Self::IndexedResourceMethod { - resource, - resource_params, - method, - }) - } - golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::IndexedResourceStaticMethod(golem_api_grpc::proto::golem::rib::IndexedResourceStaticMethodFunctionReference { - resource, - resource_params, - method - }) => { - Ok(Self::IndexedResourceStaticMethod { - resource, - resource_params, - method, - }) - } - golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::IndexedResourceDrop(golem_api_grpc::proto::golem::rib::IndexedResourceDropFunctionReference { - resource, - resource_params - }) => { - Ok(Self::IndexedResourceDrop { - resource, - resource_params, - }) - } - } - } -} - -impl From for golem_api_grpc::proto::golem::rib::ParsedFunctionReference { - fn from(value: ParsedFunctionReference) -> Self { - let function = match value { - ParsedFunctionReference::Function { function } => golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::Function( - golem_api_grpc::proto::golem::rib::FunctionFunctionReference { function }, - ), - ParsedFunctionReference::RawResourceConstructor { resource } => { - golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::RawResourceConstructor( - golem_api_grpc::proto::golem::rib::RawResourceConstructorFunctionReference { - resource, - }, - ) - } - ParsedFunctionReference::RawResourceMethod { resource, method } => { - golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::RawResourceMethod( - golem_api_grpc::proto::golem::rib::RawResourceMethodFunctionReference { - resource, - method, - }, - ) - } - ParsedFunctionReference::RawResourceStaticMethod { resource, method } => { - golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::RawResourceStaticMethod( - golem_api_grpc::proto::golem::rib::RawResourceStaticMethodFunctionReference { - resource, - method, - }, - ) - } - ParsedFunctionReference::RawResourceDrop { resource } => golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::RawResourceDrop( - golem_api_grpc::proto::golem::rib::RawResourceDropFunctionReference { resource }, - ), - ParsedFunctionReference::IndexedResourceConstructor { - resource, - resource_params, - } => golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::IndexedResourceConstructor( - golem_api_grpc::proto::golem::rib::IndexedResourceConstructorFunctionReference { - resource, - resource_params, - }, - ), - ParsedFunctionReference::IndexedResourceMethod { - resource, - resource_params, - method, - } => golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::IndexedResourceMethod( - golem_api_grpc::proto::golem::rib::IndexedResourceMethodFunctionReference { - resource, - resource_params, - method, - }, - ), - ParsedFunctionReference::IndexedResourceStaticMethod { - resource, - resource_params, - method, - } => golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::IndexedResourceStaticMethod( - golem_api_grpc::proto::golem::rib::IndexedResourceStaticMethodFunctionReference { - resource, - resource_params, - method, - }, - ), - ParsedFunctionReference::IndexedResourceDrop { - resource, - resource_params, - } => golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::IndexedResourceDrop( - golem_api_grpc::proto::golem::rib::IndexedResourceDropFunctionReference { - resource, - resource_params, - }, - ), - }; - golem_api_grpc::proto::golem::rib::ParsedFunctionReference { - function_reference: Some(function), - } - } -} - #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] pub struct ParsedFunctionName { pub site: ParsedFunctionSite, @@ -1051,52 +654,460 @@ impl ParsedFunctionName { } } -impl TryFrom - for DynamicParsedFunctionName -{ - type Error = String; +#[cfg(feature = "protobuf")] +mod protobuf { + use crate::{ + DynamicParsedFunctionName, DynamicParsedFunctionReference, Expr, ParsedFunctionName, + ParsedFunctionReference, ParsedFunctionSite, SemVer, + }; + use golem_api_grpc::proto::golem::rib::dynamic_parsed_function_reference::FunctionReference as ProtoDynamicFunctionReference; + use semver::{BuildMetadata, Prerelease}; + + impl TryFrom for SemVer { + type Error = String; + + fn try_from( + value: golem_api_grpc::proto::golem::rib::SemVersion, + ) -> Result { + Ok(SemVer(semver::Version { + major: value.major, + minor: value.minor, + patch: value.patch, + pre: Prerelease::new(&value.pre).map_err(|_| "Invalid prerelease".to_string())?, + build: BuildMetadata::new(&value.build) + .map_err(|_| "Invalid build metadata".to_string())?, + })) + } + } - fn try_from( - value: golem_api_grpc::proto::golem::rib::DynamicParsedFunctionName, - ) -> Result { - let site = ParsedFunctionSite::try_from(value.site.ok_or("Missing site".to_string())?)?; - let function = DynamicParsedFunctionReference::try_from( - value.function.ok_or("Missing function".to_string())?, - )?; - Ok(Self { site, function }) + impl From for golem_api_grpc::proto::golem::rib::SemVersion { + fn from(value: SemVer) -> Self { + golem_api_grpc::proto::golem::rib::SemVersion { + major: value.0.major, + minor: value.0.minor, + patch: value.0.patch, + pre: value.0.pre.to_string(), + build: value.0.build.to_string(), + } + } } -} -impl From - for golem_api_grpc::proto::golem::rib::DynamicParsedFunctionName -{ - fn from(value: DynamicParsedFunctionName) -> Self { - golem_api_grpc::proto::golem::rib::DynamicParsedFunctionName { - site: Some(value.site.into()), - function: Some(value.function.into()), + impl TryFrom for ParsedFunctionSite { + type Error = String; + + fn try_from( + value: golem_api_grpc::proto::golem::rib::ParsedFunctionSite, + ) -> Result { + let site = value.site.ok_or("Missing site".to_string())?; + match site { + golem_api_grpc::proto::golem::rib::parsed_function_site::Site::Global(_) => { + Ok(Self::Global) + } + golem_api_grpc::proto::golem::rib::parsed_function_site::Site::Interface( + golem_api_grpc::proto::golem::rib::InterfaceFunctionSite { name }, + ) => Ok(Self::Interface { name }), + golem_api_grpc::proto::golem::rib::parsed_function_site::Site::PackageInterface( + golem_api_grpc::proto::golem::rib::PackageInterfaceFunctionSite { + namespace, + package, + interface, + version, + }, + ) => { + let version = match version { + Some(version) => Some(version.try_into()?), + None => None, + }; + + Ok(Self::PackagedInterface { + namespace, + package, + interface, + version, + }) + } + } + } + } + + impl From for golem_api_grpc::proto::golem::rib::ParsedFunctionSite { + fn from(value: ParsedFunctionSite) -> Self { + let site = match value { + ParsedFunctionSite::Global => { + golem_api_grpc::proto::golem::rib::parsed_function_site::Site::Global( + golem_api_grpc::proto::golem::rib::GlobalFunctionSite {}, + ) + } + ParsedFunctionSite::Interface { name } => { + golem_api_grpc::proto::golem::rib::parsed_function_site::Site::Interface( + golem_api_grpc::proto::golem::rib::InterfaceFunctionSite { name }, + ) + } + ParsedFunctionSite::PackagedInterface { + namespace, + package, + interface, + version, + } => { + golem_api_grpc::proto::golem::rib::parsed_function_site::Site::PackageInterface( + golem_api_grpc::proto::golem::rib::PackageInterfaceFunctionSite { + namespace, + package, + interface, + version: version.map(|v| v.into()), + }, + ) + } + }; + golem_api_grpc::proto::golem::rib::ParsedFunctionSite { site: Some(site) } } } -} -impl TryFrom for ParsedFunctionName { - type Error = String; + impl From + for golem_api_grpc::proto::golem::rib::DynamicParsedFunctionReference + { + fn from(value: DynamicParsedFunctionReference) -> Self { + let function = match value { + DynamicParsedFunctionReference::Function { function } => ProtoDynamicFunctionReference::Function( + golem_api_grpc::proto::golem::rib::FunctionFunctionReference { function }, + ), + DynamicParsedFunctionReference::RawResourceConstructor { resource } => ProtoDynamicFunctionReference::RawResourceConstructor( + golem_api_grpc::proto::golem::rib::RawResourceConstructorFunctionReference { resource }, + ), + DynamicParsedFunctionReference::RawResourceMethod { resource, method } => ProtoDynamicFunctionReference::RawResourceMethod( + golem_api_grpc::proto::golem::rib::RawResourceMethodFunctionReference { resource, method }, + ), + DynamicParsedFunctionReference::RawResourceStaticMethod { resource, method } => ProtoDynamicFunctionReference::RawResourceStaticMethod( + golem_api_grpc::proto::golem::rib::RawResourceStaticMethodFunctionReference { resource, method }, + ), + DynamicParsedFunctionReference::RawResourceDrop { resource } => ProtoDynamicFunctionReference::RawResourceDrop( + golem_api_grpc::proto::golem::rib::RawResourceDropFunctionReference { resource }, + ), + DynamicParsedFunctionReference::IndexedResourceConstructor { resource, resource_params } => ProtoDynamicFunctionReference::IndexedResourceConstructor( + golem_api_grpc::proto::golem::rib::DynamicIndexedResourceConstructorFunctionReference { + resource, + resource_params: resource_params.into_iter().map(|x| x.into()).collect(), + }, + ), + DynamicParsedFunctionReference::IndexedResourceMethod { resource, resource_params, method } => ProtoDynamicFunctionReference::IndexedResourceMethod( + golem_api_grpc::proto::golem::rib::DynamicIndexedResourceMethodFunctionReference { + resource, + resource_params: resource_params.into_iter().map(|x| x.into()).collect(), + method, + }, + ), + DynamicParsedFunctionReference::IndexedResourceStaticMethod { resource, resource_params, method } => ProtoDynamicFunctionReference::IndexedResourceStaticMethod( + golem_api_grpc::proto::golem::rib::DynamicIndexedResourceStaticMethodFunctionReference { + resource, + resource_params: resource_params.into_iter().map(|x| x.into()).collect(), + method, + }, + ), + DynamicParsedFunctionReference::IndexedResourceDrop { resource, resource_params } => ProtoDynamicFunctionReference::IndexedResourceDrop( + golem_api_grpc::proto::golem::rib::DynamicIndexedResourceDropFunctionReference { + resource, + resource_params: resource_params.into_iter().map(|x| x.into()).collect(), + }, + ), + }; - fn try_from( - value: golem_api_grpc::proto::golem::rib::ParsedFunctionName, - ) -> Result { - let site = ParsedFunctionSite::try_from(value.site.ok_or("Missing site".to_string())?)?; - let function = ParsedFunctionReference::try_from( - value.function.ok_or("Missing function".to_string())?, - )?; - Ok(Self { site, function }) + golem_api_grpc::proto::golem::rib::DynamicParsedFunctionReference { + function_reference: Some(function), + } + } } -} -impl From for golem_api_grpc::proto::golem::rib::ParsedFunctionName { - fn from(value: ParsedFunctionName) -> Self { - golem_api_grpc::proto::golem::rib::ParsedFunctionName { - site: Some(value.site.into()), - function: Some(value.function.into()), + impl TryFrom + for DynamicParsedFunctionReference + { + type Error = String; + + fn try_from( + value: golem_api_grpc::proto::golem::rib::DynamicParsedFunctionReference, + ) -> Result { + let function = value + .function_reference + .ok_or("Missing function reference".to_string())?; + + match function { + ProtoDynamicFunctionReference::Function(golem_api_grpc::proto::golem::rib::FunctionFunctionReference { + function + }) => { + Ok(Self::Function { function }) + } + ProtoDynamicFunctionReference::RawResourceConstructor(golem_api_grpc::proto::golem::rib::RawResourceConstructorFunctionReference { + resource + }) => { + Ok(Self::RawResourceConstructor { resource }) + } + ProtoDynamicFunctionReference::RawResourceMethod(golem_api_grpc::proto::golem::rib::RawResourceMethodFunctionReference { + resource, + method + }) => { + Ok(Self::RawResourceMethod { resource, method }) + } + ProtoDynamicFunctionReference::RawResourceStaticMethod(golem_api_grpc::proto::golem::rib::RawResourceStaticMethodFunctionReference { + resource, + method + }) => { + Ok(Self::RawResourceStaticMethod { resource, method }) + } + ProtoDynamicFunctionReference::RawResourceDrop(golem_api_grpc::proto::golem::rib::RawResourceDropFunctionReference { + resource + }) => { + Ok(Self::RawResourceDrop { resource }) + } + ProtoDynamicFunctionReference::IndexedResourceConstructor(golem_api_grpc::proto::golem::rib::DynamicIndexedResourceConstructorFunctionReference { + resource, + resource_params + }) => { + let resource_params: Vec = + resource_params.into_iter().map(Expr::try_from).collect::, String>>()?; + + Ok(Self::IndexedResourceConstructor { resource, resource_params }) + } + ProtoDynamicFunctionReference::IndexedResourceMethod(golem_api_grpc::proto::golem::rib::DynamicIndexedResourceMethodFunctionReference { + resource, + resource_params, + method + }) => { + let resource_params: Vec = + resource_params.into_iter().map(Expr::try_from).collect::, String>>()?; + + Ok(Self::IndexedResourceMethod { resource, resource_params, method }) + } + ProtoDynamicFunctionReference::IndexedResourceStaticMethod(golem_api_grpc::proto::golem::rib::DynamicIndexedResourceStaticMethodFunctionReference { + resource, + resource_params, + method + }) => { + let resource_params: Vec = + resource_params.into_iter().map(Expr::try_from).collect::, String>>()?; + + Ok(Self::IndexedResourceStaticMethod { resource, resource_params, method }) + } + ProtoDynamicFunctionReference::IndexedResourceDrop(golem_api_grpc::proto::golem::rib::DynamicIndexedResourceDropFunctionReference { + resource, + resource_params + }) => { + let resource_params: Vec = + resource_params.into_iter().map(Expr::try_from).collect::, String>>()?; + + Ok(Self::IndexedResourceDrop { resource, resource_params }) + } + } + } + } + + impl TryFrom + for ParsedFunctionReference + { + type Error = String; + + fn try_from( + value: golem_api_grpc::proto::golem::rib::ParsedFunctionReference, + ) -> Result { + let function = value + .function_reference + .ok_or("Missing function".to_string())?; + match function { + golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::Function(golem_api_grpc::proto::golem::rib::FunctionFunctionReference { + function + }) => { + Ok(Self::Function { function }) + } + golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::RawResourceConstructor(golem_api_grpc::proto::golem::rib::RawResourceConstructorFunctionReference { + resource + }) => { + Ok(Self::RawResourceConstructor { resource }) + } + golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::RawResourceMethod(golem_api_grpc::proto::golem::rib::RawResourceMethodFunctionReference { + resource, + method + }) => { + Ok(Self::RawResourceMethod { resource, method }) + } + golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::RawResourceStaticMethod(golem_api_grpc::proto::golem::rib::RawResourceStaticMethodFunctionReference { + resource, + method + }) => { + Ok(Self::RawResourceStaticMethod { resource, method }) + } + golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::RawResourceDrop(golem_api_grpc::proto::golem::rib::RawResourceDropFunctionReference { + resource + }) => { + Ok(Self::RawResourceDrop { resource }) + } + golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::IndexedResourceConstructor(golem_api_grpc::proto::golem::rib::IndexedResourceConstructorFunctionReference { + resource, + resource_params + }) => { + Ok(Self::IndexedResourceConstructor { + resource, + resource_params, + }) + } + golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::IndexedResourceMethod(golem_api_grpc::proto::golem::rib::IndexedResourceMethodFunctionReference { + resource, + resource_params, + method + }) => { + Ok(Self::IndexedResourceMethod { + resource, + resource_params, + method, + }) + } + golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::IndexedResourceStaticMethod(golem_api_grpc::proto::golem::rib::IndexedResourceStaticMethodFunctionReference { + resource, + resource_params, + method + }) => { + Ok(Self::IndexedResourceStaticMethod { + resource, + resource_params, + method, + }) + } + golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::IndexedResourceDrop(golem_api_grpc::proto::golem::rib::IndexedResourceDropFunctionReference { + resource, + resource_params + }) => { + Ok(Self::IndexedResourceDrop { + resource, + resource_params, + }) + } + } + } + } + + impl From for golem_api_grpc::proto::golem::rib::ParsedFunctionReference { + fn from(value: ParsedFunctionReference) -> Self { + let function = match value { + ParsedFunctionReference::Function { function } => golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::Function( + golem_api_grpc::proto::golem::rib::FunctionFunctionReference { function }, + ), + ParsedFunctionReference::RawResourceConstructor { resource } => { + golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::RawResourceConstructor( + golem_api_grpc::proto::golem::rib::RawResourceConstructorFunctionReference { + resource, + }, + ) + } + ParsedFunctionReference::RawResourceMethod { resource, method } => { + golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::RawResourceMethod( + golem_api_grpc::proto::golem::rib::RawResourceMethodFunctionReference { + resource, + method, + }, + ) + } + ParsedFunctionReference::RawResourceStaticMethod { resource, method } => { + golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::RawResourceStaticMethod( + golem_api_grpc::proto::golem::rib::RawResourceStaticMethodFunctionReference { + resource, + method, + }, + ) + } + ParsedFunctionReference::RawResourceDrop { resource } => golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::RawResourceDrop( + golem_api_grpc::proto::golem::rib::RawResourceDropFunctionReference { resource }, + ), + ParsedFunctionReference::IndexedResourceConstructor { + resource, + resource_params, + } => golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::IndexedResourceConstructor( + golem_api_grpc::proto::golem::rib::IndexedResourceConstructorFunctionReference { + resource, + resource_params, + }, + ), + ParsedFunctionReference::IndexedResourceMethod { + resource, + resource_params, + method, + } => golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::IndexedResourceMethod( + golem_api_grpc::proto::golem::rib::IndexedResourceMethodFunctionReference { + resource, + resource_params, + method, + }, + ), + ParsedFunctionReference::IndexedResourceStaticMethod { + resource, + resource_params, + method, + } => golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::IndexedResourceStaticMethod( + golem_api_grpc::proto::golem::rib::IndexedResourceStaticMethodFunctionReference { + resource, + resource_params, + method, + }, + ), + ParsedFunctionReference::IndexedResourceDrop { + resource, + resource_params, + } => golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::IndexedResourceDrop( + golem_api_grpc::proto::golem::rib::IndexedResourceDropFunctionReference { + resource, + resource_params, + }, + ), + }; + golem_api_grpc::proto::golem::rib::ParsedFunctionReference { + function_reference: Some(function), + } + } + } + + impl TryFrom + for DynamicParsedFunctionName + { + type Error = String; + + fn try_from( + value: golem_api_grpc::proto::golem::rib::DynamicParsedFunctionName, + ) -> Result { + let site = ParsedFunctionSite::try_from(value.site.ok_or("Missing site".to_string())?)?; + let function = DynamicParsedFunctionReference::try_from( + value.function.ok_or("Missing function".to_string())?, + )?; + Ok(Self { site, function }) + } + } + + impl TryFrom for ParsedFunctionName { + type Error = String; + + fn try_from( + value: golem_api_grpc::proto::golem::rib::ParsedFunctionName, + ) -> Result { + let site = ParsedFunctionSite::try_from(value.site.ok_or("Missing site".to_string())?)?; + let function = ParsedFunctionReference::try_from( + value.function.ok_or("Missing function".to_string())?, + )?; + Ok(Self { site, function }) + } + } + + impl From for golem_api_grpc::proto::golem::rib::ParsedFunctionName { + fn from(value: ParsedFunctionName) -> Self { + golem_api_grpc::proto::golem::rib::ParsedFunctionName { + site: Some(value.site.into()), + function: Some(value.function.into()), + } + } + } + + impl From + for golem_api_grpc::proto::golem::rib::DynamicParsedFunctionName + { + fn from(value: DynamicParsedFunctionName) -> Self { + golem_api_grpc::proto::golem::rib::DynamicParsedFunctionName { + site: Some(value.site.into()), + function: Some(value.function.into()), + } } } } @@ -1719,7 +1730,7 @@ mod function_name_tests { ])]) .expect("Resource params parsing failed") .expect("Resource params not found"); - let nums = if let Value::Record(nums) = &args[0] { + let nums = if let Value::Record(nums) = &args[0].value { nums.clone() } else { panic!("Expected record") diff --git a/golem-rib/src/interpreter/env.rs b/golem-rib/src/interpreter/env.rs index 1c88722d9..3d60ad426 100644 --- a/golem-rib/src/interpreter/env.rs +++ b/golem-rib/src/interpreter/env.rs @@ -14,7 +14,7 @@ use crate::interpreter::interpreter_stack_value::RibInterpreterStackValue; use crate::{RibInput, VariableId}; -use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; +use golem_wasm_rpc::ValueAndType; use std::collections::HashMap; use std::fmt::Debug; use std::future::Future; @@ -37,8 +37,8 @@ impl Debug for InterpreterEnv { pub type RibFunctionInvoke = Arc< dyn Fn( String, - Vec, - ) -> Pin> + Send>> + Vec, + ) -> Pin> + Send>> + Send + Sync, >; @@ -56,8 +56,8 @@ impl InterpreterEnv { pub fn invoke_worker_function_async( &self, function_name: String, - args: Vec, - ) -> Pin> + Send>> { + args: Vec, + ) -> Pin> + Send>> { (self.call_worker_function_async)(function_name, args) } @@ -114,18 +114,13 @@ impl EnvironmentKey { mod internal { use crate::interpreter::env::RibFunctionInvoke; - use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; - use golem_wasm_rpc::protobuf::TypedTuple; + use golem_wasm_ast::analysis::analysed_type::tuple; + use golem_wasm_rpc::{Value, ValueAndType}; use std::sync::Arc; pub(crate) fn default_worker_invoke_async() -> RibFunctionInvoke { Arc::new(|_, _| { - Box::pin(async { - Ok(TypeAnnotatedValue::Tuple(TypedTuple { - typ: vec![], - value: vec![], - })) - }) + Box::pin(async { Ok(ValueAndType::new(Value::Tuple(vec![]), tuple(vec![]))) }) }) } } diff --git a/golem-rib/src/interpreter/interpreter_input.rs b/golem-rib/src/interpreter/interpreter_input.rs index 96e8ae3ea..585f70f19 100644 --- a/golem-rib/src/interpreter/interpreter_input.rs +++ b/golem-rib/src/interpreter/interpreter_input.rs @@ -12,17 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; +use golem_wasm_rpc::ValueAndType; use std::collections::HashMap; // Acts as the structure to hold the global input values #[derive(Debug, Default, Clone)] pub struct RibInput { - pub input: HashMap, + pub input: HashMap, } impl RibInput { - pub fn new(input: HashMap) -> RibInput { + pub fn new(input: HashMap) -> RibInput { RibInput { input } } diff --git a/golem-rib/src/interpreter/interpreter_result.rs b/golem-rib/src/interpreter/interpreter_result.rs index 90ce2b153..848f72254 100644 --- a/golem-rib/src/interpreter/interpreter_result.rs +++ b/golem-rib/src/interpreter/interpreter_result.rs @@ -14,13 +14,13 @@ use crate::interpreter::interpreter_stack_value::RibInterpreterStackValue; use crate::{GetLiteralValue, LiteralValue}; -use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; -use golem_wasm_rpc::protobuf::NameValuePair; +use golem_wasm_ast::analysis::AnalysedType; +use golem_wasm_rpc::{Value, ValueAndType}; #[derive(Debug)] pub enum RibResult { Unit, - Val(TypeAnnotatedValue), + Val(ValueAndType), } impl RibResult { @@ -29,8 +29,8 @@ impl RibResult { ) -> Option { match stack_value { RibInterpreterStackValue::Unit => Some(RibResult::Unit), - RibInterpreterStackValue::Val(type_annotated_value) => { - Some(RibResult::Val(type_annotated_value.clone())) + RibInterpreterStackValue::Val(value_and_type) => { + Some(RibResult::Val(value_and_type.clone())) } RibInterpreterStackValue::Iterator(_) => None, RibInterpreterStackValue::Sink(_, _) => None, @@ -39,12 +39,15 @@ impl RibResult { pub fn get_bool(&self) -> Option { match self { - RibResult::Val(TypeAnnotatedValue::Bool(bool)) => Some(*bool), + RibResult::Val(ValueAndType { + value: Value::Bool(bool), + .. + }) => Some(*bool), RibResult::Val(_) => None, RibResult::Unit => None, } } - pub fn get_val(&self) -> Option { + pub fn get_val(&self) -> Option { match self { RibResult::Val(val) => Some(val.clone()), RibResult::Unit => None, @@ -55,9 +58,18 @@ impl RibResult { self.get_val().and_then(|x| x.get_literal()) } - pub fn get_record(&self) -> Option> { + pub fn get_record(&self) -> Option> { self.get_val().and_then(|x| match x { - TypeAnnotatedValue::Record(record) => Some(record.value), + ValueAndType { + value: Value::Record(field_values), + typ: AnalysedType::Record(typ), + } => Some( + field_values + .into_iter() + .zip(typ.fields) + .map(|(value, typ)| (typ.name, ValueAndType::new(value, typ.typ))) + .collect(), + ), _ => None, }) } diff --git a/golem-rib/src/interpreter/interpreter_stack_value.rs b/golem-rib/src/interpreter/interpreter_stack_value.rs index 4a86a641f..b5a268b87 100644 --- a/golem-rib/src/interpreter/interpreter_stack_value.rs +++ b/golem-rib/src/interpreter/interpreter_stack_value.rs @@ -15,10 +15,9 @@ use crate::interpreter::literal::{GetLiteralValue, LiteralValue}; use crate::CoercedNumericValue; use golem_wasm_ast::analysis::AnalysedType; -use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; -use golem_wasm_rpc::protobuf::typed_result::ResultValue; -use poem_openapi::types::ToJSON; +use golem_wasm_rpc::{IntoValueAndType, Value, ValueAndType}; use std::fmt; +use std::ops::Deref; // A result of a function can be unit, which is not representable using type_annotated_value // A result can be a type_annotated_value @@ -26,9 +25,9 @@ use std::fmt; // A result can also be stored as an iterator, that its easy to stream through any iterables, given a sink is following it. pub enum RibInterpreterStackValue { Unit, - Val(TypeAnnotatedValue), - Iterator(Box + Send>), - Sink(Vec, AnalysedType), + Val(ValueAndType), + Iterator(Box + Send>), + Sink(Vec, AnalysedType), } impl RibInterpreterStackValue { @@ -55,11 +54,7 @@ impl RibInterpreterStackValue { ) { Ok(op(left_lit, right_lit)) } else { - Err(format!( - "Unable to complete the math operation on {}, {}", - left.to_json_string(), - right.to_json_string() - )) + Err(internal::unable_to_complete_math_operation(&left, &right)) } } _ => Err("Failed to obtain values to complete the math operation".to_string()), @@ -75,9 +70,7 @@ impl RibInterpreterStackValue { F: Fn(LiteralValue, LiteralValue) -> bool, { if self.is_unit() && right.is_unit() { - Ok(RibInterpreterStackValue::Val(TypeAnnotatedValue::Bool( - true, - ))) + Ok(RibInterpreterStackValue::Val(true.into_value_and_type())) } else { match (self.get_val(), right.get_val()) { (Some(left), Some(right)) => { @@ -91,14 +84,17 @@ impl RibInterpreterStackValue { pub fn get_bool(&self) -> Option { match self { - RibInterpreterStackValue::Val(TypeAnnotatedValue::Bool(bool)) => Some(*bool), + RibInterpreterStackValue::Val(ValueAndType { + value: Value::Bool(bool), + .. + }) => Some(*bool), RibInterpreterStackValue::Val(_) => None, RibInterpreterStackValue::Unit => None, RibInterpreterStackValue::Iterator(_) => None, RibInterpreterStackValue::Sink(_, _) => None, } } - pub fn get_val(&self) -> Option { + pub fn get_val(&self) -> Option { match self { RibInterpreterStackValue::Val(val) => Some(val.clone()), RibInterpreterStackValue::Unit => None, @@ -120,32 +116,59 @@ impl RibInterpreterStackValue { matches!(self, RibInterpreterStackValue::Unit) } - pub fn val(val: TypeAnnotatedValue) -> Self { + pub fn val(val: ValueAndType) -> Self { RibInterpreterStackValue::Val(val) } - pub fn unwrap(&self) -> Option { + pub fn unwrap(&self) -> Option { match self { - RibInterpreterStackValue::Val(val) => match val { - TypeAnnotatedValue::Option(option) => option - .value - .as_deref() - .and_then(|x| x.type_annotated_value.clone()), - TypeAnnotatedValue::Result(result) => { - let result = match &result.result_value { - Some(ResultValue::OkValue(ok)) => Some(ok.clone()), - Some(ResultValue::ErrorValue(err)) => Some(err.clone()), - None => None, - }; - - // GRPC wrapper - result.and_then(|x| x.type_annotated_value) + RibInterpreterStackValue::Val(val) => match (val.value.clone(), val.typ.clone()) { + (Value::Option(Some(option)), AnalysedType::Option(option_type)) => { + let inner_value = option.deref().clone(); + let inner_type = option_type.inner.deref().clone(); + Some(ValueAndType { + value: inner_value, + typ: inner_type, + }) + } + + (Value::Result(Ok(Some(ok))), AnalysedType::Result(result_type)) => { + let ok_value = ok.deref().clone(); + let ok_type = result_type.ok.as_ref()?.deref().clone(); + Some(ValueAndType { + value: ok_value, + typ: ok_type, + }) + } + + (Value::Result(Err(Some(err))), AnalysedType::Result(result_type)) => { + let err_value = err.deref().clone(); + let err_type = result_type.err.as_ref()?.deref().clone(); + Some(ValueAndType { + value: err_value, + typ: err_type, + }) + } + + ( + Value::Variant { + case_value: Some(case_value), + case_idx, + }, + AnalysedType::Variant(variant_type), + ) => { + let case_type = variant_type + .cases + .get(case_idx as usize)? + .typ + .as_ref()? + .clone(); + Some(ValueAndType { + value: case_value.deref().clone(), + typ: case_type, + }) } - TypeAnnotatedValue::Variant(variant) => variant - .case_value - .as_deref() - .and_then(|x| x.type_annotated_value.clone()), _ => None, }, RibInterpreterStackValue::Unit => None, @@ -168,88 +191,147 @@ impl fmt::Debug for RibInterpreterStackValue { mod internal { use crate::interpreter::literal::{GetLiteralValue, LiteralValue}; - use golem_wasm_ast::analysis::AnalysedType; - use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; - use golem_wasm_rpc::protobuf::{TypedEnum, TypedFlags, TypedVariant}; + use golem_wasm_ast::analysis::{AnalysedType, TypeVariant}; + use golem_wasm_rpc::{IntoValueAndType, Value, ValueAndType}; + + #[cfg(not(feature = "json_in_errors"))] + pub fn unable_to_complete_math_operation(left: &ValueAndType, right: &ValueAndType) -> String { + format!( + "Unable to complete math operation for {:?}, {:?}", + left, right + ) + } + + #[cfg(feature = "json_in_errors")] + pub fn unable_to_complete_math_operation(left: &ValueAndType, right: &ValueAndType) -> String { + format!( + "Unable to complete math operation for {}, {}", + serde_json::to_string(left).unwrap_or_default(), + serde_json::to_string(right).unwrap_or_default() + ) + } pub(crate) fn compare_typed_value( - left: &TypeAnnotatedValue, - right: &TypeAnnotatedValue, + left: &ValueAndType, + right: &ValueAndType, compare: F, - ) -> Result + ) -> Result where F: Fn(LiteralValue, LiteralValue) -> bool, { if let (Some(left_lit), Some(right_lit)) = (left.get_literal(), right.get_literal()) { - Ok(TypeAnnotatedValue::Bool(compare(left_lit, right_lit))) - } else if let (TypeAnnotatedValue::Variant(left), TypeAnnotatedValue::Variant(right)) = - (left, right) + Ok(compare(left_lit, right_lit).into_value_and_type()) + } else if let ( + ValueAndType { + value: + Value::Variant { + case_idx: left_case_idx, + case_value: left_case_value, + }, + typ: AnalysedType::Variant(left_typ), + }, + ValueAndType { + value: + Value::Variant { + case_idx: right_cast_idx, + case_value: right_case_value, + }, + typ: AnalysedType::Variant(right_typ), + }, + ) = (left, right) { - compare_variants(left.as_ref(), right.as_ref(), compare) - } else if let (TypeAnnotatedValue::Enum(left), TypeAnnotatedValue::Enum(right)) = - (left, right) + compare_variants( + *left_case_idx, + left_case_value, + left_typ, + *right_cast_idx, + right_case_value, + right_typ, + compare, + ) + } else if let ( + ValueAndType { + value: Value::Enum(left_idx), + .. + }, + ValueAndType { + value: Value::Enum(right_idx), + .. + }, + ) = (left, right) { - compare_enums(left, right) - } else if let (TypeAnnotatedValue::Flags(left), TypeAnnotatedValue::Flags(right)) = - (left, right) + compare_enums(*left_idx, *right_idx) + } else if let ( + ValueAndType { + value: Value::Flags(left_bitmap), + .. + }, + ValueAndType { + value: Value::Flags(right_bitmap), + .. + }, + ) = (left, right) { - compare_flags(left, right) + compare_flags(left_bitmap, right_bitmap) } else { Err(unsupported_type_error(left, right)) } } - fn compare_flags(left: &TypedFlags, right: &TypedFlags) -> Result { - if left.values == right.values { - Ok(TypeAnnotatedValue::Bool(true)) - } else { - Ok(TypeAnnotatedValue::Bool(false)) - } + fn compare_flags(left: &[bool], right: &[bool]) -> Result { + Ok((left == right).into_value_and_type()) } fn compare_variants( - left: &TypedVariant, - right: &TypedVariant, + left_case_idx: u32, + left_case_value: &Option>, + left_type: &TypeVariant, + right_case_idx: u32, + right_case_value: &Option>, + right_type: &TypeVariant, compare: F, - ) -> Result + ) -> Result where F: Fn(LiteralValue, LiteralValue) -> bool, { - if left.case_name == right.case_name { - match ( - left.case_value.clone().and_then(|x| x.type_annotated_value), - right - .case_value - .clone() - .and_then(|x| x.type_annotated_value), - ) { + if left_case_idx == right_case_idx { + match (left_case_value, right_case_value) { (Some(left_val), Some(right_val)) => { - compare_typed_value(&left_val, &right_val, compare) + let left_typ = left_type + .cases + .get(left_case_idx as usize) + .ok_or("Left case index is out of bounds for the type variant".to_string())? + .typ + .clone(); + let right_typ = right_type + .cases + .get(right_case_idx as usize) + .ok_or( + "Right case index is out of bounds for the type variant".to_string(), + )? + .typ + .clone(); + match (left_typ, right_typ) { + (Some(left_typ), Some(right_typ)) => compare_typed_value( + &ValueAndType::new(*left_val.clone(), left_typ), + &ValueAndType::new(*right_val.clone(), right_typ), + compare, + ), + _ => Ok(true.into_value_and_type()), + } } - _ => Ok(TypeAnnotatedValue::Bool(true)), + _ => Ok(true.into_value_and_type()), } } else { - Ok(TypeAnnotatedValue::Bool(false)) + Ok(false.into_value_and_type()) } } - fn compare_enums(left: &TypedEnum, right: &TypedEnum) -> Result { - if left.value == right.value { - Ok(TypeAnnotatedValue::Bool(true)) - } else { - Ok(TypeAnnotatedValue::Bool(false)) - } + fn compare_enums(left_idx: u32, right_idx: u32) -> Result { + Ok((left_idx == right_idx).into_value_and_type()) } - fn unsupported_type_error(left: &TypeAnnotatedValue, right: &TypeAnnotatedValue) -> String { - let left = AnalysedType::try_from(left); - let right = AnalysedType::try_from(right); - - match (left, right) { - (Ok(left), Ok(right)) => { - format!("Unsupported op {:?}, {:?}", left, right) - } - _ => "Unsupported types. Un-identified types".to_string(), - } + fn unsupported_type_error(left: &ValueAndType, right: &ValueAndType) -> String { + format!("Unsupported op {:?}, {:?}", left.typ, right.typ) } } diff --git a/golem-rib/src/interpreter/literal.rs b/golem-rib/src/interpreter/literal.rs index d3a197fde..6d2eeed48 100644 --- a/golem-rib/src/interpreter/literal.rs +++ b/golem-rib/src/interpreter/literal.rs @@ -13,7 +13,7 @@ // limitations under the License. use golem_wasm_ast::analysis::AnalysedType; -use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; +use golem_wasm_rpc::{IntoValueAndType, Value, ValueAndType}; use std::cmp::Ordering; use std::fmt::Display; use std::ops::{Add, Div, Mul, Sub}; @@ -22,22 +22,43 @@ pub trait GetLiteralValue { fn get_literal(&self) -> Option; } -impl GetLiteralValue for TypeAnnotatedValue { +impl GetLiteralValue for ValueAndType { fn get_literal(&self) -> Option { match self { - TypeAnnotatedValue::Str(value) => Some(LiteralValue::String(value.clone())), - TypeAnnotatedValue::Char(code_point) => char::from_u32(*code_point as u32) + ValueAndType { + value: Value::String(value), + .. + } => Some(LiteralValue::String(value.clone())), + ValueAndType { + value: Value::Char(code_point), + .. + } => char::from_u32(*code_point as u32) .map(|c| c.to_string()) .map(LiteralValue::String), - TypeAnnotatedValue::Bool(value) => Some(LiteralValue::Bool(*value)), - TypeAnnotatedValue::Enum(value) => { + ValueAndType { + value: Value::Bool(value), + .. + } => Some(LiteralValue::Bool(*value)), + ValueAndType { + value: Value::Enum(idx), + typ: AnalysedType::Enum(typ), + } => { // An enum can be turned into a simple literal and can be part of string concatenations - Some(LiteralValue::String(value.value.clone())) + Some(LiteralValue::String(typ.cases[*idx as usize].clone())) } - TypeAnnotatedValue::Variant(value) => { + ValueAndType { + value: + Value::Variant { + case_idx, + case_value, + }, + typ: AnalysedType::Variant(typ), + } => { // A no arg variant can be turned into a simple literal and can be part of string concatenations - if value.case_value.is_none() { - Some(LiteralValue::String(value.case_name.clone())) + if case_value.is_none() { + Some(LiteralValue::String( + typ.cases[*case_idx as usize].name.clone(), + )) } else { None } @@ -103,47 +124,47 @@ pub enum CoercedNumericValue { } impl CoercedNumericValue { - pub fn cast_to(&self, analysed_type: &AnalysedType) -> Option { + pub fn cast_to(&self, analysed_type: &AnalysedType) -> Option { match (self, analysed_type) { - (CoercedNumericValue::PosInt(val), AnalysedType::U64(_)) => { - Some(TypeAnnotatedValue::U64(*val)) - } - (CoercedNumericValue::PosInt(val), AnalysedType::U32(_)) if *val <= u32::MAX as u64 => { - Some(TypeAnnotatedValue::U32(*val as u32)) + (CoercedNumericValue::PosInt(val), AnalysedType::U8(_)) if *val <= u8::MAX as u64 => { + Some((*val as u8).into_value_and_type()) } (CoercedNumericValue::PosInt(val), AnalysedType::U16(_)) if *val <= u16::MAX as u64 => { - Some(TypeAnnotatedValue::U16(*val as u32)) + Some((*val as u16).into_value_and_type()) } - (CoercedNumericValue::PosInt(val), AnalysedType::U8(_)) if *val <= u8::MAX as u64 => { - Some(TypeAnnotatedValue::U8(*val as u32)) + (CoercedNumericValue::PosInt(val), AnalysedType::U32(_)) if *val <= u32::MAX as u64 => { + Some((*val as u32).into_value_and_type()) } - - (CoercedNumericValue::NegInt(val), AnalysedType::S64(_)) => { - Some(TypeAnnotatedValue::S64(*val)) + (CoercedNumericValue::PosInt(val), AnalysedType::U64(_)) => { + Some((*val).into_value_and_type()) } - (CoercedNumericValue::NegInt(val), AnalysedType::S32(_)) - if *val >= i32::MIN as i64 && *val <= i32::MAX as i64 => + + (CoercedNumericValue::NegInt(val), AnalysedType::S8(_)) + if *val >= i8::MIN as i64 && *val <= i8::MAX as i64 => { - Some(TypeAnnotatedValue::S32(*val as i32)) + Some((*val as i8).into_value_and_type()) } (CoercedNumericValue::NegInt(val), AnalysedType::S16(_)) if *val >= i16::MIN as i64 && *val <= i16::MAX as i64 => { - Some(TypeAnnotatedValue::S16(*val as i32)) + Some((*val as i16).into_value_and_type()) } - (CoercedNumericValue::NegInt(val), AnalysedType::S8(_)) - if *val >= i8::MIN as i64 && *val <= i8::MAX as i64 => + (CoercedNumericValue::NegInt(val), AnalysedType::S32(_)) + if *val >= i32::MIN as i64 && *val <= i32::MAX as i64 => { - Some(TypeAnnotatedValue::S8(*val as i32)) + Some((*val as i32).into_value_and_type()) + } + (CoercedNumericValue::NegInt(val), AnalysedType::S64(_)) => { + Some((*val).into_value_and_type()) } (CoercedNumericValue::Float(val), AnalysedType::F64(_)) => { - Some(TypeAnnotatedValue::F64(*val)) + Some((*val).into_value_and_type()) } (CoercedNumericValue::Float(val), AnalysedType::F32(_)) if *val >= f32::MIN as f64 && *val <= f32::MAX as f64 => { - Some(TypeAnnotatedValue::F32(*val as f32)) + Some((*val as f32).into_value_and_type()) } _ => None, @@ -299,21 +320,22 @@ impl Display for LiteralValue { mod internal { use crate::interpreter::literal::CoercedNumericValue; - use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; + use golem_wasm_rpc::{Value, ValueAndType}; pub(crate) fn get_numeric_value( - type_annotated_value: &TypeAnnotatedValue, + type_annotated_value: &ValueAndType, ) -> Option { - match type_annotated_value { - TypeAnnotatedValue::S16(value) => Some(CoercedNumericValue::NegInt(*value as i64)), - TypeAnnotatedValue::S32(value) => Some(CoercedNumericValue::NegInt(*value as i64)), - TypeAnnotatedValue::S64(value) => Some(CoercedNumericValue::NegInt(*value)), - TypeAnnotatedValue::U16(value) => Some(CoercedNumericValue::PosInt(*value as u64)), - TypeAnnotatedValue::U32(value) => Some(CoercedNumericValue::PosInt(*value as u64)), - TypeAnnotatedValue::U64(value) => Some(CoercedNumericValue::PosInt(*value)), - TypeAnnotatedValue::F32(value) => Some(CoercedNumericValue::Float(*value as f64)), - TypeAnnotatedValue::F64(value) => Some(CoercedNumericValue::Float(*value)), - TypeAnnotatedValue::U8(value) => Some(CoercedNumericValue::PosInt(*value as u64)), + match &type_annotated_value.value { + Value::S8(value) => Some(CoercedNumericValue::NegInt(*value as i64)), + Value::S16(value) => Some(CoercedNumericValue::NegInt(*value as i64)), + Value::S32(value) => Some(CoercedNumericValue::NegInt(*value as i64)), + Value::S64(value) => Some(CoercedNumericValue::NegInt(*value)), + Value::U8(value) => Some(CoercedNumericValue::PosInt(*value as u64)), + Value::U16(value) => Some(CoercedNumericValue::PosInt(*value as u64)), + Value::U32(value) => Some(CoercedNumericValue::PosInt(*value as u64)), + Value::U64(value) => Some(CoercedNumericValue::PosInt(*value)), + Value::F32(value) => Some(CoercedNumericValue::Float(*value as f64)), + Value::F64(value) => Some(CoercedNumericValue::Float(*value)), _ => None, } } diff --git a/golem-rib/src/interpreter/rib_interpreter.rs b/golem-rib/src/interpreter/rib_interpreter.rs index bcfe61db8..8847ed8b3 100644 --- a/golem-rib/src/interpreter/rib_interpreter.rs +++ b/golem-rib/src/interpreter/rib_interpreter.rs @@ -275,23 +275,20 @@ mod internal { }; use golem_wasm_ast::analysis::AnalysedType; use golem_wasm_ast::analysis::TypeResult; - use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; - use golem_wasm_rpc::protobuf::typed_result::ResultValue; - use golem_wasm_rpc::protobuf::{NameValuePair, TypedRecord, TypedTuple}; - use golem_wasm_rpc::type_annotated_value_to_string; + use golem_wasm_rpc::{print_value_and_type, IntoValueAndType, Value, ValueAndType}; use crate::interpreter::instruction_cursor::RibByteCodeCursor; - use golem_wasm_ast::analysis::analysed_type::str; + use golem_wasm_ast::analysis::analysed_type::{str, tuple}; use std::ops::Deref; use std::sync::Arc; pub(crate) fn default_worker_invoke_async() -> RibFunctionInvoke { Arc::new(|_, _| { Box::pin(async { - Ok(TypeAnnotatedValue::Tuple(TypedTuple { - typ: vec![], - value: vec![], - })) + Ok(ValueAndType { + value: Value::Tuple(vec![]), + typ: tuple(vec![]), + }) }) }) } @@ -304,9 +301,10 @@ mod internal { )?; let bool_opt = match rib_result { - RibInterpreterStackValue::Val(TypeAnnotatedValue::List(typed_list)) => { - Some(typed_list.values.is_empty()) - } + RibInterpreterStackValue::Val(ValueAndType { + value: Value::List(items), + .. + }) => Some(items.is_empty()), RibInterpreterStackValue::Iterator(iter) => { let mut peekable_iter = iter.peekable(); let result = peekable_iter.peek().is_some(); @@ -337,7 +335,7 @@ mod internal { }; let bool = bool_opt.ok_or("Internal Error: Failed to run instruction is_empty")?; - interpreter_stack.push_val(TypeAnnotatedValue::Bool(bool)); + interpreter_stack.push_val(bool.into_value_and_type()); Ok(()) } @@ -362,15 +360,14 @@ mod internal { pub(crate) fn run_list_to_iterator_instruction( interpreter_stack: &mut InterpreterStack, ) -> Result<(), String> { - if let Some(RibInterpreterStackValue::Val(TypeAnnotatedValue::List(items))) = - interpreter_stack.pop() + if let Some(items) = interpreter_stack + .pop() + .and_then(|v| v.get_val()) + .and_then(|v| v.into_list_items()) { - let iter = items - .values - .into_iter() - .map(|x| x.clone().type_annotated_value.unwrap()); - - interpreter_stack.push(RibInterpreterStackValue::Iterator(Box::new(iter))); + interpreter_stack.push(RibInterpreterStackValue::Iterator(Box::new( + items.into_iter(), + ))); Ok(()) } else { @@ -456,7 +453,7 @@ mod internal { let result = interpreter_stack .pop_sink() .ok_or("Failed to retrieve items from sink")?; - interpreter_stack.push_list(result, &str()); + interpreter_stack.push_list(result.into_iter().map(|vnt| vnt.value).collect(), &str()); Ok(()) } @@ -507,14 +504,7 @@ mod internal { interpreter_stack: &mut InterpreterStack, ) -> Result<(), String> { let name_type_pair = match analysed_type { - AnalysedType::Record(type_record) => type_record - .fields - .into_iter() - .map(|field| golem_wasm_ast::analysis::protobuf::NameTypePair { - name: field.name, - typ: Some((&field.typ).into()), - }) - .collect(), + AnalysedType::Record(type_record) => type_record.fields, _ => { return Err(format!( "Internal Error: Expected a record type to create a record. But obtained {:?}", @@ -531,25 +521,30 @@ mod internal { field_name: String, interpreter_stack: &mut InterpreterStack, ) -> Result<(), String> { - let current_record = interpreter_stack.try_pop_record()?; + let (current_record_fields, record_type) = interpreter_stack.try_pop_record()?; + let idx = record_type + .fields + .iter() + .position(|pair| pair.name == field_name) + .ok_or(format!( + "Invalid field name {field_name}, should be one of {}", + record_type + .fields + .iter() + .map(|pair| pair.name.clone()) + .collect::>() + .join(", ") + ))?; let value = interpreter_stack.try_pop_val()?; - let mut existing_fields = current_record.value; - - let name_value_pair = NameValuePair { - name: field_name.clone(), - value: Some(golem_wasm_rpc::protobuf::TypeAnnotatedValue { - type_annotated_value: Some(value), - }), - }; - - existing_fields.push(name_value_pair); - interpreter_stack.push_val(TypeAnnotatedValue::Record(TypedRecord { - value: existing_fields, - typ: current_record.typ, - })); + let mut fields = current_record_fields; + fields[idx] = value.value; + interpreter_stack.push_val(ValueAndType { + value: Value::Record(fields), + typ: AnalysedType::Record(record_type), + }); Ok(()) } @@ -560,16 +555,16 @@ mod internal { ) -> Result<(), String> { match analysed_type { AnalysedType::List(inner_type) => { - let type_annotated_values = + let items = interpreter_stack.try_pop_n_val(list_size)?; - interpreter_stack.push_list(type_annotated_values, inner_type.inner.deref()); + interpreter_stack.push_list(items.into_iter().map(|vnt| vnt.value).collect(), inner_type.inner.deref()); Ok(()) } - _ => Err(format!("Internal Error: Failed to create tuple due to mismatch in types. Expected: list, Actual: {:?}", analysed_type)), + _ => Err(format!("Internal Error: Failed to create tuple due to mismatch in types. Expected: list, Actual: {:?}", analysed_type)), } } @@ -579,13 +574,10 @@ mod internal { interpreter_stack: &mut InterpreterStack, ) -> Result<(), String> { match analysed_type { - AnalysedType::Tuple(inner_type) => { - let type_annotated_values = + AnalysedType::Tuple(_inner_type) => { + let items = interpreter_stack.try_pop_n_val(list_size)?; - - - interpreter_stack.push_tuple(type_annotated_values, &inner_type.items); - + interpreter_stack.push_tuple(items); Ok(()) } @@ -599,7 +591,7 @@ mod internal { let bool = interpreter_stack.try_pop_bool()?; let negated = !bool; - interpreter_stack.push_val(TypeAnnotatedValue::Bool(negated)); + interpreter_stack.push_val(negated.into_value_and_type()); Ok(()) } @@ -675,20 +667,18 @@ mod internal { let record = interpreter_stack.try_pop()?; match record { - RibInterpreterStackValue::Val(TypeAnnotatedValue::Record(record)) => { - let field = record - .value + RibInterpreterStackValue::Val(ValueAndType { + value: Value::Record(field_values), + typ: AnalysedType::Record(typ), + }) => { + let field = field_values .into_iter() - .find(|field| field.name == field_name) + .zip(typ.fields) + .find(|(_value, field)| field.name == field_name) .ok_or(format!("Field {} not found in the record", field_name))?; - let value = field.value.ok_or("Field value not found".to_string())?; - - let inner_type_annotated_value = value - .type_annotated_value - .ok_or("Field value not found".to_string())?; - - interpreter_stack.push_val(inner_type_annotated_value); + let value = field.0; + interpreter_stack.push_val(ValueAndType::new(value, field.1.typ)); Ok(()) } result => Err(format!( @@ -707,32 +697,34 @@ mod internal { .ok_or("Failed to get a record from the stack to select a field".to_string())?; match record { - RibInterpreterStackValue::Val(TypeAnnotatedValue::List(typed_list)) => { - let value = typed_list - .values + RibInterpreterStackValue::Val(ValueAndType { + value: Value::List(items), + typ: AnalysedType::List(typ), + }) => { + let value = items .get(index) .ok_or(format!("Index {} not found in the list", index))? .clone(); - let inner_type_annotated_value = value - .type_annotated_value - .ok_or("Field value not found".to_string())?; - - interpreter_stack.push_val(inner_type_annotated_value); + interpreter_stack.push_val(ValueAndType::new(value, (*typ.inner).clone())); Ok(()) } - RibInterpreterStackValue::Val(TypeAnnotatedValue::Tuple(typed_tuple)) => { - let value = typed_tuple - .value + RibInterpreterStackValue::Val(ValueAndType { + value: Value::Tuple(items), + typ: AnalysedType::Tuple(typ), + }) => { + let value = items .get(index) .ok_or(format!("Index {} not found in the tuple", index))? .clone(); - let inner_type_annotated_value = value - .type_annotated_value - .ok_or("Field value not found".to_string())?; + let item_type = typ + .items + .get(index) + .ok_or(format!("Index {} not found in the tuple type", index))? + .clone(); - interpreter_stack.push_val(inner_type_annotated_value); + interpreter_stack.push_val(ValueAndType::new(value, item_type)); Ok(()) } result => Err(format!( @@ -781,7 +773,7 @@ mod internal { interpreter_stack.push_variant( variant_name.clone(), - arg_value, + arg_value.map(|vnt| vnt.value), variants.cases.clone(), ); Ok(()) @@ -806,8 +798,7 @@ mod internal { function: ParsedFunctionReference::Function { function }, }; - interpreter_stack - .push_val(TypeAnnotatedValue::Str(parsed_function_name.to_string())); + interpreter_stack.push_val(parsed_function_name.to_string().into_value_and_type()); } FunctionReferenceType::RawResourceConstructor { resource } => { @@ -816,8 +807,7 @@ mod internal { function: ParsedFunctionReference::RawResourceConstructor { resource }, }; - interpreter_stack - .push_val(TypeAnnotatedValue::Str(parsed_function_name.to_string())); + interpreter_stack.push_val(parsed_function_name.to_string().into_value_and_type()); } FunctionReferenceType::RawResourceDrop { resource } => { let parsed_function_name = ParsedFunctionName { @@ -825,8 +815,7 @@ mod internal { function: ParsedFunctionReference::RawResourceDrop { resource }, }; - interpreter_stack - .push_val(TypeAnnotatedValue::Str(parsed_function_name.to_string())); + interpreter_stack.push_val(parsed_function_name.to_string().into_value_and_type()); } FunctionReferenceType::RawResourceMethod { resource, method } => { let parsed_function_name = ParsedFunctionName { @@ -834,8 +823,7 @@ mod internal { function: ParsedFunctionReference::RawResourceMethod { resource, method }, }; - interpreter_stack - .push_val(TypeAnnotatedValue::Str(parsed_function_name.to_string())); + interpreter_stack.push_val(parsed_function_name.to_string().into_value_and_type()); } FunctionReferenceType::RawResourceStaticMethod { resource, method } => { let parsed_function_name = ParsedFunctionName { @@ -843,36 +831,34 @@ mod internal { function: ParsedFunctionReference::RawResourceStaticMethod { resource, method }, }; - interpreter_stack - .push_val(TypeAnnotatedValue::Str(parsed_function_name.to_string())); + interpreter_stack.push_val(parsed_function_name.to_string().into_value_and_type()); } FunctionReferenceType::IndexedResourceConstructor { resource, arg_size } => { let last_n_elements = interpreter_stack .pop_n(arg_size) .ok_or("Failed to get values from the stack".to_string())?; - let type_annotated_value = last_n_elements + let parameter_values = last_n_elements .iter() .map(|interpreter_result| { interpreter_result .get_val() .ok_or("Internal Error: Failed to construct resource".to_string()) }) - .collect::, String>>()?; + .collect::, String>>()?; let parsed_function_name = ParsedFunctionName { site, function: ParsedFunctionReference::IndexedResourceConstructor { resource, - resource_params: type_annotated_value + resource_params: parameter_values .iter() - .map(type_annotated_value_to_string) + .map(print_value_and_type) .collect::, String>>()?, }, }; - interpreter_stack - .push_val(TypeAnnotatedValue::Str(parsed_function_name.to_string())); + interpreter_stack.push_val(parsed_function_name.to_string().into_value_and_type()); } FunctionReferenceType::IndexedResourceMethod { resource, @@ -883,29 +869,28 @@ mod internal { .pop_n(arg_size) .ok_or("Failed to get values from the stack".to_string())?; - let type_anntoated_values = last_n_elements + let param_values = last_n_elements .iter() .map(|interpreter_result| { interpreter_result.get_val().ok_or( "Internal Error: Failed to call indexed resource method".to_string(), ) }) - .collect::, String>>()?; + .collect::, String>>()?; let parsed_function_name = ParsedFunctionName { site, function: ParsedFunctionReference::IndexedResourceMethod { resource, - resource_params: type_anntoated_values + resource_params: param_values .iter() - .map(type_annotated_value_to_string) + .map(print_value_and_type) .collect::, String>>()?, method, }, }; - interpreter_stack - .push_val(TypeAnnotatedValue::Str(parsed_function_name.to_string())); + interpreter_stack.push_val(parsed_function_name.to_string().into_value_and_type()); } FunctionReferenceType::IndexedResourceStaticMethod { resource, @@ -917,29 +902,28 @@ mod internal { .to_string(), )?; - let type_anntoated_values = last_n_elements + let param_values = last_n_elements .iter() .map(|interpreter_result| { interpreter_result.get_val().ok_or( "Internal error: Failed to call static resource method".to_string(), ) }) - .collect::, String>>()?; + .collect::, String>>()?; let parsed_function_name = ParsedFunctionName { site, function: ParsedFunctionReference::IndexedResourceStaticMethod { resource, - resource_params: type_anntoated_values + resource_params: param_values .iter() - .map(type_annotated_value_to_string) + .map(print_value_and_type) .collect::, String>>()?, method, }, }; - interpreter_stack - .push_val(TypeAnnotatedValue::Str(parsed_function_name.to_string())); + interpreter_stack.push_val(parsed_function_name.to_string().into_value_and_type()); } FunctionReferenceType::IndexedResourceDrop { resource, arg_size } => { let last_n_elements = interpreter_stack.pop_n(arg_size).ok_or( @@ -947,28 +931,27 @@ mod internal { .to_string(), )?; - let type_annotated_values = last_n_elements + let param_values = last_n_elements .iter() .map(|interpreter_result| { interpreter_result.get_val().ok_or( "Internal Error: Failed to call indexed resource drop".to_string(), ) }) - .collect::, String>>()?; + .collect::, String>>()?; let parsed_function_name = ParsedFunctionName { site, function: ParsedFunctionReference::IndexedResourceDrop { resource, - resource_params: type_annotated_values + resource_params: param_values .iter() - .map(type_annotated_value_to_string) + .map(print_value_and_type) .collect::, String>>()?, }, }; - interpreter_stack - .push_val(TypeAnnotatedValue::Str(parsed_function_name.to_string())); + interpreter_stack.push_val(parsed_function_name.to_string().into_value_and_type()); } } @@ -988,7 +971,7 @@ mod internal { .pop_n(arg_size) .ok_or("Internal Error: Failed to get arguments for the function call".to_string())?; - let type_annotated_values = last_n_elements + let parameter_values = last_n_elements .iter() .map(|interpreter_result| { interpreter_result.get_val().ok_or(format!( @@ -996,22 +979,27 @@ mod internal { function_name )) }) - .collect::, String>>()?; + .collect::, String>>()?; let result = interpreter_env - .invoke_worker_function_async(function_name, type_annotated_values) + .invoke_worker_function_async(function_name, parameter_values) .await?; let interpreter_result = match result { - TypeAnnotatedValue::Tuple(TypedTuple { value, .. }) if value.is_empty() => { - Ok(RibInterpreterStackValue::Unit) - } - TypeAnnotatedValue::Tuple(TypedTuple { value, .. }) if value.len() == 1 => { - let inner = value[0] - .clone() - .type_annotated_value - .ok_or("Internal Error. Unexpected empty result")?; - Ok(RibInterpreterStackValue::Val(inner)) + ValueAndType { + value: Value::Tuple(value), + .. + } if value.is_empty() => Ok(RibInterpreterStackValue::Unit), + ValueAndType { + value: Value::Tuple(value), + typ: AnalysedType::Tuple(typ), + } if value.len() == 1 => { + let inner_value = value[0].clone(); + let inner_type = typ.items[0].clone(); + Ok(RibInterpreterStackValue::Val(ValueAndType::new( + inner_value, + inner_type, + ))) } _ => Err("Named multiple results are not supported yet".to_string()), }; @@ -1043,23 +1031,32 @@ mod internal { .ok_or("Failed to get a tag value from the stack to unwrap".to_string())?; let tag = match value { - TypeAnnotatedValue::Variant(variant) => variant.case_name, - TypeAnnotatedValue::Option(option) => match option.value { + ValueAndType { + value: Value::Variant { case_idx, .. }, + typ: AnalysedType::Variant(typ), + } => typ.cases[case_idx as usize].name.clone(), + ValueAndType { + value: Value::Option(option), + .. + } => match option { Some(_) => "some".to_string(), None => "none".to_string(), }, - TypeAnnotatedValue::Result(result) => match result.result_value { - Some(result_value) => match result_value { - ResultValue::OkValue(_) => "ok".to_string(), - ResultValue::ErrorValue(_) => "err".to_string(), - }, - None => "err".to_string(), + ValueAndType { + value: Value::Result(result_value), + .. + } => match result_value { + Ok(_) => "ok".to_string(), + Err(_) => "err".to_string(), }, - TypeAnnotatedValue::Enum(enum_) => enum_.value, + ValueAndType { + value: Value::Enum(idx), + typ: AnalysedType::Enum(typ), + } => typ.cases[idx as usize].clone(), _ => "untagged".to_string(), }; - interpreter_stack.push_val(TypeAnnotatedValue::Str(tag)); + interpreter_stack.push_val(tag.into_value_and_type()); Ok(()) } @@ -1071,7 +1068,7 @@ mod internal { match analysed_type { AnalysedType::Option(analysed_type) => { - interpreter_stack.push_some(value, analysed_type.inner.deref()); + interpreter_stack.push_some(value.value, analysed_type.inner.deref()); Ok(()) } _ => Err(format!( @@ -1105,7 +1102,7 @@ mod internal { match analysed_type { AnalysedType::Result(TypeResult { ok, err }) => { - interpreter_stack.push_ok(value, ok.as_deref(), err.as_deref()); + interpreter_stack.push_ok(value.value, ok.as_deref(), err.as_deref()); Ok(()) } _ => Err(format!( @@ -1123,7 +1120,7 @@ mod internal { match analysed_type { AnalysedType::Result(TypeResult { ok, err }) => { - interpreter_stack.push_err(value, ok.as_deref(), err.as_deref()); + interpreter_stack.push_err(value.value, ok.as_deref(), err.as_deref()); Ok(()) } _ => Err(format!( @@ -1146,7 +1143,7 @@ mod internal { acc }); - interpreter_stack.push_val(TypeAnnotatedValue::Str(str)); + interpreter_stack.push_val(str.into_value_and_type()); Ok(()) } @@ -1159,19 +1156,18 @@ mod interpreter_tests { use super::*; use crate::{InstructionId, VariableId}; use golem_wasm_ast::analysis::analysed_type::{field, list, record, s32}; - use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; - use golem_wasm_rpc::protobuf::{NameValuePair, TypedList, TypedRecord}; + use golem_wasm_rpc::{IntoValue, IntoValueAndType, Value, ValueAndType}; #[test] async fn test_interpreter_for_literal() { let mut interpreter = Interpreter::default(); let instructions = RibByteCode { - instructions: vec![RibIR::PushLit(TypeAnnotatedValue::S32(1))], + instructions: vec![RibIR::PushLit(1i32.into_value_and_type())], }; let result = interpreter.run(instructions).await.unwrap(); - assert_eq!(result.get_val().unwrap(), TypeAnnotatedValue::S32(1)); + assert_eq!(result.get_val().unwrap(), 1i32.into_value_and_type()); } #[test] @@ -1180,8 +1176,8 @@ mod interpreter_tests { let instructions = RibByteCode { instructions: vec![ - RibIR::PushLit(TypeAnnotatedValue::S32(1)), - RibIR::PushLit(TypeAnnotatedValue::U32(1)), + RibIR::PushLit(1i32.into_value_and_type()), + RibIR::PushLit(1u32.into_value_and_type()), RibIR::EqualTo, ], }; @@ -1196,8 +1192,8 @@ mod interpreter_tests { let instructions = RibByteCode { instructions: vec![ - RibIR::PushLit(TypeAnnotatedValue::S32(1)), - RibIR::PushLit(TypeAnnotatedValue::U32(2)), + RibIR::PushLit(1i32.into_value_and_type()), + RibIR::PushLit(2u32.into_value_and_type()), RibIR::GreaterThan, ], }; @@ -1212,8 +1208,8 @@ mod interpreter_tests { let instructions = RibByteCode { instructions: vec![ - RibIR::PushLit(TypeAnnotatedValue::S32(2)), - RibIR::PushLit(TypeAnnotatedValue::U32(1)), + RibIR::PushLit(2i32.into_value_and_type()), + RibIR::PushLit(1u32.into_value_and_type()), RibIR::LessThan, ], }; @@ -1228,8 +1224,8 @@ mod interpreter_tests { let instructions = RibByteCode { instructions: vec![ - RibIR::PushLit(TypeAnnotatedValue::S32(2)), - RibIR::PushLit(TypeAnnotatedValue::U32(3)), + RibIR::PushLit(2i32.into_value_and_type()), + RibIR::PushLit(3u32.into_value_and_type()), RibIR::GreaterThanOrEqualTo, ], }; @@ -1244,8 +1240,8 @@ mod interpreter_tests { let instructions = RibByteCode { instructions: vec![ - RibIR::PushLit(TypeAnnotatedValue::S32(2)), // rhs - RibIR::PushLit(TypeAnnotatedValue::S32(1)), // lhs + RibIR::PushLit(2i32.into_value_and_type()), // rhs + RibIR::PushLit(1i32.into_value_and_type()), // lhs RibIR::LessThanOrEqualTo, ], }; @@ -1260,14 +1256,14 @@ mod interpreter_tests { let instructions = RibByteCode { instructions: vec![ - RibIR::PushLit(TypeAnnotatedValue::S32(1)), + RibIR::PushLit(1i32.into_value_and_type()), RibIR::AssignVar(VariableId::local_with_no_id("x")), RibIR::LoadVar(VariableId::local_with_no_id("x")), ], }; let result = interpreter.run(instructions).await.unwrap(); - assert_eq!(result.get_val().unwrap(), TypeAnnotatedValue::S32(1)); + assert_eq!(result.get_val().unwrap(), 1i32.into_value_and_type()); } #[test] @@ -1277,7 +1273,7 @@ mod interpreter_tests { let instructions = RibByteCode { instructions: vec![ RibIR::Jump(InstructionId::init()), - RibIR::PushLit(TypeAnnotatedValue::S32(1)), + RibIR::PushLit(1i32.into_value_and_type()), RibIR::Label(InstructionId::init()), ], }; @@ -1294,9 +1290,9 @@ mod interpreter_tests { let instructions = RibByteCode { instructions: vec![ - RibIR::PushLit(TypeAnnotatedValue::Bool(false)), + RibIR::PushLit(false.into_value_and_type()), RibIR::JumpIfFalse(id.clone()), - RibIR::PushLit(TypeAnnotatedValue::S32(1)), + RibIR::PushLit(1i32.into_value_and_type()), RibIR::Label(id), ], }; @@ -1311,8 +1307,8 @@ mod interpreter_tests { let instructions = RibByteCode { instructions: vec![ - RibIR::PushLit(TypeAnnotatedValue::S32(2)), - RibIR::PushLit(TypeAnnotatedValue::S32(1)), + RibIR::PushLit(2i32.into_value_and_type()), + RibIR::PushLit(1i32.into_value_and_type()), RibIR::CreateAndPushRecord(record(vec![field("x", s32()), field("y", s32())])), RibIR::UpdateRecord("x".to_string()), RibIR::UpdateRecord("y".to_string()), @@ -1320,32 +1316,11 @@ mod interpreter_tests { }; let result = interpreter.run(instructions).await.unwrap(); - let expected = TypeAnnotatedValue::Record(TypedRecord { - value: vec![ - NameValuePair { - name: "x".to_string(), - value: Some(golem_wasm_rpc::protobuf::TypeAnnotatedValue { - type_annotated_value: Some(TypeAnnotatedValue::S32(1)), - }), - }, - NameValuePair { - name: "y".to_string(), - value: Some(golem_wasm_rpc::protobuf::TypeAnnotatedValue { - type_annotated_value: Some(TypeAnnotatedValue::S32(2)), - }), - }, - ], - typ: vec![ - golem_wasm_ast::analysis::protobuf::NameTypePair { - name: "x".to_string(), - typ: Some(golem_wasm_ast::analysis::protobuf::Type::from(&s32())), - }, - golem_wasm_ast::analysis::protobuf::NameTypePair { - name: "y".to_string(), - typ: Some(golem_wasm_ast::analysis::protobuf::Type::from(&s32())), - }, - ], - }); + let expected = ValueAndType::new( + Value::Record(vec![1i32.into_value(), 2i32.into_value()]), + record(vec![field("x", s32()), field("y", s32())]), + ); + assert_eq!(result.get_val().unwrap(), expected); } @@ -1355,24 +1330,17 @@ mod interpreter_tests { let instructions = RibByteCode { instructions: vec![ - RibIR::PushLit(TypeAnnotatedValue::S32(2)), - RibIR::PushLit(TypeAnnotatedValue::S32(1)), + RibIR::PushLit(2i32.into_value_and_type()), + RibIR::PushLit(1i32.into_value_and_type()), RibIR::PushList(list(s32()), 2), ], }; let result = interpreter.run(instructions).await.unwrap(); - let expected = TypeAnnotatedValue::List(TypedList { - values: vec![ - golem_wasm_rpc::protobuf::TypeAnnotatedValue { - type_annotated_value: Some(TypeAnnotatedValue::S32(1)), - }, - golem_wasm_rpc::protobuf::TypeAnnotatedValue { - type_annotated_value: Some(TypeAnnotatedValue::S32(2)), - }, - ], - typ: Some(golem_wasm_ast::analysis::protobuf::Type::from(&s32())), - }); + let expected = ValueAndType::new( + Value::List(vec![1i32.into_value(), 2i32.into_value()]), + list(s32()), + ); assert_eq!(result.get_val().unwrap(), expected); } @@ -1382,8 +1350,8 @@ mod interpreter_tests { let instructions = RibByteCode { instructions: vec![ - RibIR::PushLit(TypeAnnotatedValue::S32(1)), - RibIR::PushLit(TypeAnnotatedValue::S32(2)), + RibIR::PushLit(1i32.into_value_and_type()), + RibIR::PushLit(2i32.into_value_and_type()), RibIR::CreateAndPushRecord(record(vec![field("x", s32())])), RibIR::UpdateRecord("x".to_string()), RibIR::SelectField("x".to_string()), @@ -1391,7 +1359,7 @@ mod interpreter_tests { }; let result = interpreter.run(instructions).await.unwrap(); - assert_eq!(result.get_val().unwrap(), TypeAnnotatedValue::S32(2)); + assert_eq!(result.get_val().unwrap(), 2i32.into_value_and_type()); } #[test] @@ -1400,23 +1368,22 @@ mod interpreter_tests { let instructions = RibByteCode { instructions: vec![ - RibIR::PushLit(TypeAnnotatedValue::S32(1)), - RibIR::PushLit(TypeAnnotatedValue::S32(2)), + RibIR::PushLit(1i32.into_value_and_type()), + RibIR::PushLit(2i32.into_value_and_type()), RibIR::PushList(list(s32()), 2), RibIR::SelectIndex(0), ], }; let result = interpreter.run(instructions).await.unwrap(); - assert_eq!(result.get_val().unwrap(), TypeAnnotatedValue::S32(2)); + assert_eq!(result.get_val().unwrap(), 2i32.into_value_and_type()); } mod list_reduce_interpreter_tests { - use test_r::test; - use crate::interpreter::rib_interpreter::Interpreter; use crate::{compiler, Expr}; - use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; + use golem_wasm_rpc::IntoValueAndType; + use test_r::test; #[test] async fn test_list_reduce() { @@ -1442,7 +1409,7 @@ mod interpreter_tests { .get_val() .unwrap(); - assert_eq!(result, TypeAnnotatedValue::U8(3)); + assert_eq!(result, 3u8.into_value_and_type()); } #[test] @@ -1475,7 +1442,7 @@ mod interpreter_tests { .get_val() .unwrap(); - assert_eq!(result, TypeAnnotatedValue::Str("foo, bar".to_string())); + assert_eq!(result, "foo, bar".into_value_and_type()); } #[test] @@ -1504,7 +1471,7 @@ mod interpreter_tests { .get_val() .unwrap(); - assert_eq!(result, TypeAnnotatedValue::Str("foo, bar".to_string())); + assert_eq!(result, "foo, bar".into_value_and_type()); } #[test] @@ -1531,7 +1498,7 @@ mod interpreter_tests { .get_val() .unwrap(); - assert_eq!(result, TypeAnnotatedValue::U8(0)); + assert_eq!(result, 0u8.into_value_and_type()); } } @@ -1566,10 +1533,10 @@ mod interpreter_tests { .unwrap(); let expected = r#"["foo", "bar"]"#; - let expected_type_annotated_value = - golem_wasm_rpc::type_annotated_value_from_str(&list(str()), expected).unwrap(); + let expected_value = + golem_wasm_rpc::parse_value_and_type(&list(str()), expected).unwrap(); - assert_eq!(result, expected_type_annotated_value); + assert_eq!(result, expected_value); } #[test] @@ -1598,7 +1565,7 @@ mod interpreter_tests { let expected = r#"[]"#; let expected_type_annotated_value = - golem_wasm_rpc::type_annotated_value_from_str(&list(str()), expected).unwrap(); + golem_wasm_rpc::parse_value_and_type(&list(str()), expected).unwrap(); assert_eq!(result, expected_type_annotated_value); } @@ -1611,7 +1578,7 @@ mod interpreter_tests { use crate::interpreter::rib_interpreter::Interpreter; use crate::{compiler, Expr, FunctionTypeRegistry}; use golem_wasm_ast::analysis::analysed_type::{field, record, str, tuple, u16, u64}; - use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; + use golem_wasm_rpc::IntoValueAndType; #[test] async fn test_pattern_match_on_option_nested() { @@ -1633,7 +1600,7 @@ mod interpreter_tests { let compiled = compiler::compile(&expr, &vec![]).unwrap(); let result = interpreter.run(compiled.byte_code).await.unwrap(); - assert_eq!(result.get_val().unwrap(), TypeAnnotatedValue::U64(0)); + assert_eq!(result.get_val().unwrap(), 0u64.into_value_and_type()); } #[test] @@ -1653,10 +1620,7 @@ mod interpreter_tests { let compiled = compiler::compile(&expr, &vec![]).unwrap(); let result = interpreter.run(compiled.byte_code).await.unwrap(); - assert_eq!( - result.get_val().unwrap(), - TypeAnnotatedValue::Str("1 foo bar".to_string()) - ); + assert_eq!(result.get_val().unwrap(), "1 foo bar".into_value_and_type()); } #[test] @@ -1678,10 +1642,7 @@ mod interpreter_tests { let compiled = compiler::compile(&expr, &vec![]).unwrap(); let result = interpreter.run(compiled.byte_code).await.unwrap(); - assert_eq!( - result.get_val().unwrap(), - TypeAnnotatedValue::Str("1 foo bar".to_string()) - ); + assert_eq!(result.get_val().unwrap(), "1 foo bar".into_value_and_type()); } #[test] @@ -1701,10 +1662,7 @@ mod interpreter_tests { let compiled = compiler::compile(&expr, &vec![]).unwrap(); let result = interpreter.run(compiled.byte_code).await.unwrap(); - assert_eq!( - result.get_val().unwrap(), - TypeAnnotatedValue::Str("1 bar".to_string()) - ); + assert_eq!(result.get_val().unwrap(), "1 bar".into_value_and_type()); } #[test] @@ -1734,7 +1692,7 @@ mod interpreter_tests { assert_eq!( result.get_val().unwrap(), - TypeAnnotatedValue::Str("foo 100 1 bar jak validate prod dev test".to_string()) + "foo 100 1 bar jak validate prod dev test".into_value_and_type() ); } @@ -1764,7 +1722,7 @@ mod interpreter_tests { assert_eq!( result.get_val().unwrap(), - TypeAnnotatedValue::Str("dev 1 bar jak baz".to_string()) + "dev 1 bar jak baz".into_value_and_type() ); } @@ -1773,11 +1731,9 @@ mod interpreter_tests { let input_analysed_type = internal::get_analysed_type_record(); let output_analysed_type = internal::get_analysed_type_result(); - let result_value = - internal::get_type_annotated_value(&output_analysed_type, r#"ok(1)"#); + let result_value = internal::get_value_and_type(&output_analysed_type, r#"ok(1)"#); - let mut interpreter = - internal::static_test_interpreter(&output_analysed_type, &result_value); + let mut interpreter = internal::static_test_interpreter(&result_value); let analysed_exports = internal::get_component_metadata( "my-worker-function", @@ -1799,7 +1755,7 @@ mod interpreter_tests { let compiled = compiler::compile(&expr, &analysed_exports).unwrap(); let result = interpreter.run(compiled.byte_code).await.unwrap(); - let expected = internal::get_type_annotated_value( + let expected = internal::get_value_and_type( &record(vec![field("body", u64()), field("status", u16())]), r#"{body: 1, status: 200}"#, ); @@ -1813,10 +1769,9 @@ mod interpreter_tests { let output_analysed_type = internal::get_analysed_type_result(); let result_value = - internal::get_type_annotated_value(&output_analysed_type, r#"err("failed")"#); + internal::get_value_and_type(&output_analysed_type, r#"err("failed")"#); - let mut interpreter = - internal::static_test_interpreter(&output_analysed_type, &result_value); + let mut interpreter = internal::static_test_interpreter(&result_value); let analysed_exports = internal::get_component_metadata( "my-worker-function", @@ -1838,10 +1793,8 @@ mod interpreter_tests { let compiled = compiler::compile(&expr, &analysed_exports).unwrap(); let result = interpreter.run(compiled.byte_code).await.unwrap(); - let expected = internal::get_type_annotated_value( - &tuple(vec![str(), str()]), - r#"("failed", "bar")"#, - ); + let expected = + internal::get_value_and_type(&tuple(vec![str(), str()]), r#"("failed", "bar")"#); assert_eq!(result.get_val().unwrap(), expected); } @@ -1856,7 +1809,7 @@ mod interpreter_tests { use golem_wasm_ast::analysis::analysed_type::{ case, f32, field, list, record, str, u32, variant, }; - use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; + use golem_wasm_rpc::IntoValueAndType; #[test] async fn test_interpreter_with_indexed_resource_drop() { @@ -1874,10 +1827,7 @@ mod interpreter_tests { let mut rib_interpreter = Interpreter::default(); let result = rib_interpreter.run(compiled.byte_code).await.unwrap(); - assert_eq!( - result.get_val().unwrap(), - TypeAnnotatedValue::Str("success".to_string()) - ); + assert_eq!(result.get_val().unwrap(), "success".into_value_and_type()); } #[test] @@ -1895,7 +1845,7 @@ mod interpreter_tests { case("success", record(vec![field("order-id", str())])), ]); - let result_value = internal::get_type_annotated_value( + let result_value = internal::get_value_and_type( &result_type, r#" success({order-id: "foo"}) @@ -1906,7 +1856,7 @@ mod interpreter_tests { internal::get_shopping_cart_metadata_with_cart_resource_with_parameters(); let compiled = compiler::compile(&expr, &component_metadata).unwrap(); - let mut rib_executor = internal::static_test_interpreter(&result_type, &result_value); + let mut rib_executor = internal::static_test_interpreter(&result_value); let result = rib_executor.run(compiled.byte_code).await.unwrap(); assert_eq!(result.get_val().unwrap(), result_value); @@ -1929,7 +1879,7 @@ mod interpreter_tests { field("quantity", u32()), ])); - let result_value = internal::get_type_annotated_value( + let result_value = internal::get_value_and_type( &result_type, r#" [{product-id: "foo", name: "bar", price: 100.0, quantity: 1}, {product-id: "bar", name: "baz", price: 200.0, quantity: 2}] @@ -1940,13 +1890,10 @@ mod interpreter_tests { internal::get_shopping_cart_metadata_with_cart_resource_with_parameters(); let compiled = compiler::compile(&expr, &component_metadata).unwrap(); - let mut rib_executor = internal::static_test_interpreter(&result_type, &result_value); + let mut rib_executor = internal::static_test_interpreter(&result_value); let result = rib_executor.run(compiled.byte_code).await.unwrap(); - assert_eq!( - result.get_val().unwrap(), - TypeAnnotatedValue::Str("foo".to_string()) - ); + assert_eq!(result.get_val().unwrap(), "foo".into_value_and_type()); } #[test] @@ -1971,7 +1918,7 @@ mod interpreter_tests { assert_eq!( result.get_val().unwrap(), - TypeAnnotatedValue::Str("successfully updated".to_string()) + "successfully updated".into_value_and_type() ); } @@ -1998,7 +1945,7 @@ mod interpreter_tests { assert_eq!( result.get_val().unwrap(), - TypeAnnotatedValue::Str("successfully added".to_string()) + "successfully added".into_value_and_type() ); } @@ -2024,7 +1971,7 @@ mod interpreter_tests { assert_eq!( result.get_val().unwrap(), - TypeAnnotatedValue::Str("successfully added".to_string()) + "successfully added".into_value_and_type() ); } @@ -2044,7 +1991,7 @@ mod interpreter_tests { field("quantity", u32()), ])); - let result_value = internal::get_type_annotated_value( + let result_value = internal::get_value_and_type( &result_type, r#" [{product-id: "foo", name: "bar", price: 100.0, quantity: 1}, {product-id: "bar", name: "baz", price: 200.0, quantity: 2}] @@ -2054,13 +2001,10 @@ mod interpreter_tests { let component_metadata = internal::get_shopping_cart_metadata_with_cart_raw_resource(); let compiled = compiler::compile(&expr, &component_metadata).unwrap(); - let mut rib_executor = internal::static_test_interpreter(&result_type, &result_value); + let mut rib_executor = internal::static_test_interpreter(&result_value); let result = rib_executor.run(compiled.byte_code).await.unwrap(); - assert_eq!( - result.get_val().unwrap(), - TypeAnnotatedValue::Str("foo".to_string()) - ); + assert_eq!(result.get_val().unwrap(), "foo".into_value_and_type()); } #[test] @@ -2083,7 +2027,7 @@ mod interpreter_tests { assert_eq!( result.get_val().unwrap(), - TypeAnnotatedValue::Str("successfully updated".to_string()) + "successfully updated".into_value_and_type() ); } @@ -2101,7 +2045,7 @@ mod interpreter_tests { case("success", record(vec![field("order-id", str())])), ]); - let result_value = internal::get_type_annotated_value( + let result_value = internal::get_value_and_type( &result_type, r#" success({order-id: "foo"}) @@ -2111,7 +2055,7 @@ mod interpreter_tests { let component_metadata = internal::get_shopping_cart_metadata_with_cart_raw_resource(); let compiled = compiler::compile(&expr, &component_metadata).unwrap(); - let mut rib_executor = internal::static_test_interpreter(&result_type, &result_value); + let mut rib_executor = internal::static_test_interpreter(&result_value); let result = rib_executor.run(compiled.byte_code).await.unwrap(); assert_eq!(result.get_val().unwrap(), result_value); @@ -2131,10 +2075,7 @@ mod interpreter_tests { let mut rib_interpreter = Interpreter::default(); let result = rib_interpreter.run(compiled.byte_code).await.unwrap(); - assert_eq!( - result.get_val().unwrap(), - TypeAnnotatedValue::Str("success".to_string()) - ); + assert_eq!(result.get_val().unwrap(), "success".into_value_and_type()); } } @@ -2149,8 +2090,7 @@ mod interpreter_tests { AnalysedExport, AnalysedFunction, AnalysedFunctionParameter, AnalysedFunctionResult, AnalysedInstance, AnalysedResourceId, AnalysedResourceMode, AnalysedType, }; - use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; - use golem_wasm_rpc::protobuf::TypedTuple; + use golem_wasm_rpc::{Value, ValueAndType}; use std::sync::Arc; pub(crate) fn get_analysed_type_variant() -> AnalysedType { @@ -2368,46 +2308,33 @@ mod interpreter_tests { vec![instance] } - pub(crate) fn get_type_annotated_value( + pub(crate) fn get_value_and_type( analysed_type: &AnalysedType, wasm_wave_str: &str, - ) -> TypeAnnotatedValue { - golem_wasm_rpc::type_annotated_value_from_str(analysed_type, wasm_wave_str).unwrap() + ) -> ValueAndType { + golem_wasm_rpc::parse_value_and_type(analysed_type, wasm_wave_str).unwrap() } - pub(crate) fn static_test_interpreter( - result_type: &AnalysedType, - result_value: &TypeAnnotatedValue, - ) -> Interpreter { + pub(crate) fn static_test_interpreter(result_value: &ValueAndType) -> Interpreter { Interpreter { input: RibInput::default(), - invoke: static_worker_invoke(result_type, result_value), + invoke: static_worker_invoke(result_value), } } - fn static_worker_invoke( - result_type: &AnalysedType, - value: &TypeAnnotatedValue, - ) -> RibFunctionInvoke { - let analysed_type = result_type.clone(); + fn static_worker_invoke(value: &ValueAndType) -> RibFunctionInvoke { let value = value.clone(); Arc::new(move |_, _| { Box::pin({ - let analysed_type = analysed_type.clone(); let value = value.clone(); async move { - let analysed_type = analysed_type.clone(); let value = value.clone(); - Ok(TypeAnnotatedValue::Tuple(TypedTuple { - typ: vec![golem_wasm_ast::analysis::protobuf::Type::from( - &analysed_type, - )], - value: vec![golem_wasm_rpc::protobuf::TypeAnnotatedValue { - type_annotated_value: Some(value.clone()), - }], - })) + Ok(ValueAndType::new( + Value::Tuple(vec![value.value]), + tuple(vec![value.typ]), + )) } }) }) diff --git a/golem-rib/src/interpreter/stack.rs b/golem-rib/src/interpreter/stack.rs index dd6938237..7aa6da87d 100644 --- a/golem-rib/src/interpreter/stack.rs +++ b/golem-rib/src/interpreter/stack.rs @@ -14,12 +14,11 @@ use crate::interpreter::interpreter_stack_value::RibInterpreterStackValue; use crate::{GetLiteralValue, LiteralValue}; -use golem_wasm_ast::analysis::protobuf::NameTypePair; -use golem_wasm_ast::analysis::{AnalysedType, NameOptionTypePair}; -use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; -use golem_wasm_rpc::protobuf::{ - TypedEnum, TypedList, TypedOption, TypedRecord, TypedTuple, TypedVariant, +use golem_wasm_ast::analysis::analysed_type::{list, option, record, str, tuple, variant}; +use golem_wasm_ast::analysis::{ + AnalysedType, NameOptionTypePair, NameTypePair, TypeEnum, TypeRecord, TypeResult, }; +use golem_wasm_rpc::{Value, ValueAndType}; #[derive(Debug)] pub struct InterpreterStack { @@ -38,11 +37,13 @@ impl InterpreterStack { } // Initialise a record in the stack - pub fn create_record(&mut self, analysed_type: Vec) { - self.push_val(TypeAnnotatedValue::Record(TypedRecord { - value: vec![], - typ: analysed_type, - })); + pub fn create_record(&mut self, fields: Vec) { + self.push_val(ValueAndType::new( + Value::Record( + vec![Value::Tuple(vec![]); fields.len()], // pre-initializing with () values, to be replaced later by UpdateRecord instructions + ), + record(fields), + )); } pub fn pop(&mut self) -> Option { @@ -54,7 +55,7 @@ impl InterpreterStack { .ok_or("Internal Error: Failed to pop value from the interpreter stack".to_string()) } - pub fn pop_sink(&mut self) -> Option> { + pub fn pop_sink(&mut self) -> Option> { match self.pop() { Some(RibInterpreterStackValue::Sink(vec, _)) => Some(vec.clone()), _ => None, @@ -76,17 +77,18 @@ impl InterpreterStack { )) } - pub fn try_pop_n_val(&mut self, n: usize) -> Result, String> { + pub fn try_pop_n_val(&mut self, n: usize) -> Result, String> { let stack_values = self.try_pop_n(n)?; stack_values .iter() .map(|interpreter_result| { - interpreter_result - .get_val() - .ok_or(format!("Internal Error: Failed to convert last {} in the stack to type_annotated_value", n)) + interpreter_result.get_val().ok_or(format!( + "Internal Error: Failed to convert last {} in the stack to ValueAndType", + n + )) }) - .collect::, String>>() + .collect::, String>>() } pub fn try_pop_n_literals(&mut self, n: usize) -> Result, String> { @@ -95,7 +97,7 @@ impl InterpreterStack { .iter() .map(|type_value| { type_value.get_literal().ok_or(format!( - "Internal Error: Failed to convert last {} in the stack to literals", + "Internal Error: Failed to convert last {} in the stack to literals {type_value:?}", n )) }) @@ -104,30 +106,34 @@ impl InterpreterStack { pub fn pop_str(&mut self) -> Option { self.pop_val().and_then(|v| match v { - TypeAnnotatedValue::Str(s) => Some(s), + ValueAndType { + value: Value::String(s), + .. + } => Some(s), _ => None, }) } - pub fn pop_val(&mut self) -> Option { + pub fn pop_val(&mut self) -> Option { self.stack.pop().and_then(|v| v.get_val()) } - pub fn try_pop_val(&mut self) -> Result { + pub fn try_pop_val(&mut self) -> Result { self.try_pop().and_then(|x| { x.get_val().ok_or( - "Internal Error: Failed to pop type_annotated_value from the interpreter stack" - .to_string(), + "Internal Error: Failed to pop ValueAndType from the interpreter stack".to_string(), ) }) } - pub fn try_pop_record(&mut self) -> Result { + pub fn try_pop_record(&mut self) -> Result<(Vec, TypeRecord), String> { let value = self.try_pop_val()?; match value { - TypeAnnotatedValue::Record(record) => Ok(record), - + ValueAndType { + value: Value::Record(field_values), + typ: AnalysedType::Record(typ), + } => Ok((field_values, typ)), _ => Err("Internal Error: Failed to pop a record from the interpreter".to_string()), } } @@ -151,11 +157,11 @@ impl InterpreterStack { )) } - pub fn push_val(&mut self, element: TypeAnnotatedValue) { + pub fn push_val(&mut self, element: ValueAndType) { self.stack.push(RibInterpreterStackValue::val(element)); } - pub fn push_to_sink(&mut self, type_annotated_value: TypeAnnotatedValue) -> Result<(), String> { + pub fn push_to_sink(&mut self, type_annotated_value: ValueAndType) -> Result<(), String> { let sink = self.pop(); // sink always followed by an iterator let possible_iterator = self @@ -184,143 +190,95 @@ impl InterpreterStack { pub fn push_variant( &mut self, variant_name: String, - optional_variant_value: Option, - typ: Vec, + optional_variant_value: Option, + cases: Vec, ) { - // The GRPC issues - let optional_type_annotated_value = optional_variant_value.map(|type_value| { - Box::new(golem_wasm_rpc::protobuf::TypeAnnotatedValue { - type_annotated_value: Some(type_value), - }) - }); - - let value = TypeAnnotatedValue::Variant(Box::new(TypedVariant { - case_name: variant_name.clone(), - case_value: optional_type_annotated_value, - typ: Some(golem_wasm_ast::analysis::protobuf::TypeVariant { - cases: typ - .into_iter() - .map( - |name| golem_wasm_ast::analysis::protobuf::NameOptionTypePair { - name: name.name, - typ: name - .typ - .map(|x| golem_wasm_ast::analysis::protobuf::Type::from(&x)), - }, - ) - .collect(), - }), - })); - - self.push_val(value); + let case_idx = cases + .iter() + .position(|case| case.name == variant_name) + .unwrap() as u32; // TODO: return error + let case_value = optional_variant_value.map(Box::new); + self.push_val(ValueAndType::new( + Value::Variant { + case_idx, + case_value, + }, + variant(cases), + )); } - pub fn push_enum(&mut self, enum_name: String, typ: Vec) { - self.push_val(TypeAnnotatedValue::Enum(TypedEnum { - typ, - value: enum_name, - })) + pub fn push_enum(&mut self, enum_name: String, cases: Vec) { + let idx = cases.iter().position(|x| x == &enum_name).unwrap() as u32; // TODO: return error + self.push_val(ValueAndType::new( + Value::Enum(idx), + AnalysedType::Enum(TypeEnum { + cases: cases.into_iter().collect(), + }), + )); } - pub fn push_some(&mut self, inner_element: TypeAnnotatedValue, inner_type: &AnalysedType) { - self.push_val(TypeAnnotatedValue::Option(Box::new(TypedOption { - typ: Some(golem_wasm_ast::analysis::protobuf::Type::from(inner_type)), - value: Some(Box::new(golem_wasm_rpc::protobuf::TypeAnnotatedValue { - type_annotated_value: Some(inner_element), - })), - }))); + pub fn push_some(&mut self, inner_element: Value, inner_type: &AnalysedType) { + self.push_val(ValueAndType { + value: Value::Option(Some(Box::new(inner_element))), + typ: option(inner_type.clone()), + }); } // We allow untyped none to be in stack, // Need to verify how strict we should be // Example: ${match ok(1) { ok(value) => none }} should be allowed pub fn push_none(&mut self, analysed_type: Option) { - self.push_val(TypeAnnotatedValue::Option(Box::new(TypedOption { - typ: analysed_type.map(|x| golem_wasm_ast::analysis::protobuf::Type::from(&x)), - value: None, - }))); + self.push_val(ValueAndType { + value: Value::Option(None), + typ: option(analysed_type.unwrap_or(str())), // TODO: this used to be a "missing value in protobuf" + }); } pub fn push_ok( &mut self, - inner_element: TypeAnnotatedValue, + inner_element: Value, ok_type: Option<&AnalysedType>, err_type: Option<&AnalysedType>, ) { - let ok_type = golem_wasm_ast::analysis::protobuf::Type::from( - ok_type.unwrap_or(&AnalysedType::try_from(&inner_element).unwrap()), - ); - - self.push_val(TypeAnnotatedValue::Result(Box::new( - golem_wasm_rpc::protobuf::TypedResult { - result_value: Some( - golem_wasm_rpc::protobuf::typed_result::ResultValue::OkValue(Box::new( - golem_wasm_rpc::protobuf::TypeAnnotatedValue { - type_annotated_value: Some(inner_element), - }, - )), - ), - ok: Some(ok_type), - error: err_type.map(golem_wasm_ast::analysis::protobuf::Type::from), - }, - ))); + self.push_val(ValueAndType { + value: Value::Result(Ok(Some(Box::new(inner_element)))), + typ: AnalysedType::Result(TypeResult { + ok: ok_type.map(|x| Box::new(x.clone())), + err: err_type.map(|x| Box::new(x.clone())), + }), + }); } pub fn push_err( &mut self, - inner_element: TypeAnnotatedValue, + inner_element: Value, ok_type: Option<&AnalysedType>, err_type: Option<&AnalysedType>, ) { - let err_type = golem_wasm_ast::analysis::protobuf::Type::from( - err_type.unwrap_or(&AnalysedType::try_from(&inner_element).unwrap()), - ); - - self.push_val(TypeAnnotatedValue::Result(Box::new( - golem_wasm_rpc::protobuf::TypedResult { - result_value: Some( - golem_wasm_rpc::protobuf::typed_result::ResultValue::ErrorValue(Box::new( - golem_wasm_rpc::protobuf::TypeAnnotatedValue { - type_annotated_value: Some(inner_element), - }, - )), - ), - ok: ok_type.map(golem_wasm_ast::analysis::protobuf::Type::from), - error: Some(err_type), - }, - ))); + self.push_val(ValueAndType { + value: Value::Result(Err(Some(Box::new(inner_element)))), + typ: AnalysedType::Result(TypeResult { + ok: ok_type.map(|x| Box::new(x.clone())), + err: err_type.map(|x| Box::new(x.clone())), + }), + }); } pub fn push_list( &mut self, - values: Vec, + values: Vec, list_elem_type: &AnalysedType, // Expecting a list type and not inner ) { - self.push_val(TypeAnnotatedValue::List(TypedList { - values: values - .into_iter() - .map(|x| golem_wasm_rpc::protobuf::TypeAnnotatedValue { - type_annotated_value: Some(x), - }) - .collect(), - typ: Some(golem_wasm_ast::analysis::protobuf::Type::from( - list_elem_type, - )), - })); + self.push_val(ValueAndType { + value: Value::List(values), + typ: list(list_elem_type.clone()), + }); } - pub fn push_tuple(&mut self, values: Vec, types: &[AnalysedType]) { - self.push_val(TypeAnnotatedValue::Tuple(TypedTuple { - value: values - .into_iter() - .map(|x| golem_wasm_rpc::protobuf::TypeAnnotatedValue { - type_annotated_value: Some(x), - }) - .collect(), - typ: types - .iter() - .map(golem_wasm_ast::analysis::protobuf::Type::from) - .collect(), - })); + pub fn push_tuple(&mut self, values: Vec) { + self.push_val(ValueAndType { + value: Value::Tuple(values.iter().map(|x| x.value.clone()).collect()), + typ: tuple(values.into_iter().map(|x| x.typ).collect()), + }); } } diff --git a/golem-rib/src/interpreter/tests/mod.rs b/golem-rib/src/interpreter/tests/mod.rs index e156fbc2b..6eb1ed1fa 100644 --- a/golem-rib/src/interpreter/tests/mod.rs +++ b/golem-rib/src/interpreter/tests/mod.rs @@ -21,7 +21,7 @@ mod comprehensive_test { AnalysedType, NameTypePair, TypeBool, TypeF32, TypeF64, TypeRecord, TypeS16, TypeS32, TypeStr, TypeU64, TypeU8, }; - use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; + use golem_wasm_rpc::ValueAndType; #[test] async fn test_interpreter_complex_rib() { @@ -491,11 +491,10 @@ mod comprehensive_test { let mut rib_executor = mock_interpreter::interpreter(); let result = rib_executor.run(compiled_expr).await.unwrap(); - let actual_as_text = - test_utils::convert_type_annotated_value_to_str(&result.get_val().unwrap()); + let actual_as_text = test_utils::convert_value_and_type_to_str(&result.get_val().unwrap()); let expected_as_text = - test_utils::convert_type_annotated_value_to_str(&expected_type_annotated_value()); + test_utils::convert_value_and_type_to_str(&expected_type_annotated_value()); assert_eq!( result.get_val().unwrap(), @@ -506,7 +505,7 @@ mod comprehensive_test { ); } - fn expected_type_annotated_value() -> TypeAnnotatedValue { + fn expected_type_annotated_value() -> ValueAndType { let wasm_wave_str = r#" { a: "foo", @@ -563,7 +562,7 @@ mod comprehensive_test { } "#; - test_utils::get_type_annotated_value(&expected_analysed_type(), wasm_wave_str) + test_utils::get_value_and_type(&expected_analysed_type(), wasm_wave_str) } fn expected_analysed_type() -> AnalysedType { @@ -1738,276 +1737,243 @@ mod comprehensive_test { mod mock_data { use crate::interpreter::tests::comprehensive_test::{data_types, test_utils}; - use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; + use golem_wasm_rpc::ValueAndType; - pub(crate) fn ok_of_str() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value(&data_types::result_of_str_type(), "ok(\"foo\")") + pub(crate) fn ok_of_str() -> ValueAndType { + test_utils::get_value_and_type(&data_types::result_of_str_type(), "ok(\"foo\")") } - pub(crate) fn err_of_str() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value(&data_types::result_of_str_type(), "err(\"foo\")") + pub(crate) fn err_of_str() -> ValueAndType { + test_utils::get_value_and_type(&data_types::result_of_str_type(), "err(\"foo\")") } - pub(crate) fn ok_of_number() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value(&data_types::result_of_number_type(), "ok(42)") + pub(crate) fn ok_of_number() -> ValueAndType { + test_utils::get_value_and_type(&data_types::result_of_number_type(), "ok(42)") } - pub(crate) fn err_of_number() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value(&data_types::result_of_number_type(), "err(42)") + pub(crate) fn err_of_number() -> ValueAndType { + test_utils::get_value_and_type(&data_types::result_of_number_type(), "err(42)") } - pub(crate) fn ok_of_option() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value( + pub(crate) fn ok_of_option() -> ValueAndType { + test_utils::get_value_and_type( &data_types::result_of_option_type(), "ok(some(\"foo\"))", ) } - pub(crate) fn err_of_option() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value( + pub(crate) fn err_of_option() -> ValueAndType { + test_utils::get_value_and_type( &data_types::result_of_option_type(), "err(some(\"foo\"))", ) } - pub(crate) fn ok_of_variant() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value( + pub(crate) fn ok_of_variant() -> ValueAndType { + test_utils::get_value_and_type( &data_types::result_of_variant_type(), "ok(case-str(\"foo\"))", ) } - pub(crate) fn err_of_variant() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value( + pub(crate) fn err_of_variant() -> ValueAndType { + test_utils::get_value_and_type( &data_types::result_of_variant_type(), "err(case-str(\"foo\"))", ) } - pub(crate) fn ok_of_enum() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value(&data_types::result_of_enum_type(), "ok(enum-a)") + pub(crate) fn ok_of_enum() -> ValueAndType { + test_utils::get_value_and_type(&data_types::result_of_enum_type(), "ok(enum-a)") } - pub(crate) fn err_of_enum() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value(&data_types::result_of_enum_type(), "err(enum-a)") + pub(crate) fn err_of_enum() -> ValueAndType { + test_utils::get_value_and_type(&data_types::result_of_enum_type(), "err(enum-a)") } - pub(crate) fn ok_of_tuple() -> TypeAnnotatedValue { - let tuple_str = test_utils::convert_type_annotated_value_to_str(&tuple()); + pub(crate) fn ok_of_tuple() -> ValueAndType { + let tuple_str = test_utils::convert_value_and_type_to_str(&tuple()); let wave_str = format!("ok({})", tuple_str); - test_utils::get_type_annotated_value( - &data_types::result_of_tuple_type(), - wave_str.as_str(), - ) + test_utils::get_value_and_type(&data_types::result_of_tuple_type(), wave_str.as_str()) } - pub(crate) fn err_of_tuple() -> TypeAnnotatedValue { - let tuple_str = test_utils::convert_type_annotated_value_to_str(&tuple()); + pub(crate) fn err_of_tuple() -> ValueAndType { + let tuple_str = test_utils::convert_value_and_type_to_str(&tuple()); let wave_str = format!("err({})", tuple_str); - test_utils::get_type_annotated_value( - &data_types::result_of_tuple_type(), - wave_str.as_str(), - ) + test_utils::get_value_and_type(&data_types::result_of_tuple_type(), wave_str.as_str()) } - pub(crate) fn ok_of_flag() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value( - &data_types::result_of_flag_type(), - "ok({featurex})", - ) + pub(crate) fn ok_of_flag() -> ValueAndType { + test_utils::get_value_and_type(&data_types::result_of_flag_type(), "ok({featurex})") } - pub(crate) fn err_of_flag() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value( - &data_types::result_of_flag_type(), - "err({featurex})", - ) + pub(crate) fn err_of_flag() -> ValueAndType { + test_utils::get_value_and_type(&data_types::result_of_flag_type(), "err({featurex})") } - pub(crate) fn ok_of_record() -> TypeAnnotatedValue { - let record_str = test_utils::convert_type_annotated_value_to_str(&record()); + pub(crate) fn ok_of_record() -> ValueAndType { + let record_str = test_utils::convert_value_and_type_to_str(&record()); let wave_str = format!("ok({})", &record_str); - test_utils::get_type_annotated_value( - &data_types::result_of_record_type(), - wave_str.as_str(), - ) + test_utils::get_value_and_type(&data_types::result_of_record_type(), wave_str.as_str()) } - pub(crate) fn err_of_record() -> TypeAnnotatedValue { - let record_str = test_utils::convert_type_annotated_value_to_str(&record()); + pub(crate) fn err_of_record() -> ValueAndType { + let record_str = test_utils::convert_value_and_type_to_str(&record()); let wave_str = format!("err({})", &record_str); - test_utils::get_type_annotated_value( - &data_types::result_of_record_type(), - wave_str.as_str(), - ) + test_utils::get_value_and_type(&data_types::result_of_record_type(), wave_str.as_str()) } - pub(crate) fn ok_of_list() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value( - &data_types::result_of_list_type(), - "ok([\"foo\"])", - ) + pub(crate) fn ok_of_list() -> ValueAndType { + test_utils::get_value_and_type(&data_types::result_of_list_type(), "ok([\"foo\"])") } - pub(crate) fn err_of_list() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value( - &data_types::result_of_list_type(), - "err([\"foo\"])", - ) + pub(crate) fn err_of_list() -> ValueAndType { + test_utils::get_value_and_type(&data_types::result_of_list_type(), "err([\"foo\"])") } - pub(crate) fn list_of_number() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value(&data_types::list_of_number_type_type(), "[42]") + pub(crate) fn list_of_number() -> ValueAndType { + test_utils::get_value_and_type(&data_types::list_of_number_type_type(), "[42]") } - pub(crate) fn list_of_str() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value(&data_types::list_of_str_type(), "[\"foo\"]") + pub(crate) fn list_of_str() -> ValueAndType { + test_utils::get_value_and_type(&data_types::list_of_str_type(), "[\"foo\"]") } - pub(crate) fn list_of_option() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value( - &data_types::list_of_option_type(), - "[some(\"foo\")]", - ) + pub(crate) fn list_of_option() -> ValueAndType { + test_utils::get_value_and_type(&data_types::list_of_option_type(), "[some(\"foo\")]") } - pub(crate) fn list_of_list() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value(&data_types::list_of_list_type(), "[[\"foo\"]]") + pub(crate) fn list_of_list() -> ValueAndType { + test_utils::get_value_and_type(&data_types::list_of_list_type(), "[[\"foo\"]]") } - pub(crate) fn list_of_variant() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value( + pub(crate) fn list_of_variant() -> ValueAndType { + test_utils::get_value_and_type( &data_types::list_of_variant_type(), "[case-str(\"foo\")]", ) } - pub(crate) fn list_of_enum() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value(&data_types::list_of_enum_type(), "[enum-a]") + pub(crate) fn list_of_enum() -> ValueAndType { + test_utils::get_value_and_type(&data_types::list_of_enum_type(), "[enum-a]") } - pub(crate) fn list_of_tuple() -> TypeAnnotatedValue { - let tuple_str = test_utils::convert_type_annotated_value_to_str(&tuple()); + pub(crate) fn list_of_tuple() -> ValueAndType { + let tuple_str = test_utils::convert_value_and_type_to_str(&tuple()); let wave_str = format!("[{}, {}]", &tuple_str, &tuple_str); - test_utils::get_type_annotated_value(&data_types::list_of_tuple(), wave_str.as_str()) + test_utils::get_value_and_type(&data_types::list_of_tuple(), wave_str.as_str()) } - pub(crate) fn list_of_record() -> TypeAnnotatedValue { - let record_str = test_utils::convert_type_annotated_value_to_str(&record()); + pub(crate) fn list_of_record() -> ValueAndType { + let record_str = test_utils::convert_value_and_type_to_str(&record()); let wave_str = format!("[{}]", &record_str); - test_utils::get_type_annotated_value( - &data_types::list_of_record_type(), - wave_str.as_str(), - ) + test_utils::get_value_and_type(&data_types::list_of_record_type(), wave_str.as_str()) } - pub(crate) fn some_of_number() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value(&data_types::option_of_number_type(), "some(42)") + pub(crate) fn some_of_number() -> ValueAndType { + test_utils::get_value_and_type(&data_types::option_of_number_type(), "some(42)") } - pub(crate) fn none_of_number() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value(&data_types::option_of_number_type(), "none") + pub(crate) fn none_of_number() -> ValueAndType { + test_utils::get_value_and_type(&data_types::option_of_number_type(), "none") } - pub(crate) fn some_of_str() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value(&data_types::option_of_str_type(), "some(\"foo\")") + pub(crate) fn some_of_str() -> ValueAndType { + test_utils::get_value_and_type(&data_types::option_of_str_type(), "some(\"foo\")") } - pub(crate) fn none_of_str() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value(&data_types::option_of_str_type(), "none") + pub(crate) fn none_of_str() -> ValueAndType { + test_utils::get_value_and_type(&data_types::option_of_str_type(), "none") } - pub(crate) fn some_of_some() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value( + pub(crate) fn some_of_some() -> ValueAndType { + test_utils::get_value_and_type( &data_types::option_of_option_type(), "some(some(\"foo\"))", ) } - pub(crate) fn none_of_some() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value(&data_types::option_of_option_type(), "none") + pub(crate) fn none_of_some() -> ValueAndType { + test_utils::get_value_and_type(&data_types::option_of_option_type(), "none") } - pub(crate) fn some_of_variant() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value( + pub(crate) fn some_of_variant() -> ValueAndType { + test_utils::get_value_and_type( &data_types::option_of_variant_type(), "some(case-str(\"foo\"))", ) } - pub(crate) fn none_of_variant() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value(&data_types::option_of_variant_type(), "none") + pub(crate) fn none_of_variant() -> ValueAndType { + test_utils::get_value_and_type(&data_types::option_of_variant_type(), "none") } - pub(crate) fn some_of_enum() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value(&data_types::option_of_enum_type(), "some(enum-a)") + pub(crate) fn some_of_enum() -> ValueAndType { + test_utils::get_value_and_type(&data_types::option_of_enum_type(), "some(enum-a)") } - pub(crate) fn none_of_enum() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value(&data_types::option_of_enum_type(), "none") + pub(crate) fn none_of_enum() -> ValueAndType { + test_utils::get_value_and_type(&data_types::option_of_enum_type(), "none") } - pub(crate) fn some_of_tuple() -> TypeAnnotatedValue { - let tuple_str = test_utils::convert_type_annotated_value_to_str(&tuple()); + pub(crate) fn some_of_tuple() -> ValueAndType { + let tuple_str = test_utils::convert_value_and_type_to_str(&tuple()); let wave_str = format!("some({})", tuple_str); - test_utils::get_type_annotated_value(&data_types::option_of_tuple(), wave_str.as_str()) + test_utils::get_value_and_type(&data_types::option_of_tuple(), wave_str.as_str()) } - pub(crate) fn none_of_tuple() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value(&data_types::option_of_tuple(), "none") + pub(crate) fn none_of_tuple() -> ValueAndType { + test_utils::get_value_and_type(&data_types::option_of_tuple(), "none") } - pub(crate) fn some_of_record() -> TypeAnnotatedValue { - let record_str = test_utils::convert_type_annotated_value_to_str(&record()); + pub(crate) fn some_of_record() -> ValueAndType { + let record_str = test_utils::convert_value_and_type_to_str(&record()); let wave_str = format!("some({})", &record_str); - test_utils::get_type_annotated_value( - &data_types::option_of_record_type(), - wave_str.as_str(), - ) + test_utils::get_value_and_type(&data_types::option_of_record_type(), wave_str.as_str()) } - pub(crate) fn none_of_record() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value(&data_types::option_of_record_type(), "none") + pub(crate) fn none_of_record() -> ValueAndType { + test_utils::get_value_and_type(&data_types::option_of_record_type(), "none") } - pub(crate) fn some_of_list() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value(&data_types::option_of_list(), "some([\"foo\"])") + pub(crate) fn some_of_list() -> ValueAndType { + test_utils::get_value_and_type(&data_types::option_of_list(), "some([\"foo\"])") } - pub(crate) fn none_of_list() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value(&data_types::option_of_list(), "none") + pub(crate) fn none_of_list() -> ValueAndType { + test_utils::get_value_and_type(&data_types::option_of_list(), "none") } - pub(crate) fn tuple() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value( + pub(crate) fn tuple() -> ValueAndType { + test_utils::get_value_and_type( &data_types::tuple_type(), r#" ("foo", 42, 42, 42, 42, true, 'a', some(42), ok(42), [true], case-hello(42.0), {field-one: true, field-two: "foo"})"#, ) } - pub(crate) fn enum_data() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value(&data_types::enum_type(), "enum-a") + pub(crate) fn enum_data() -> ValueAndType { + test_utils::get_value_and_type(&data_types::enum_type(), "enum-a") } - pub(crate) fn str_data() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value(&data_types::str_type(), "\"foo\"") + pub(crate) fn str_data() -> ValueAndType { + test_utils::get_value_and_type(&data_types::str_type(), "\"foo\"") } - pub(crate) fn number_data() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value(&data_types::number_type(), "42") + pub(crate) fn number_data() -> ValueAndType { + test_utils::get_value_and_type(&data_types::number_type(), "42") } - pub(crate) fn flag() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value(&data_types::flag_type(), "{featurex}") + pub(crate) fn flag() -> ValueAndType { + test_utils::get_value_and_type(&data_types::flag_type(), "{featurex}") } - pub(crate) fn variant() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value(&data_types::variant_type(), "case-str(\"foo\")") + pub(crate) fn variant() -> ValueAndType { + test_utils::get_value_and_type(&data_types::variant_type(), "case-str(\"foo\")") } - pub(crate) fn record() -> TypeAnnotatedValue { - test_utils::get_type_annotated_value( + pub(crate) fn record() -> ValueAndType { + test_utils::get_value_and_type( &data_types::record_type(), r#" { @@ -2079,15 +2045,14 @@ mod comprehensive_test { use crate::interpreter::rib_interpreter::Interpreter; use crate::interpreter::tests::comprehensive_test::{mock_data, test_utils}; use crate::{RibFunctionInvoke, RibInput}; + use golem_wasm_ast::analysis::analysed_type::tuple; use golem_wasm_ast::analysis::{AnalysedType, TypeStr}; - use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; - use golem_wasm_rpc::protobuf::TypedTuple; - #[cfg(test)] + use golem_wasm_rpc::{Value, ValueAndType}; use std::collections::HashMap; use std::sync::Arc; pub(crate) fn interpreter() -> Interpreter { - let functions_and_results: Vec<(&str, Option)> = vec![ + let functions_and_results: Vec<(&str, Option)> = vec![ ("function-unit-response", None), ("function-no-arg", Some(mock_data::str_data())), ("function-no-arg-unit", None), @@ -2233,7 +2198,7 @@ mod comprehensive_test { ("function-all-inputs", Some(mock_data::str_data())), ]; - let functions_and_result: HashMap> = + let functions_and_result: HashMap> = functions_and_results .into_iter() .map(|(name, result)| (FunctionName(name.to_string()), result)) @@ -2254,12 +2219,12 @@ mod comprehensive_test { ), ]); - let record_input_value = test_utils::get_type_annotated_value( + let record_input_value = test_utils::get_value_and_type( &record_input_type, r#" { headers : { name : "foo" }, body : { name : "bar" }, path : { name : "baz" } }"#, ); - let mut interpreter_env_input: HashMap = HashMap::new(); + let mut interpreter_env_input: HashMap = HashMap::new(); interpreter_env_input.insert("request".to_string(), record_input_value); dynamic_test_interpreter(functions_and_result, interpreter_env_input) @@ -2269,8 +2234,8 @@ mod comprehensive_test { struct FunctionName(pub(crate) String); fn dynamic_test_interpreter( - functions_and_result: HashMap>, - interpreter_env_input: HashMap, + functions_and_result: HashMap>, + interpreter_env_input: HashMap, ) -> Interpreter { Interpreter::new( &RibInput::new(interpreter_env_input), @@ -2279,34 +2244,23 @@ mod comprehensive_test { } fn dynamic_worker_invoke( - functions_and_result: HashMap>, + functions_and_result: HashMap>, ) -> RibFunctionInvoke { let value = functions_and_result.clone(); Arc::new(move |a, _| { Box::pin({ let value = value.get(&FunctionName(a)).cloned().flatten(); - let analysed_type = value.clone().map(|x| AnalysedType::try_from(&x).unwrap()); async move { - let analysed_type = analysed_type.clone(); - let value = value.clone(); - if let Some(value) = value { - Ok(TypeAnnotatedValue::Tuple(TypedTuple { - typ: vec![golem_wasm_ast::analysis::protobuf::Type::from( - &analysed_type.unwrap(), - )], - value: vec![golem_wasm_rpc::protobuf::TypeAnnotatedValue { - type_annotated_value: Some(value), - }], - })) + Ok(ValueAndType::new( + Value::Tuple(vec![value.value]), + tuple(vec![value.typ]), + )) } else { // Representing Unit - Ok(TypeAnnotatedValue::Tuple(TypedTuple { - typ: vec![], - value: vec![], - })) + Ok(ValueAndType::new(Value::Tuple(vec![]), tuple(vec![]))) } } }) @@ -2315,9 +2269,8 @@ mod comprehensive_test { } mod test_utils { - #[cfg(test)] use golem_wasm_ast::analysis::*; - use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; + use golem_wasm_rpc::ValueAndType; pub(crate) fn analysed_type_record(fields: Vec<(&str, AnalysedType)>) -> AnalysedType { AnalysedType::Record(TypeRecord { @@ -2331,12 +2284,11 @@ mod comprehensive_test { }) } - pub(crate) fn get_type_annotated_value( + pub(crate) fn get_value_and_type( analysed_type: &AnalysedType, wasm_wave_str: &str, - ) -> TypeAnnotatedValue { - let result = - golem_wasm_rpc::type_annotated_value_from_str(analysed_type, wasm_wave_str); + ) -> ValueAndType { + let result = golem_wasm_rpc::parse_value_and_type(analysed_type, wasm_wave_str); match result { Ok(value) => value, @@ -2347,10 +2299,8 @@ mod comprehensive_test { } } - pub(crate) fn convert_type_annotated_value_to_str( - type_annotated_value: &TypeAnnotatedValue, - ) -> String { - golem_wasm_rpc::type_annotated_value_to_string(type_annotated_value).unwrap() + pub(crate) fn convert_value_and_type_to_str(value: &ValueAndType) -> String { + golem_wasm_rpc::print_value_and_type(value).unwrap() } pub(crate) fn get_function_component_metadata( diff --git a/golem-rib/src/parser/type_name.rs b/golem-rib/src/parser/type_name.rs index 652a63628..ff2245b3e 100644 --- a/golem-rib/src/parser/type_name.rs +++ b/golem-rib/src/parser/type_name.rs @@ -23,12 +23,6 @@ use combine::{attempt, between, sep_by, Parser}; use combine::{parser, ParseError}; use golem_wasm_ast::analysis::{AnalysedType, TypeResult}; -use golem_api_grpc::proto::golem::rib::type_name::Kind as InnerTypeName; -use golem_api_grpc::proto::golem::rib::{ - BasicTypeName, EnumType, FlagType, KeyValue, ListType, OptionType, RecordType, ResultType, - TupleType, TypeName as ProtoTypeName, VariantCase, VariantType, -}; - use crate::parser::errors::RibParseError; use crate::InferredType; @@ -152,158 +146,6 @@ impl Display for TypeName { } } -impl From for ProtoTypeName { - fn from(value: TypeName) -> Self { - let inner = match value { - TypeName::Bool => InnerTypeName::BasicType(BasicTypeName::Bool as i32), - TypeName::S8 => InnerTypeName::BasicType(BasicTypeName::S8 as i32), - TypeName::U8 => InnerTypeName::BasicType(BasicTypeName::U8 as i32), - TypeName::S16 => InnerTypeName::BasicType(BasicTypeName::S16 as i32), - TypeName::U16 => InnerTypeName::BasicType(BasicTypeName::U16 as i32), - TypeName::S32 => InnerTypeName::BasicType(BasicTypeName::S32 as i32), - TypeName::U32 => InnerTypeName::BasicType(BasicTypeName::U32 as i32), - TypeName::S64 => InnerTypeName::BasicType(BasicTypeName::S64 as i32), - TypeName::U64 => InnerTypeName::BasicType(BasicTypeName::U64 as i32), - TypeName::F32 => InnerTypeName::BasicType(BasicTypeName::F32 as i32), - TypeName::F64 => InnerTypeName::BasicType(BasicTypeName::F64 as i32), - TypeName::Chr => InnerTypeName::BasicType(BasicTypeName::Chr as i32), - TypeName::Str => InnerTypeName::BasicType(BasicTypeName::Str as i32), - TypeName::List(inner_type) => InnerTypeName::ListType(Box::new(ListType { - inner_type: Some(Box::new(inner_type.deref().clone().into())), - })), - TypeName::Tuple(inner_types) => InnerTypeName::TupleType(TupleType { - types: inner_types.into_iter().map(|t| t.into()).collect(), - }), - TypeName::Option(type_name) => InnerTypeName::OptionType(Box::new(OptionType { - inner_type: Some(Box::new(type_name.deref().clone().into())), - })), - TypeName::Result { ok, error } => InnerTypeName::ResultType(Box::new(ResultType { - ok_type: ok.map(|ok| Box::new(ok.deref().clone().into())), - err_type: error.map(|error| Box::new(error.deref().clone().into())), - })), - TypeName::Record(fields) => InnerTypeName::RecordType(RecordType { - fields: fields - .into_iter() - .map(|(field, typ)| KeyValue { - key: field, - value: Some(typ.deref().clone().into()), - }) - .collect(), - }), - TypeName::Flags(flags) => InnerTypeName::FlagType(FlagType { - flags: flags.into_iter().collect(), - }), - TypeName::Enum(cases) => InnerTypeName::EnumType(EnumType { - cases: cases.into_iter().collect(), - }), - TypeName::Variant { cases } => InnerTypeName::VariantType(VariantType { - cases: cases - .into_iter() - .map(|(case, typ)| VariantCase { - case_name: case, - variant_arg: typ.map(|x| x.deref().clone().into()), - }) - .collect(), - }), - }; - - ProtoTypeName { kind: Some(inner) } - } -} - -impl TryFrom for TypeName { - type Error = String; - - fn try_from(value: ProtoTypeName) -> Result { - match value.kind { - Some(inner) => match inner { - InnerTypeName::BasicType(value) => match BasicTypeName::try_from(value) { - Ok(BasicTypeName::Bool) => Ok(TypeName::Bool), - Ok(BasicTypeName::S8) => Ok(TypeName::S8), - Ok(BasicTypeName::U8) => Ok(TypeName::U8), - Ok(BasicTypeName::S16) => Ok(TypeName::S16), - Ok(BasicTypeName::U16) => Ok(TypeName::U16), - Ok(BasicTypeName::S32) => Ok(TypeName::S32), - Ok(BasicTypeName::U32) => Ok(TypeName::U32), - Ok(BasicTypeName::S64) => Ok(TypeName::S64), - Ok(BasicTypeName::U64) => Ok(TypeName::U64), - Ok(BasicTypeName::F32) => Ok(TypeName::F32), - Ok(BasicTypeName::F64) => Ok(TypeName::F64), - Ok(BasicTypeName::Chr) => Ok(TypeName::Chr), - Ok(BasicTypeName::Str) => Ok(TypeName::Str), - _ => Err(format!("Unknown basic type: {:?}", value)), - }, - InnerTypeName::ListType(inner_type) => { - let proto_list_type = inner_type - .inner_type - .ok_or("No inner type for list provided")?; - let list_type = proto_list_type.deref().clone().try_into()?; - Ok(TypeName::List(Box::new(list_type))) - } - InnerTypeName::TupleType(inner_types) => { - let tuple_type = inner_types - .types - .into_iter() - .map(|t| t.try_into()) - .collect::, String>>()?; - Ok(TypeName::Tuple(tuple_type)) - } - InnerTypeName::OptionType(type_name) => { - let proto_option_type = type_name - .inner_type - .ok_or("No inner type for option provided")?; - let option_type = proto_option_type.deref().clone().try_into()?; - Ok(TypeName::Option(Box::new(option_type))) - } - InnerTypeName::ResultType(result_type) => { - let ok = result_type - .ok_type - .map(|ok| ok.deref().clone().try_into()) - .transpose()?; - let error = result_type - .err_type - .map(|error| error.deref().clone().try_into()) - .transpose()?; - Ok(TypeName::Result { - ok: ok.map(Box::new), - error: error.map(Box::new), - }) - } - InnerTypeName::RecordType(fields) => { - let record_type = fields - .fields - .into_iter() - .map(|key_value| { - key_value - .value - .ok_or("Field type missing")? - .try_into() - .map(|typ| (key_value.key, Box::new(typ))) - }) - .collect::)>, String>>()?; - Ok(TypeName::Record(record_type)) - } - InnerTypeName::FlagType(flag_type) => Ok(TypeName::Flags(flag_type.flags)), - InnerTypeName::EnumType(enum_type) => Ok(TypeName::Enum(enum_type.cases)), - InnerTypeName::VariantType(variant_type) => { - let mut cases = vec![]; - for variant_case in variant_type.cases { - let case = variant_case.case_name; - let typ = match variant_case.variant_arg { - Some(typ) => Some(Box::new(TypeName::try_from(typ)?)), - None => None, - }; - cases.push((case, typ)); - } - - Ok(TypeName::Variant { cases }) - } - }, - None => Err("No type kind provided".to_string()), - } - } -} - impl TryFrom for TypeName { type Error = String; fn try_from(analysed_type: AnalysedType) -> Result { @@ -562,6 +404,170 @@ parser! { } } +#[cfg(feature = "protobuf")] +mod protobuf { + use golem_api_grpc::proto::golem::rib::type_name::Kind as InnerTypeName; + use golem_api_grpc::proto::golem::rib::{ + BasicTypeName, EnumType, FlagType, KeyValue, ListType, OptionType, RecordType, ResultType, + TupleType, TypeName as ProtoTypeName, VariantCase, VariantType, + }; + use std::ops::Deref; + + use crate::TypeName; + + impl From for ProtoTypeName { + fn from(value: TypeName) -> Self { + let inner = match value { + TypeName::Bool => InnerTypeName::BasicType(BasicTypeName::Bool as i32), + TypeName::S8 => InnerTypeName::BasicType(BasicTypeName::S8 as i32), + TypeName::U8 => InnerTypeName::BasicType(BasicTypeName::U8 as i32), + TypeName::S16 => InnerTypeName::BasicType(BasicTypeName::S16 as i32), + TypeName::U16 => InnerTypeName::BasicType(BasicTypeName::U16 as i32), + TypeName::S32 => InnerTypeName::BasicType(BasicTypeName::S32 as i32), + TypeName::U32 => InnerTypeName::BasicType(BasicTypeName::U32 as i32), + TypeName::S64 => InnerTypeName::BasicType(BasicTypeName::S64 as i32), + TypeName::U64 => InnerTypeName::BasicType(BasicTypeName::U64 as i32), + TypeName::F32 => InnerTypeName::BasicType(BasicTypeName::F32 as i32), + TypeName::F64 => InnerTypeName::BasicType(BasicTypeName::F64 as i32), + TypeName::Chr => InnerTypeName::BasicType(BasicTypeName::Chr as i32), + TypeName::Str => InnerTypeName::BasicType(BasicTypeName::Str as i32), + TypeName::List(inner_type) => InnerTypeName::ListType(Box::new(ListType { + inner_type: Some(Box::new(inner_type.deref().clone().into())), + })), + TypeName::Tuple(inner_types) => InnerTypeName::TupleType(TupleType { + types: inner_types.into_iter().map(|t| t.into()).collect(), + }), + TypeName::Option(type_name) => InnerTypeName::OptionType(Box::new(OptionType { + inner_type: Some(Box::new(type_name.deref().clone().into())), + })), + TypeName::Result { ok, error } => InnerTypeName::ResultType(Box::new(ResultType { + ok_type: ok.map(|ok| Box::new(ok.deref().clone().into())), + err_type: error.map(|error| Box::new(error.deref().clone().into())), + })), + TypeName::Record(fields) => InnerTypeName::RecordType(RecordType { + fields: fields + .into_iter() + .map(|(field, typ)| KeyValue { + key: field, + value: Some(typ.deref().clone().into()), + }) + .collect(), + }), + TypeName::Flags(flags) => InnerTypeName::FlagType(FlagType { + flags: flags.into_iter().collect(), + }), + TypeName::Enum(cases) => InnerTypeName::EnumType(EnumType { + cases: cases.into_iter().collect(), + }), + TypeName::Variant { cases } => InnerTypeName::VariantType(VariantType { + cases: cases + .into_iter() + .map(|(case, typ)| VariantCase { + case_name: case, + variant_arg: typ.map(|x| x.deref().clone().into()), + }) + .collect(), + }), + }; + + ProtoTypeName { kind: Some(inner) } + } + } + + impl TryFrom for TypeName { + type Error = String; + + fn try_from(value: ProtoTypeName) -> Result { + match value.kind { + Some(inner) => match inner { + InnerTypeName::BasicType(value) => match BasicTypeName::try_from(value) { + Ok(BasicTypeName::Bool) => Ok(TypeName::Bool), + Ok(BasicTypeName::S8) => Ok(TypeName::S8), + Ok(BasicTypeName::U8) => Ok(TypeName::U8), + Ok(BasicTypeName::S16) => Ok(TypeName::S16), + Ok(BasicTypeName::U16) => Ok(TypeName::U16), + Ok(BasicTypeName::S32) => Ok(TypeName::S32), + Ok(BasicTypeName::U32) => Ok(TypeName::U32), + Ok(BasicTypeName::S64) => Ok(TypeName::S64), + Ok(BasicTypeName::U64) => Ok(TypeName::U64), + Ok(BasicTypeName::F32) => Ok(TypeName::F32), + Ok(BasicTypeName::F64) => Ok(TypeName::F64), + Ok(BasicTypeName::Chr) => Ok(TypeName::Chr), + Ok(BasicTypeName::Str) => Ok(TypeName::Str), + _ => Err(format!("Unknown basic type: {:?}", value)), + }, + InnerTypeName::ListType(inner_type) => { + let proto_list_type = inner_type + .inner_type + .ok_or("No inner type for list provided")?; + let list_type = proto_list_type.deref().clone().try_into()?; + Ok(TypeName::List(Box::new(list_type))) + } + InnerTypeName::TupleType(inner_types) => { + let tuple_type = inner_types + .types + .into_iter() + .map(|t| t.try_into()) + .collect::, String>>()?; + Ok(TypeName::Tuple(tuple_type)) + } + InnerTypeName::OptionType(type_name) => { + let proto_option_type = type_name + .inner_type + .ok_or("No inner type for option provided")?; + let option_type = proto_option_type.deref().clone().try_into()?; + Ok(TypeName::Option(Box::new(option_type))) + } + InnerTypeName::ResultType(result_type) => { + let ok = result_type + .ok_type + .map(|ok| ok.deref().clone().try_into()) + .transpose()?; + let error = result_type + .err_type + .map(|error| error.deref().clone().try_into()) + .transpose()?; + Ok(TypeName::Result { + ok: ok.map(Box::new), + error: error.map(Box::new), + }) + } + InnerTypeName::RecordType(fields) => { + let record_type = fields + .fields + .into_iter() + .map(|key_value| { + key_value + .value + .ok_or("Field type missing")? + .try_into() + .map(|typ| (key_value.key, Box::new(typ))) + }) + .collect::)>, String>>()?; + Ok(TypeName::Record(record_type)) + } + InnerTypeName::FlagType(flag_type) => Ok(TypeName::Flags(flag_type.flags)), + InnerTypeName::EnumType(enum_type) => Ok(TypeName::Enum(enum_type.cases)), + InnerTypeName::VariantType(variant_type) => { + let mut cases = vec![]; + for variant_case in variant_type.cases { + let case = variant_case.case_name; + let typ = match variant_case.variant_arg { + Some(typ) => Some(Box::new(TypeName::try_from(typ)?)), + None => None, + }; + cases.push((case, typ)); + } + + Ok(TypeName::Variant { cases }) + } + }, + None => Err("No type kind provided".to_string()), + } + } + } +} + #[cfg(test)] mod type_name_tests { use combine::EasyParser; diff --git a/golem-rib/src/type_inference/mod.rs b/golem-rib/src/type_inference/mod.rs index b44658294..975f1c50f 100644 --- a/golem-rib/src/type_inference/mod.rs +++ b/golem-rib/src/type_inference/mod.rs @@ -1769,7 +1769,6 @@ mod type_inference_tests { use crate::type_inference::type_inference_tests::internal; use crate::{Expr, FunctionTypeRegistry, InferredType, Number, VariableId}; use golem_wasm_ast::analysis::analysed_type::{list, option, str}; - use golem_wasm_ast::analysis::AnalysedType; #[test] fn test_record_type_inference() { @@ -1925,14 +1924,14 @@ mod type_inference_tests { ), ]); - let worker_response = internal::create_none(Some(&str())); + let worker_response = internal::create_none(&str()); let request_type = internal::get_analysed_type_record(vec![( "body".to_string(), request_body_type.clone(), )]); - let return_type = option(AnalysedType::try_from(&worker_response).unwrap()); + let return_type = option(worker_response.typ); let component_metadata = internal::get_analysed_exports("foo", vec![request_type.clone()], return_type); @@ -2204,14 +2203,13 @@ mod type_inference_tests { ArmPattern, Expr, FunctionTypeRegistry, InferredType, MatchArm, MatchIdentifier, ParsedFunctionSite, VariableId, }; - use golem_wasm_ast::analysis::analysed_type::u64; + use golem_wasm_ast::analysis::analysed_type::{option, u64}; use golem_wasm_ast::analysis::TypeVariant; use golem_wasm_ast::analysis::{ AnalysedExport, AnalysedFunction, AnalysedFunctionParameter, AnalysedFunctionResult, AnalysedType, NameOptionTypePair, NameTypePair, TypeEnum, TypeRecord, TypeU32, }; - use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; - use golem_wasm_rpc::protobuf::TypedOption; + use golem_wasm_rpc::{Value, ValueAndType}; pub(crate) fn get_function_type_registry() -> FunctionTypeRegistry { let metadata = vec![ @@ -2271,11 +2269,8 @@ mod type_inference_tests { AnalysedType::Record(record) } - pub(crate) fn create_none(typ: Option<&AnalysedType>) -> TypeAnnotatedValue { - TypeAnnotatedValue::Option(Box::new(TypedOption { - value: None, - typ: typ.map(|t| t.into()), - })) + pub(crate) fn create_none(typ: &AnalysedType) -> ValueAndType { + ValueAndType::new(Value::Option(None), option(typ.clone())) } pub(crate) fn get_analysed_exports( diff --git a/golem-rib/src/type_inference/rib_input_type.rs b/golem-rib/src/type_inference/rib_input_type.rs index 15a7c00d4..a1128baee 100644 --- a/golem-rib/src/type_inference/rib_input_type.rs +++ b/golem-rib/src/type_inference/rib_input_type.rs @@ -14,15 +14,14 @@ use crate::{Expr, InferredExpr}; use bincode::{Decode, Encode}; -use golem_api_grpc::proto::golem::rib::RibInputType as ProtoRibInputType; use golem_wasm_ast::analysis::AnalysedType; -use poem_openapi::Object; use serde::{Deserialize, Serialize}; use std::collections::{HashMap, VecDeque}; // RibInputTypeInfo refers to the required global inputs to a RibScript // with its type information. Example: `request` variable which should be of the type `Record`. -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, Object)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] pub struct RibInputTypeInfo { pub types: HashMap, } @@ -59,23 +58,31 @@ impl RibInputTypeInfo { } } -impl TryFrom for RibInputTypeInfo { - type Error = String; - fn try_from(value: ProtoRibInputType) -> Result { - let mut types = HashMap::new(); - for (key, value) in value.types { - types.insert(key, AnalysedType::try_from(&value)?); +#[cfg(feature = "protobuf")] +mod protobuf { + use crate::RibInputTypeInfo; + use golem_api_grpc::proto::golem::rib::RibInputType as ProtoRibInputType; + use golem_wasm_ast::analysis::AnalysedType; + use std::collections::HashMap; + + impl TryFrom for RibInputTypeInfo { + type Error = String; + fn try_from(value: ProtoRibInputType) -> Result { + let mut types = HashMap::new(); + for (key, value) in value.types { + types.insert(key, AnalysedType::try_from(&value)?); + } + Ok(RibInputTypeInfo { types }) } - Ok(RibInputTypeInfo { types }) } -} -impl From for ProtoRibInputType { - fn from(value: RibInputTypeInfo) -> Self { - let mut types = HashMap::new(); - for (key, value) in value.types { - types.insert(key, golem_wasm_ast::analysis::protobuf::Type::from(&value)); + impl From for ProtoRibInputType { + fn from(value: RibInputTypeInfo) -> Self { + let mut types = HashMap::new(); + for (key, value) in value.types { + types.insert(key, golem_wasm_ast::analysis::protobuf::Type::from(&value)); + } + ProtoRibInputType { types } } - ProtoRibInputType { types } } } diff --git a/golem-rib/src/type_inference/rib_output_type.rs b/golem-rib/src/type_inference/rib_output_type.rs index 99e9a954f..4cb869e7b 100644 --- a/golem-rib/src/type_inference/rib_output_type.rs +++ b/golem-rib/src/type_inference/rib_output_type.rs @@ -1,10 +1,9 @@ use crate::InferredExpr; -use golem_api_grpc::proto::golem::rib::RibOutputType as ProtoRibOutputType; use golem_wasm_ast::analysis::AnalysedType; -use poem_openapi::Object; use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Object)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[cfg_attr(feature = "poem", derive(poem_openapi::Object))] pub struct RibOutputTypeInfo { pub analysed_type: AnalysedType, } @@ -18,22 +17,29 @@ impl RibOutputTypeInfo { } } -impl From for ProtoRibOutputType { - fn from(value: RibOutputTypeInfo) -> Self { - ProtoRibOutputType { - r#type: Some(golem_wasm_ast::analysis::protobuf::Type::from( - &value.analysed_type, - )), +#[cfg(feature = "protobuf")] +mod protobuf { + use crate::RibOutputTypeInfo; + use golem_api_grpc::proto::golem::rib::RibOutputType as ProtoRibOutputType; + use golem_wasm_ast::analysis::AnalysedType; + + impl From for ProtoRibOutputType { + fn from(value: RibOutputTypeInfo) -> Self { + ProtoRibOutputType { + r#type: Some(golem_wasm_ast::analysis::protobuf::Type::from( + &value.analysed_type, + )), + } } } -} -impl TryFrom for RibOutputTypeInfo { - type Error = String; - fn try_from(value: ProtoRibOutputType) -> Result { - let proto_type = value.r#type.ok_or("Missing type")?; - let analysed_type = AnalysedType::try_from(&proto_type)?; + impl TryFrom for RibOutputTypeInfo { + type Error = String; + fn try_from(value: ProtoRibOutputType) -> Result { + let proto_type = value.r#type.ok_or("Missing type")?; + let analysed_type = AnalysedType::try_from(&proto_type)?; - Ok(RibOutputTypeInfo { analysed_type }) + Ok(RibOutputTypeInfo { analysed_type }) + } } } diff --git a/golem-rib/src/type_registry.rs b/golem-rib/src/type_registry.rs index 7cbef5836..0f176632e 100644 --- a/golem-rib/src/type_registry.rs +++ b/golem-rib/src/type_registry.rs @@ -14,7 +14,6 @@ use crate::call_type::CallType; use crate::DynamicParsedFunctionName; -use golem_api_grpc::proto::golem::rib::registry_key::KeyType; use golem_wasm_ast::analysis::AnalysedType; use golem_wasm_ast::analysis::{AnalysedExport, TypeVariant}; use std::collections::{HashMap, HashSet}; @@ -220,8 +219,9 @@ impl RegistryKey { } // A parsed function name (the one that gets invoked with a worker) can correspond - // to multiple registry keys. This is mainly because a function may have a constructor component - // along with the method name. Otherwise it's only 1 key that correspond to the Fqn. + // to multiple registry keys. For example: this is mainly because a function can have a constructor component + // along with the method name (2 registry keys correspond to this 1 function). + // Otherwise it's only 1 key that correspond to the Fqn always. pub fn registry_keys_of_function( function_name: &DynamicParsedFunctionName, ) -> Vec { @@ -235,7 +235,8 @@ impl RegistryKey { } // To obtain the registry key that correspond to the FQN of the function - // Not that it doesn't provide the registry key corresponding to the constructor of a resource + // Note that, it will not provide the registry key corresponding to the constructor of a resource + // if the function was part of a resource pub fn fqn_registry_key(function: &DynamicParsedFunctionName) -> RegistryKey { let resource_method_name_in_metadata = function.function_name_with_prefix_identifiers(); @@ -287,54 +288,6 @@ impl RegistryKey { } } -impl TryFrom for RegistryKey { - type Error = String; - - fn try_from( - value: golem_api_grpc::proto::golem::rib::RegistryKey, - ) -> Result { - let key_type = value.key_type.ok_or("key type missing")?; - - let registry_key = match key_type { - KeyType::FunctionName(string) => RegistryKey::FunctionName(string.name), - KeyType::FunctionNameWithInterface(function_with_interface) => { - let interface_name = function_with_interface.interface_name.clone(); - let function_name = function_with_interface.function_name; - - RegistryKey::FunctionNameWithInterface { - interface_name, - function_name, - } - } - }; - - Ok(registry_key) - } -} - -impl From for golem_api_grpc::proto::golem::rib::RegistryKey { - fn from(value: RegistryKey) -> Self { - match value { - RegistryKey::FunctionName(str) => golem_api_grpc::proto::golem::rib::RegistryKey { - key_type: Some(KeyType::FunctionName( - golem_api_grpc::proto::golem::rib::FunctionName { name: str }, - )), - }, - RegistryKey::FunctionNameWithInterface { - function_name, - interface_name, - } => golem_api_grpc::proto::golem::rib::RegistryKey { - key_type: Some(KeyType::FunctionNameWithInterface( - golem_api_grpc::proto::golem::rib::FunctionNameWithInterface { - interface_name, - function_name, - }, - )), - }, - } - } -} - #[derive(PartialEq, Clone, Debug)] pub enum RegistryValue { Value(AnalysedType), @@ -458,3 +411,58 @@ mod internal { } } } + +#[cfg(feature = "protobuf")] +mod protobuf { + + use crate::RegistryKey; + use golem_api_grpc::proto::golem::rib::registry_key::KeyType; + + impl TryFrom for RegistryKey { + type Error = String; + + fn try_from( + value: golem_api_grpc::proto::golem::rib::RegistryKey, + ) -> Result { + let key_type = value.key_type.ok_or("key type missing")?; + + let registry_key = match key_type { + KeyType::FunctionName(string) => RegistryKey::FunctionName(string.name), + KeyType::FunctionNameWithInterface(function_with_interface) => { + let interface_name = function_with_interface.interface_name.clone(); + let function_name = function_with_interface.function_name; + + RegistryKey::FunctionNameWithInterface { + interface_name, + function_name, + } + } + }; + + Ok(registry_key) + } + } + + impl From for golem_api_grpc::proto::golem::rib::RegistryKey { + fn from(value: RegistryKey) -> Self { + match value { + RegistryKey::FunctionName(str) => golem_api_grpc::proto::golem::rib::RegistryKey { + key_type: Some(KeyType::FunctionName( + golem_api_grpc::proto::golem::rib::FunctionName { name: str }, + )), + }, + RegistryKey::FunctionNameWithInterface { + function_name, + interface_name, + } => golem_api_grpc::proto::golem::rib::RegistryKey { + key_type: Some(KeyType::FunctionNameWithInterface( + golem_api_grpc::proto::golem::rib::FunctionNameWithInterface { + interface_name, + function_name, + }, + )), + }, + } + } + } +} diff --git a/golem-rib/src/variable_id.rs b/golem-rib/src/variable_id.rs index 9a8fd21cf..5ebc3953c 100644 --- a/golem-rib/src/variable_id.rs +++ b/golem-rib/src/variable_id.rs @@ -13,7 +13,6 @@ // limitations under the License. use bincode::{Decode, Encode}; -use golem_api_grpc::proto::golem::rib::VariableId as ProtoVariableId; use serde::{Deserialize, Serialize}; use std::fmt::Display; @@ -144,66 +143,72 @@ impl Display for VariableId { } } #[derive(Hash, Eq, Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode)] -pub struct Id(u32); +pub struct Id(pub(crate) u32); -impl TryFrom for VariableId { - type Error = String; +#[cfg(feature = "protobuf")] +mod protobuf { + use crate::{Id, VariableId}; + use golem_api_grpc::proto::golem::rib::VariableId as ProtoVariableId; - fn try_from(value: ProtoVariableId) -> Result { - let variable_id = value.variable_id.ok_or("Missing variable_id".to_string())?; + impl TryFrom for VariableId { + type Error = String; - match variable_id { - golem_api_grpc::proto::golem::rib::variable_id::VariableId::Global(global) => { - Ok(VariableId::Global(global.name)) + fn try_from(value: ProtoVariableId) -> Result { + let variable_id = value.variable_id.ok_or("Missing variable_id".to_string())?; + + match variable_id { + golem_api_grpc::proto::golem::rib::variable_id::VariableId::Global(global) => { + Ok(VariableId::Global(global.name)) + } + golem_api_grpc::proto::golem::rib::variable_id::VariableId::Local(local) => Ok( + VariableId::Local(local.name, local.id.map(|x| Id(x as u32))), + ), } - golem_api_grpc::proto::golem::rib::variable_id::VariableId::Local(local) => Ok( - VariableId::Local(local.name, local.id.map(|x| Id(x as u32))), - ), } } -} -impl From for ProtoVariableId { - fn from(value: VariableId) -> Self { - match value { - VariableId::Global(name) => ProtoVariableId { - variable_id: Some( - golem_api_grpc::proto::golem::rib::variable_id::VariableId::Global( - golem_api_grpc::proto::golem::rib::Global { name }, + impl From for ProtoVariableId { + fn from(value: VariableId) -> Self { + match value { + VariableId::Global(name) => ProtoVariableId { + variable_id: Some( + golem_api_grpc::proto::golem::rib::variable_id::VariableId::Global( + golem_api_grpc::proto::golem::rib::Global { name }, + ), ), - ), - }, - VariableId::MatchIdentifier(m) => ProtoVariableId { - variable_id: Some( - golem_api_grpc::proto::golem::rib::variable_id::VariableId::Global( - golem_api_grpc::proto::golem::rib::Global { name: m.name }, + }, + VariableId::MatchIdentifier(m) => ProtoVariableId { + variable_id: Some( + golem_api_grpc::proto::golem::rib::variable_id::VariableId::Global( + golem_api_grpc::proto::golem::rib::Global { name: m.name }, + ), ), - ), - }, - VariableId::Local(name, id) => ProtoVariableId { - variable_id: Some( - golem_api_grpc::proto::golem::rib::variable_id::VariableId::Local( - golem_api_grpc::proto::golem::rib::Local { - name, - id: id.map(|x| x.0 as u64), - }, + }, + VariableId::Local(name, id) => ProtoVariableId { + variable_id: Some( + golem_api_grpc::proto::golem::rib::variable_id::VariableId::Local( + golem_api_grpc::proto::golem::rib::Local { + name, + id: id.map(|x| x.0 as u64), + }, + ), ), - ), - }, - VariableId::ListComprehension(l) => ProtoVariableId { - variable_id: Some( - golem_api_grpc::proto::golem::rib::variable_id::VariableId::Global( - golem_api_grpc::proto::golem::rib::Global { name: l.name }, + }, + VariableId::ListComprehension(l) => ProtoVariableId { + variable_id: Some( + golem_api_grpc::proto::golem::rib::variable_id::VariableId::Global( + golem_api_grpc::proto::golem::rib::Global { name: l.name }, + ), ), - ), - }, - VariableId::ListReduce(r) => ProtoVariableId { - variable_id: Some( - golem_api_grpc::proto::golem::rib::variable_id::VariableId::Global( - golem_api_grpc::proto::golem::rib::Global { name: r.name }, + }, + VariableId::ListReduce(r) => ProtoVariableId { + variable_id: Some( + golem_api_grpc::proto::golem::rib::variable_id::VariableId::Global( + golem_api_grpc::proto::golem::rib::Global { name: r.name }, + ), ), - ), - }, + }, + } } } } diff --git a/golem-service-base/src/config.rs b/golem-service-base/src/config.rs index 71cd6193b..a5a4fda03 100644 --- a/golem-service-base/src/config.rs +++ b/golem-service-base/src/config.rs @@ -12,7 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -use golem_common::config::{DbSqliteConfig, RetryConfig}; +use golem_common::config::DbSqliteConfig; +use golem_common::model::RetryConfig; use serde::{Deserialize, Serialize}; use std::{path::PathBuf, time::Duration}; diff --git a/golem-shard-manager/src/healthcheck.rs b/golem-shard-manager/src/healthcheck.rs index e152f511c..07c827922 100644 --- a/golem-shard-manager/src/healthcheck.rs +++ b/golem-shard-manager/src/healthcheck.rs @@ -5,7 +5,7 @@ use std::sync::Arc; use async_trait::async_trait; -use golem_common::config::RetryConfig; +use golem_common::model::RetryConfig; use golem_common::retries::with_retriable_errors; use crate::error::HealthCheckError; @@ -104,7 +104,7 @@ pub mod kubernetes { use k8s_openapi::api::core::v1::{Pod, PodStatus}; use kube::{Api, Client}; - use golem_common::config::RetryConfig; + use golem_common::model::RetryConfig; use crate::healthcheck::{health_check_with_retries, HealthCheck, HealthCheckError}; diff --git a/golem-shard-manager/src/shard_manager_config.rs b/golem-shard-manager/src/shard_manager_config.rs index 446505492..2260cd6c0 100644 --- a/golem-shard-manager/src/shard_manager_config.rs +++ b/golem-shard-manager/src/shard_manager_config.rs @@ -17,9 +17,8 @@ use std::time::Duration; use serde::{Deserialize, Serialize}; -use golem_common::config::{ - ConfigExample, ConfigLoader, HasConfigExamples, RedisConfig, RetryConfig, -}; +use golem_common::config::{ConfigExample, ConfigLoader, HasConfigExamples, RedisConfig}; +use golem_common::model::RetryConfig; use golem_common::tracing::TracingConfig; use crate::model::Empty; diff --git a/golem-worker-executor-base/src/durable_host/golem/mod.rs b/golem-worker-executor-base/src/durable_host/golem/mod.rs index 6fd126450..a386645df 100644 --- a/golem-worker-executor-base/src/durable_host/golem/mod.rs +++ b/golem-worker-executor-base/src/durable_host/golem/mod.rs @@ -16,7 +16,7 @@ pub mod v11; use anyhow::anyhow; use async_trait::async_trait; -use golem_common::config::RetryConfig; +use golem_common::model::RetryConfig; use std::time::Duration; use tracing::debug; use uuid::Uuid; diff --git a/golem-worker-executor-base/src/durable_host/golem/v11.rs b/golem-worker-executor-base/src/durable_host/golem/v11.rs index 15d5685eb..fa6b4e7bf 100644 --- a/golem-worker-executor-base/src/durable_host/golem/v11.rs +++ b/golem-worker-executor-base/src/durable_host/golem/v11.rs @@ -34,8 +34,8 @@ use crate::services::{HasOplogService, HasPlugins}; use crate::workerctx::WorkerCtx; use anyhow::anyhow; use async_trait::async_trait; -use golem_common::config::RetryConfig; use golem_common::model::OwnedWorkerId; +use golem_common::model::RetryConfig; use std::time::Duration; use wasmtime::component::Resource; use wasmtime_wasi::WasiView; diff --git a/golem-worker-executor-base/src/durable_host/mod.rs b/golem-worker-executor-base/src/durable_host/mod.rs index 382439f13..b42fdd74b 100644 --- a/golem-worker-executor-base/src/durable_host/mod.rs +++ b/golem-worker-executor-base/src/durable_host/mod.rs @@ -58,7 +58,6 @@ pub use durability::*; use futures::future::try_join_all; use futures_util::TryFutureExt; use futures_util::TryStreamExt; -use golem_common::config::RetryConfig; use golem_common::model::component::ComponentOwner; use golem_common::model::oplog::{ IndexedResourceKey, LogLevel, OplogEntry, OplogIndex, UpdateDescription, WorkerError, @@ -66,6 +65,7 @@ use golem_common::model::oplog::{ }; use golem_common::model::plugin::{PluginOwner, PluginScope}; use golem_common::model::regions::{DeletedRegions, OplogRegion}; +use golem_common::model::RetryConfig; use golem_common::model::{exports, PluginInstallationId}; use golem_common::model::{ AccountId, ComponentFilePath, ComponentFilePermissions, ComponentFileSystemNode, diff --git a/golem-worker-executor-base/src/invocation.rs b/golem-worker-executor-base/src/invocation.rs index 4f5156b9c..efe9e3045 100644 --- a/golem-worker-executor-base/src/invocation.rs +++ b/golem-worker-executor-base/src/invocation.rs @@ -285,7 +285,7 @@ async fn get_or_create_indexed_resource<'a, Ctx: WorkerCtx>( Ok(InvokeResult::from_success( 0, vec![Value::Handle { - uri: store.data().self_uri(), + uri: store.data().self_uri().value, resource_id: resource_id.0, }], )) @@ -303,6 +303,11 @@ async fn get_or_create_indexed_resource<'a, Ctx: WorkerCtx>( "Could not extract resource constructor parameters from function name", ))?; + let constructor_params: Vec = constructor_params + .into_iter() + .map(|vnt| vnt.value) + .collect(); + debug!("Creating new indexed resource with parameters {constructor_params:?}"); let constructor_result = invoke( @@ -407,13 +412,13 @@ async fn drop_resource( let resource_id = match function_input.first() { Some(Value::Handle { uri, resource_id }) => { - if uri == &self_uri { + if uri == &self_uri.value { Ok(*resource_id) } else { Err(GolemError::ValueMismatch { details: format!( "trying to drop handle for on wrong worker ({} vs {}) {}", - uri.value, self_uri.value, raw_function_name + uri, self_uri.value, raw_function_name ), }) } diff --git a/golem-worker-executor-base/src/model/public_oplog/mod.rs b/golem-worker-executor-base/src/model/public_oplog/mod.rs index 59950dd9e..f097f1375 100644 --- a/golem-worker-executor-base/src/model/public_oplog/mod.rs +++ b/golem-worker-executor-base/src/model/public_oplog/mod.rs @@ -62,7 +62,7 @@ use golem_wasm_ast::analysis::analysed_type::{ use golem_wasm_ast::analysis::{AnalysedType, NameOptionTypePair, TypeVariant}; use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; use golem_wasm_rpc::{ - type_annotated_value_from_str, IntoValue, IntoValueAndType, Value, ValueAndType, WitValue, + parse_type_annotated_value, IntoValue, IntoValueAndType, Value, ValueAndType, WitValue, }; use rib::{ParsedFunctionName, ParsedFunctionReference}; use std::collections::{BTreeSet, HashMap}; @@ -660,7 +660,7 @@ impl PublicOplogEntryOps .zip(constructor_def.parameters) { let type_annotated_value: TypeAnnotatedValue = - type_annotated_value_from_str(¶m.typ, value_str)?; + parse_type_annotated_value(¶m.typ, value_str)?; let value = type_annotated_value.try_into()?; let value_and_type = ValueAndType::new(value, param.typ.clone()); resource_params.push(value_and_type); diff --git a/golem-worker-executor-base/src/services/component.rs b/golem-worker-executor-base/src/services/component.rs index fba3a95fd..0b9ae6377 100644 --- a/golem-worker-executor-base/src/services/component.rs +++ b/golem-worker-executor-base/src/services/component.rs @@ -34,10 +34,10 @@ use golem_api_grpc::proto::golem::component::v1::{ }; use golem_common::cache::{BackgroundEvictionMode, Cache, FullCacheEvictionMode, SimpleCache}; use golem_common::client::{GrpcClient, GrpcClientConfig}; -use golem_common::config::RetryConfig; use golem_common::metrics::external_calls::record_external_call_response_size_bytes; use golem_common::model::component_metadata::LinearMemory; use golem_common::model::plugin::PluginInstallation; +use golem_common::model::RetryConfig; use golem_common::model::{ AccountId, ComponentId, ComponentType, ComponentVersion, InitialComponentFile, }; diff --git a/golem-worker-executor-base/src/services/golem_config.rs b/golem-worker-executor-base/src/services/golem_config.rs index 35dc1ab6c..44899e75c 100644 --- a/golem-worker-executor-base/src/services/golem_config.rs +++ b/golem-worker-executor-base/src/services/golem_config.rs @@ -25,8 +25,9 @@ use serde::{Deserialize, Serialize}; use url::Url; use golem_common::config::{ - ConfigExample, ConfigLoader, DbSqliteConfig, HasConfigExamples, RedisConfig, RetryConfig, + ConfigExample, ConfigLoader, DbSqliteConfig, HasConfigExamples, RedisConfig, }; +use golem_common::model::RetryConfig; use golem_common::tracing::TracingConfig; /// The shared global Golem configuration diff --git a/golem-worker-executor-base/src/services/plugins.rs b/golem-worker-executor-base/src/services/plugins.rs index 3ae838f93..d5ffd4431 100644 --- a/golem-worker-executor-base/src/services/plugins.rs +++ b/golem-worker-executor-base/src/services/plugins.rs @@ -24,11 +24,11 @@ use golem_api_grpc::proto::golem::component::v1::{ }; use golem_common::cache::{BackgroundEvictionMode, Cache, FullCacheEvictionMode, SimpleCache}; use golem_common::client::{GrpcClient, GrpcClientConfig}; -use golem_common::config::RetryConfig; use golem_common::model::plugin::{ DefaultPluginOwner, DefaultPluginScope, PluginDefinition, PluginInstallation, PluginOwner, PluginScope, }; +use golem_common::model::RetryConfig; use golem_common::model::{AccountId, ComponentId, ComponentVersion, PluginInstallationId}; use http::Uri; use std::sync::Arc; diff --git a/golem-worker-executor-base/src/worker.rs b/golem-worker-executor-base/src/worker.rs index 8d2e66e0e..a7de8b183 100644 --- a/golem-worker-executor-base/src/worker.rs +++ b/golem-worker-executor-base/src/worker.rs @@ -41,12 +41,12 @@ use crate::workerctx::{PublicWorkerIo, WorkerCtx}; use anyhow::anyhow; use drop_stream::DropStream; use futures::channel::oneshot; -use golem_common::config::RetryConfig; use golem_common::model::oplog::{ OplogEntry, OplogIndex, TimestampedUpdateDescription, UpdateDescription, WorkerError, WorkerResourceId, }; use golem_common::model::regions::{DeletedRegions, DeletedRegionsBuilder, OplogRegion}; +use golem_common::model::RetryConfig; use golem_common::model::{ exports, ComponentFilePath, ComponentType, PluginInstallationId, WorkerStatusRecordExtensions, }; diff --git a/golem-worker-executor-base/tests/compatibility/v1.rs b/golem-worker-executor-base/tests/compatibility/v1.rs index bc784cc67..177fa699e 100644 --- a/golem-worker-executor-base/tests/compatibility/v1.rs +++ b/golem-worker-executor-base/tests/compatibility/v1.rs @@ -23,13 +23,13 @@ use test_r::test; use bincode::{Decode, Encode}; use goldenfile::Mint; -use golem_common::config::RetryConfig; use golem_common::model::oplog::{ IndexedResourceKey, LogLevel, OplogEntry, OplogIndex, OplogPayload, PayloadId, TimestampedUpdateDescription, UpdateDescription, WorkerError, WorkerResourceId, WrappedFunctionType, }; use golem_common::model::regions::{DeletedRegions, OplogRegion}; +use golem_common::model::RetryConfig; use golem_common::model::{ AccountId, ComponentId, FailedUpdateRecord, IdempotencyKey, OwnedWorkerId, PromiseId, ScheduledAction, ShardId, SuccessfulUpdateRecord, Timestamp, TimestampedWorkerInvocation, @@ -44,7 +44,7 @@ use golem_wasm_ast::analysis::{ TypeU32, TypeU64, TypeU8, TypeVariant, }; use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; -use golem_wasm_rpc::{TypeAnnotatedValueConstructors, Uri, Value, WitValue}; +use golem_wasm_rpc::{TypeAnnotatedValueConstructors, Value, WitValue}; use golem_worker_executor_base::durable_host::http::serialized::{ SerializableDnsErrorPayload, SerializableErrorCode, SerializableFieldSizePayload, SerializableResponse, SerializableResponseHeaders, SerializableTlsAlertReceivedPayload, @@ -226,9 +226,7 @@ pub fn wasm_rpc_value() { let v21c = Value::Result(Ok(None)); let v21d = Value::Result(Err(None)); let v22 = Value::Handle { - uri: Uri { - value: "uri".to_string(), - }, + uri: "uri".to_string(), resource_id: 123, }; @@ -1179,9 +1177,7 @@ pub fn wit_value() { let wv21c: WitValue = Value::Result(Ok(None)).into(); let wv21d: WitValue = Value::Result(Err(None)).into(); let wv22: WitValue = Value::Handle { - uri: Uri { - value: "uri".to_string(), - }, + uri: "uri".to_string(), resource_id: 123, } .into(); @@ -1648,9 +1644,7 @@ pub fn proto_val() { let pv21c: golem_wasm_rpc::protobuf::Val = Value::Result(Ok(None)).into(); let pv21d: golem_wasm_rpc::protobuf::Val = Value::Result(Err(None)).into(); let pv22: golem_wasm_rpc::protobuf::Val = Value::Handle { - uri: Uri { - value: "uri".to_string(), - }, + uri: "uri".to_string(), resource_id: 123, } .into(); @@ -1856,9 +1850,7 @@ pub fn type_annotated_value() { .unwrap(); let tav22 = TypeAnnotatedValue::create( &Value::Handle { - uri: Uri { - value: "uri".to_string(), - }, + uri: "uri".to_string(), resource_id: 123, }, &AnalysedType::Handle(TypeHandle { diff --git a/golem-worker-executor-base/tests/compatibility/v1_1.rs b/golem-worker-executor-base/tests/compatibility/v1_1.rs index 475c10c1c..7f7bc91d1 100644 --- a/golem-worker-executor-base/tests/compatibility/v1_1.rs +++ b/golem-worker-executor-base/tests/compatibility/v1_1.rs @@ -17,10 +17,10 @@ use test_r::test; use crate::compatibility::v1::backward_compatible; use goldenfile::Mint; -use golem_common::config::RetryConfig; use golem_common::model::oplog::{ IndexedResourceKey, OplogEntry, OplogIndex, OplogPayload, WorkerResourceId, WrappedFunctionType, }; +use golem_common::model::RetryConfig; use golem_common::model::{ AccountId, ComponentId, IdempotencyKey, PluginInstallationId, Timestamp, TimestampedWorkerInvocation, WorkerId, WorkerInvocation, WorkerResourceDescription, diff --git a/golem-worker-service-base/src/api/custom_http_request_api.rs b/golem-worker-service-base/src/api/custom_http_request_api.rs index ab0fdcf79..71290bcb7 100644 --- a/golem-worker-service-base/src/api/custom_http_request_api.rs +++ b/golem-worker-service-base/src/api/custom_http_request_api.rs @@ -17,42 +17,25 @@ use std::sync::Arc; use crate::gateway_api_definition::http::CompiledHttpApiDefinition; use crate::gateway_execution::api_definition_lookup::ApiDefinitionsLookup; -use crate::gateway_execution::file_server_binding_handler::FileServerBindingHandler; -use crate::gateway_rib_interpreter::DefaultRibInterpreter; -use futures_util::FutureExt; -use golem_common::SafeDisplay; -use poem::http::StatusCode; -use poem::{Body, Endpoint, Request, Response}; -use tracing::error; - -use crate::gateway_binding::{ - DefaultGatewayBindingResolver, ErrorOrRedirect, GatewayBindingResolver, GatewayRequestDetails, -}; use crate::gateway_execution::auth_call_back_binding_handler::DefaultAuthCallBack; +use crate::gateway_execution::file_server_binding_handler::FileServerBindingHandler; use crate::gateway_execution::gateway_http_input_executor::{ - DefaultGatewayInputExecutor, GatewayHttpInput, GatewayHttpInputExecutor, + DefaultGatewayInputExecutor, GatewayHttpInputExecutor, }; -use crate::gateway_execution::gateway_session::{GatewaySession, GatewaySessionStore}; +use crate::gateway_execution::gateway_session::GatewaySession; use crate::gateway_execution::GatewayWorkerRequestExecutor; use crate::gateway_request::http_request::InputHttpRequest; +use crate::gateway_rib_interpreter::DefaultRibInterpreter; use crate::gateway_security::DefaultIdentityProvider; +use futures_util::FutureExt; +use poem::{Endpoint, Request, Response}; -// Executes custom request with the help of worker_request_executor and definition_service -// This is a common API projects can make use of, similar to healthcheck service -pub struct CustomHttpRequestApi { - pub api_definition_lookup_service: Arc< - dyn ApiDefinitionsLookup< - InputHttpRequest, - ApiDefinition = CompiledHttpApiDefinition, - > + Sync - + Send, - >, - pub gateway_http_input_executor: Arc + Sync + Send>, - pub gateway_session_store: GatewaySessionStore, +pub struct CustomHttpRequestApi { + pub gateway_http_input_executor: Arc, } -impl CustomHttpRequestApi { - pub fn new( +impl CustomHttpRequestApi { + pub fn new( worker_request_executor_service: Arc< dyn GatewayWorkerRequestExecutor + Sync + Send, >, @@ -72,88 +55,28 @@ impl CustomHttpRequestApi { let auth_call_back_binding_handler = Arc::new(DefaultAuthCallBack); - let gateway_binding_executor = Arc::new(DefaultGatewayInputExecutor { + let gateway_http_input_executor = Arc::new(DefaultGatewayInputExecutor { evaluator, file_server_binding_handler, auth_call_back_binding_handler, + api_definition_lookup_service, + gateway_session_store, + identity_provider: Arc::new(DefaultIdentityProvider), }); Self { - api_definition_lookup_service, - gateway_http_input_executor: gateway_binding_executor, - gateway_session_store, + gateway_http_input_executor, } } pub async fn execute(&self, request: Request) -> Response { - let input_http_request_result = InputHttpRequest::from_request(request).await; - - match input_http_request_result { - Ok(input_http_request) => { - let possible_api_definitions = match self - .api_definition_lookup_service - .get(&input_http_request) - .await - { - Ok(api_defs) => api_defs, - Err(api_defs_lookup_error) => { - error!( - "API request host: {} - error: {}", - input_http_request.host, api_defs_lookup_error - ); - return Response::builder() - .status(StatusCode::INTERNAL_SERVER_ERROR) - .body(Body::from_string("Internal error".to_string())); - } - }; - - let resolver = DefaultGatewayBindingResolver::new( - input_http_request, - Arc::clone(&self.gateway_session_store), - Arc::new(DefaultIdentityProvider), - ); - - match resolver - .resolve_gateway_binding(possible_api_definitions) - .await - { - Ok(resolved_gateway_binding) => { - let GatewayRequestDetails::Http(request) = - resolved_gateway_binding.request_details; - - let input = GatewayHttpInput::new( - &request, - resolved_gateway_binding.resolved_binding, - Arc::clone(&self.gateway_session_store), - Arc::new(DefaultIdentityProvider), - ); - - let response: Response = self - .gateway_http_input_executor - .execute_binding(&input) - .await; - - response - } - - Err(ErrorOrRedirect::Error(error)) => { - error!( - "Failed to resolve the API definition; error: {}", - error.to_safe_string() - ); - - error.to_http_response() - } - - Err(ErrorOrRedirect::Redirect(response)) => response, - } - } - Err(response) => response.into(), - } + self.gateway_http_input_executor + .execute_http_request(request) + .await } } -impl Endpoint for CustomHttpRequestApi { +impl Endpoint for CustomHttpRequestApi { type Output = Response; fn call(&self, req: Request) -> impl Future> + Send { diff --git a/golem-worker-service-base/src/app_config.rs b/golem-worker-service-base/src/app_config.rs index 9f4543d1d..ff1045129 100644 --- a/golem-worker-service-base/src/app_config.rs +++ b/golem-worker-service-base/src/app_config.rs @@ -21,8 +21,9 @@ use serde::{Deserialize, Serialize}; use url::Url; use uuid::Uuid; -use golem_common::config::{ConfigExample, HasConfigExamples, RedisConfig, RetryConfig}; +use golem_common::config::{ConfigExample, HasConfigExamples, RedisConfig}; use golem_common::config::{DbConfig, DbSqliteConfig}; +use golem_common::model::RetryConfig; use golem_common::tracing::TracingConfig; use golem_service_base::service::routing_table::RoutingTableConfig; diff --git a/golem-worker-service-base/src/gateway_binding/gateway_binding_compiled.rs b/golem-worker-service-base/src/gateway_binding/gateway_binding_compiled.rs index f954365d9..10eb03617 100644 --- a/golem-worker-service-base/src/gateway_binding/gateway_binding_compiled.rs +++ b/golem-worker-service-base/src/gateway_binding/gateway_binding_compiled.rs @@ -78,14 +78,14 @@ impl TryFrom Ok(internal::to_gateway_binding_compiled_proto( worker_binding, GatewayBindingType::Default, - )) + )?) } GatewayBindingCompiled::FileServer(worker_binding) => { Ok(internal::to_gateway_binding_compiled_proto( worker_binding, GatewayBindingType::FileServer, - )) + )?) } GatewayBindingCompiled::Static(static_binding) => { @@ -239,7 +239,7 @@ mod internal { pub(crate) fn to_gateway_binding_compiled_proto( worker_binding: WorkerBindingCompiled, binding_type: GatewayBindingType, - ) -> golem_api_grpc::proto::golem::apidefinition::CompiledGatewayBinding { + ) -> Result { let component = Some(worker_binding.component_id.into()); let worker_name = worker_binding .worker_name_compiled @@ -248,7 +248,8 @@ mod internal { let compiled_worker_name_expr = worker_binding .worker_name_compiled .clone() - .map(|w| w.compiled_worker_name.into()); + .map(|w| w.compiled_worker_name.try_into()) + .transpose()?; let worker_name_rib_input = worker_binding .worker_name_compiled .map(|w| w.rib_input_type_info.into()); @@ -256,7 +257,7 @@ mod internal { match worker_binding.idempotency_key_compiled { Some(x) => ( Some(x.idempotency_key.into()), - Some(x.compiled_idempotency_key.into()), + Some(x.compiled_idempotency_key.try_into()?), Some(x.rib_input.into()), ), None => (None, None, None), @@ -272,7 +273,7 @@ mod internal { worker_binding .response_compiled .response_mapping_compiled - .into(), + .try_into()?, ); let response_rib_input = Some(worker_binding.response_compiled.rib_input.into()); let response_rib_output = worker_binding @@ -291,21 +292,23 @@ mod internal { GatewayBindingType::CorsPreflight => 2, }; - golem_api_grpc::proto::golem::apidefinition::CompiledGatewayBinding { - component, - worker_name, - compiled_worker_name_expr, - worker_name_rib_input, - idempotency_key, - compiled_idempotency_key_expr, - idempotency_key_rib_input, - response, - compiled_response_expr, - response_rib_input, - worker_functions_in_response, - binding_type: Some(binding_type), - static_binding: None, - response_rib_output, - } + Ok( + golem_api_grpc::proto::golem::apidefinition::CompiledGatewayBinding { + component, + worker_name, + compiled_worker_name_expr, + worker_name_rib_input, + idempotency_key, + compiled_idempotency_key_expr, + idempotency_key_rib_input, + response, + compiled_response_expr, + response_rib_input, + worker_functions_in_response, + binding_type: Some(binding_type), + static_binding: None, + response_rib_output, + }, + ) } } diff --git a/golem-worker-service-base/src/gateway_execution/file_server_binding_handler.rs b/golem-worker-service-base/src/gateway_execution/file_server_binding_handler.rs index 7171e6a96..570851db1 100644 --- a/golem-worker-service-base/src/gateway_execution/file_server_binding_handler.rs +++ b/golem-worker-service-base/src/gateway_execution/file_server_binding_handler.rs @@ -14,8 +14,7 @@ use crate::empty_worker_metadata; use crate::gateway_binding::WorkerDetail; -use crate::getter::{get_response_headers_or_default, get_status_code, GetterExt}; -use crate::path::Path; +use crate::getter::{get_response_headers_or_default, get_status_code}; use crate::service::component::{ComponentService, ComponentServiceError}; use crate::service::worker::{WorkerService, WorkerServiceError}; use async_trait::async_trait; @@ -26,9 +25,8 @@ use golem_common::model::{ComponentFilePath, HasAccountId, TargetWorkerId}; use golem_service_base::auth::EmptyAuthCtx; use golem_service_base::model::validate_worker_name; use golem_service_base::service::initial_component_files::InitialComponentFilesService; -use golem_wasm_rpc::json::TypeAnnotatedValueJsonExtensions; -use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; -use golem_wasm_rpc::protobuf::typed_result::ResultValue; +use golem_wasm_ast::analysis::AnalysedType; +use golem_wasm_rpc::{Value, ValueAndType}; use http::StatusCode; use poem::web::headers::ContentType; use rib::RibResult; @@ -188,20 +186,22 @@ impl FileServerBindingDetails { // 3. A result of either of the above, with the same rules applied. match result { RibResult::Val(value) => match value { - TypeAnnotatedValue::Result(inner) => { - let value = inner - .result_value - .ok_or("Expected a result value".to_string())?; - match value { - ResultValue::OkValue(ok) => Self::from_rib_happy( - ok.type_annotated_value.ok_or("ok unset".to_string())?, - ), - ResultValue::ErrorValue(err) => { - let value = err.type_annotated_value.ok_or("err unset".to_string())?; - Err(format!("Error result: {}", value.to_json_value())) - } + ValueAndType { + value: Value::Result(value), + typ: AnalysedType::Result(typ), + } => match value { + Ok(ok) => { + let ok = ValueAndType::new( + *ok.ok_or("ok unset".to_string())?, + (*typ.ok.ok_or("Missing 'ok' type")?).clone(), + ); + Self::from_rib_happy(ok) } - } + Err(err) => { + let value = err.ok_or("err unset".to_string())?; + Err(format!("Error result: {value:?}")) + } + }, other => Self::from_rib_happy(other), }, RibResult::Unit => Err("Expected a value".to_string()), @@ -209,25 +209,33 @@ impl FileServerBindingDetails { } /// Like the above, just without the result case. - fn from_rib_happy(value: TypeAnnotatedValue) -> Result { - match value { - TypeAnnotatedValue::Str(raw_path) => Self::make_from(raw_path, None, None), - record @ TypeAnnotatedValue::Record(_) => { - let path = record - .get_optional(&Path::from_key("file-path")) + fn from_rib_happy(value: ValueAndType) -> Result { + match &value { + ValueAndType { + value: Value::String(raw_path), + .. + } => Self::make_from(raw_path.clone(), None, None), + ValueAndType { + value: Value::Record(field_values), + typ: AnalysedType::Record(record), + } => { + let path_position = record + .fields + .iter() + .position(|pair| &pair.name == "file-path") .ok_or("Record must contain 'file-path' field")?; - let path = if let TypeAnnotatedValue::Str(path) = path { + let path = if let Value::String(path) = &field_values[path_position] { path } else { return Err("file-path must be a string".to_string()); }; - let status = get_status_code(&record)?; - let headers = get_response_headers_or_default(&record)?; + let status = get_status_code(field_values, record)?; + let headers = get_response_headers_or_default(&value)?; let content_type = headers.get_content_type(); - Self::make_from(path, content_type, status) + Self::make_from(path.to_string(), content_type, status) } _ => Err("Response value expected".to_string()), } diff --git a/golem-worker-service-base/src/gateway_execution/gateway_binding_resolver.rs b/golem-worker-service-base/src/gateway_execution/gateway_binding_resolver.rs index d55cdedb6..097cf71a7 100644 --- a/golem-worker-service-base/src/gateway_execution/gateway_binding_resolver.rs +++ b/golem-worker-service-base/src/gateway_execution/gateway_binding_resolver.rs @@ -207,13 +207,13 @@ pub struct DefaultGatewayBindingResolver { impl DefaultGatewayBindingResolver { pub fn new( input: InputHttpRequest, - gateway_session_store: GatewaySessionStore, - identity_provider: Arc, + gateway_session_store: &GatewaySessionStore, + identity_provider: &Arc, ) -> Self { DefaultGatewayBindingResolver { input, - gateway_session_store, - identity_provider, + gateway_session_store: Arc::clone(gateway_session_store), + identity_provider: Arc::clone(identity_provider), } } } diff --git a/golem-worker-service-base/src/gateway_execution/gateway_http_input_executor.rs b/golem-worker-service-base/src/gateway_execution/gateway_http_input_executor.rs index fed0c115a..1e20a1f2d 100644 --- a/golem-worker-service-base/src/gateway_execution/gateway_http_input_executor.rs +++ b/golem-worker-service-base/src/gateway_execution/gateway_http_input_executor.rs @@ -12,60 +12,49 @@ // See the License for the specific language governing permissions and // limitations under the License. +use crate::gateway_api_definition::http::CompiledHttpApiDefinition; use crate::gateway_binding::{ - HttpRequestDetails, ResolvedBinding, ResolvedWorkerBinding, RibInputTypeMismatch, - RibInputValueResolver, StaticBinding, + DefaultGatewayBindingResolver, ErrorOrRedirect, GatewayBindingResolver, GatewayRequestDetails, + HttpRequestDetails, ResolvedBinding, ResolvedWorkerBinding, RibInputValueResolver, + StaticBinding, }; +use crate::gateway_execution::api_definition_lookup::ApiDefinitionsLookup; use crate::gateway_execution::auth_call_back_binding_handler::{ AuthCallBackBindingHandler, AuthCallBackResult, }; -use crate::gateway_execution::file_server_binding_handler::{ - FileServerBindingHandler, FileServerBindingResult, -}; -use crate::gateway_execution::gateway_session::{GatewaySession, GatewaySessionStore}; +use crate::gateway_execution::file_server_binding_handler::FileServerBindingHandler; +use crate::gateway_execution::gateway_session::GatewaySessionStore; use crate::gateway_execution::to_response::ToHttpResponse; use crate::gateway_execution::to_response_failure::ToHttpResponseFromSafeDisplay; +use crate::gateway_request::http_request::InputHttpRequest; use crate::gateway_rib_interpreter::{EvaluationError, WorkerServiceRibInterpreter}; use crate::gateway_security::{IdentityProvider, SecuritySchemeWithProviderMetadata}; use async_trait::async_trait; +use golem_common::SafeDisplay; use http::StatusCode; +use poem::Body; use rib::{RibInput, RibResult}; use std::sync::Arc; +use tracing::error; #[async_trait] -pub trait GatewayHttpInputExecutor { - async fn execute_binding(&self, input: &GatewayHttpInput) -> poem::Response; -} - -// A product of actual request input (contained in the ResolvedGatewayBinding) -// and other details and resolvers that are needed to process the input. -pub struct GatewayHttpInput { - pub http_request_details: HttpRequestDetails, - pub resolved_gateway_binding: ResolvedBinding, - pub session_store: Arc, - pub identity_provider: Arc, -} - -impl GatewayHttpInput { - pub fn new( - http_request_details: &HttpRequestDetails, - resolved_gateway_binding: ResolvedBinding, - session_store: GatewaySessionStore, - identity_provider: Arc, - ) -> Self { - GatewayHttpInput { - http_request_details: http_request_details.clone(), - resolved_gateway_binding, - session_store, - identity_provider, - } - } +pub trait GatewayHttpInputExecutor { + async fn execute_http_request(&self, input: poem::Request) -> poem::Response; } pub struct DefaultGatewayInputExecutor { pub evaluator: Arc + Sync + Send>, pub file_server_binding_handler: Arc + Sync + Send>, pub auth_call_back_binding_handler: Arc, + pub api_definition_lookup_service: Arc< + dyn ApiDefinitionsLookup< + InputHttpRequest, + ApiDefinition = CompiledHttpApiDefinition, + > + Sync + + Send, + >, + pub gateway_session_store: GatewaySessionStore, + pub identity_provider: Arc, } impl DefaultGatewayInputExecutor { @@ -73,11 +62,80 @@ impl DefaultGatewayInputExecutor { evaluator: Arc + Sync + Send>, file_server_binding_handler: Arc + Sync + Send>, auth_call_back_binding_handler: Arc, + api_definition_lookup_service: Arc< + dyn ApiDefinitionsLookup< + InputHttpRequest, + ApiDefinition = CompiledHttpApiDefinition, + > + Sync + + Send, + >, + gateway_session_store: GatewaySessionStore, + identity_provider: Arc, ) -> Self { Self { evaluator, file_server_binding_handler, auth_call_back_binding_handler, + api_definition_lookup_service, + gateway_session_store, + identity_provider, + } + } + + pub async fn execute( + &self, + http_request_details: &HttpRequestDetails, + binding: ResolvedBinding, + ) -> poem::Response { + let middleware_opt = &http_request_details.http_middlewares; + let mut request_details = http_request_details.clone(); + + match &binding { + ResolvedBinding::Static(StaticBinding::HttpCorsPreflight(cors_preflight)) => { + cors_preflight + .clone() + .to_response(http_request_details, &self.gateway_session_store) + .await + } + + ResolvedBinding::Static(StaticBinding::HttpAuthCallBack(auth_call_back)) => { + self.handle_http_auth_call_binding( + &auth_call_back.security_scheme_with_metadata, + http_request_details, + ) + .await + } + + ResolvedBinding::Worker(resolved_worker_binding) => { + let mut response = self + .handle_worker_binding( + &self.gateway_session_store, + &mut request_details, + resolved_worker_binding, + ) + .await; + + if let Some(middleware) = middleware_opt { + let result = middleware.process_middleware_out(&mut response).await; + match result { + Ok(_) => response, + Err(err) => { + err.to_response_from_safe_display(|_| StatusCode::INTERNAL_SERVER_ERROR) + } + } + } else { + response + } + } + + ResolvedBinding::FileServer(resolved_file_server_binding) => { + self.handle_file_server_binding( + &self.gateway_session_store, + &mut request_details, + resolved_file_server_binding, + ) + .await + } } } @@ -85,10 +143,7 @@ impl DefaultGatewayInputExecutor { &self, request_details: &HttpRequestDetails, resolved_worker_binding: &ResolvedWorkerBinding, - ) -> Result<(RibInput, RibInput), poem::Response> - where - RibInputTypeMismatch: ToHttpResponseFromSafeDisplay, - { + ) -> Result<(RibInput, RibInput), poem::Response> { let rib_input_from_request_details = request_details .resolve_rib_input_value(&resolved_worker_binding.compiled_response_mapping.rib_input) .map_err(|err| err.to_response_from_safe_display(|_| StatusCode::BAD_REQUEST))?; @@ -162,13 +217,7 @@ impl DefaultGatewayInputExecutor { session_store: &GatewaySessionStore, request_details: &mut HttpRequestDetails, resolved_binding: &ResolvedWorkerBinding, - ) -> poem::Response - where - RibResult: ToHttpResponse, - EvaluationError: ToHttpResponseFromSafeDisplay, - RibInputTypeMismatch: ToHttpResponseFromSafeDisplay, - FileServerBindingResult: ToHttpResponse, - { + ) -> poem::Response { match self .resolve_rib_inputs(request_details, resolved_binding) .await @@ -201,83 +250,87 @@ impl DefaultGatewayInputExecutor { async fn handle_http_auth_call_binding( &self, security_scheme_with_metadata: &SecuritySchemeWithProviderMetadata, - input: &GatewayHttpInput, + http_request: &HttpRequestDetails, ) -> poem::Response where AuthCallBackResult: ToHttpResponse, { - let http_request = &input.http_request_details; let authorisation_result = self .auth_call_back_binding_handler .handle_auth_call_back( http_request, security_scheme_with_metadata, - &input.session_store, - &input.identity_provider, + &self.gateway_session_store, + &self.identity_provider, ) .await; authorisation_result - .to_response(&input.http_request_details, &input.session_store) + .to_response(http_request, &self.gateway_session_store) .await } } #[async_trait] -impl GatewayHttpInputExecutor +impl GatewayHttpInputExecutor for DefaultGatewayInputExecutor { - async fn execute_binding(&self, input: &GatewayHttpInput) -> poem::Response { - let binding = &input.resolved_gateway_binding; - let middleware_opt = &input.http_request_details.http_middlewares; - let mut request_details = input.http_request_details.clone(); + async fn execute_http_request(&self, request: poem::Request) -> poem::Response { + let input_http_request_result = InputHttpRequest::from_request(request).await; - match &binding { - ResolvedBinding::Static(StaticBinding::HttpCorsPreflight(cors_preflight)) => { - cors_preflight - .clone() - .to_response(&input.http_request_details, &input.session_store) + match input_http_request_result { + Ok(input_http_request) => { + let possible_api_definitions = match self + .api_definition_lookup_service + .get(&input_http_request) .await - } + { + Ok(api_defs) => api_defs, + Err(api_defs_lookup_error) => { + error!( + "API request host: {} - error: {}", + input_http_request.host, api_defs_lookup_error + ); + return poem::Response::builder() + .status(StatusCode::INTERNAL_SERVER_ERROR) + .body(Body::from_string("Internal error".to_string())); + } + }; - ResolvedBinding::Static(StaticBinding::HttpAuthCallBack(auth_call_back)) => { - self.handle_http_auth_call_binding( - &auth_call_back.security_scheme_with_metadata, - input, - ) - .await - } + let resolver = DefaultGatewayBindingResolver::new( + input_http_request, + &self.gateway_session_store, + &self.identity_provider, + ); - ResolvedBinding::Worker(resolved_worker_binding) => { - let mut response = self - .handle_worker_binding( - &input.session_store, - &mut request_details, - resolved_worker_binding, - ) - .await; + match resolver + .resolve_gateway_binding(possible_api_definitions) + .await + { + Ok(resolved_gateway_binding) => { + let GatewayRequestDetails::Http(request) = + resolved_gateway_binding.request_details; - if let Some(middleware) = middleware_opt { - let result = middleware.process_middleware_out(&mut response).await; - match result { - Ok(_) => response, - Err(err) => { - err.to_response_from_safe_display(|_| StatusCode::INTERNAL_SERVER_ERROR) - } + let response: poem::Response = self + .execute(&request, resolved_gateway_binding.resolved_binding) + .await; + + response } - } else { - response - } - } - ResolvedBinding::FileServer(resolved_file_server_binding) => { - self.handle_file_server_binding( - &input.session_store, - &mut request_details, - resolved_file_server_binding, - ) - .await + Err(ErrorOrRedirect::Error(error)) => { + error!( + "Failed to resolve the API definition; error: {}", + error.to_safe_string() + ); + + error.to_http_response() + } + + Err(ErrorOrRedirect::Redirect(response)) => response, + } } + Err(response) => response.into(), } } } diff --git a/golem-worker-service-base/src/gateway_execution/rib_input_value_resolver.rs b/golem-worker-service-base/src/gateway_execution/rib_input_value_resolver.rs index 09d7fafa3..5f2fcca94 100644 --- a/golem-worker-service-base/src/gateway_execution/rib_input_value_resolver.rs +++ b/golem-worker-service-base/src/gateway_execution/rib_input_value_resolver.rs @@ -61,6 +61,11 @@ impl RibInputValueResolver for HttpRequestDetails { warn!("received: {:?}", rib_input_with_request_content); let input = TypeAnnotatedValue::parse_with_type(rib_input_with_request_content, request_type) .map_err(|err| RibInputTypeMismatch(format!("Input request details don't match the requirements for rib expression to execute: {}. Requirements. {:?}", err.join(", "), request_type)))?; + let input = input.try_into().map_err(|err| { + RibInputTypeMismatch(format!( + "Internal error converting between value representations: {err}" + )) + })?; let mut rib_input_map = HashMap::new(); rib_input_map.insert("request".to_string(), input); @@ -86,6 +91,11 @@ impl RibInputValueResolver for WorkerDetail { let request_value = TypeAnnotatedValue::parse_with_type(rib_input_with_request_content, worker_details_type) .map_err(|err| RibInputTypeMismatch(format!("Worker details don't match the requirements for rib expression to execute: {}. Requirements. {:?}", err.join(", "), worker_details_type)))?; + let request_value = request_value.try_into().map_err(|err| { + RibInputTypeMismatch(format!( + "Internal error converting between value representations: {err}" + )) + })?; let mut rib_input_map = HashMap::new(); rib_input_map.insert("worker".to_string(), request_value); diff --git a/golem-worker-service-base/src/gateway_execution/to_response.rs b/golem-worker-service-base/src/gateway_execution/to_response.rs index 12749388a..c8b3c544e 100644 --- a/golem-worker-service-base/src/gateway_execution/to_response.rs +++ b/golem-worker-service-base/src/gateway_execution/to_response.rs @@ -215,9 +215,14 @@ mod internal { let headers = get_response_headers_or_default(rib_result).map_err(EvaluationError)?; - let body = rib_result + let tav: TypeAnnotatedValue = rib_result + .clone() + .try_into() + .map_err(|errs: Vec| EvaluationError(errs.join(", ")))?; + + let body = tav .get_optional(&Path::from_key("body")) - .unwrap_or(rib_result.clone()); + .unwrap_or(tav.clone()); Ok(IntermediateHttpResponse { body: Some(body), @@ -282,9 +287,6 @@ mod internal { #[cfg(test)] mod test { use async_trait::async_trait; - use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; - use golem_wasm_rpc::protobuf::Type; - use golem_wasm_rpc::protobuf::{NameTypePair, NameValuePair, TypedRecord}; use std::sync::Arc; use test_r::test; @@ -293,50 +295,43 @@ mod test { DataKey, DataValue, GatewaySession, GatewaySessionError, SessionId, }; use crate::gateway_execution::to_response::ToHttpResponse; + use golem_wasm_ast::analysis::analysed_type::record; + use golem_wasm_ast::analysis::NameTypePair; + use golem_wasm_rpc::{IntoValueAndType, Value, ValueAndType}; use http::header::CONTENT_TYPE; use http::StatusCode; use rib::RibResult; - fn create_record(values: Vec<(String, TypeAnnotatedValue)>) -> TypeAnnotatedValue { - let mut name_type_pairs = vec![]; - let mut name_value_pairs = vec![]; - - for (key, value) in values.iter() { - let typ = Type::try_from(value).unwrap(); - name_type_pairs.push(NameTypePair { - name: key.to_string(), - typ: Some(typ), - }); + fn create_record(values: Vec<(String, ValueAndType)>) -> ValueAndType { + let mut fields = vec![]; + let mut field_values = vec![]; - name_value_pairs.push(NameValuePair { - name: key.to_string(), - value: Some(golem_wasm_rpc::protobuf::TypeAnnotatedValue { - type_annotated_value: Some(value.clone()), - }), + for (key, vnt) in values { + fields.push(NameTypePair { + name: key, + typ: vnt.typ, }); + field_values.push(vnt.value); } - TypeAnnotatedValue::Record(TypedRecord { - typ: name_type_pairs, - value: name_value_pairs, - }) + ValueAndType { + value: Value::Record(field_values), + typ: record(fields), + } } #[test] async fn test_evaluation_result_to_response_with_http_specifics() { let record = create_record(vec![ - ("status".to_string(), TypeAnnotatedValue::U16(400)), + ("status".to_string(), 400u16.into_value_and_type()), ( "headers".to_string(), create_record(vec![( "Content-Type".to_string(), - TypeAnnotatedValue::Str("application/json".to_string()), + "application/json".into_value_and_type(), )]), ), - ( - "body".to_string(), - TypeAnnotatedValue::Str("Hello".to_string()), - ), + ("body".to_string(), "Hello".into_value_and_type()), ]); let evaluation_result: RibResult = RibResult::Val(record); @@ -367,8 +362,7 @@ mod test { #[test] async fn test_evaluation_result_to_response_with_no_http_specifics() { - let evaluation_result: RibResult = - RibResult::Val(TypeAnnotatedValue::Str("Healthy".to_string())); + let evaluation_result: RibResult = RibResult::Val("Healthy".into_value_and_type()); let session_store: Arc = Arc::new(TestSessionStore); diff --git a/golem-worker-service-base/src/gateway_middleware/http/cors.rs b/golem-worker-service-base/src/gateway_middleware/http/cors.rs index e56061abe..576d6523b 100644 --- a/golem-worker-service-base/src/gateway_middleware/http/cors.rs +++ b/golem-worker-service-base/src/gateway_middleware/http/cors.rs @@ -142,18 +142,8 @@ impl HttpCors { let mut cors = HttpCors::default(); - for name_value in record { - let key = &name_value.name; - let value = name_value - .value - .as_ref() - .ok_or("Missing value in type_annotated_value record")? - .type_annotated_value - .as_ref() - .ok_or(format!( - "Unable to fetch value for key {} in type_annotated_value", - key - ))? + for (key, value) in record { + let value = value .get_literal() .ok_or(format!( "Invalid value for key {} in CORS preflight response", @@ -161,7 +151,7 @@ impl HttpCors { ))? .as_string(); - internal::set_cors_field(&mut cors, key, &value)?; + internal::set_cors_field(&mut cors, &key, &value)?; } Ok(cors) diff --git a/golem-worker-service-base/src/gateway_rib_interpreter/mod.rs b/golem-worker-service-base/src/gateway_rib_interpreter/mod.rs index 43d95135d..5c4eb540c 100644 --- a/golem-worker-service-base/src/gateway_rib_interpreter/mod.rs +++ b/golem-worker-service-base/src/gateway_rib_interpreter/mod.rs @@ -21,6 +21,7 @@ use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; use golem_common::model::{ComponentId, IdempotencyKey}; use golem_common::SafeDisplay; +use golem_wasm_rpc::ValueAndType; use rib::{RibByteCode, RibFunctionInvoke, RibInput, RibResult}; use crate::gateway_execution::{GatewayResolvedWorkerRequest, GatewayWorkerRequestExecutor}; @@ -97,7 +98,7 @@ impl WorkerServiceRibInterpreter| { + move |function_name: String, parameters: Vec| { let component_id = component_id.clone(); let worker_name = worker_name.clone(); let idempotency_key = idempotency_key.clone(); @@ -105,20 +106,29 @@ impl WorkerServiceRibInterpreter TypeAnnotatedValue + let function_params: Vec = parameters + .into_iter() + .map(TypeAnnotatedValue::try_from) + .collect::, _>>() + .map_err(|errs: Vec| errs.join(", "))?; + let worker_request = GatewayResolvedWorkerRequest { component_id, worker_name, function_name, - function_params: parameters, + function_params, idempotency_key, namespace, }; - executor + let tav = executor .execute(worker_request) .await .map(|v| v.result) - .map_err(|e| e.to_string()) + .map_err(|e| e.to_string())?; + + tav.try_into() } .boxed() } diff --git a/golem-worker-service-base/src/getter.rs b/golem-worker-service-base/src/getter.rs index 815d56ca1..0d3adf965 100644 --- a/golem-worker-service-base/src/getter.rs +++ b/golem-worker-service-base/src/getter.rs @@ -14,9 +14,11 @@ use crate::headers::ResolvedResponseHeaders; use crate::path::{Path, PathComponent}; +use golem_wasm_ast::analysis::{AnalysedType, TypeRecord}; use golem_wasm_rpc::json::TypeAnnotatedValueJsonExtensions; use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; use golem_wasm_rpc::protobuf::{TypedList, TypedRecord, TypedTuple}; +use golem_wasm_rpc::{Value, ValueAndType}; use http::StatusCode; use rib::GetLiteralValue; use rib::LiteralValue; @@ -35,6 +37,8 @@ pub enum GetError { NotRecord { key_name: String, found: String }, #[error("Not an array: index: {index}, original_value: {found}")] NotArray { index: usize, found: String }, + #[error("Internal error: {0}")] + Internal(String), } // To deal with fields in a TypeAnnotatedValue (that's returned from golem-rib) @@ -90,6 +94,17 @@ impl Getter for TypeAnnotatedValue { } } +impl Getter for ValueAndType { + fn get(&self, key: &Path) -> Result { + let tav: TypeAnnotatedValue = self + .clone() + .try_into() + .map_err(|errs: Vec| GetError::Internal(errs.join(", ")))?; + let result = tav.get(key)?; + result.try_into().map_err(GetError::Internal) + } +} + fn get_array(value: &TypeAnnotatedValue) -> Option> { match value { TypeAnnotatedValue::List(TypedList { values, .. }) => { @@ -124,32 +139,64 @@ impl> GetterExt for T { } pub fn get_response_headers( - typed_value: &TypeAnnotatedValue, + field_values: &[Value], + record: &TypeRecord, ) -> Result, String> { - match typed_value.get_optional(&Path::from_key("headers")) { + match record + .fields + .iter() + .position(|pair| &pair.name == "headers") + { None => Ok(None), - Some(header) => Ok(Some(ResolvedResponseHeaders::from_typed_value(&header)?)), + Some(field_position) => Ok(Some(ResolvedResponseHeaders::from_typed_value( + ValueAndType::new( + field_values[field_position].clone(), + record.fields[field_position].typ.clone(), + ), + )?)), } } pub fn get_response_headers_or_default( - typed_value: &TypeAnnotatedValue, + value: &ValueAndType, ) -> Result { - get_response_headers(typed_value).map(|headers| headers.unwrap_or_default()) + match value { + ValueAndType { + value: Value::Record(field_values), + typ: AnalysedType::Record(record), + } => get_response_headers(field_values, record).map(|headers| headers.unwrap_or_default()), + _ => Ok(ResolvedResponseHeaders::default()), + } } -pub fn get_status_code(typed_value: &TypeAnnotatedValue) -> Result, String> { - match typed_value.get_optional(&Path::from_key("status")) { +pub fn get_status_code( + field_values: &[Value], + record: &TypeRecord, +) -> Result, String> { + match record + .fields + .iter() + .position(|field| &field.name == "status") + { None => Ok(None), - Some(typed_value) => Ok(Some(get_status_code_inner(&typed_value)?)), + Some(field_position) => Ok(Some(get_status_code_inner(ValueAndType::new( + field_values[field_position].clone(), + record.fields[field_position].typ.clone(), + ))?)), } } -pub fn get_status_code_or_ok(typed_value: &TypeAnnotatedValue) -> Result { - get_status_code(typed_value).map(|status| status.unwrap_or(StatusCode::OK)) +pub fn get_status_code_or_ok(value: &ValueAndType) -> Result { + match value { + ValueAndType { + value: Value::Record(field_values), + typ: AnalysedType::Record(record), + } => get_status_code(field_values, record).map(|status| status.unwrap_or(StatusCode::OK)), + _ => Ok(StatusCode::OK), + } } -fn get_status_code_inner(status_code: &TypeAnnotatedValue) -> Result { +fn get_status_code_inner(status_code: ValueAndType) -> Result { let status_res: Result = match status_code.get_literal() { Some(LiteralValue::String(status_str)) => status_str.parse().map_err(|e| { @@ -166,7 +213,7 @@ fn get_status_code_inner(status_code: &TypeAnnotatedValue) -> Result Err(format!( "Status Code Expression is evaluated to a complex value. It is resolved to {:?}", - status_code.to_json_value() + status_code.value )) }; @@ -174,7 +221,7 @@ fn get_status_code_inner(status_code: &TypeAnnotatedValue) -> Result Result { + pub fn from_typed_value(header_map: ValueAndType) -> Result { match header_map { - TypeAnnotatedValue::Record(TypedRecord { value, .. }) => { + ValueAndType { + value: Value::Record(field_values), + typ: AnalysedType::Record(record), + } => { let mut resolved_headers: HashMap = HashMap::new(); - for name_value_pair in value { - let value_str = name_value_pair - .value - .as_ref() - .and_then(|v| v.type_annotated_value.clone()) - .ok_or("Unable to resolve header value".to_string())? + for (value, field_def) in field_values.into_iter().zip(record.fields) { + let value = ValueAndType::new(value, field_def.typ); + let value_str = value .get_literal() .map(|primitive| primitive.to_string()) .unwrap_or_else(|| "Unable to resolve header".to_string()); - resolved_headers.insert(name_value_pair.name.clone(), value_str); + resolved_headers.insert(field_def.name, value_str); } let headers = (&resolved_headers) @@ -56,8 +53,7 @@ impl ResolvedResponseHeaders { } _ => Err(format!( - "Header expression is not a record. It is resolved to {}", - header_map.to_json_value() + "Header expression is not a record. It is resolved to {header_map}", )), } } diff --git a/golem-worker-service-base/src/service/component/default.rs b/golem-worker-service-base/src/service/component/default.rs index 67fbbc47e..bd1598926 100644 --- a/golem-worker-service-base/src/service/component/default.rs +++ b/golem-worker-service-base/src/service/component/default.rs @@ -24,9 +24,9 @@ use golem_api_grpc::proto::golem::component::v1::{ use golem_api_grpc::proto::golem::component::ComponentConstraints; use golem_api_grpc::proto::golem::component::FunctionConstraintCollection as FunctionConstraintCollectionProto; use golem_common::client::{GrpcClient, GrpcClientConfig}; -use golem_common::config::RetryConfig; use golem_common::model::component_constraint::FunctionConstraintCollection; use golem_common::model::ComponentId; +use golem_common::model::RetryConfig; use golem_common::retries::with_retries; use golem_service_base::model::Component; use http::Uri; diff --git a/golem-worker-service-base/src/service/worker/default.rs b/golem-worker-service-base/src/service/worker/default.rs index 3a0d751ae..6f19b9d0d 100644 --- a/golem-worker-service-base/src/service/worker/default.rs +++ b/golem-worker-service-base/src/service/worker/default.rs @@ -31,9 +31,9 @@ use golem_api_grpc::proto::golem::workerexecutor::v1::{ ResumeWorkerRequest, SearchOplogResponse, UpdateWorkerRequest, }; use golem_common::client::MultiTargetGrpcClient; -use golem_common::config::RetryConfig; use golem_common::model::oplog::OplogIndex; use golem_common::model::public_oplog::{OplogCursor, PublicOplogEntry}; +use golem_common::model::RetryConfig; use golem_common::model::{ AccountId, ComponentFilePath, ComponentFileSystemNode, ComponentId, ComponentVersion, FilterComparator, IdempotencyKey, PluginInstallationId, PromiseId, ScanCursor, TargetWorkerId, diff --git a/golem-worker-service-base/src/service/worker/routing_logic.rs b/golem-worker-service-base/src/service/worker/routing_logic.rs index 007e80f81..56b026156 100644 --- a/golem-worker-service-base/src/service/worker/routing_logic.rs +++ b/golem-worker-service-base/src/service/worker/routing_logic.rs @@ -27,7 +27,7 @@ use tracing::{debug, error, info, warn, Instrument}; use golem_api_grpc::proto::golem::worker::v1::WorkerExecutionError; use golem_api_grpc::proto::golem::workerexecutor::v1::worker_executor_client::WorkerExecutorClient; use golem_common::client::MultiTargetGrpcClient; -use golem_common::config::RetryConfig; +use golem_common::model::RetryConfig; use golem_common::model::{Pod, ShardId, TargetWorkerId, WorkerId}; use golem_common::retriable_error::IsRetriableError; use golem_common::retries::get_delay; diff --git a/golem-worker-service-base/tests/api_gateway_end_to_end_tests.rs b/golem-worker-service-base/tests/api_gateway_end_to_end_tests.rs index 3643e4f9d..b330c742b 100644 --- a/golem-worker-service-base/tests/api_gateway_end_to_end_tests.rs +++ b/golem-worker-service-base/tests/api_gateway_end_to_end_tests.rs @@ -25,29 +25,26 @@ use crate::internal::get_preflight_from_response; use crate::security::TestIdentityProvider; use chrono::{DateTime, Utc}; use golem_common::model::IdempotencyKey; -use golem_worker_service_base::gateway_api_deployment::ApiSiteString; use golem_worker_service_base::gateway_execution::auth_call_back_binding_handler::DefaultAuthCallBack; use golem_worker_service_base::gateway_execution::gateway_binding_resolver::{ - DefaultGatewayBindingResolver, ErrorOrRedirect, GatewayBindingResolver, + DefaultGatewayBindingResolver, GatewayBindingResolver, }; use golem_worker_service_base::gateway_execution::gateway_http_input_executor::{ - DefaultGatewayInputExecutor, GatewayHttpInput, GatewayHttpInputExecutor, + DefaultGatewayInputExecutor, GatewayHttpInputExecutor, }; use golem_worker_service_base::gateway_execution::gateway_session::{ GatewaySession, GatewaySessionStore, }; use golem_worker_service_base::gateway_middleware::HttpCors; use golem_worker_service_base::gateway_request::http_request::{ApiInputPath, InputHttpRequest}; -use golem_worker_service_base::gateway_request::request_details::GatewayRequestDetails; use golem_worker_service_base::gateway_security::{ - Provider, SecurityScheme, SecuritySchemeIdentifier, + IdentityProvider, Provider, SecurityScheme, SecuritySchemeIdentifier, }; use golem_worker_service_base::{api, gateway_api_definition}; use http::header::LOCATION; -use http::uri::Scheme; -use http::{HeaderMap, HeaderValue, Method, StatusCode}; +use http::{HeaderMap, HeaderValue, Method, StatusCode, Uri}; use openidconnect::{ClientId, ClientSecret, RedirectUrl, Scope}; -use poem::Response; +use poem::{Request, Response}; use serde_json::Value; use url::Url; @@ -60,17 +57,11 @@ use url::Url; // Example: RibResult has an instance of `ToResponse`. // The tests skips validation and transformations done at the service side. async fn execute( - api_request: &InputHttpRequest, + api_request: Request, api_specification: &HttpApiDefinition, session_store: &GatewaySessionStore, test_identity_provider: &TestIdentityProvider, ) -> Response { - let test_executor = DefaultGatewayInputExecutor::new( - internal::get_test_rib_interpreter(), - internal::get_test_file_server_binding_handler(), - Arc::new(DefaultAuthCallBack), - ); - // Compile the API definition let compiled = CompiledHttpApiDefinition::from_http_api_definition( api_specification, @@ -79,35 +70,16 @@ async fn execute( ) .expect("Failed to compile API definition"); - // Resolve the API definition binding from input - let resolver = DefaultGatewayBindingResolver::new( - api_request.clone(), + let test_executor = DefaultGatewayInputExecutor::new( + internal::get_test_rib_interpreter(), + internal::get_test_file_server_binding_handler(), + Arc::new(DefaultAuthCallBack), + Arc::new(internal::TestApiDefinitionLookup::new(compiled)), Arc::clone(session_store), Arc::new(test_identity_provider.clone()), ); - let resolved_gateway_binding = resolver.resolve_gateway_binding(vec![compiled]).await; - - match resolved_gateway_binding { - Ok(resolved_binding) => { - let GatewayRequestDetails::Http(http) = resolved_binding.request_details; - - // Create the input for the executor - let input = GatewayHttpInput::new( - &http, - resolved_binding.resolved_binding, - Arc::clone(session_store), - Arc::new(test_identity_provider.clone()), - ); - - test_executor.execute_binding(&input).await - } - - Err(binding_resolver_error) => match binding_resolver_error { - ErrorOrRedirect::Redirect(response) => response, - ErrorOrRedirect::Error(error) => error.to_http_response(), - }, - } + test_executor.execute_http_request(api_request).await } #[test] @@ -131,7 +103,7 @@ async fn test_api_def_for_valid_input() { let session_store: Arc = internal::get_session_store(); let response = execute( - &api_request, + api_request, &api_specification, &session_store, &TestIdentityProvider::default(), @@ -176,7 +148,7 @@ async fn test_api_def_for_invalid_input_with_type_mismatch_for_worker_name_rib_i get_gateway_request("/foo/bar", None, &HeaderMap::new(), serde_json::Value::Null); let response = execute( - &api_request, + api_request, &api_specification, &session_store, &TestIdentityProvider::default(), @@ -209,7 +181,7 @@ async fn test_api_def_for_invalid_input_with_type_mismatch_for_response_mapping_ get_gateway_request("/foo/bar", None, &HeaderMap::new(), serde_json::Value::Null); let response = execute( - &api_request, + api_request, &api_specification, &session_store, &TestIdentityProvider::default(), @@ -252,7 +224,7 @@ async fn test_api_def_with_security_for_input_with_invalid_signatures() { let session_store = internal::get_session_store(); let initial_redirect_response = execute( - &api_request, + api_request, &api_specification, &session_store, &invalid_identity_provider_resolver, @@ -285,13 +257,8 @@ async fn test_api_def_with_security_for_input_with_invalid_signatures() { "localhost", ); - let request_to_auth_call_back_endpoint = - InputHttpRequest::from_request(call_back_request_from_identity_provider) - .await - .expect("Failed to get request"); - let auth_call_back_response = execute( - &request_to_auth_call_back_endpoint, + call_back_request_from_identity_provider, &api_specification, &session_store, &invalid_identity_provider_resolver, @@ -308,7 +275,7 @@ async fn test_api_def_with_security_for_input_with_invalid_signatures() { // Hitting the endpoint with an expired token let test_response_from_actual_endpoint = execute( - &input_http_request, + input_http_request, &api_specification, &session_store, &invalid_identity_provider_resolver, @@ -356,7 +323,7 @@ async fn test_api_def_with_security_for_input_when_session_expired() { let session_store = internal::get_session_store(); let initial_response_to_identity_provider = execute( - &api_request, + api_request, &api_specification, &session_store, &invalid_identity_provider, @@ -389,13 +356,8 @@ async fn test_api_def_with_security_for_input_when_session_expired() { "localhost", ); - let request_to_auth_call_back_endpoint = - InputHttpRequest::from_request(call_back_request_from_identity_provider) - .await - .expect("Failed to get request"); - let auth_call_back_response = execute( - &request_to_auth_call_back_endpoint, + call_back_request_from_identity_provider, &api_specification, &session_store, &invalid_identity_provider, @@ -415,7 +377,7 @@ async fn test_api_def_with_security_for_input_when_session_expired() { // Hitting the protected resource with an expired token let test_response_from_actual_endpoint = execute( - &api_request_from_browser, + api_request_from_browser, &api_specification, &session_store, &invalid_identity_provider, @@ -464,7 +426,7 @@ async fn test_api_def_with_security_for_input_with_expired_token() { let session_store = internal::get_session_store(); let initial_response_to_identity_provider = execute( - &api_request, + api_request, &api_specification, &session_store, &invalid_identity_provider_resolver, @@ -497,13 +459,8 @@ async fn test_api_def_with_security_for_input_with_expired_token() { "localhost", ); - let request_to_auth_call_back_endpoint = - InputHttpRequest::from_request(call_back_request_from_identity_provider) - .await - .expect("Failed to get request"); - let auth_call_back_response = execute( - &request_to_auth_call_back_endpoint, + call_back_request_from_identity_provider, &api_specification, &session_store, &invalid_identity_provider_resolver, @@ -520,7 +477,7 @@ async fn test_api_def_with_security_for_input_with_expired_token() { // Hitting the protected resource with an expired token let test_response_from_actual_endpoint = execute( - &api_request_from_browser, + api_request_from_browser, &api_specification, &session_store, &invalid_identity_provider_resolver, @@ -569,7 +526,7 @@ async fn test_api_def_with_security_for_valid_input() { let session_store = internal::get_session_store(); let initial_response_to_identity_provider = execute( - &api_request, + api_request, &api_specification, &session_store, &identity_provider, @@ -621,9 +578,7 @@ async fn test_api_def_with_security_for_valid_input() { // If successful, then it implies auth call back is successful and we get another redirect response. // This time, the redirect response will have a location that points to the original protected resource. let final_redirect_response = execute( - &InputHttpRequest::from_request(call_back_request_from_identity_provider) - .await - .expect("Failed to get request"), + call_back_request_from_identity_provider, &api_specification, &session_store, &identity_provider, @@ -636,7 +591,7 @@ async fn test_api_def_with_security_for_valid_input() { let api_request = security::create_request_from_redirect(redirect_response_headers).await; let response = execute( - &api_request, + api_request, &api_specification, &session_store, &identity_provider, @@ -685,7 +640,7 @@ async fn test_api_def_with_cors_preflight_for_valid_input() { let session_store = internal::get_session_store(); let response = execute( - &api_request, + api_request, &api_specification, &session_store, &TestIdentityProvider::get_provider_with_valid_id_token(), @@ -709,7 +664,7 @@ async fn test_api_def_with_default_cors_preflight_for_valid_input() { let session_store = internal::get_session_store(); let response = execute( - &api_request, + api_request, &api_specification, &session_store, &TestIdentityProvider::default(), @@ -752,14 +707,14 @@ async fn test_api_def_with_cors_preflight_default_for_preflight_input_and_simple let session_store = internal::get_session_store(); let preflight_response = execute( - &preflight_request, + preflight_request, &api_specification, &session_store, &TestIdentityProvider::default(), ) .await; let response_from_other_endpoint = execute( - &api_request, + api_request, &api_specification, &session_store, &TestIdentityProvider::default(), @@ -823,14 +778,14 @@ async fn test_api_def_with_cors_preflight_for_preflight_input_and_simple_input() let session_store = internal::get_session_store(); let preflight_response = execute( - &preflight_request, + preflight_request, &api_specification, &session_store, &TestIdentityProvider::default(), ) .await; let actual_response = execute( - &api_request, + api_request, &api_specification, &session_store, &TestIdentityProvider::default(), @@ -893,7 +848,7 @@ async fn test_api_def_with_path_and_query_params_lookup_for_valid_input() { let session_store = internal::get_session_store(); let response = execute( - &api_request, + api_request, &api_specification, &session_store, &TestIdentityProvider::default(), @@ -952,7 +907,7 @@ async fn test_api_def_with_path_and_query_params_lookup_complex_for_valid_input( let session_store = internal::get_session_store(); let response = execute( - &api_request, + api_request, &api_specification, &session_store, &TestIdentityProvider::default(), @@ -1010,7 +965,7 @@ async fn test_api_def_with_request_body_params_lookup_for_valid_input1() { let session_store = internal::get_session_store(); let test_response = execute( - &api_request, + api_request, &api_specification, &session_store, &TestIdentityProvider::default(), @@ -1082,7 +1037,7 @@ async fn test_api_def_with_request_body_params_lookup_for_valid_input2() { let session_store = internal::get_session_store(); let response = execute( - &api_request, + api_request, &api_specification, &session_store, &TestIdentityProvider::default(), @@ -1152,7 +1107,7 @@ async fn test_api_def_with_request_body_params_lookup_for_valid_input3() { let session_store = internal::get_session_store(); let response = execute( - &api_request, + api_request, &api_specification, &session_store, &TestIdentityProvider::default(), @@ -1203,11 +1158,16 @@ async fn test_api_def_for_valid_input_with_idempotency_key_in_header() { ) .unwrap(); + let input_http_request = InputHttpRequest::from_request(api_request).await.unwrap(); + + let identity_provider: Arc = + Arc::new(TestIdentityProvider::default()); + // Resolve the API definition binding from input let resolver = DefaultGatewayBindingResolver::new( - api_request.clone(), - internal::get_session_store(), - Arc::new(TestIdentityProvider::default()), + input_http_request, + &internal::get_session_store(), + &identity_provider, ); let resolved_route = resolver @@ -1235,18 +1195,36 @@ fn get_gateway_request( query_path: Option<&str>, headers: &HeaderMap, req_body: serde_json::Value, -) -> InputHttpRequest { - InputHttpRequest { - scheme: Some(Scheme::HTTP), - host: ApiSiteString("localhost".to_string()), - api_input_path: ApiInputPath { - base_path: base_path.to_string(), - query_path: query_path.map(|x| x.to_string()), - }, - headers: headers.clone(), - req_method: Method::GET, - req_body, +) -> Request { + let full_uri = match query_path { + Some(query) => format!("{}?{}", base_path.trim_end_matches('/'), query), + None => base_path.to_string(), + }; + + // Construct the URI object + + let uri = Uri::builder() + .scheme("http") + .authority("localhost") + .path_and_query(full_uri) + .build() + .unwrap(); + // Create the request + let mut request = Request::builder() + .method(Method::GET) + .uri(uri) + .body(req_body.to_string()); + + // Add headers + for (key, value) in headers.iter() { + request.headers_mut().insert(key.clone(), value.clone()); } + + request + .headers_mut() + .insert("host", "localhost".parse().unwrap()); + + request } fn get_preflight_gateway_request( @@ -1254,18 +1232,33 @@ fn get_preflight_gateway_request( query_path: Option<&str>, headers: &HeaderMap, req_body: Value, -) -> InputHttpRequest { - InputHttpRequest { - scheme: Some(Scheme::HTTP), - host: ApiSiteString("localhost".to_string()), - api_input_path: ApiInputPath { - base_path: base_path.to_string(), - query_path: query_path.map(|x| x.to_string()), - }, - headers: headers.clone(), - req_method: Method::OPTIONS, - req_body, +) -> Request { + let full_uri = match query_path { + Some(query) => format!("{}?{}", base_path.trim_end_matches('/'), query), + None => base_path.to_string(), + }; + + let uri = Uri::builder() + .scheme("http") + .authority("localhost") + .path_and_query(full_uri) + .build() + .unwrap(); + + let mut request: Request = Request::builder() + .method(Method::OPTIONS) + .uri(uri) + .body(req_body.to_string()); + + for (key, value) in headers.iter() { + request.headers_mut().insert(key.clone(), value.clone()); } + + request + .headers_mut() + .insert("host", "localhost".parse().unwrap()); + + request } async fn get_api_def_with_worker_binding( @@ -1594,7 +1587,9 @@ mod internal { }; use golem_wasm_rpc::protobuf::type_annotated_value::TypeAnnotatedValue; use golem_wasm_rpc::protobuf::{NameTypePair, NameValuePair, Type, TypedRecord, TypedTuple}; - use golem_worker_service_base::gateway_api_definition::http::ComponentMetadataDictionary; + use golem_worker_service_base::gateway_api_definition::http::{ + CompiledHttpApiDefinition, ComponentMetadataDictionary, + }; use golem_worker_service_base::gateway_execution::file_server_binding_handler::{ FileServerBindingHandler, FileServerBindingResult, }; @@ -1618,13 +1613,39 @@ mod internal { use poem::Response; use rib::RibResult; + use golem_worker_service_base::gateway_execution::api_definition_lookup::{ + ApiDefinitionLookupError, ApiDefinitionsLookup, + }; use golem_worker_service_base::gateway_execution::gateway_session::{ DataKey, DataValue, GatewaySession, GatewaySessionError, GatewaySessionStore, SessionId, }; + use golem_worker_service_base::gateway_request::http_request::InputHttpRequest; use serde_json::Value; use std::collections::HashMap; use std::sync::{Arc, Mutex}; + pub struct TestApiDefinitionLookup { + pub api_definition: CompiledHttpApiDefinition, + } + + impl TestApiDefinitionLookup { + pub fn new(api_definition: CompiledHttpApiDefinition) -> Self { + Self { api_definition } + } + } + + #[async_trait] + impl ApiDefinitionsLookup for TestApiDefinitionLookup { + type ApiDefinition = CompiledHttpApiDefinition; + + async fn get( + &self, + _input: &InputHttpRequest, + ) -> Result, ApiDefinitionLookupError> { + Ok(vec![self.api_definition.clone()]) + } + } + pub struct TestApiGatewayWorkerRequestExecutor {} #[async_trait] @@ -1778,9 +1799,9 @@ mod internal { name: None, typ: record(vec![ field("component_id", str()), - field("name", str()), field("function_name", str()), - field("function_params", tuple(vec![str()])), + field("function_params", tuple(vec![str(), str()])), + field("worker_name", str()), ]), }], }], @@ -2080,7 +2101,6 @@ pub mod security { use std::str::FromStr; use std::sync::Arc; - use golem_worker_service_base::gateway_request::http_request::InputHttpRequest; use tokio::sync::Mutex; // These keys are used over the default JwkKeySet of the actual client @@ -2424,7 +2444,7 @@ nUhg4edJVHjqxYyoQT+YSPLlHl6AkLZt9/n1NJ+bft0= ) .unwrap(); - let request = poem::Request::builder() + let request = Request::builder() .method(Method::GET) .uri(uri) .header("host", redirect_host) @@ -2646,7 +2666,7 @@ nUhg4edJVHjqxYyoQT+YSPLlHl6AkLZt9/n1NJ+bft0= )])) } - pub async fn create_request_from_redirect(headers: &HeaderMap) -> InputHttpRequest { + pub async fn create_request_from_redirect(headers: &HeaderMap) -> Request { let cookies = extract_cookies_from_redirect(headers); let cookie_header = cookies @@ -2664,16 +2684,12 @@ nUhg4edJVHjqxYyoQT+YSPLlHl6AkLZt9/n1NJ+bft0= .and_then(|loc| loc.to_str().ok()) .unwrap_or("/"); - let request = Request::builder() + Request::builder() .method(Method::GET) .uri(Uri::from_str(format!("http://localhost/{}", location).as_str()).unwrap()) // Use the "Location" header as the URL .header(HOST, "localhost") .header(COOKIE, cookie_header) - .finish(); - - InputHttpRequest::from_request(request) - .await - .expect("Failed to get http request") + .finish() } fn extract_cookies_from_redirect(headers: &HeaderMap) -> HashMap { diff --git a/golem-worker-service-base/tests/services_tests.rs b/golem-worker-service-base/tests/services_tests.rs index 532f882d3..5e1c04f39 100644 --- a/golem-worker-service-base/tests/services_tests.rs +++ b/golem-worker-service-base/tests/services_tests.rs @@ -16,8 +16,8 @@ use golem_service_base::migration::{Migrations, MigrationsDir}; use test_r::test; use async_trait::async_trait; -use golem_common::config::{DbPostgresConfig, DbSqliteConfig, RedisConfig, RetryConfig}; -use golem_common::model::ComponentId; +use golem_common::config::{DbPostgresConfig, DbSqliteConfig, RedisConfig}; +use golem_common::model::{ComponentId, RetryConfig}; use golem_service_base::auth::{DefaultNamespace, EmptyAuthCtx}; use golem_service_base::db; use golem_service_base::model::Component; diff --git a/golem-worker-service/src/service/mod.rs b/golem-worker-service/src/service/mod.rs index 6347fca37..449f07759 100644 --- a/golem-worker-service/src/service/mod.rs +++ b/golem-worker-service/src/service/mod.rs @@ -47,7 +47,7 @@ use golem_worker_service_base::service::worker::WorkerServiceDefault; use golem_api_grpc::proto::golem::workerexecutor::v1::worker_executor_client::WorkerExecutorClient; use golem_common::client::{GrpcClientConfig, MultiTargetGrpcClient}; -use golem_common::config::RetryConfig; +use golem_common::model::RetryConfig; use golem_common::config::DbConfig; use golem_common::redis::RedisPool; diff --git a/wasm-ast/src/component/writer.rs b/wasm-ast/src/component/writer.rs index cccd050c8..62c5c692c 100644 --- a/wasm-ast/src/component/writer.rs +++ b/wasm-ast/src/component/writer.rs @@ -13,7 +13,7 @@ // limitations under the License. use crate::component::*; -use crate::core::{ExportDesc, RetainsInstructions}; +use crate::core::{Data, ExportDesc, RetainsInstructions}; impl From<&InstantiationArgRef> for wasm_encoder::ModuleArg { fn from(value: &InstantiationArgRef) -> Self { diff --git a/wasm-rpc/Cargo.toml b/wasm-rpc/Cargo.toml index 8b4ea733e..964c68a9e 100644 --- a/wasm-rpc/Cargo.toml +++ b/wasm-rpc/Cargo.toml @@ -44,17 +44,20 @@ cargo_metadata = "0.19.1" [features] default = ["host"] +host-bindings = [ + "wasmtime" +] host = [ "dep:async-trait", "arbitrary", "bincode", + "host-bindings", "json", "poem_openapi", "protobuf", "serde", "text", - "typeinfo", - "wasmtime", + "typeinfo" ] arbitrary = ["dep:arbitrary"] bincode = ["dep:bincode", "golem-wasm-ast/bincode"] @@ -71,15 +74,13 @@ poem_openapi = [ "typeinfo", "golem-wasm-ast/poem_openapi", ] -protobuf = ["dep:bincode", "dep:serde", "dep:prost"] +protobuf = ["dep:bincode", "dep:serde", "dep:prost", "golem-wasm-ast/protobuf"] serde = ["dep:serde"] stub = [] -text = ["wasmtime", "dep:wasm-wave", "golem-wasm-ast/wave"] +text = ["typeinfo", "dep:wasm-wave", "golem-wasm-ast/wave"] typeinfo = [ "dep:golem-wasm-ast", "golem-wasm-ast/analysis", - "golem-wasm-ast/protobuf", - "protobuf", ] wasmtime = [ "dep:wasmtime", diff --git a/wasm-rpc/src/lib.rs b/wasm-rpc/src/lib.rs index 112378793..c11ef701d 100644 --- a/wasm-rpc/src/lib.rs +++ b/wasm-rpc/src/lib.rs @@ -14,7 +14,7 @@ #[allow(unused)] #[rustfmt::skip] -#[cfg(not(feature = "host"))] +#[cfg(not(feature = "host-bindings"))] #[cfg(feature = "stub")] mod bindings; @@ -22,12 +22,15 @@ mod bindings; test_r::enable!(); /// Implements bincode encoders and decoders for WitValue instances -#[cfg(feature = "bincode")] +#[cfg(all(feature = "bincode", feature = "host-bindings"))] pub mod bincode; + /// A builder interface for WitValue instances +#[cfg(any(feature = "host-bindings", feature = "stub"))] mod builder; /// Extension methods for extracting values from WitValue instances +#[cfg(any(feature = "host-bindings", feature = "stub"))] mod extractor; /// Conversion to and from JSON, in the presence of golem-wasm-ast generated type information @@ -51,9 +54,12 @@ pub mod serde; mod text; /// A version of values annotated with golem-wasm-ast generated type information -#[cfg(feature = "typeinfo")] +#[cfg(all(feature = "typeinfo", feature = "protobuf"))] mod type_annotated_value; +#[cfg(feature = "typeinfo")] +mod value_and_type; + /// For getting current lib version from git tags or cargo mod version; @@ -61,26 +67,29 @@ mod version; #[cfg(feature = "wasmtime")] pub mod wasmtime; +#[cfg(any(feature = "host-bindings", feature = "stub"))] use crate::builder::WitValueBuilder; +#[cfg(any(feature = "host-bindings", feature = "stub"))] pub use builder::{NodeBuilder, WitValueBuilderExtensions}; +#[cfg(any(feature = "host-bindings", feature = "stub"))] pub use extractor::{WitNodePointer, WitValueExtractor}; -#[cfg(not(feature = "host"))] +#[cfg(not(feature = "host-bindings"))] #[cfg(feature = "stub")] pub use bindings::golem::rpc::types::{ FutureInvokeResult, NodeIndex, RpcError, Uri, WasmRpc, WitNode, WitValue, }; -#[cfg(not(feature = "host"))] +#[cfg(not(feature = "host-bindings"))] #[cfg(feature = "stub")] pub use bindings::wasi::io::poll::Pollable; -#[cfg(feature = "host")] +#[cfg(feature = "host-bindings")] use ::wasmtime::component::bindgen; -#[cfg(feature = "host")] +#[cfg(feature = "host-bindings")] pub use wasmtime_wasi::Pollable; -#[cfg(feature = "host")] +#[cfg(feature = "host-bindings")] bindgen!({ path: "wit", interfaces: " @@ -96,15 +105,15 @@ bindgen!({ } }); -#[cfg(feature = "host")] +#[cfg(feature = "host-bindings")] pub use golem::rpc::types::{Host, HostWasmRpc, NodeIndex, RpcError, Uri, WitNode, WitValue}; -#[cfg(feature = "host")] +#[cfg(feature = "host-bindings")] pub struct WasmRpcEntry { pub payload: Box, } -#[cfg(feature = "host")] +#[cfg(feature = "host-bindings")] #[async_trait::async_trait] pub trait SubscribeAny: std::any::Any { async fn ready(&mut self); @@ -112,12 +121,12 @@ pub trait SubscribeAny: std::any::Any { fn as_any_mut(&mut self) -> &mut dyn std::any::Any; } -#[cfg(feature = "host")] +#[cfg(feature = "host-bindings")] pub struct FutureInvokeResultEntry { pub payload: Box, } -#[cfg(feature = "host")] +#[cfg(feature = "host-bindings")] #[async_trait::async_trait] impl wasmtime_wasi::Subscribe for FutureInvokeResultEntry { async fn ready(&mut self) { @@ -125,13 +134,19 @@ impl wasmtime_wasi::Subscribe for FutureInvokeResultEntry { } } -#[cfg(feature = "typeinfo")] +#[cfg(all(feature = "typeinfo", feature = "protobuf"))] pub use type_annotated_value::*; +#[cfg(all(feature = "text", feature = "protobuf"))] +pub use text::{parse_type_annotated_value, print_type_annotated_value}; + #[cfg(feature = "text")] -pub use text::{type_annotated_value_from_str, type_annotated_value_to_string}; +pub use text::{parse_value_and_type, print_value_and_type}; + +#[cfg(feature = "typeinfo")] +pub use value_and_type::*; -#[cfg(feature = "arbitrary")] +#[cfg(all(feature = "arbitrary", feature = "host-bindings"))] impl arbitrary::Arbitrary<'_> for Uri { fn arbitrary(u: &mut arbitrary::Unstructured) -> arbitrary::Result { let uri = u.arbitrary::()?; @@ -139,6 +154,7 @@ impl arbitrary::Arbitrary<'_> for Uri { } } +#[cfg(feature = "host-bindings")] impl PartialEq for Uri { fn eq(&self, other: &Self) -> bool { self.value == other.value @@ -175,11 +191,12 @@ pub enum Value { Option(Option>), Result(Result>, Option>>), Handle { - uri: Uri, + uri: String, resource_id: u64, }, } +#[cfg(any(feature = "host-bindings", feature = "stub"))] impl From for WitValue { fn from(value: Value) -> Self { let mut builder = WitValueBuilder::new(); @@ -188,6 +205,7 @@ impl From for WitValue { } } +#[cfg(any(feature = "host-bindings", feature = "stub"))] impl PartialEq for WitValue { fn eq(&self, other: &Self) -> bool { let a: Value = self.clone().into(); @@ -196,6 +214,7 @@ impl PartialEq for WitValue { } } +#[cfg(any(feature = "host-bindings", feature = "stub"))] fn build_wit_value(value: Value, builder: &mut WitValueBuilder) -> NodeIndex { match value { Value::Bool(value) => builder.add_bool(value), @@ -282,7 +301,7 @@ fn build_wit_value(value: Value, builder: &mut WitValueBuilder) -> NodeIndex { } Err(None) => builder.add_result_err_unit(), }, - Value::Handle { uri, resource_id } => builder.add_handle(uri, resource_id), + Value::Handle { uri, resource_id } => builder.add_handle(Uri { value: uri }, resource_id), } } @@ -315,6 +334,7 @@ impl Value { } } +#[cfg(any(feature = "host-bindings", feature = "stub"))] impl From for Value { fn from(value: WitValue) -> Self { assert!(!value.nodes.is_empty()); @@ -322,6 +342,7 @@ impl From for Value { } } +#[cfg(any(feature = "host-bindings", feature = "stub"))] fn build_tree(node: &WitNode, nodes: &[WitNode]) -> Value { match node { WitNode::RecordValue(field_indices) => { @@ -390,13 +411,13 @@ fn build_tree(node: &WitNode, nodes: &[WitNode]) -> Value { WitNode::PrimBool(value) => Value::Bool(*value), WitNode::PrimString(value) => Value::String(value.clone()), WitNode::Handle((uri, value)) => Value::Handle { - uri: uri.clone(), + uri: uri.value.clone(), resource_id: *value, }, } } -#[cfg(feature = "arbitrary")] +#[cfg(all(feature = "arbitrary", feature = "host-bindings"))] impl<'a> arbitrary::Arbitrary<'a> for WitValue { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { let arbitrary_value = u.arbitrary::()?; @@ -404,9 +425,9 @@ impl<'a> arbitrary::Arbitrary<'a> for WitValue { } } -#[cfg(feature = "host")] +#[cfg(feature = "host-bindings")] pub const WASM_RPC_WIT: &str = include_str!("../wit/wasm-rpc.wit"); -#[cfg(feature = "host")] +#[cfg(feature = "host-bindings")] pub const WASI_POLL_WIT: &str = include_str!("../wit/deps/io/poll.wit"); pub const WASM_RPC_VERSION: &str = version::lib_version!(); diff --git a/wasm-rpc/src/protobuf.rs b/wasm-rpc/src/protobuf.rs index 014c45a10..3ed69f1a9 100644 --- a/wasm-rpc/src/protobuf.rs +++ b/wasm-rpc/src/protobuf.rs @@ -13,7 +13,7 @@ // limitations under the License. use crate::protobuf::typed_result::ResultValue; -use crate::{Uri, Value}; +use crate::Value; use golem_wasm_ast::analysis::{AnalysedFunctionParameter, AnalysedType}; include!(concat!(env!("OUT_DIR"), "/wasm.rpc.rs")); @@ -480,7 +480,7 @@ impl TryFrom for Value { } } type_annotated_value::TypeAnnotatedValue::Handle(handle) => Ok(Value::Handle { - uri: Uri { value: handle.uri }, + uri: handle.uri, resource_id: handle.resource_id, }), type_annotated_value::TypeAnnotatedValue::Variant(variant) => { @@ -632,7 +632,7 @@ impl From for Val { }, Value::Handle { uri, resource_id } => Val { val: Some(val::Val::Handle(ValHandle { - uri: uri.value, + uri, value: resource_id, })), }, @@ -738,7 +738,7 @@ impl TryFrom for Value { } } Some(val::Val::Handle(ValHandle { uri, value })) => Ok(Value::Handle { - uri: super::Uri { value: uri }, + uri, resource_id: value, }), } diff --git a/wasm-rpc/src/text.rs b/wasm-rpc/src/text.rs index 2de026324..cd52aefe2 100644 --- a/wasm-rpc/src/text.rs +++ b/wasm-rpc/src/text.rs @@ -1,181 +1,126 @@ -use crate::protobuf::type_annotated_value::TypeAnnotatedValue; -use crate::protobuf::typed_result::ResultValue; -use crate::protobuf::{ - NameValuePair, TypedEnum, TypedFlags, TypedList, TypedOption, TypedRecord, TypedTuple, - TypedVariant, -}; -use crate::protobuf::{TypeAnnotatedValue as RootTypeAnnotatedValue, TypedResult}; -use golem_wasm_ast::analysis::{protobuf, TypeEnum, TypeFlags}; -use golem_wasm_ast::analysis::{AnalysedType, TypeList, TypeRecord, TypeTuple, TypeVariant}; +// Copyright 2024 Golem Cloud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::{IntoValueAndType, Value, ValueAndType}; +use golem_wasm_ast::analysis::AnalysedType; use std::borrow::Cow; -use std::ops::Deref; +use std::collections::HashSet; use wasm_wave::wasm::{WasmType, WasmTypeKind, WasmValue, WasmValueError}; use wasm_wave::{from_str, to_string}; -pub fn type_annotated_value_from_str( +#[cfg(all(feature = "typeinfo", feature = "protobuf"))] +pub use type_annotated_value::*; + +pub fn parse_value_and_type( analysed_type: &AnalysedType, input: &str, -) -> Result { - let parsed_typed_value: TypeAnnotatedValuePrintable = - from_str(analysed_type, input).map_err(|err| err.to_string())?; - - Ok(parsed_typed_value.0) +) -> Result { + let parsed: ValueAndType = from_str(analysed_type, input).map_err(|err| err.to_string())?; + Ok(parsed) } -pub fn type_annotated_value_to_string(value: &TypeAnnotatedValue) -> Result { - let printable_typed_value: TypeAnnotatedValuePrintable = - TypeAnnotatedValuePrintable(value.clone()); - - let typed_value_str = to_string(&printable_typed_value).map_err(|err| err.to_string())?; - - Ok(typed_value_str) +pub fn print_value_and_type(value: &ValueAndType) -> Result { + to_string(value).map_err(|err| err.to_string()) } -#[derive(Debug, Clone)] -pub struct TypeAnnotatedValuePrintable(pub TypeAnnotatedValue); - -impl WasmValue for TypeAnnotatedValuePrintable { +impl WasmValue for ValueAndType { type Type = AnalysedType; fn kind(&self) -> WasmTypeKind { - let analysed_type = AnalysedType::try_from(&self.0) - .expect("Failed to retrieve AnalysedType from TypeAnnotatedValue"); - analysed_type.kind() + self.typ.kind() } fn make_bool(val: bool) -> Self { - TypeAnnotatedValuePrintable(TypeAnnotatedValue::Bool(val)) + val.into_value_and_type() } fn make_s8(val: i8) -> Self { - TypeAnnotatedValuePrintable(TypeAnnotatedValue::S8(val as i32)) + val.into_value_and_type() } fn make_s16(val: i16) -> Self { - TypeAnnotatedValuePrintable(TypeAnnotatedValue::S16(val as i32)) + val.into_value_and_type() } fn make_s32(val: i32) -> Self { - TypeAnnotatedValuePrintable(TypeAnnotatedValue::S32(val)) + val.into_value_and_type() } fn make_s64(val: i64) -> Self { - TypeAnnotatedValuePrintable(TypeAnnotatedValue::S64(val)) + val.into_value_and_type() } fn make_u8(val: u8) -> Self { - TypeAnnotatedValuePrintable(TypeAnnotatedValue::U8(val as u32)) + val.into_value_and_type() } fn make_u16(val: u16) -> Self { - TypeAnnotatedValuePrintable(TypeAnnotatedValue::U16(val as u32)) + val.into_value_and_type() } fn make_u32(val: u32) -> Self { - TypeAnnotatedValuePrintable(TypeAnnotatedValue::U32(val)) + val.into_value_and_type() } fn make_u64(val: u64) -> Self { - TypeAnnotatedValuePrintable(TypeAnnotatedValue::U64(val)) + val.into_value_and_type() } fn make_float32(val: f32) -> Self { - TypeAnnotatedValuePrintable(TypeAnnotatedValue::F32(val)) + val.into_value_and_type() } fn make_float64(val: f64) -> Self { - TypeAnnotatedValuePrintable(TypeAnnotatedValue::F64(val)) + val.into_value_and_type() } fn make_char(val: char) -> Self { - TypeAnnotatedValuePrintable(TypeAnnotatedValue::Char(val as i32)) + val.into_value_and_type() } fn make_string(val: Cow) -> Self { - TypeAnnotatedValuePrintable(TypeAnnotatedValue::Str(val.to_string())) + val.to_string().into_value_and_type() } fn make_list( ty: &Self::Type, vals: impl IntoIterator, ) -> Result { - if let AnalysedType::List(TypeList { inner: typ }) = ty { - let list = TypedList { - values: vals - .into_iter() - .map(|v| RootTypeAnnotatedValue { - type_annotated_value: Some(v.0), - }) - .collect(), - typ: Some(typ.deref().into()), - }; - - Ok(TypeAnnotatedValuePrintable(TypeAnnotatedValue::List(list))) - } else { - Err(WasmValueError::WrongTypeKind { - kind: ty.kind(), - ty: format!("{ty:?}"), - }) - } + Ok(ValueAndType { + value: Value::List(vals.into_iter().map(|vnt| vnt.value).collect()), + typ: ty.clone(), + }) } fn make_record<'a>( ty: &Self::Type, fields: impl IntoIterator, ) -> Result { - if let AnalysedType::Record(TypeRecord { fields: types }) = ty { - let record = TypedRecord { - value: fields - .into_iter() - .map(|(name, value)| NameValuePair { - name: name.to_string(), - value: Some(RootTypeAnnotatedValue { - type_annotated_value: Some(value.0), - }), - }) - .collect(), - typ: types - .iter() - .map(|pair| protobuf::NameTypePair { - name: pair.name.clone(), - typ: Some((&pair.typ).into()), - }) - .collect(), - }; - Ok(TypeAnnotatedValuePrintable(TypeAnnotatedValue::Record( - record, - ))) - } else { - Err(WasmValueError::WrongTypeKind { - kind: ty.kind(), - ty: format!("{ty:?}"), - }) - } + Ok(ValueAndType { + value: Value::Record(fields.into_iter().map(|(_, vnt)| vnt.value).collect()), + typ: ty.clone(), + }) } fn make_tuple( ty: &Self::Type, vals: impl IntoIterator, ) -> Result { - if let AnalysedType::Tuple(TypeTuple { items: types }) = ty { - let tuple = TypedTuple { - value: vals - .into_iter() - .map(|v| RootTypeAnnotatedValue { - type_annotated_value: Some(v.0), - }) - .collect(), - typ: types.iter().map(|t| t.into()).collect(), - }; - Ok(TypeAnnotatedValuePrintable(TypeAnnotatedValue::Tuple( - tuple, - ))) - } else { - Err(WasmValueError::WrongTypeKind { - kind: ty.kind(), - ty: format!("{ty:?}"), - }) - } + Ok(ValueAndType { + value: Value::Tuple(vals.into_iter().map(|vnt| vnt.value).collect()), + typ: ty.clone(), + }) } fn make_variant( @@ -183,261 +128,203 @@ impl WasmValue for TypeAnnotatedValuePrintable { case: &str, val: Option, ) -> Result { - if let AnalysedType::Variant(TypeVariant { cases }) = ty { - let case_type = cases.iter().find_map(|pair| { - if pair.name == case { - Some(&pair.typ) - } else { - None - } - }); - if case_type.is_some() { - let variant = TypedVariant { - typ: Some(protobuf::TypeVariant { - cases: cases - .iter() - .map(|pair| protobuf::NameOptionTypePair { - name: pair.name.clone(), - typ: pair.typ.as_ref().map(|v| v.into()), - }) - .collect(), - }), - case_name: case.to_string(), - case_value: val.map(|v| { - Box::new(RootTypeAnnotatedValue { - type_annotated_value: Some(v.0), - }) - }), - }; - Ok(TypeAnnotatedValuePrintable(TypeAnnotatedValue::Variant( - Box::new(variant), - ))) - } else { - Err(WasmValueError::UnknownCase(case.to_string())) - } + if let AnalysedType::Variant(typ) = ty { + let case_idx = typ + .cases + .iter() + .position(|pair| pair.name == case) + .ok_or_else(|| WasmValueError::UnknownCase(case.to_string()))? + as u32; + Ok(ValueAndType { + value: Value::Variant { + case_idx, + case_value: val.map(|vnt| Box::new(vnt.value)), + }, + typ: ty.clone(), + }) } else { Err(WasmValueError::WrongTypeKind { - kind: ty.kind(), - ty: format!("{ty:?}"), + kind: WasmTypeKind::Variant, + ty: ty.kind().to_string(), }) } } fn make_enum(ty: &Self::Type, case: &str) -> Result { - if let AnalysedType::Enum(TypeEnum { cases }) = ty { - if cases.contains(&case.to_string()) { - let enum_value = TypedEnum { - typ: cases.to_vec(), - value: case.to_string(), - }; - Ok(TypeAnnotatedValuePrintable(TypeAnnotatedValue::Enum( - enum_value, - ))) - } else { - Err(WasmValueError::UnknownCase(case.to_string())) - } + if let AnalysedType::Enum(typ) = ty { + let case_idx = typ + .cases + .iter() + .position(|c| c == case) + .ok_or_else(|| WasmValueError::UnknownCase(case.to_string()))? + as u32; + Ok(ValueAndType { + value: Value::Enum(case_idx), + typ: ty.clone(), + }) } else { Err(WasmValueError::WrongTypeKind { - kind: ty.kind(), - ty: format!("{ty:?}"), + kind: WasmTypeKind::Enum, + ty: ty.kind().to_string(), }) } } fn make_option(ty: &Self::Type, val: Option) -> Result { - let option = TypedOption { - typ: Some(ty.into()), - value: val.map(|v| { - Box::new(RootTypeAnnotatedValue { - type_annotated_value: Some(v.0), - }) - }), - }; - - Ok(TypeAnnotatedValuePrintable(TypeAnnotatedValue::Option( - Box::new(option), - ))) + Ok(ValueAndType { + value: Value::Option(val.map(|vnt| Box::new(vnt.value))), + typ: ty.clone(), + }) } fn make_result( ty: &Self::Type, val: Result, Option>, ) -> Result { - if let AnalysedType::Result(golem_wasm_ast::analysis::TypeResult { ok, err }) = ty { - let result0 = TypedResult { - ok: ok.clone().map(|v| v.deref().into()), - error: err.clone().map(|v| v.deref().into()), - result_value: match val { - Ok(Some(v)) => Some(ResultValue::OkValue(Box::new(RootTypeAnnotatedValue { - type_annotated_value: Some(v.0), - }))), - Ok(None) => None, - Err(Some(v)) => { - Some(ResultValue::ErrorValue(Box::new(RootTypeAnnotatedValue { - type_annotated_value: Some(v.0), - }))) - } - Err(None) => None, - }, - }; - Ok(TypeAnnotatedValuePrintable(TypeAnnotatedValue::Result( - Box::new(result0), - ))) - } else { - Err(WasmValueError::WrongTypeKind { - kind: ty.kind(), - ty: format!("{ty:?}"), - }) - } + Ok(ValueAndType { + value: Value::Result( + val.map(|maybe_ok| maybe_ok.map(|vnt| Box::new(vnt.value))) + .map_err(|maybe_err| maybe_err.map(|vnt| Box::new(vnt.value))), + ), + typ: ty.clone(), + }) } fn make_flags<'a>( ty: &Self::Type, names: impl IntoIterator, ) -> Result { - if let AnalysedType::Flags(TypeFlags { names: all_names }) = ty { - let names: Vec = names.into_iter().map(|name| name.to_string()).collect(); - - let invalid_names: Vec = names - .iter() - .filter(|&name| !all_names.contains(&name.to_string())) - .cloned() - .collect(); - - if invalid_names.is_empty() { - let flags = TypedFlags { - typ: all_names.to_vec(), - values: names.to_vec(), - }; - - Ok(TypeAnnotatedValuePrintable(TypeAnnotatedValue::Flags( - flags, - ))) - } else { - Err(WasmValueError::UnknownCase(invalid_names.join(", "))) + if let AnalysedType::Flags(typ) = ty { + let mut bitmap = Vec::new(); + let names: HashSet<&'a str> = HashSet::from_iter(names); + for name in &typ.names { + bitmap.push(names.contains(name.as_str())); } + Ok(ValueAndType { + value: Value::Flags(bitmap), + typ: ty.clone(), + }) } else { Err(WasmValueError::WrongTypeKind { - kind: ty.kind(), - ty: format!("{ty:?}"), + kind: WasmTypeKind::Flags, + ty: ty.kind().to_string(), }) } } fn unwrap_bool(&self) -> bool { - match self.0 { - TypeAnnotatedValue::Bool(value) => value, + match self.value { + Value::Bool(val) => val, _ => panic!("Expected bool, found {:?}", self), } } fn unwrap_s8(&self) -> i8 { - match self.0 { - TypeAnnotatedValue::S8(value) => value as i8, + match self.value { + Value::S8(val) => val, _ => panic!("Expected s8, found {:?}", self), } } fn unwrap_s16(&self) -> i16 { - match self.0 { - TypeAnnotatedValue::S16(value) => value as i16, + match self.value { + Value::S16(val) => val, _ => panic!("Expected s16, found {:?}", self), } } fn unwrap_s32(&self) -> i32 { - match self.0 { - TypeAnnotatedValue::S32(value) => value, + match self.value { + Value::S32(val) => val, _ => panic!("Expected s32, found {:?}", self), } } fn unwrap_s64(&self) -> i64 { - match self.0 { - TypeAnnotatedValue::S64(value) => value, + match self.value { + Value::S64(val) => val, _ => panic!("Expected s64, found {:?}", self), } } fn unwrap_u8(&self) -> u8 { - match self.0 { - TypeAnnotatedValue::U8(value) => value as u8, + match self.value { + Value::U8(val) => val, _ => panic!("Expected u8, found {:?}", self), } } fn unwrap_u16(&self) -> u16 { - match self.0 { - TypeAnnotatedValue::U16(value) => value as u16, + match self.value { + Value::U16(val) => val, _ => panic!("Expected u16, found {:?}", self), } } fn unwrap_u32(&self) -> u32 { - match self.0 { - TypeAnnotatedValue::U32(value) => value, + match self.value { + Value::U32(val) => val, _ => panic!("Expected u32, found {:?}", self), } } fn unwrap_u64(&self) -> u64 { - match self.0 { - TypeAnnotatedValue::U64(value) => value, + match self.value { + Value::U64(val) => val, _ => panic!("Expected u64, found {:?}", self), } } fn unwrap_float32(&self) -> f32 { - match self.0 { - TypeAnnotatedValue::F32(value) => value, + match self.value { + Value::F32(val) => val, _ => panic!("Expected f32, found {:?}", self), } } fn unwrap_float64(&self) -> f64 { - match self.0 { - TypeAnnotatedValue::F64(value) => value, + match self.value { + Value::F64(val) => val, _ => panic!("Expected f64, found {:?}", self), } } fn unwrap_char(&self) -> char { - match self.0 { - TypeAnnotatedValue::Char(value) => char::from_u32(value as u32).unwrap(), - _ => panic!("Expected chr, found {:?}", self), + match self.value { + Value::Char(val) => val, + _ => panic!("Expected char, found {:?}", self), } } fn unwrap_string(&self) -> Cow { - match self.0.clone() { - TypeAnnotatedValue::Str(value) => Cow::Owned(value.clone()), + match &self.value { + Value::String(val) => Cow::Borrowed(val), _ => panic!("Expected string, found {:?}", self), } } fn unwrap_list(&self) -> Box> + '_> { - match self.0.clone() { - TypeAnnotatedValue::List(TypedList { typ: _, values }) => { - Box::new(values.into_iter().map(|v| { - Cow::Owned(TypeAnnotatedValuePrintable( - v.type_annotated_value.as_ref().unwrap().clone(), - )) - })) - } + match (&self.value, &self.typ) { + (Value::List(vals), AnalysedType::List(typ)) => Box::new(vals.iter().map(|v| { + Cow::Owned(ValueAndType { + value: v.clone(), + typ: (*typ.inner).clone(), + }) + })), _ => panic!("Expected list, found {:?}", self), } } fn unwrap_record(&self) -> Box, Cow)> + '_> { - match self.0.clone() { - TypeAnnotatedValue::Record(TypedRecord { typ: _, value }) => { - Box::new(value.into_iter().map(|name_value| { - let name = name_value.name.clone(); - let type_annotated_value = - name_value.value.unwrap().type_annotated_value.unwrap(); + match (&self.value, &self.typ) { + (Value::Record(vals), AnalysedType::Record(typ)) => { + Box::new(vals.iter().zip(typ.fields.iter()).map(|(v, f)| { ( - Cow::Owned(name), - Cow::Owned(TypeAnnotatedValuePrintable(type_annotated_value)), + Cow::Borrowed(f.name.as_str()), + Cow::Owned(ValueAndType { + value: v.clone(), + typ: f.typ.clone(), + }), ) })) } @@ -446,14 +333,13 @@ impl WasmValue for TypeAnnotatedValuePrintable { } fn unwrap_tuple(&self) -> Box> + '_> { - match self.0.clone() { - TypeAnnotatedValue::Tuple(TypedTuple { typ: _, value }) => { - Box::new(value.into_iter().map(|x| { - if let Some(ref v) = x.type_annotated_value { - Cow::Owned(TypeAnnotatedValuePrintable(v.clone())) - } else { - panic!("Expected value, found None") - } + match (&self.value, &self.typ) { + (Value::Tuple(vals), AnalysedType::Tuple(typ)) => { + Box::new(vals.iter().zip(typ.items.iter()).map(|(v, t)| { + Cow::Owned(ValueAndType { + value: v.clone(), + typ: t.clone(), + }) })) } _ => panic!("Expected tuple, found {:?}", self), @@ -461,64 +347,97 @@ impl WasmValue for TypeAnnotatedValuePrintable { } fn unwrap_variant(&self) -> (Cow, Option>) { - match self.0.clone() { - TypeAnnotatedValue::Variant(variant) => { - let case_name = Cow::Owned(variant.case_name); - let case_value = variant.case_value.clone().map(|v| { - Cow::Owned(TypeAnnotatedValuePrintable(v.type_annotated_value.unwrap())) + match (&self.value, &self.typ) { + ( + Value::Variant { + case_idx, + case_value, + }, + AnalysedType::Variant(typ), + ) => { + let case_name = &typ.cases[*case_idx as usize].name; + let case_value = case_value.as_ref().map(|v| { + let typ = &typ.cases[*case_idx as usize].typ; + Cow::Owned(ValueAndType { + value: *v.clone(), + typ: typ + .as_ref() + .unwrap_or_else(|| { + panic!("No type information for non-unit variant case {case_name}") + }) + .clone(), + }) }); - (case_name, case_value) + (Cow::Borrowed(case_name), case_value) } _ => panic!("Expected variant, found {:?}", self), } } fn unwrap_enum(&self) -> Cow { - match self.0.clone() { - TypeAnnotatedValue::Enum(TypedEnum { typ: _, value }) => Cow::Owned(value), + match (&self.value, &self.typ) { + (Value::Enum(case_idx), AnalysedType::Enum(typ)) => { + Cow::Borrowed(&typ.cases[*case_idx as usize]) + } _ => panic!("Expected enum, found {:?}", self), } } fn unwrap_option(&self) -> Option> { - match self.0.clone() { - TypeAnnotatedValue::Option(option) => option.value.as_ref().and_then(|v| { - v.type_annotated_value - .as_ref() - .map(|inner| Cow::Owned(TypeAnnotatedValuePrintable(inner.clone()))) - }), + match (&self.value, &self.typ) { + (Value::Option(Some(val)), AnalysedType::Option(typ)) => { + Some(Cow::Owned(ValueAndType { + value: *val.clone(), + typ: (*typ.inner).clone(), + })) + } + (Value::Option(None), AnalysedType::Option(_)) => None, _ => panic!("Expected option, found {:?}", self), } } fn unwrap_result(&self) -> Result>, Option>> { - match self.0.clone() { - TypeAnnotatedValue::Result(result0) => match result0.result_value { - Some(result) => match result { - ResultValue::OkValue(ok) => match ok.type_annotated_value { - Some(ok_value) => { - Ok(Some(Cow::Owned(TypeAnnotatedValuePrintable(ok_value)))) - } - None => Ok(None), - }, - ResultValue::ErrorValue(error) => match error.type_annotated_value { - Some(error_value) => { - Err(Some(Cow::Owned(TypeAnnotatedValuePrintable(error_value)))) - } - None => Ok(None), - }, - }, - None => panic!("Expected ok, found None"), - }, + match (&self.value, &self.typ) { + (Value::Result(Ok(Some(val))), AnalysedType::Result(typ)) => { + Ok(Some(Cow::Owned(ValueAndType { + value: *val.clone(), + typ: *typ + .ok + .as_ref() + .expect("No type information for non-unit ok value") + .clone(), + }))) + } + (Value::Result(Ok(None)), AnalysedType::Result(_)) => Ok(None), + (Value::Result(Err(Some(val))), AnalysedType::Result(typ)) => { + Err(Some(Cow::Owned(ValueAndType { + value: *val.clone(), + typ: *typ + .err + .as_ref() + .expect("No type information for non-unit error value") + .clone(), + }))) + } + (Value::Result(Err(None)), AnalysedType::Result(_)) => Err(None), _ => panic!("Expected result, found {:?}", self), } } fn unwrap_flags(&self) -> Box> + '_> { - match self.0.clone() { - TypeAnnotatedValue::Flags(TypedFlags { typ: _, values }) => { - Box::new(values.into_iter().map(Cow::Owned)) - } + match (&self.value, &self.typ) { + (Value::Flags(bitmap), AnalysedType::Flags(typ)) => Box::new( + bitmap + .iter() + .zip(typ.names.iter()) + .filter_map(|(is_set, name)| { + if *is_set { + Some(Cow::Borrowed(name.as_str())) + } else { + None + } + }), + ), _ => panic!("Expected flags, found {:?}", self), } } @@ -528,9 +447,8 @@ impl WasmValue for TypeAnnotatedValuePrintable { mod tests { use test_r::test; - use crate::protobuf::type_annotated_value::TypeAnnotatedValue; - use crate::text::type_annotated_value_from_str; - use crate::{type_annotated_value_to_string, TypeAnnotatedValueConstructors, Value}; + use crate::text::{parse_value_and_type, print_value_and_type}; + use crate::{Value, ValueAndType}; use golem_wasm_ast::analysis::analysed_type::{ bool, case, chr, f32, f64, field, flags, list, option, r#enum, record, result_err, result_ok, s16, s32, s64, s8, str, tuple, u16, u32, u64, u8, unit_case, variant, @@ -538,14 +456,11 @@ mod tests { use golem_wasm_ast::analysis::AnalysedType; fn round_trip(value: Value, typ: AnalysedType) { - let typed_value = TypeAnnotatedValue::create(&value, &typ).unwrap(); - println!("{:?}", typed_value.clone()); - - let s = type_annotated_value_to_string(&typed_value).unwrap(); - let round_trip_value: TypeAnnotatedValue = - type_annotated_value_from_str(&AnalysedType::try_from(&typed_value).unwrap(), &s) - .unwrap(); - let result: Value = Value::try_from(round_trip_value).unwrap(); + let typed_value = ValueAndType::new(value.clone(), typ.clone()); + + let s = print_value_and_type(&typed_value).unwrap(); + let round_trip_value: ValueAndType = parse_value_and_type(&typ, &s).unwrap(); + let result: Value = Value::from(round_trip_value); assert_eq!(value, result); } @@ -706,3 +621,717 @@ mod tests { ); } } + +#[cfg(all(feature = "typeinfo", feature = "protobuf"))] +mod type_annotated_value { + use crate::protobuf::type_annotated_value::TypeAnnotatedValue; + use crate::protobuf::typed_result::ResultValue; + use crate::protobuf::{ + NameValuePair, TypedEnum, TypedFlags, TypedList, TypedOption, TypedRecord, TypedTuple, + TypedVariant, + }; + use crate::protobuf::{TypeAnnotatedValue as RootTypeAnnotatedValue, TypedResult}; + use golem_wasm_ast::analysis::{protobuf, TypeEnum, TypeFlags}; + use golem_wasm_ast::analysis::{AnalysedType, TypeList, TypeRecord, TypeTuple, TypeVariant}; + use std::borrow::Cow; + use std::ops::Deref; + use wasm_wave::wasm::{WasmType, WasmTypeKind, WasmValue, WasmValueError}; + use wasm_wave::{from_str, to_string}; + + pub fn parse_type_annotated_value( + analysed_type: &AnalysedType, + input: &str, + ) -> Result { + let parsed_typed_value: TypeAnnotatedValuePrintable = + from_str(analysed_type, input).map_err(|err| err.to_string())?; + + Ok(parsed_typed_value.0) + } + + pub fn print_type_annotated_value(value: &TypeAnnotatedValue) -> Result { + let printable_typed_value: TypeAnnotatedValuePrintable = + TypeAnnotatedValuePrintable(value.clone()); + + let typed_value_str = to_string(&printable_typed_value).map_err(|err| err.to_string())?; + + Ok(typed_value_str) + } + + #[derive(Debug, Clone)] + pub struct TypeAnnotatedValuePrintable(pub TypeAnnotatedValue); + + impl WasmValue for TypeAnnotatedValuePrintable { + type Type = AnalysedType; + + fn kind(&self) -> WasmTypeKind { + let analysed_type = AnalysedType::try_from(&self.0) + .expect("Failed to retrieve AnalysedType from TypeAnnotatedValue"); + analysed_type.kind() + } + + fn make_bool(val: bool) -> Self { + TypeAnnotatedValuePrintable(TypeAnnotatedValue::Bool(val)) + } + + fn make_s8(val: i8) -> Self { + TypeAnnotatedValuePrintable(TypeAnnotatedValue::S8(val as i32)) + } + + fn make_s16(val: i16) -> Self { + TypeAnnotatedValuePrintable(TypeAnnotatedValue::S16(val as i32)) + } + + fn make_s32(val: i32) -> Self { + TypeAnnotatedValuePrintable(TypeAnnotatedValue::S32(val)) + } + + fn make_s64(val: i64) -> Self { + TypeAnnotatedValuePrintable(TypeAnnotatedValue::S64(val)) + } + + fn make_u8(val: u8) -> Self { + TypeAnnotatedValuePrintable(TypeAnnotatedValue::U8(val as u32)) + } + + fn make_u16(val: u16) -> Self { + TypeAnnotatedValuePrintable(TypeAnnotatedValue::U16(val as u32)) + } + + fn make_u32(val: u32) -> Self { + TypeAnnotatedValuePrintable(TypeAnnotatedValue::U32(val)) + } + + fn make_u64(val: u64) -> Self { + TypeAnnotatedValuePrintable(TypeAnnotatedValue::U64(val)) + } + + fn make_float32(val: f32) -> Self { + TypeAnnotatedValuePrintable(TypeAnnotatedValue::F32(val)) + } + + fn make_float64(val: f64) -> Self { + TypeAnnotatedValuePrintable(TypeAnnotatedValue::F64(val)) + } + + fn make_char(val: char) -> Self { + TypeAnnotatedValuePrintable(TypeAnnotatedValue::Char(val as i32)) + } + + fn make_string(val: Cow) -> Self { + TypeAnnotatedValuePrintable(TypeAnnotatedValue::Str(val.to_string())) + } + + fn make_list( + ty: &Self::Type, + vals: impl IntoIterator, + ) -> Result { + if let AnalysedType::List(TypeList { inner: typ }) = ty { + let list = TypedList { + values: vals + .into_iter() + .map(|v| RootTypeAnnotatedValue { + type_annotated_value: Some(v.0), + }) + .collect(), + typ: Some(typ.deref().into()), + }; + + Ok(TypeAnnotatedValuePrintable(TypeAnnotatedValue::List(list))) + } else { + Err(WasmValueError::WrongTypeKind { + kind: ty.kind(), + ty: format!("{ty:?}"), + }) + } + } + + fn make_record<'a>( + ty: &Self::Type, + fields: impl IntoIterator, + ) -> Result { + if let AnalysedType::Record(TypeRecord { fields: types }) = ty { + let record = TypedRecord { + value: fields + .into_iter() + .map(|(name, value)| NameValuePair { + name: name.to_string(), + value: Some(RootTypeAnnotatedValue { + type_annotated_value: Some(value.0), + }), + }) + .collect(), + typ: types + .iter() + .map(|pair| protobuf::NameTypePair { + name: pair.name.clone(), + typ: Some((&pair.typ).into()), + }) + .collect(), + }; + Ok(TypeAnnotatedValuePrintable(TypeAnnotatedValue::Record( + record, + ))) + } else { + Err(WasmValueError::WrongTypeKind { + kind: ty.kind(), + ty: format!("{ty:?}"), + }) + } + } + + fn make_tuple( + ty: &Self::Type, + vals: impl IntoIterator, + ) -> Result { + if let AnalysedType::Tuple(TypeTuple { items: types }) = ty { + let tuple = TypedTuple { + value: vals + .into_iter() + .map(|v| RootTypeAnnotatedValue { + type_annotated_value: Some(v.0), + }) + .collect(), + typ: types.iter().map(|t| t.into()).collect(), + }; + Ok(TypeAnnotatedValuePrintable(TypeAnnotatedValue::Tuple( + tuple, + ))) + } else { + Err(WasmValueError::WrongTypeKind { + kind: ty.kind(), + ty: format!("{ty:?}"), + }) + } + } + + fn make_variant( + ty: &Self::Type, + case: &str, + val: Option, + ) -> Result { + if let AnalysedType::Variant(TypeVariant { cases }) = ty { + let case_type = cases.iter().find_map(|pair| { + if pair.name == case { + Some(&pair.typ) + } else { + None + } + }); + if case_type.is_some() { + let variant = TypedVariant { + typ: Some(protobuf::TypeVariant { + cases: cases + .iter() + .map(|pair| protobuf::NameOptionTypePair { + name: pair.name.clone(), + typ: pair.typ.as_ref().map(|v| v.into()), + }) + .collect(), + }), + case_name: case.to_string(), + case_value: val.map(|v| { + Box::new(RootTypeAnnotatedValue { + type_annotated_value: Some(v.0), + }) + }), + }; + Ok(TypeAnnotatedValuePrintable(TypeAnnotatedValue::Variant( + Box::new(variant), + ))) + } else { + Err(WasmValueError::UnknownCase(case.to_string())) + } + } else { + Err(WasmValueError::WrongTypeKind { + kind: ty.kind(), + ty: format!("{ty:?}"), + }) + } + } + + fn make_enum(ty: &Self::Type, case: &str) -> Result { + if let AnalysedType::Enum(TypeEnum { cases }) = ty { + if cases.contains(&case.to_string()) { + let enum_value = TypedEnum { + typ: cases.to_vec(), + value: case.to_string(), + }; + Ok(TypeAnnotatedValuePrintable(TypeAnnotatedValue::Enum( + enum_value, + ))) + } else { + Err(WasmValueError::UnknownCase(case.to_string())) + } + } else { + Err(WasmValueError::WrongTypeKind { + kind: ty.kind(), + ty: format!("{ty:?}"), + }) + } + } + + fn make_option(ty: &Self::Type, val: Option) -> Result { + let option = TypedOption { + typ: Some(ty.into()), + value: val.map(|v| { + Box::new(RootTypeAnnotatedValue { + type_annotated_value: Some(v.0), + }) + }), + }; + + Ok(TypeAnnotatedValuePrintable(TypeAnnotatedValue::Option( + Box::new(option), + ))) + } + + fn make_result( + ty: &Self::Type, + val: Result, Option>, + ) -> Result { + if let AnalysedType::Result(golem_wasm_ast::analysis::TypeResult { ok, err }) = ty { + let result0 = TypedResult { + ok: ok.clone().map(|v| v.deref().into()), + error: err.clone().map(|v| v.deref().into()), + result_value: match val { + Ok(Some(v)) => { + Some(ResultValue::OkValue(Box::new(RootTypeAnnotatedValue { + type_annotated_value: Some(v.0), + }))) + } + Ok(None) => None, + Err(Some(v)) => { + Some(ResultValue::ErrorValue(Box::new(RootTypeAnnotatedValue { + type_annotated_value: Some(v.0), + }))) + } + Err(None) => None, + }, + }; + Ok(TypeAnnotatedValuePrintable(TypeAnnotatedValue::Result( + Box::new(result0), + ))) + } else { + Err(WasmValueError::WrongTypeKind { + kind: ty.kind(), + ty: format!("{ty:?}"), + }) + } + } + + fn make_flags<'a>( + ty: &Self::Type, + names: impl IntoIterator, + ) -> Result { + if let AnalysedType::Flags(TypeFlags { names: all_names }) = ty { + let names: Vec = names.into_iter().map(|name| name.to_string()).collect(); + + let invalid_names: Vec = names + .iter() + .filter(|&name| !all_names.contains(&name.to_string())) + .cloned() + .collect(); + + if invalid_names.is_empty() { + let flags = TypedFlags { + typ: all_names.to_vec(), + values: names.to_vec(), + }; + + Ok(TypeAnnotatedValuePrintable(TypeAnnotatedValue::Flags( + flags, + ))) + } else { + Err(WasmValueError::UnknownCase(invalid_names.join(", "))) + } + } else { + Err(WasmValueError::WrongTypeKind { + kind: ty.kind(), + ty: format!("{ty:?}"), + }) + } + } + + fn unwrap_bool(&self) -> bool { + match self.0 { + TypeAnnotatedValue::Bool(value) => value, + _ => panic!("Expected bool, found {:?}", self), + } + } + + fn unwrap_s8(&self) -> i8 { + match self.0 { + TypeAnnotatedValue::S8(value) => value as i8, + _ => panic!("Expected s8, found {:?}", self), + } + } + + fn unwrap_s16(&self) -> i16 { + match self.0 { + TypeAnnotatedValue::S16(value) => value as i16, + _ => panic!("Expected s16, found {:?}", self), + } + } + + fn unwrap_s32(&self) -> i32 { + match self.0 { + TypeAnnotatedValue::S32(value) => value, + _ => panic!("Expected s32, found {:?}", self), + } + } + + fn unwrap_s64(&self) -> i64 { + match self.0 { + TypeAnnotatedValue::S64(value) => value, + _ => panic!("Expected s64, found {:?}", self), + } + } + + fn unwrap_u8(&self) -> u8 { + match self.0 { + TypeAnnotatedValue::U8(value) => value as u8, + _ => panic!("Expected u8, found {:?}", self), + } + } + + fn unwrap_u16(&self) -> u16 { + match self.0 { + TypeAnnotatedValue::U16(value) => value as u16, + _ => panic!("Expected u16, found {:?}", self), + } + } + + fn unwrap_u32(&self) -> u32 { + match self.0 { + TypeAnnotatedValue::U32(value) => value, + _ => panic!("Expected u32, found {:?}", self), + } + } + + fn unwrap_u64(&self) -> u64 { + match self.0 { + TypeAnnotatedValue::U64(value) => value, + _ => panic!("Expected u64, found {:?}", self), + } + } + + fn unwrap_float32(&self) -> f32 { + match self.0 { + TypeAnnotatedValue::F32(value) => value, + _ => panic!("Expected f32, found {:?}", self), + } + } + + fn unwrap_float64(&self) -> f64 { + match self.0 { + TypeAnnotatedValue::F64(value) => value, + _ => panic!("Expected f64, found {:?}", self), + } + } + + fn unwrap_char(&self) -> char { + match self.0 { + TypeAnnotatedValue::Char(value) => char::from_u32(value as u32).unwrap(), + _ => panic!("Expected chr, found {:?}", self), + } + } + + fn unwrap_string(&self) -> Cow { + match self.0.clone() { + TypeAnnotatedValue::Str(value) => Cow::Owned(value.clone()), + _ => panic!("Expected string, found {:?}", self), + } + } + + fn unwrap_list(&self) -> Box> + '_> { + match self.0.clone() { + TypeAnnotatedValue::List(TypedList { typ: _, values }) => { + Box::new(values.into_iter().map(|v| { + Cow::Owned(TypeAnnotatedValuePrintable( + v.type_annotated_value.as_ref().unwrap().clone(), + )) + })) + } + _ => panic!("Expected list, found {:?}", self), + } + } + + fn unwrap_record(&self) -> Box, Cow)> + '_> { + match self.0.clone() { + TypeAnnotatedValue::Record(TypedRecord { typ: _, value }) => { + Box::new(value.into_iter().map(|name_value| { + let name = name_value.name.clone(); + let type_annotated_value = + name_value.value.unwrap().type_annotated_value.unwrap(); + ( + Cow::Owned(name), + Cow::Owned(TypeAnnotatedValuePrintable(type_annotated_value)), + ) + })) + } + _ => panic!("Expected record, found {:?}", self), + } + } + + fn unwrap_tuple(&self) -> Box> + '_> { + match self.0.clone() { + TypeAnnotatedValue::Tuple(TypedTuple { typ: _, value }) => { + Box::new(value.into_iter().map(|x| { + if let Some(ref v) = x.type_annotated_value { + Cow::Owned(TypeAnnotatedValuePrintable(v.clone())) + } else { + panic!("Expected value, found None") + } + })) + } + _ => panic!("Expected tuple, found {:?}", self), + } + } + + fn unwrap_variant(&self) -> (Cow, Option>) { + match self.0.clone() { + TypeAnnotatedValue::Variant(variant) => { + let case_name = Cow::Owned(variant.case_name); + let case_value = variant.case_value.clone().map(|v| { + Cow::Owned(TypeAnnotatedValuePrintable(v.type_annotated_value.unwrap())) + }); + (case_name, case_value) + } + _ => panic!("Expected variant, found {:?}", self), + } + } + + fn unwrap_enum(&self) -> Cow { + match self.0.clone() { + TypeAnnotatedValue::Enum(TypedEnum { typ: _, value }) => Cow::Owned(value), + _ => panic!("Expected enum, found {:?}", self), + } + } + + fn unwrap_option(&self) -> Option> { + match self.0.clone() { + TypeAnnotatedValue::Option(option) => option.value.as_ref().and_then(|v| { + v.type_annotated_value + .as_ref() + .map(|inner| Cow::Owned(TypeAnnotatedValuePrintable(inner.clone()))) + }), + _ => panic!("Expected option, found {:?}", self), + } + } + + fn unwrap_result(&self) -> Result>, Option>> { + match self.0.clone() { + TypeAnnotatedValue::Result(result0) => match result0.result_value { + Some(result) => match result { + ResultValue::OkValue(ok) => match ok.type_annotated_value { + Some(ok_value) => { + Ok(Some(Cow::Owned(TypeAnnotatedValuePrintable(ok_value)))) + } + None => Ok(None), + }, + ResultValue::ErrorValue(error) => match error.type_annotated_value { + Some(error_value) => { + Err(Some(Cow::Owned(TypeAnnotatedValuePrintable(error_value)))) + } + None => Ok(None), + }, + }, + None => panic!("Expected ok, found None"), + }, + _ => panic!("Expected result, found {:?}", self), + } + } + + fn unwrap_flags(&self) -> Box> + '_> { + match self.0.clone() { + TypeAnnotatedValue::Flags(TypedFlags { typ: _, values }) => { + Box::new(values.into_iter().map(Cow::Owned)) + } + _ => panic!("Expected flags, found {:?}", self), + } + } + } + + #[cfg(test)] + mod tests { + use test_r::test; + + use crate::protobuf::type_annotated_value::TypeAnnotatedValue; + use crate::text::parse_type_annotated_value; + use crate::{print_type_annotated_value, TypeAnnotatedValueConstructors, Value}; + use golem_wasm_ast::analysis::analysed_type::{ + bool, case, chr, f32, f64, field, flags, list, option, r#enum, record, result_err, + result_ok, s16, s32, s64, s8, str, tuple, u16, u32, u64, u8, unit_case, variant, + }; + use golem_wasm_ast::analysis::AnalysedType; + + fn round_trip(value: Value, typ: AnalysedType) { + let typed_value = TypeAnnotatedValue::create(&value, &typ).unwrap(); + println!("{:?}", typed_value.clone()); + + let s = print_type_annotated_value(&typed_value).unwrap(); + let round_trip_value: TypeAnnotatedValue = + parse_type_annotated_value(&AnalysedType::try_from(&typed_value).unwrap(), &s) + .unwrap(); + let result: Value = Value::try_from(round_trip_value).unwrap(); + assert_eq!(value, result); + } + + #[test] + fn round_trip_u8() { + round_trip(Value::U8(42), u8()); + } + + #[test] + fn round_trip_u16() { + round_trip(Value::U16(1234), u16()); + } + + #[test] + fn round_trip_u32() { + round_trip(Value::U32(123456), u32()); + } + + #[test] + fn round_trip_u64() { + round_trip(Value::U64(1234567890123456), u64()); + } + + #[test] + fn round_trip_s8() { + round_trip(Value::S8(-42), s8()); + } + + #[test] + fn round_trip_s16() { + round_trip(Value::S16(-1234), s16()); + } + + #[test] + fn round_trip_s32() { + round_trip(Value::S32(-123456), s32()); + } + + #[test] + fn round_trip_s64() { + round_trip(Value::S64(-1234567890123456), s64()); + } + + #[test] + fn round_trip_f32() { + round_trip(Value::F32(1234.5678), f32()); + } + + #[test] + fn round_trip_f64() { + round_trip(Value::F64(1_234_567_890_123_456.8), f64()); + } + + #[test] + fn round_trip_bool() { + round_trip(Value::Bool(true), bool()); + } + + #[test] + fn round_trip_char() { + round_trip(Value::Char('a'), chr()); + } + + #[test] + fn round_trip_string() { + round_trip(Value::String("hello".to_string()), str()); + } + + #[test] + fn round_trip_list_1() { + round_trip( + Value::List(vec![Value::U8(1), Value::U8(2), Value::U8(3)]), + list(u8()), + ); + } + + #[test] + fn round_trip_list_2() { + round_trip( + Value::List(vec![Value::List(vec![ + Value::String("hello".to_string()), + Value::String("world".to_string()), + ])]), + list(list(str())), + ); + } + + #[test] + fn round_trip_record() { + round_trip( + Value::Record(vec![ + Value::U8(1), + Value::String("hello".to_string()), + Value::Bool(true), + ]), + record(vec![ + field("a", u8()), + field("b", str()), + field("c", bool()), + ]), + ); + } + + #[test] + fn round_trip_tuple() { + round_trip( + Value::Tuple(vec![ + Value::U8(1), + Value::String("hello".to_string()), + Value::Bool(true), + ]), + tuple(vec![u8(), str(), bool()]), + ); + } + + #[test] + fn round_trip_variant() { + round_trip( + Value::Variant { + case_idx: 1, + case_value: Some(Box::new(Value::String("hello".to_string()))), + }, + variant(vec![unit_case("A"), case("B", str())]), + ); + } + + #[test] + fn round_trip_enum() { + round_trip(Value::Enum(1), r#enum(&["A", "B"])); + } + + #[test] + fn round_trip_option() { + round_trip(Value::Option(Some(Box::new(Value::U8(1)))), option(u8())); + } + + #[test] + fn round_trip_result_ok() { + round_trip( + Value::Result(Ok(Some(Box::new(Value::U8(1))))), + result_ok(u8()), + ); + } + + #[test] + fn round_trip_result_err() { + round_trip( + Value::Result(Err(Some(Box::new(Value::U8(1))))), + result_err(u8()), + ); + } + + #[test] + fn round_trip_flags() { + round_trip( + Value::Flags(vec![true, false, true]), + flags(&["A", "B", "C"]), + ); + } + } +} diff --git a/wasm-rpc/src/type_annotated_value.rs b/wasm-rpc/src/type_annotated_value.rs index d90ad88b9..b78082727 100644 --- a/wasm-rpc/src/type_annotated_value.rs +++ b/wasm-rpc/src/type_annotated_value.rs @@ -1,3 +1,17 @@ +// Copyright 2024 Golem Cloud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use crate::protobuf::type_annotated_value::TypeAnnotatedValue; use crate::protobuf::typed_result::ResultValue; use crate::protobuf::{NameValuePair, TypedOption}; @@ -5,47 +19,9 @@ use crate::protobuf::{TypeAnnotatedValue as RootTypeAnnotatedValue, TypedResult} use crate::protobuf::{ TypedEnum, TypedFlags, TypedHandle, TypedList, TypedRecord, TypedTuple, TypedVariant, }; -use crate::{NodeIndex, Uri, Value, WitNode, WitValue}; -use golem_wasm_ast::analysis::analysed_type::{ - bool, case, chr, f32, f64, field, list, option, record, result, result_err, result_ok, s16, - s32, s64, s8, str, tuple, u16, u32, u64, u8, variant, -}; +use crate::{Value, ValueAndType}; use golem_wasm_ast::analysis::protobuf::Type; use golem_wasm_ast::analysis::AnalysedType; -use std::collections::HashMap; -use std::time::{Duration, Instant}; -use uuid::Uuid; - -#[derive(Clone, Debug, PartialEq)] -#[cfg_attr(feature = "bincode", derive(::bincode::Encode, ::bincode::Decode))] -pub struct ValueAndType { - pub value: Value, - pub typ: AnalysedType, -} - -impl ValueAndType { - pub fn new(value: Value, typ: AnalysedType) -> Self { - Self { value, typ } - } -} - -impl From for Value { - fn from(value_and_type: ValueAndType) -> Self { - value_and_type.value - } -} - -impl From for AnalysedType { - fn from(value_and_type: ValueAndType) -> Self { - value_and_type.typ - } -} - -impl From for WitValue { - fn from(value_and_type: ValueAndType) -> Self { - value_and_type.value.into() - } -} impl TryFrom for TypeAnnotatedValue { type Error = Vec; @@ -96,441 +72,6 @@ impl TryFrom for crate::protobuf::TypeAnnotatedValue { } } -/// Specific trait to convert a type into a pair of `Value` and `AnalysedType`. -pub trait IntoValue { - fn into_value(self) -> Value; - fn get_type() -> AnalysedType; -} - -pub trait IntoValueAndType { - fn into_value_and_type(self) -> ValueAndType; -} - -impl IntoValueAndType for T { - fn into_value_and_type(self) -> ValueAndType { - ValueAndType::new(self.into_value(), Self::get_type()) - } -} - -impl IntoValue for u8 { - fn into_value(self) -> Value { - Value::U8(self) - } - - fn get_type() -> AnalysedType { - u8() - } -} - -impl IntoValue for u16 { - fn into_value(self) -> Value { - Value::U16(self) - } - - fn get_type() -> AnalysedType { - u16() - } -} - -impl IntoValue for u32 { - fn into_value(self) -> Value { - Value::U32(self) - } - - fn get_type() -> AnalysedType { - u32() - } -} - -impl IntoValue for u64 { - fn into_value(self) -> Value { - Value::U64(self) - } - - fn get_type() -> AnalysedType { - u64() - } -} - -impl IntoValue for i8 { - fn into_value(self) -> Value { - Value::S8(self) - } - - fn get_type() -> AnalysedType { - s8() - } -} - -impl IntoValue for i16 { - fn into_value(self) -> Value { - Value::S16(self) - } - - fn get_type() -> AnalysedType { - s16() - } -} - -impl IntoValue for i32 { - fn into_value(self) -> Value { - Value::S32(self) - } - - fn get_type() -> AnalysedType { - s32() - } -} - -impl IntoValue for i64 { - fn into_value(self) -> Value { - Value::S64(self) - } - - fn get_type() -> AnalysedType { - s64() - } -} - -impl IntoValue for f32 { - fn into_value(self) -> Value { - Value::F32(self) - } - - fn get_type() -> AnalysedType { - f32() - } -} - -impl IntoValue for f64 { - fn into_value(self) -> Value { - Value::F64(self) - } - - fn get_type() -> AnalysedType { - f64() - } -} - -impl IntoValue for bool { - fn into_value(self) -> Value { - Value::Bool(self) - } - - fn get_type() -> AnalysedType { - bool() - } -} - -impl IntoValue for char { - fn into_value(self) -> Value { - Value::Char(self) - } - - fn get_type() -> AnalysedType { - chr() - } -} - -impl IntoValue for String { - fn into_value(self) -> Value { - Value::String(self) - } - - fn get_type() -> AnalysedType { - str() - } -} - -impl IntoValue for Result { - fn into_value(self) -> Value { - match self { - Ok(s) => Value::Result(Ok(Some(Box::new(s.into_value())))), - Err(e) => Value::Result(Err(Some(Box::new(e.into_value())))), - } - } - - fn get_type() -> AnalysedType { - result(S::get_type(), E::get_type()) - } -} - -impl IntoValue for Result<(), E> { - fn into_value(self) -> Value { - match self { - Ok(_) => Value::Result(Ok(None)), - Err(e) => Value::Result(Err(Some(Box::new(e.into_value())))), - } - } - - fn get_type() -> AnalysedType { - result_err(E::get_type()) - } -} - -impl IntoValue for Result { - fn into_value(self) -> Value { - match self { - Ok(s) => Value::Result(Ok(Some(Box::new(s.into_value())))), - Err(_) => Value::Result(Err(None)), - } - } - - fn get_type() -> AnalysedType { - result_ok(S::get_type()) - } -} - -impl IntoValue for Option { - fn into_value(self) -> Value { - match self { - Some(t) => Value::Option(Some(Box::new(t.into_value()))), - None => Value::Option(None), - } - } - - fn get_type() -> AnalysedType { - option(T::get_type()) - } -} - -impl IntoValue for Vec { - fn into_value(self) -> Value { - Value::List(self.into_iter().map(IntoValue::into_value).collect()) - } - - fn get_type() -> AnalysedType { - list(T::get_type()) - } -} - -impl IntoValue for (A, B) { - fn into_value(self) -> Value { - Value::Tuple(vec![self.0.into_value(), self.1.into_value()]) - } - - fn get_type() -> AnalysedType { - tuple(vec![A::get_type(), B::get_type()]) - } -} - -impl IntoValue for (A, B, C) { - fn into_value(self) -> Value { - Value::Tuple(vec![ - self.0.into_value(), - self.1.into_value(), - self.2.into_value(), - ]) - } - - fn get_type() -> AnalysedType { - tuple(vec![A::get_type(), B::get_type(), C::get_type()]) - } -} - -impl IntoValue for HashMap { - fn into_value(self) -> Value { - Value::List( - self.into_iter() - .map(|(k, v)| Value::Tuple(vec![k.into_value(), v.into_value()])) - .collect(), - ) - } - - fn get_type() -> AnalysedType { - list(tuple(vec![K::get_type(), V::get_type()])) - } -} - -impl IntoValue for Uuid { - fn into_value(self) -> Value { - Value::String(self.to_string()) - } - - fn get_type() -> AnalysedType { - str() - } -} - -impl IntoValue for WitValue { - fn into_value(self) -> Value { - // NOTE: this is different than From for Value. That conversion creates - // the Value the WitValue describes, while this conversion creates a Value version of - // the WitValue representation itself. - Value::Record(vec![self.nodes.into_value()]) - } - - fn get_type() -> AnalysedType { - record(vec![field("nodes", list(WitNode::get_type()))]) - } -} - -impl IntoValue for WitNode { - fn into_value(self) -> Value { - match self { - WitNode::RecordValue(indices) => Value::Variant { - case_idx: 0, - case_value: Some(Box::new(indices.into_value())), - }, - WitNode::VariantValue((idx, value)) => Value::Variant { - case_idx: 1, - case_value: Some(Box::new(Value::Tuple(vec![ - idx.into_value(), - value - .map(IntoValue::into_value) - .unwrap_or(Value::Option(None)), - ]))), - }, - WitNode::EnumValue(idx) => Value::Variant { - case_idx: 2, - case_value: Some(Box::new(idx.into_value())), - }, - WitNode::FlagsValue(flags) => Value::Variant { - case_idx: 3, - case_value: Some(Box::new(flags.into_value())), - }, - WitNode::TupleValue(indices) => Value::Variant { - case_idx: 4, - case_value: Some(Box::new(indices.into_value())), - }, - WitNode::ListValue(indices) => Value::Variant { - case_idx: 5, - case_value: Some(Box::new(indices.into_value())), - }, - WitNode::OptionValue(index) => Value::Variant { - case_idx: 6, - case_value: Some(Box::new(index.into_value())), - }, - WitNode::ResultValue(result) => Value::Variant { - case_idx: 7, - case_value: Some(Box::new(result.into_value())), - }, - WitNode::PrimU8(value) => Value::Variant { - case_idx: 8, - case_value: Some(Box::new(value.into_value())), - }, - WitNode::PrimU16(value) => Value::Variant { - case_idx: 9, - case_value: Some(Box::new(value.into_value())), - }, - WitNode::PrimU32(value) => Value::Variant { - case_idx: 10, - case_value: Some(Box::new(value.into_value())), - }, - WitNode::PrimU64(value) => Value::Variant { - case_idx: 11, - case_value: Some(Box::new(value.into_value())), - }, - WitNode::PrimS8(value) => Value::Variant { - case_idx: 12, - case_value: Some(Box::new(value.into_value())), - }, - WitNode::PrimS16(value) => Value::Variant { - case_idx: 13, - case_value: Some(Box::new(value.into_value())), - }, - WitNode::PrimS32(value) => Value::Variant { - case_idx: 14, - case_value: Some(Box::new(value.into_value())), - }, - WitNode::PrimS64(value) => Value::Variant { - case_idx: 15, - case_value: Some(Box::new(value.into_value())), - }, - WitNode::PrimFloat32(value) => Value::Variant { - case_idx: 16, - case_value: Some(Box::new(value.into_value())), - }, - WitNode::PrimFloat64(value) => Value::Variant { - case_idx: 17, - case_value: Some(Box::new(value.into_value())), - }, - WitNode::PrimChar(value) => Value::Variant { - case_idx: 18, - case_value: Some(Box::new(value.into_value())), - }, - WitNode::PrimBool(value) => Value::Variant { - case_idx: 19, - case_value: Some(Box::new(value.into_value())), - }, - WitNode::PrimString(value) => Value::Variant { - case_idx: 20, - case_value: Some(Box::new(value.into_value())), - }, - WitNode::Handle((uri, resource_id)) => Value::Variant { - case_idx: 21, - case_value: Some(Box::new(Value::Tuple(vec![ - uri.into_value(), - resource_id.into_value(), - ]))), - }, - } - } - - fn get_type() -> AnalysedType { - variant(vec![ - case("record-value", list(NodeIndex::get_type())), - case( - "variant-value", - tuple(vec![u32(), option(NodeIndex::get_type())]), - ), - case("enum-value", u32()), - case("flags-value", list(bool())), - case("tuple-value", list(NodeIndex::get_type())), - case("list-value", list(NodeIndex::get_type())), - case("option-value", option(NodeIndex::get_type())), - case( - "result-value", - result(option(NodeIndex::get_type()), option(NodeIndex::get_type())), - ), - case("prim-u8", u8()), - case("prim-u16", u16()), - case("prim-u32", u32()), - case("prim-u64", u64()), - case("prim-s8", s8()), - case("prim-s16", s16()), - case("prim-s32", s32()), - case("prim-s64", s64()), - case("prim-float32", f32()), - case("prim-float64", f64()), - case("prim-char", chr()), - case("prim-bool", bool()), - case("prim-string", str()), - case("handle", tuple(vec![Uri::get_type(), u64()])), - ]) - } -} - -impl IntoValue for Uri { - fn into_value(self) -> Value { - Value::Record(vec![Value::String(self.value)]) - } - - fn get_type() -> AnalysedType { - record(vec![field("value", str())]) - } -} - -impl IntoValue for Instant { - fn into_value(self) -> Value { - Value::U64(self.elapsed().as_nanos() as u64) - } - - fn get_type() -> AnalysedType { - u64() - } -} - -impl IntoValue for Duration { - fn into_value(self) -> Value { - Value::U64(self.as_nanos() as u64) - } - - fn get_type() -> AnalysedType { - u64() - } -} - pub trait TypeAnnotatedValueConstructors: Sized { fn create>(value: &Value, typ: T) -> Result>; } @@ -850,7 +391,7 @@ fn create_from_type(val: &Value, typ: &Type) -> Result match &typ.r#type { Some(golem_wasm_ast::analysis::protobuf::r#type::Type::Handle(typ_handle)) => { let handle = TypedHandle { - uri: uri.value.clone(), + uri: uri.clone(), resource_id: *resource_id, typ: Some(*typ_handle), }; diff --git a/wasm-rpc/src/value_and_type.rs b/wasm-rpc/src/value_and_type.rs new file mode 100644 index 000000000..9c4365494 --- /dev/null +++ b/wasm-rpc/src/value_and_type.rs @@ -0,0 +1,534 @@ +// Copyright 2024 Golem Cloud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::Value; +use golem_wasm_ast::analysis::analysed_type::{list, option, result, result_err, result_ok, tuple}; +use golem_wasm_ast::analysis::{analysed_type, AnalysedType}; +use std::collections::HashMap; +use std::time::{Duration, Instant}; +use uuid::Uuid; + +#[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "bincode", derive(::bincode::Encode, ::bincode::Decode))] +pub struct ValueAndType { + pub value: Value, + pub typ: AnalysedType, +} + +#[cfg(feature = "text")] +impl std::fmt::Display for ValueAndType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + crate::text::print_value_and_type(self).unwrap_or("".to_string()) + ) + } +} + +impl ValueAndType { + pub fn new(value: Value, typ: AnalysedType) -> Self { + Self { value, typ } + } + + pub fn into_list_items(self) -> Option> { + match (self.value, self.typ) { + (Value::List(items), AnalysedType::List(item_type)) => Some( + items + .into_iter() + .map(|item| ValueAndType::new(item, (*item_type.inner).clone())) + .collect(), + ), + _ => None, + } + } +} + +impl From for Value { + fn from(value_and_type: ValueAndType) -> Self { + value_and_type.value + } +} + +impl From for AnalysedType { + fn from(value_and_type: ValueAndType) -> Self { + value_and_type.typ + } +} + +#[cfg(feature = "host-bindings")] +impl From for crate::WitValue { + fn from(value_and_type: ValueAndType) -> Self { + value_and_type.value.into() + } +} + +/// Specific trait to convert a type into a pair of `Value` and `AnalysedType`. +pub trait IntoValue { + fn into_value(self) -> Value; + fn get_type() -> AnalysedType; +} + +pub trait IntoValueAndType { + fn into_value_and_type(self) -> ValueAndType; +} + +impl IntoValueAndType for T { + fn into_value_and_type(self) -> ValueAndType { + ValueAndType::new(self.into_value(), Self::get_type()) + } +} + +impl IntoValue for u8 { + fn into_value(self) -> Value { + Value::U8(self) + } + + fn get_type() -> AnalysedType { + analysed_type::u8() + } +} + +impl IntoValue for u16 { + fn into_value(self) -> Value { + Value::U16(self) + } + + fn get_type() -> AnalysedType { + analysed_type::u16() + } +} + +impl IntoValue for u32 { + fn into_value(self) -> Value { + Value::U32(self) + } + + fn get_type() -> AnalysedType { + analysed_type::u32() + } +} + +impl IntoValue for u64 { + fn into_value(self) -> Value { + Value::U64(self) + } + + fn get_type() -> AnalysedType { + analysed_type::u64() + } +} + +impl IntoValue for i8 { + fn into_value(self) -> Value { + Value::S8(self) + } + + fn get_type() -> AnalysedType { + analysed_type::s8() + } +} + +impl IntoValue for i16 { + fn into_value(self) -> Value { + Value::S16(self) + } + + fn get_type() -> AnalysedType { + analysed_type::s16() + } +} + +impl IntoValue for i32 { + fn into_value(self) -> Value { + Value::S32(self) + } + + fn get_type() -> AnalysedType { + analysed_type::s32() + } +} + +impl IntoValue for i64 { + fn into_value(self) -> Value { + Value::S64(self) + } + + fn get_type() -> AnalysedType { + analysed_type::s64() + } +} + +impl IntoValue for f32 { + fn into_value(self) -> Value { + Value::F32(self) + } + + fn get_type() -> AnalysedType { + analysed_type::f32() + } +} + +impl IntoValue for f64 { + fn into_value(self) -> Value { + Value::F64(self) + } + + fn get_type() -> AnalysedType { + analysed_type::f64() + } +} + +impl IntoValue for bool { + fn into_value(self) -> Value { + Value::Bool(self) + } + + fn get_type() -> AnalysedType { + analysed_type::bool() + } +} + +impl IntoValue for char { + fn into_value(self) -> Value { + Value::Char(self) + } + + fn get_type() -> AnalysedType { + analysed_type::chr() + } +} + +impl IntoValue for String { + fn into_value(self) -> Value { + Value::String(self) + } + + fn get_type() -> AnalysedType { + analysed_type::str() + } +} + +impl IntoValue for &str { + fn into_value(self) -> Value { + Value::String(self.to_string()) + } + + fn get_type() -> AnalysedType { + analysed_type::str() + } +} + +impl IntoValue for Result { + fn into_value(self) -> Value { + match self { + Ok(s) => Value::Result(Ok(Some(Box::new(s.into_value())))), + Err(e) => Value::Result(Err(Some(Box::new(e.into_value())))), + } + } + + fn get_type() -> AnalysedType { + result(S::get_type(), E::get_type()) + } +} + +impl IntoValue for Result<(), E> { + fn into_value(self) -> Value { + match self { + Ok(_) => Value::Result(Ok(None)), + Err(e) => Value::Result(Err(Some(Box::new(e.into_value())))), + } + } + + fn get_type() -> AnalysedType { + result_err(E::get_type()) + } +} + +impl IntoValue for Result { + fn into_value(self) -> Value { + match self { + Ok(s) => Value::Result(Ok(Some(Box::new(s.into_value())))), + Err(_) => Value::Result(Err(None)), + } + } + + fn get_type() -> AnalysedType { + result_ok(S::get_type()) + } +} + +impl IntoValue for Option { + fn into_value(self) -> Value { + match self { + Some(t) => Value::Option(Some(Box::new(t.into_value()))), + None => Value::Option(None), + } + } + + fn get_type() -> AnalysedType { + option(T::get_type()) + } +} + +impl IntoValue for Vec { + fn into_value(self) -> Value { + Value::List(self.into_iter().map(IntoValue::into_value).collect()) + } + + fn get_type() -> AnalysedType { + list(T::get_type()) + } +} + +impl IntoValue for (A, B) { + fn into_value(self) -> Value { + Value::Tuple(vec![self.0.into_value(), self.1.into_value()]) + } + + fn get_type() -> AnalysedType { + tuple(vec![A::get_type(), B::get_type()]) + } +} + +impl IntoValue for (A, B, C) { + fn into_value(self) -> Value { + Value::Tuple(vec![ + self.0.into_value(), + self.1.into_value(), + self.2.into_value(), + ]) + } + + fn get_type() -> AnalysedType { + tuple(vec![A::get_type(), B::get_type(), C::get_type()]) + } +} + +impl IntoValue for HashMap { + fn into_value(self) -> Value { + Value::List( + self.into_iter() + .map(|(k, v)| Value::Tuple(vec![k.into_value(), v.into_value()])) + .collect(), + ) + } + + fn get_type() -> AnalysedType { + list(tuple(vec![K::get_type(), V::get_type()])) + } +} + +impl IntoValue for Uuid { + fn into_value(self) -> Value { + Value::String(self.to_string()) + } + + fn get_type() -> AnalysedType { + analysed_type::str() + } +} + +#[cfg(feature = "host-bindings")] +impl IntoValue for crate::WitValue { + fn into_value(self) -> Value { + // NOTE: this is different than From for Value. That conversion creates + // the Value the WitValue describes, while this conversion creates a Value version of + // the WitValue representation itself. + Value::Record(vec![self.nodes.into_value()]) + } + + fn get_type() -> AnalysedType { + analysed_type::record(vec![analysed_type::field( + "nodes", + list(crate::WitNode::get_type()), + )]) + } +} + +#[cfg(feature = "host-bindings")] +impl IntoValue for crate::WitNode { + fn into_value(self) -> Value { + use crate::WitNode; + + match self { + WitNode::RecordValue(indices) => Value::Variant { + case_idx: 0, + case_value: Some(Box::new(indices.into_value())), + }, + WitNode::VariantValue((idx, value)) => Value::Variant { + case_idx: 1, + case_value: Some(Box::new(Value::Tuple(vec![ + idx.into_value(), + value + .map(IntoValue::into_value) + .unwrap_or(Value::Option(None)), + ]))), + }, + WitNode::EnumValue(idx) => Value::Variant { + case_idx: 2, + case_value: Some(Box::new(idx.into_value())), + }, + WitNode::FlagsValue(flags) => Value::Variant { + case_idx: 3, + case_value: Some(Box::new(flags.into_value())), + }, + WitNode::TupleValue(indices) => Value::Variant { + case_idx: 4, + case_value: Some(Box::new(indices.into_value())), + }, + WitNode::ListValue(indices) => Value::Variant { + case_idx: 5, + case_value: Some(Box::new(indices.into_value())), + }, + WitNode::OptionValue(index) => Value::Variant { + case_idx: 6, + case_value: Some(Box::new(index.into_value())), + }, + WitNode::ResultValue(result) => Value::Variant { + case_idx: 7, + case_value: Some(Box::new(result.into_value())), + }, + WitNode::PrimU8(value) => Value::Variant { + case_idx: 8, + case_value: Some(Box::new(value.into_value())), + }, + WitNode::PrimU16(value) => Value::Variant { + case_idx: 9, + case_value: Some(Box::new(value.into_value())), + }, + WitNode::PrimU32(value) => Value::Variant { + case_idx: 10, + case_value: Some(Box::new(value.into_value())), + }, + WitNode::PrimU64(value) => Value::Variant { + case_idx: 11, + case_value: Some(Box::new(value.into_value())), + }, + WitNode::PrimS8(value) => Value::Variant { + case_idx: 12, + case_value: Some(Box::new(value.into_value())), + }, + WitNode::PrimS16(value) => Value::Variant { + case_idx: 13, + case_value: Some(Box::new(value.into_value())), + }, + WitNode::PrimS32(value) => Value::Variant { + case_idx: 14, + case_value: Some(Box::new(value.into_value())), + }, + WitNode::PrimS64(value) => Value::Variant { + case_idx: 15, + case_value: Some(Box::new(value.into_value())), + }, + WitNode::PrimFloat32(value) => Value::Variant { + case_idx: 16, + case_value: Some(Box::new(value.into_value())), + }, + WitNode::PrimFloat64(value) => Value::Variant { + case_idx: 17, + case_value: Some(Box::new(value.into_value())), + }, + WitNode::PrimChar(value) => Value::Variant { + case_idx: 18, + case_value: Some(Box::new(value.into_value())), + }, + WitNode::PrimBool(value) => Value::Variant { + case_idx: 19, + case_value: Some(Box::new(value.into_value())), + }, + WitNode::PrimString(value) => Value::Variant { + case_idx: 20, + case_value: Some(Box::new(value.into_value())), + }, + WitNode::Handle((uri, resource_id)) => Value::Variant { + case_idx: 21, + case_value: Some(Box::new(Value::Tuple(vec![ + uri.into_value(), + resource_id.into_value(), + ]))), + }, + } + } + + fn get_type() -> AnalysedType { + use crate::NodeIndex; + use analysed_type::{case, variant}; + + variant(vec![ + case("record-value", list(NodeIndex::get_type())), + case( + "variant-value", + tuple(vec![analysed_type::u32(), option(NodeIndex::get_type())]), + ), + case("enum-value", analysed_type::u32()), + case("flags-value", list(analysed_type::bool())), + case("tuple-value", list(NodeIndex::get_type())), + case("list-value", list(NodeIndex::get_type())), + case("option-value", option(NodeIndex::get_type())), + case( + "result-value", + result(option(NodeIndex::get_type()), option(NodeIndex::get_type())), + ), + case("prim-u8", analysed_type::u8()), + case("prim-u16", analysed_type::u16()), + case("prim-u32", analysed_type::u32()), + case("prim-u64", analysed_type::u64()), + case("prim-s8", analysed_type::s8()), + case("prim-s16", analysed_type::s16()), + case("prim-s32", analysed_type::s32()), + case("prim-s64", analysed_type::s64()), + case("prim-float32", analysed_type::f32()), + case("prim-float64", analysed_type::f64()), + case("prim-char", analysed_type::chr()), + case("prim-bool", analysed_type::bool()), + case("prim-string", analysed_type::str()), + case( + "handle", + tuple(vec![crate::Uri::get_type(), analysed_type::u64()]), + ), + ]) + } +} + +#[cfg(feature = "host-bindings")] +impl IntoValue for crate::Uri { + fn into_value(self) -> Value { + Value::Record(vec![Value::String(self.value)]) + } + + fn get_type() -> AnalysedType { + analysed_type::record(vec![analysed_type::field("value", analysed_type::str())]) + } +} + +impl IntoValue for Instant { + fn into_value(self) -> Value { + Value::U64(self.elapsed().as_nanos() as u64) + } + + fn get_type() -> AnalysedType { + analysed_type::u64() + } +} + +impl IntoValue for Duration { + fn into_value(self) -> Value { + Value::U64(self.as_nanos() as u64) + } + + fn get_type() -> AnalysedType { + analysed_type::u64() + } +} diff --git a/wasm-rpc/src/wasmtime.rs b/wasm-rpc/src/wasmtime.rs index 8e6770eaf..6b68e2f84 100644 --- a/wasm-rpc/src/wasmtime.rs +++ b/wasm-rpc/src/wasmtime.rs @@ -411,7 +411,8 @@ async fn decode_param_impl( Type::Own(_) => { match param { Value::Handle { uri, resource_id } => { - if resource_store.self_uri() == *uri { + let uri = Uri { value: uri.clone() }; + if resource_store.self_uri() == uri { match resource_store.get(*resource_id).await { Some(resource) => Ok(DecodeParamResult { val: Val::Resource(resource), @@ -437,7 +438,8 @@ async fn decode_param_impl( } Type::Borrow(_) => match param { Value::Handle { uri, resource_id } => { - if resource_store.self_uri() == *uri { + let uri = Uri { value: uri.clone() }; + if resource_store.self_uri() == uri { match resource_store.borrow(*resource_id).await { Some(resource) => Ok(DecodeParamResult::simple(Val::Resource(resource))), None => Err(EncodingError::ValueMismatch { @@ -644,7 +646,7 @@ pub async fn encode_output( Val::Resource(resource) => { let id = resource_store.add(*resource).await; Ok(Value::Handle { - uri: resource_store.self_uri(), + uri: resource_store.self_uri().value, resource_id: id, }) } From 8d3bee93940d409fa54471d1dd79ce78eaef395c Mon Sep 17 00:00:00 2001 From: Daniel Vigovszky Date: Fri, 13 Dec 2024 09:46:18 +0100 Subject: [PATCH 4/8] Run all jobs on ubuntu 22.04 and no need for release build before publish (#1179) --- .github/workflows/ci.yaml | 10 +++++----- Makefile.toml | 1 - 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 364ce38b9..fb6de5753 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -20,7 +20,7 @@ env: jobs: docker-targets-build: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 if: github.event_name == 'push' && github.ref_type == 'tag' strategy: fail-fast: false @@ -75,7 +75,7 @@ jobs: name: docker-targets-build-${{ env.PLATFORM_PAIR }} path: target/${{ matrix.platform.target }}.tar docker-publish: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 needs: [ docker-targets-build ] if: github.event_name == 'push' && github.ref_type == 'tag' steps: @@ -247,7 +247,7 @@ jobs: include_passed: true wasm-rpc-stub: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - name: Checkout uses: actions/checkout@v4 @@ -492,7 +492,7 @@ jobs: sharding-tests, ] if: "startsWith(github.ref, 'refs/tags/v')" - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - name: Checkout uses: actions/checkout@v4 @@ -596,7 +596,7 @@ jobs: publish-slack-notification: if: ${{ always() && startsWith(github.ref, 'refs/tags/v') }} needs: [ publish, docker-publish, publish_cli_binaries ] - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - name: Publish Slack Notification uses: rtCamp/action-slack-notify@v2 diff --git a/Makefile.toml b/Makefile.toml index da1cb7a89..9e9a71a54 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -375,7 +375,6 @@ args = ["-v", "./target/golem-service.yaml", "./openapi/golem-service.yaml"] [tasks.publish] description = "Publishes packages to crates.io" dependencies = [ - "build-release", "publish-golem-wasm-ast", "publish-golem-wasm-rpc", "publish-golem-wasm-rpc-stubgen", From 38a5ceb27ddee82bf7d2f57f0c1231d059df160a Mon Sep 17 00:00:00 2001 From: Daniel Vigovszky Date: Fri, 13 Dec 2024 11:22:27 +0100 Subject: [PATCH 5/8] --no-verify (#1183) --- Makefile.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile.toml b/Makefile.toml index 9e9a71a54..3cedf0d3b 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -422,7 +422,8 @@ args = [ "-p", "golem-wasm-ast", "--all-features", - "--allow-dirty" + "--allow-dirty", + "--no-verify", ] [tasks.publish-golem-wasm-rpc] @@ -434,6 +435,7 @@ args = [ "golem-wasm-rpc", "--all-features", "--allow-dirty", + "--no-verify", ] [tasks.publish-golem-wasm-rpc-stubgen] @@ -445,6 +447,7 @@ args = [ "golem-wasm-rpc-stubgen", "--all-features", "--allow-dirty", + "--no-verify", ] [tasks.publish-golem-client] From 292ab10c14c702a2f3b2fd76b295c8623ef264c7 Mon Sep 17 00:00:00 2001 From: Daniel Vigovszky Date: Fri, 13 Dec 2024 13:12:44 +0100 Subject: [PATCH 6/8] Call set-version before publish (previously done by release) (#1187) --- Makefile.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.toml b/Makefile.toml index 3cedf0d3b..668997614 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -375,6 +375,7 @@ args = ["-v", "./target/golem-service.yaml", "./openapi/golem-service.yaml"] [tasks.publish] description = "Publishes packages to crates.io" dependencies = [ + "set-version", "publish-golem-wasm-ast", "publish-golem-wasm-rpc", "publish-golem-wasm-rpc-stubgen", From 7a68607ef76956cfd302603405fdc32b0fcc3148 Mon Sep 17 00:00:00 2001 From: Daniel Vigovszky Date: Fri, 13 Dec 2024 19:24:53 +0100 Subject: [PATCH 7/8] Disable all sharding tests temporarily (#1190) --- integration-tests/tests/sharding.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/integration-tests/tests/sharding.rs b/integration-tests/tests/sharding.rs index 91dae5ab9..806b76334 100644 --- a/integration-tests/tests/sharding.rs +++ b/integration-tests/tests/sharding.rs @@ -114,6 +114,7 @@ mod tests { #[test] #[timeout(120000)] #[flaky(5)] + #[ignore] // TEMPORARILY IGNORED AS IT IS VERY FLAKY ON CI async fn coordinated_scenario_01_01(deps: &EnvBasedTestDependencies, _tracing: &Tracing) { for _ in 0..coordinated_scenario_retries() { coordinated_scenario( @@ -182,6 +183,7 @@ mod tests { #[test] #[timeout(120000)] #[flaky(5)] + #[ignore] // TEMPORARILY IGNORED AS IT IS VERY FLAKY ON CI async fn coordinated_scenario_03_01(deps: &EnvBasedTestDependencies, _tracing: &Tracing) { for _ in 0..coordinated_scenario_retries() { coordinated_scenario( @@ -204,6 +206,7 @@ mod tests { #[test] #[timeout(120000)] #[flaky(5)] + #[ignore] // TEMPORARILY IGNORED AS IT IS VERY FLAKY ON CI async fn service_is_responsive_to_shard_changes( deps: &EnvBasedTestDependencies, _tracing: &Tracing, From 873db135031b6b0ec5315c0c0b6ee64840f0a359 Mon Sep 17 00:00:00 2001 From: Daniel Vigovszky Date: Fri, 13 Dec 2024 21:12:03 +0100 Subject: [PATCH 8/8] Restore build release during publish (#1192) --- Makefile.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.toml b/Makefile.toml index 668997614..c3d59a7d6 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -375,7 +375,7 @@ args = ["-v", "./target/golem-service.yaml", "./openapi/golem-service.yaml"] [tasks.publish] description = "Publishes packages to crates.io" dependencies = [ - "set-version", + "build-release", "publish-golem-wasm-ast", "publish-golem-wasm-rpc", "publish-golem-wasm-rpc-stubgen",