diff --git a/Cargo.lock b/Cargo.lock index bdf8fd0..cef0638 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,20 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "serde", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -195,18 +209,45 @@ dependencies = [ "which", ] +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + [[package]] name = "bitflags" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "borrow-or-share" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eeab4423108c5d7c744f4d234de88d18d636100093ae04caf4825134b9c3a32" + [[package]] name = "bumpalo" version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +[[package]] +name = "bytecount" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce" + [[package]] name = "byteorder" version = "1.5.0" @@ -435,6 +476,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + [[package]] name = "edgelink-app" version = "0.1.0" @@ -472,6 +524,7 @@ dependencies = [ "edgelink-macro", "inventory", "itertools 0.13.0", + "jsonschema", "log", "log4rs", "nom", @@ -482,6 +535,7 @@ dependencies = [ "semver", "serde", "serde_json", + "serde_yaml", "smallstr", "smallvec", "thiserror", @@ -533,6 +587,15 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +[[package]] +name = "email_address" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e079f19b08ca6239f47f8ba8509c11cf3ea30095831f7fed61441475edd8c449" +dependencies = [ + "serde", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -570,12 +633,53 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "fancy-regex" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "531e46835a22af56d1e3b66f04844bed63158bc094a628bec1d321d9b4c44bf2" +dependencies = [ + "bit-set", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "fluent-uri" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1918b65d96df47d3591bed19c5cca17e3fa5d0707318e4b5ef2eae01764df7e5" +dependencies = [ + "borrow-or-share", + "ref-cast", + "serde", +] + [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fraction" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f158e3ff0a1b334408dc9fb811cd99b446986f4d8b741bb08f9df1604085ae7" +dependencies = [ + "lazy_static", + "num", +] + [[package]] name = "futures" version = "0.3.30" @@ -721,12 +825,90 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" + [[package]] name = "humantime" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +[[package]] +name = "hyper" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + [[package]] name = "iana-time-zone" version = "0.1.61" @@ -750,12 +932,152 @@ dependencies = [ "cc", ] +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + [[package]] name = "ident_case" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "idna" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd69211b9b519e98303c015e21a007e293db403b6c85b9b124e133d25e242cdd" +dependencies = [ + "icu_normalizer", + "icu_properties", + "smallvec", + "utf8_iter", +] + [[package]] name = "indexmap" version = "2.5.0" @@ -778,6 +1100,12 @@ version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f958d3d68f4167080a18141e10381e7634563984a537f2a49a30fd8e53ac5767" +[[package]] +name = "ipnet" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" + [[package]] name = "is_terminal_polyfill" version = "1.70.1" @@ -817,6 +1145,33 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "jsonschema" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bea85509e7320309cc8be62d8badb46f9525157bdc748bf2ec089cd4083a3f7e" +dependencies = [ + "ahash", + "anyhow", + "base64", + "bytecount", + "email_address", + "fancy-regex", + "fraction", + "idna 1.0.2", + "itoa", + "num-cmp", + "once_cell", + "percent-encoding", + "referencing", + "regex-syntax", + "reqwest", + "serde", + "serde_json", + "url", + "uuid-simd", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -861,6 +1216,12 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +[[package]] +name = "litemap" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" + [[package]] name = "lock_api" version = "0.4.12" @@ -928,6 +1289,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -965,6 +1332,45 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-cmp" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63335b2e2c34fae2fb0aa2cecfd9f0832a1e24b3b32ecec612c3426d46dc8aaa" + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + [[package]] name = "num-derive" version = "0.4.2" @@ -976,6 +1382,37 @@ dependencies = [ "syn 2.0.79", ] +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -996,9 +1433,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "ordered-float" @@ -1009,6 +1446,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "outref" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4030760ffd992bef45b0ae3f10ce1aba99e33464c90d14dd7c039884963ddc7a" + [[package]] name = "parking" version = "2.2.1" @@ -1044,6 +1487,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + [[package]] name = "pin-project-lite" version = "0.2.14" @@ -1259,6 +1708,39 @@ dependencies = [ "thiserror", ] +[[package]] +name = "ref-cast" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf0a6f84d5f1d581da8b41b47ec8600871962f2a528115b542b362d4b744931" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "referencing" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bdf02a06a0820fcb9ce064715b424f1cdd79e24f991990a92425afe11eaf4a" +dependencies = [ + "ahash", + "fluent-uri", + "once_cell", + "percent-encoding", + "serde_json", +] + [[package]] name = "regex" version = "1.11.0" @@ -1294,6 +1776,42 @@ version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" +[[package]] +name = "reqwest" +version = "0.12.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" +dependencies = [ + "base64", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-registry", +] + [[package]] name = "rquickjs" version = "0.6.2" @@ -1451,6 +1969,31 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "shlex" version = "1.3.0" @@ -1501,6 +2044,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "strsim" version = "0.11.1" @@ -1529,6 +2078,26 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + [[package]] name = "target-lexicon" version = "0.12.16" @@ -1565,6 +2134,31 @@ dependencies = [ "winapi", ] +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "tokio" version = "1.40.0" @@ -1666,6 +2260,12 @@ dependencies = [ "winnow 0.6.20", ] +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + [[package]] name = "tracing" version = "0.1.40" @@ -1697,6 +2297,12 @@ dependencies = [ "once_cell", ] +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + [[package]] name = "typemap-ors" version = "1.0.0" @@ -1706,12 +2312,27 @@ dependencies = [ "unsafe-any-ors", ] +[[package]] +name = "unicode-bidi" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" + [[package]] name = "unicode-ident" version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +[[package]] +name = "unicode-normalization" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +dependencies = [ + "tinyvec", +] + [[package]] name = "unicode-segmentation" version = "1.12.0" @@ -1733,6 +2354,35 @@ dependencies = [ "destructure_traitobject", ] +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "url" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +dependencies = [ + "form_urlencoded", + "idna 0.5.0", + "percent-encoding", +] + +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" version = "0.2.2" @@ -1748,12 +2398,38 @@ dependencies = [ "getrandom", ] +[[package]] +name = "uuid-simd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b082222b4f6619906941c17eb2297fff4c2fb96cb60164170522942a200bd8" +dependencies = [ + "outref", + "uuid", + "vsimd", +] + [[package]] name = "version_check" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "vsimd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -1786,6 +2462,18 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.93" @@ -1815,6 +2503,16 @@ version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +[[package]] +name = "web-sys" +version = "0.3.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "which" version = "4.4.2" @@ -1858,6 +2556,36 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "windows-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets", +] + [[package]] name = "windows-sys" version = "0.52.0" @@ -1949,6 +2677,42 @@ dependencies = [ "memchr", ] +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "yoke" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", + "synstructure", +] + [[package]] name = "zerocopy" version = "0.7.35" @@ -1969,3 +2733,46 @@ dependencies = [ "quote", "syn 2.0.79", ] + +[[package]] +name = "zerofrom" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", + "synstructure", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] diff --git a/Cargo.toml b/Cargo.toml index 02ce01e..e9b4b89 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,6 +46,7 @@ config = { version = "0.14", default-features = false, features = [ "convert-case", "toml", ] } +serde_yaml = {version = "0.9.33"} serde = { version = "1" } serde_json = "1" dashmap = { version = "6", features = ["serde"] } diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index 2a5dfd0..5d5f352 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -10,6 +10,7 @@ name = "edgelink_core" [dependencies] anyhow.workspace = true +jsonschema="0.23.0" tokio = { workspace = true, features = [ "rt", "rt-multi-thread", @@ -49,8 +50,10 @@ itertools.workspace = true smallvec.workspace = true smallstr.workspace = true inventory.workspace = true +serde_yaml.workspace = true arrayvec = { workspace = true, features = ["std", "serde"] } + [dev-dependencies] # Enable test-utilities in dev mode only. This is mostly for tests. tokio = { workspace = true, features = ["test-util"] } diff --git a/crates/core/src/runtime/model/json/mod.rs b/crates/core/src/runtime/model/json/mod.rs index 747f8dd..68fc987 100644 --- a/crates/core/src/runtime/model/json/mod.rs +++ b/crates/core/src/runtime/model/json/mod.rs @@ -5,6 +5,7 @@ use serde_json::Value as JsonValue; pub mod deser; pub mod helpers; +pub mod npdeser; #[derive(serde::Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Clone)] pub struct RedPortConfig { diff --git a/crates/core/src/runtime/model/json/npdeser.rs b/crates/core/src/runtime/model/json/npdeser.rs new file mode 100644 index 0000000..2d5aabd --- /dev/null +++ b/crates/core/src/runtime/model/json/npdeser.rs @@ -0,0 +1,177 @@ +//! [npdeser] this mod use to de deserializer node logic properties transport to real logic. +//! +//! # example +//! > this appendNewline config is belong to node red core node [file], Used to determine whether +//! > to wrap a file ,it's could It should be a boolean type, but the code logic allows it to be +//! > any non undefined, true false 0 and 1, and any character ,and any str. so need this mod handle +//! > this scene +//! ```js +//! this.appendNewline = n.appendNewline; +//! +//! if ((node.appendNewline) && (!Buffer.isBuffer(data)) && aflg) { data += os.EOL; } +//! ``` +//! +#![allow(dead_code)] +use serde::de::{Error, Unexpected, Visitor}; +use serde::{de, Deserializer}; +use std::str; + +pub fn deser_bool_in_if_condition<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + struct BoolVisitor; + + impl<'de> de::Visitor<'de> for BoolVisitor { + type Value = bool; + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("a bool, convert failed") + } + fn visit_bytes(self, v: &[u8]) -> Result + where + E: Error, + { + match str::from_utf8(v) { + Ok(s) => { + if let Some(value) = Self::convert_to_bool(s) { + return value; + } + Ok(true) + } + Err(_) => Err(Error::invalid_value(Unexpected::Bool(false), &self)), + } + } + fn visit_u64(self, v: u64) -> Result + where + E: Error, + { + if v == 0 { + return Ok(false); + } + Ok(true) + } + fn visit_i64(self, v: i64) -> Result + where + E: Error, + { + if v == 0 { + return Ok(false); + } + Ok(true) + } + fn visit_u32(self, v: u32) -> Result + where + E: Error, + { + if v == 0 { + return Ok(false); + } + Ok(true) + } + fn visit_i32(self, v: i32) -> Result + where + E: Error, + { + if v == 0 { + return Ok(false); + } + Ok(true) + } + + fn visit_f64(self, v: f64) -> Result + where + E: Error, + { + if v == 0.0 { + return Ok(false); + } + Ok(true) + } + + fn visit_f32(self, v: f32) -> Result + where + E: Error, + { + if v == 0.0 { + return Ok(false); + } + Ok(true) + } + + fn visit_str(self, v: &str) -> Result + where + E: Error, + { + if let Some(value) = Self::convert_to_bool(v) { + return value; + } + Ok(true) + } + } + + impl BoolVisitor { + fn convert_to_bool(v: &str) -> Option::Value, E>> + where + E: Error, + { + if v.is_empty() || v == "0" || v.contains("false") || v.contains("False") || v.contains("FALSE") { + return Some(Ok(false)); + } + None + } + } + + deserializer.deserialize_any(BoolVisitor) +} + +#[cfg(test)] +mod tests { + use super::*; + use serde::Deserialize; + use serde_json::json; + + #[derive(Deserialize, Debug)] + struct TestNodeConfig { + #[serde(deserialize_with = "crate::runtime::model::json::npdeser::deser_bool_in_if_condition")] + test: bool, + } + + #[test] + fn test_deser_bool_in_if_condition() { + let value_str = json!({"test":"xxx"}); + let result = TestNodeConfig::deserialize(value_str).unwrap(); + assert!(result.test); + + let value_str = json!({"test":"true"}); + let result = TestNodeConfig::deserialize(value_str).unwrap(); + assert!(result.test); + + let value_str = json!({"test":"false"}); + let result = TestNodeConfig::deserialize(value_str).unwrap(); + assert!(!result.test); + + let value_str = json!({"test":"False"}); + let result = TestNodeConfig::deserialize(value_str).unwrap(); + assert!(!result.test); + + let value_str = json!({"test":"0"}); + let result = TestNodeConfig::deserialize(value_str).unwrap(); + assert!(!result.test); + + let value_str = json!({"test":1.0}); + let result = TestNodeConfig::deserialize(value_str).unwrap(); + assert!(result.test); + + let value_str = json!({"test":0.0}); + let result = TestNodeConfig::deserialize(value_str).unwrap(); + assert!(!result.test); + + let value_str = json!({"test":0}); + let result = TestNodeConfig::deserialize(value_str).unwrap(); + assert!(!result.test); + + let value_str = json!({"test":1}); + let result = TestNodeConfig::deserialize(value_str).unwrap(); + assert!(result.test); + } +} diff --git a/crates/core/src/runtime/nodes/mod.rs b/crates/core/src/runtime/nodes/mod.rs index 2126c78..fa862c2 100644 --- a/crates/core/src/runtime/nodes/mod.rs +++ b/crates/core/src/runtime/nodes/mod.rs @@ -19,6 +19,8 @@ use crate::*; pub(crate) mod common_nodes; mod function_nodes; +mod parsers_nodes; + #[cfg(feature = "net")] mod network_nodes; diff --git a/crates/core/src/runtime/nodes/parsers_nodes/json.rs b/crates/core/src/runtime/nodes/parsers_nodes/json.rs new file mode 100644 index 0000000..2d2bb15 --- /dev/null +++ b/crates/core/src/runtime/nodes/parsers_nodes/json.rs @@ -0,0 +1,217 @@ +use itertools::Itertools; +use jsonschema::Validator; +use serde::Deserialize; +use serde_json::Value; +use tokio::sync::RwLockWriteGuard; + +use crate::runtime::flow::Flow; +use crate::runtime::nodes::*; +use edgelink_macro::*; + +#[derive(Debug)] +#[flow_node("json")] +struct JsonNode { + base: FlowNode, + config: JsonNodeConfig, +} +#[derive(Deserialize, Debug)] +struct JsonNodeConfig { + #[serde(skip, default)] + pub pretty: bool, + #[serde(skip, default)] + pub action: String, + #[serde(skip, default)] + pub property: String, + pub scheme: String, + #[serde(skip, default)] + pub compile_schema: Option, +} +impl JsonNode { + fn build(_flow: &Flow, state: FlowNode, config: &RedFlowNodeConfig) -> crate::Result> { + let mut json_config = JsonNodeConfig::deserialize(&config.rest)?; + let schema = serde_json::from_str(json_config.scheme.as_str())?; + if let Ok(validator) = jsonschema::options().build(&schema) { + json_config.compile_schema = Some(validator); + } + if let Some(pro) = config.rest.get("property").map(|x| { + if let Value::String(pro) = x { + pro.to_string() + } else { + "payload".to_string() + } + }) { + json_config.property = pro; + } + + if let Some(action) = config.rest.get("action").map(|x| { + if let Value::String(act) = x { + act.to_string() + } else { + "".to_string() + } + }) { + json_config.action = action; + } + if let Some(pretty) = + config.rest.get("pretty").map(|x| matches!(x,&Value::Null)) + { + json_config.pretty = pretty; + } + let node = JsonNode { base: state, config: json_config }; + Ok(Box::new(node)) + } +} + +impl JsonNode { + async fn uow(&self, msg: MsgHandle) -> crate::Result<()> { + let mut msg_guard = msg.write().await; + + let mut validate = false; + let valid = self.config.compile_schema.as_ref().unwrap(); + match msg_guard.get("schema") { + None => {} + Some(schema) => { + if let Variant::String(schema) =schema { + if schema != &self.config.scheme { + let schema = serde_json::from_str(schema)?; + if let Ok(_validator) = jsonschema::options().build(&schema) { + // todo json node 需要进行对node的更改. + // self.config.compile_schema=validator; + } + } + } + validate = true; + } + } + + let message_key = &self.config.property; + let option = msg_guard.get(message_key).cloned(); + match option { + None => {} + Some(message) => { + match message { + Variant::String(message) => { + if self.config.action.is_empty() || self.config.action == "obj" { + match serde_yaml::from_str(&message) { + Ok(Value::Object(value)) => { + let variant = Value::Object(value); + if validate { + match valid.validate(&variant) { + Ok(_) => { + msg_guard.remove("schema"); + } + Err(err) => msg_guard.set( + "schemaError".to_string(), + Variant::from(err.into_iter().map(|e| e.to_string()).join(",")), + ), + }; + } + msg_guard.set(message_key.to_string(), Variant::from(variant)); + } + Ok(_) => {} + Err(err) => { + return Err(err.into()); + } + } + } else if validate { + match serde_yaml::from_str(&message) { + Ok(Variant::String(value)) => { + let value1 = serde_json::Value::String(value); + match valid.validate(&value1) { + Ok(_) => { + msg_guard.remove("schema"); + } + Err(err) => { + msg_guard.set( + "schemaError".to_string(), + Variant::from(err.into_iter().map(|e| e.to_string()).join(",")), + ) + // todo done(`${RED._("json.errors.schema-error")}: ${ajv.errorsText(this.compiledSchema.errors)}`); + } + }; + } + _ => { + // todo done(`${RED._("json.errors.schema-error")}: ${ajv.errorsText(this.compiledSchema.errors)}`); + } + } + } + } + Variant::Object(message_obj) => { + self.handle_deser(&mut msg_guard, validate, valid, message_key, Variant::Object(message_obj)); + } + Variant::Bool(message_obj) => { + self.handle_deser(&mut msg_guard, validate, valid, message_key, Variant::Bool(message_obj)); + } + Variant::Number(message_obj) => { + self.handle_deser(&mut msg_guard, validate, valid, message_key, Variant::Number(message_obj)); + } + _ => { + // send(msg); done(); + } + } + } + } + Ok(()) + } + + fn handle_deser( + &self, + msg_guard: &mut RwLockWriteGuard, + validate: bool, + valid: &Validator, + message_key: &String, + message_obj: Variant, + ) { + let value: Value = serde_json::from_str(&message_obj.to_string().unwrap()).unwrap(); + if self.config.action.is_empty() || self.config.action == "str" { + if validate { + match valid.validate(&value) { + Ok(_) => { + msg_guard.set( + message_key.to_string(), + Variant::String(serde_json::to_string(&value).unwrap_or_default()), + ); + msg_guard.remove("schema"); + } + Err(err) => { + msg_guard.set( + "schemaError".to_string(), + Variant::from(err.into_iter().map(|e| e.to_string()).join(",")), + ) + // todo done(`${RED._("json.errors.schema-error")}: ${ajv.errorsText(this.compiledSchema.errors)}`); + } + }; + } else { + msg_guard + .set(message_key.to_string(), Variant::String(serde_json::to_string(&value).unwrap_or_default())); + } + } else if validate { + match valid.validate(&value) { + Ok(_) => { + msg_guard.remove("schema"); + } + Err(err) => { + msg_guard.set( + "schemaError".to_string(), + Variant::from(err.into_iter().map(|e| e.to_string()).join(",")), + ) + // todo done(`${RED._("json.errors.schema-error")}: ${ajv.errorsText(this.compiledSchema.errors)}`); + } + }; + } + } +} + +#[async_trait] +impl FlowNodeBehavior for JsonNode { + fn get_node(&self) -> &FlowNode { + &self.base + } + + async fn run(self: Arc, stop_token: CancellationToken) { + while !stop_token.is_cancelled() { + let node = self.clone(); + with_uow(node.as_ref(), stop_token.clone(), |node, msg| async move { node.uow(msg).await }).await; + } + } +} diff --git a/crates/core/src/runtime/nodes/parsers_nodes/mod.rs b/crates/core/src/runtime/nodes/parsers_nodes/mod.rs new file mode 100644 index 0000000..561a72a --- /dev/null +++ b/crates/core/src/runtime/nodes/parsers_nodes/mod.rs @@ -0,0 +1,2 @@ +pub mod json; +pub mod yaml; diff --git a/crates/core/src/runtime/nodes/parsers_nodes/yaml.rs b/crates/core/src/runtime/nodes/parsers_nodes/yaml.rs new file mode 100644 index 0000000..cd03488 --- /dev/null +++ b/crates/core/src/runtime/nodes/parsers_nodes/yaml.rs @@ -0,0 +1,77 @@ +use serde::Deserialize; + +use crate::runtime::flow::Flow; +use crate::runtime::nodes::*; +use edgelink_macro::*; + +#[derive(Debug)] +#[flow_node("yaml")] +struct YamlNode { + base: FlowNode, + config: YamlNodeConfig, +} + +impl YamlNode { + fn build(_flow: &Flow, state: FlowNode, config: &RedFlowNodeConfig) -> crate::Result> { + let mut yaml_config = YamlNodeConfig::deserialize(&config.rest)?; + // yaml_config.property = + if let Some(pro) = config.rest.get("property").map(|x| { + if let serde_json::Value::String(pro) = x { + pro.to_string() + } else { + "payload".to_string() + } + }) { + yaml_config.property = pro; + } + let node = YamlNode { base: state, config: yaml_config }; + Ok(Box::new(node)) + } +} + +#[derive(Deserialize, Debug)] +struct YamlNodeConfig { + #[serde(skip, default)] + pub property: String, +} + +impl YamlNode { + async fn uow(&self, msg: MsgHandle) -> crate::Result<()> { + let mut msg_guard = msg.write().await; + let message_key = &self.config.property; + let option = msg_guard.get(message_key); + match option { + None => {} + Some(message) => { + match message { + Variant::String(message) => { + if let Ok(Variant::Object(value)) = serde_yaml::from_str(message) { + msg_guard.set(message_key.to_owned(), Variant::Object(value)); + } + } + Variant::Object(message_obj) => { + let yaml_str = serde_yaml::to_string(&message_obj)?; + msg_guard.set(message_key.to_owned(), Variant::String(yaml_str)); + } + // Variant::Bytes(_) => {} + _ => {} + } + } + } + Ok(()) + } +} + +#[async_trait] +impl FlowNodeBehavior for YamlNode { + fn get_node(&self) -> &FlowNode { + &self.base + } + + async fn run(self: Arc, stop_token: CancellationToken) { + while !stop_token.is_cancelled() { + let node = self.clone(); + with_uow(node.as_ref(), stop_token.clone(), |node, msg| async move { node.uow(msg).await }).await; + } + } +}