diff --git a/.vscode/settings.json b/.vscode/settings.json index eefcdbe..fa25aec 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,8 +1,13 @@ { "cSpell.words": [ + "Graphi", + "graphiql", "hashbrown", "Hasher", + "Joylink", + "jsonwebtoken", "rtss", + "thiserror", "timestep", "trackside" ] diff --git a/Cargo.lock b/Cargo.lock index 5d189ca..b6d62b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,31 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + +[[package]] +name = "addr2line" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "ahash" version = "0.8.11" @@ -30,6 +55,27 @@ version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "ascii_utils" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71938f30533e4d95a6d17aa530939da3842c2ab6f4f84b9dae68447e4129f74a" + [[package]] name = "async-executor" version = "1.13.0" @@ -43,18 +89,252 @@ dependencies = [ "slab", ] +[[package]] +name = "async-graphql" +version = "7.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b76aba2f176af685c2229633881a3adeae51f87ae1811781e73910b7001c93e" +dependencies = [ + "async-graphql-derive", + "async-graphql-parser", + "async-graphql-value", + "async-stream", + "async-trait", + "base64 0.22.1", + "bytes", + "chrono", + "fast_chemail", + "fnv", + "futures-util", + "handlebars", + "http", + "indexmap", + "mime", + "multer", + "num-traits", + "once_cell", + "pin-project-lite", + "regex", + "serde", + "serde_json", + "serde_urlencoded", + "static_assertions_next", + "tempfile", + "thiserror", +] + +[[package]] +name = "async-graphql-axum" +version = "7.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686e48ce7820a1cf404b5c8e9b90ae24d03c867a408d8d651183945c7a554982" +dependencies = [ + "async-graphql", + "async-trait", + "axum", + "bytes", + "futures-util", + "serde_json", + "tokio", + "tokio-stream", + "tokio-util", + "tower-service", +] + +[[package]] +name = "async-graphql-derive" +version = "7.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72e2e26a6b44bc61df3ca8546402cf9204c28e30c06084cc8e75cd5e34d4f150" +dependencies = [ + "Inflector", + "async-graphql-parser", + "darling", + "proc-macro-crate", + "proc-macro2", + "quote", + "strum", + "syn", + "thiserror", +] + +[[package]] +name = "async-graphql-parser" +version = "7.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f801451484b4977d6fe67b29030f81353cabdcbb754e5a064f39493582dac0cf" +dependencies = [ + "async-graphql-value", + "pest", + "serde", + "serde_json", +] + +[[package]] +name = "async-graphql-value" +version = "7.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69117c43c01d81a69890a9f5dd6235f2f027ca8d1ec62d6d3c5e01ca0edb4f2b" +dependencies = [ + "bytes", + "indexmap", + "serde", + "serde_json", +] + +[[package]] +name = "async-stream" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "async-task" version = "4.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" +[[package]] +name = "async-trait" +version = "0.1.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "autocfg" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +[[package]] +name = "axum" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" +dependencies = [ + "async-trait", + "axum-core", + "base64 0.21.7", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sha1", + "sync_wrapper 1.0.1", + "tokio", + "tokio-tungstenite", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-core" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper 0.1.2", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-extra" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0be6ea09c9b96cb5076af0de2e383bd2bc0c18f827cf1967bdd353e0b910d733" +dependencies = [ + "axum", + "axum-core", + "bytes", + "futures-util", + "headers", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "serde", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "backtrace" +version = "0.3.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "bevy_app" version = "0.14.1" @@ -138,7 +418,7 @@ dependencies = [ "proc-macro2", "quote", "syn", - "toml_edit", + "toml_edit 0.22.20", ] [[package]] @@ -234,18 +514,66 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "bumpalo" version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +dependencies = [ + "serde", +] + +[[package]] +name = "cc" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72db2f7947ecee9b03b510377e8bb9077afa27176fdbff55c51027e976fdcc48" +dependencies = [ + "shlex", +] + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-targets", +] + [[package]] name = "concurrent-queue" version = "2.5.0" @@ -265,6 +593,21 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" +dependencies = [ + "libc", +] + [[package]] name = "crossbeam-channel" version = "0.5.13" @@ -299,6 +642,76 @@ version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + [[package]] name = "downcast-rs" version = "1.2.1" @@ -311,6 +724,15 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +[[package]] +name = "encoding_rs" +version = "0.8.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +dependencies = [ + "cfg-if", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -327,6 +749,25 @@ dependencies = [ "typeid", ] +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "fast_chemail" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "495a39d30d624c2caabe6312bfead73e7717692b44e0b32df168c275a2e8e9e4" +dependencies = [ + "ascii_utils", +] + [[package]] name = "fastrand" version = "2.1.0" @@ -345,6 +786,30 @@ version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" +[[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 = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", +] + [[package]] name = "futures-core" version = "0.3.30" @@ -370,6 +835,56 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" version = "0.2.15" @@ -383,6 +898,26 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gimli" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" + +[[package]] +name = "handlebars" +version = "5.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d08485b96a0e6393e9e4d1b8d48cf74ad6c063cd905eb33f42c1ce3f0377539b" +dependencies = [ + "log", + "pest", + "pest_derive", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "hashbrown" version = "0.14.5" @@ -394,6 +929,161 @@ dependencies = [ "serde", ] +[[package]] +name = "headers" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322106e6bd0cba2d5ead589ddb8150a13d7c4217cf80d7c4f682ca994ccc6aa9" +dependencies = [ + "base64 0.21.7", + "bytes", + "headers-core", + "http", + "httpdate", + "mime", + "sha1", +] + +[[package]] +name = "headers-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" +dependencies = [ + "http", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", +] + +[[package]] +name = "hyper-util" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" +dependencies = [ + "bytes", + "futures-util", + "http", + "http-body", + "hyper", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[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 = "indexmap" version = "2.3.0" @@ -402,8 +1092,15 @@ checksum = "de3fc2e30ba82dd1b3911c8de1ffc143c74a914a14e99514d7637e3099df5ea0" dependencies = [ "equivalent", "hashbrown", + "serde", ] +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + [[package]] name = "js-sys" version = "0.3.69" @@ -413,6 +1110,21 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "jsonwebtoken" +version = "9.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ae10193d25051e74945f1ea2d0b42e03cc3b890f7e4cc5faa44997d808193f" +dependencies = [ + "base64 0.21.7", + "js-sys", + "pem", + "ring", + "serde", + "serde_json", + "simple_asn1", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -425,6 +1137,12 @@ version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + [[package]] name = "log" version = "0.4.22" @@ -440,12 +1158,62 @@ dependencies = [ "regex-automata 0.1.10", ] +[[package]] +name = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +dependencies = [ + "hermit-abi", + "libc", + "wasi", + "windows-sys 0.52.0", +] + +[[package]] +name = "multer" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83e87776546dc87511aa5ee218730c92b666d7264ab6ed41f9d215af9cd5224b" +dependencies = [ + "bytes", + "encoding_rs", + "futures-util", + "http", + "httparse", + "memchr", + "mime", + "spin", + "version_check", +] + [[package]] name = "nonmax" version = "0.5.5" @@ -462,6 +1230,49 @@ dependencies = [ "winapi", ] +[[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-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[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-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "object" +version = "0.36.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.19.0" @@ -480,6 +1291,67 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" +[[package]] +name = "pem" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" +dependencies = [ + "base64 0.22.1", + "serde", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pest" +version = "2.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd53dff83f26735fdc1ca837098ccf133605d794cdae66acfc2bfac3ec809d95" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a548d2beca6773b1c244554d36fcf8548a8a58e74156968211567250e48e49a" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c93a82e8d145725dcbaf44e5ea887c8a869efdcc28706df2d08c69e17077183" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pest_meta" +version = "2.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a941429fea7e08bedec25e4f6785b6ffaacc6b755da98df5ef3e7dcf4a124c4f" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + [[package]] name = "petgraph" version = "0.6.5" @@ -490,12 +1362,62 @@ dependencies = [ "indexmap", ] +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "pin-project-lite" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit 0.21.1", +] + [[package]] name = "proc-macro2" version = "1.0.86" @@ -514,6 +1436,36 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + [[package]] name = "rayon" version = "1.10.0" @@ -578,25 +1530,51 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + [[package]] name = "rtss_api" version = "0.1.0" +dependencies = [ + "async-graphql", + "async-graphql-axum", + "axum", + "axum-extra", + "base64 0.22.1", + "bevy_ecs", + "chrono", + "jsonwebtoken", + "rtss_log", + "rtss_sim_manage", + "rtss_trackside", + "serde", + "serde_json", + "tokio", + "tower-http", +] [[package]] name = "rtss_ci" version = "0.1.0" [[package]] -name = "rtss_core" +name = "rtss_common" version = "0.1.0" dependencies = [ - "bevy_app", - "bevy_core", "bevy_ecs", - "bevy_time", - "rayon", - "rtss_log", - "rtss_trackside", ] [[package]] @@ -612,12 +1590,28 @@ dependencies = [ "tracing-wasm", ] +[[package]] +name = "rtss_sim_manage" +version = "0.1.0" +dependencies = [ + "bevy_app", + "bevy_core", + "bevy_ecs", + "bevy_time", + "rayon", + "rtss_common", + "rtss_log", + "rtss_trackside", + "thiserror", +] + [[package]] name = "rtss_simulation" version = "0.1.0" dependencies = [ - "rtss_core", + "rtss_api", "rtss_log", + "tokio", ] [[package]] @@ -628,29 +1622,117 @@ dependencies = [ "bevy_core", "bevy_ecs", "bevy_time", + "rtss_common", "rtss_log", ] [[package]] -name = "serde" -version = "1.0.205" +name = "rustc-demangle" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33aedb1a7135da52b7c21791455563facbbcc43d0f0f66165b42c21b3dfb150" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustversion" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "serde" +version = "1.0.208" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.205" +version = "1.0.208" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692d6f5ac90220161d6774db30c662202721e64aed9058d2c394f451261420c1" +checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" dependencies = [ "proc-macro2", "quote", "syn", ] +[[package]] +name = "serde_json" +version = "1.0.125" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" +dependencies = [ + "itoa", + "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 = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sharded-slab" version = "0.1.7" @@ -660,6 +1742,24 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "simple_asn1" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror", + "time", +] + [[package]] name = "slab" version = "0.4.9" @@ -684,6 +1784,56 @@ dependencies = [ "serde", ] +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "static_assertions_next" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7beae5182595e9a8b683fa98c4317f956c9a2dec3b9716990d20023cc60c766" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + [[package]] name = "syn" version = "2.0.72" @@ -695,6 +1845,31 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "sync_wrapper" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" + +[[package]] +name = "tempfile" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +dependencies = [ + "cfg-if", + "fastrand", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + [[package]] name = "thiserror" version = "1.0.63" @@ -725,12 +1900,133 @@ dependencies = [ "once_cell", ] +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +dependencies = [ + "num-conv", + "time-core", +] + +[[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.39.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9babc99b9923bfa4804bd74722ff02c0381021eafa4db9949217e3be8e84fff5" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-stream" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite", +] + +[[package]] +name = "tokio-util" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +dependencies = [ + "bytes", + "futures-core", + "futures-io", + "futures-sink", + "pin-project-lite", + "tokio", +] + [[package]] name = "toml_datetime" version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow 0.5.40", +] + [[package]] name = "toml_edit" version = "0.22.20" @@ -739,15 +2035,60 @@ checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" dependencies = [ "indexmap", "toml_datetime", - "winnow", + "winnow 0.6.18", ] +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" +dependencies = [ + "bitflags", + "bytes", + "http", + "http-body", + "http-body-util", + "pin-project-lite", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -814,18 +2155,87 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "tungstenite" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand", + "sha1", + "thiserror", + "url", + "utf-8", +] + [[package]] name = "typeid" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "059d83cc991e7a42fc37bd50941885db0888e34209f8cfd9aab07ddec03bc9cf" +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + [[package]] name = "uuid" version = "1.10.0" @@ -961,6 +2371,106 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + [[package]] name = "winnow" version = "0.6.18" @@ -976,6 +2486,7 @@ version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] diff --git a/Cargo.toml b/Cargo.toml index d5247cf..446048f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,10 @@ bevy_core = "0.14.1" bevy_ecs = "0.14.1" bevy_time = "0.14.1" rayon = "1.10.0" +tokio = { version = "1.39.3", features = ["macros", "rt-multi-thread"] } +thiserror = "1.0.63" [dependencies] -rtss_core = { path = "crates/rtss_core" } +tokio = { version = "1.39.3", features = ["macros", "rt-multi-thread"] } rtss_log = { path = "crates/rtss_log" } +rtss_api = { path = "crates/rtss_api" } diff --git a/crates/rtss_api/Cargo.toml b/crates/rtss_api/Cargo.toml index 2d237e0..e51828f 100644 --- a/crates/rtss_api/Cargo.toml +++ b/crates/rtss_api/Cargo.toml @@ -4,3 +4,19 @@ version = "0.1.0" edition = "2021" [dependencies] +tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } +serde = { version = "1.0.208", features = ["derive"] } +serde_json = "1.0.125" +chrono = { version = "0.4.38", features = ["serde"] } +axum = "0.7.5" +axum-extra = { version = "0.9.3", features = ["typed-header"] } +jsonwebtoken = "9.3.0" +tower-http = { version = "0.5.0", features = ["cors"] } +async-graphql = { version = "7.0.7", features = ["chrono"] } +async-graphql-axum = "7.0.6" +base64 = "0.22.1" + +bevy_ecs = { workspace = true } +rtss_log = { path = "../rtss_log" } +rtss_sim_manage = { path = "../rtss_sim_manage" } +rtss_trackside = { path = "../rtss_trackside" } diff --git a/crates/rtss_api/src/jwt_auth.rs b/crates/rtss_api/src/jwt_auth.rs new file mode 100644 index 0000000..65e18b7 --- /dev/null +++ b/crates/rtss_api/src/jwt_auth.rs @@ -0,0 +1,82 @@ +use std::sync::LazyLock; + +use async_graphql::Result; +use axum::http::HeaderMap; +use jsonwebtoken::{decode, DecodingKey, Validation}; +use rtss_log::tracing::error; +use serde::{Deserialize, Serialize}; + +static KEYS: LazyLock = LazyLock::new(|| { + // let secret = std::env::var("JWT_SECRET").expect("JWT_SECRET must be set"); + let secret = "joylink".to_string(); + Keys::new(secret.as_bytes()) +}); + +struct Keys { + // encoding: EncodingKey, + decoding: DecodingKey, +} + +impl Keys { + pub fn new(secret: &[u8]) -> Self { + Self { + // encoding: EncodingKey::from_secret(secret), + decoding: DecodingKey::from_secret(secret), + } + } +} + +#[derive(Debug)] +pub enum AuthError { + InvalidToken, +} + +pub(crate) fn get_token_from_headers(headers: HeaderMap) -> Result, AuthError> { + let option_token = headers.get("Token"); + if let Some(token) = option_token { + let token_data = decode::( + token.to_str().unwrap(), + &KEYS.decoding, + &Validation::default(), + ) + .map_err(|err| { + error!("Error decoding token: {:?}", err); + AuthError::InvalidToken + })?; + Ok(Some(token_data.claims)) + } else { + Ok(None) + } +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct Claims { + pub id: u32, + pub sub: String, +} + +#[cfg(test)] +mod tests { + + use super::*; + + #[test] + fn test_get_token_from_headers() { + rtss_log::Logging::default().init(); + let mut headers: HeaderMap = HeaderMap::new(); + headers.insert("Token", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjQ2NzAyMjcsImlkIjo2LCJvcmlnX2lhdCI6MTcyNDIzODIyNywic3ViIjoiNiJ9.sSfjdW7d3OqOE6G1p47c4dcCan4evRGoNjGPUyVfWLk".parse().unwrap()); + let result = get_token_from_headers(headers); + match result { + Ok(Some(claims)) => { + assert_eq!(claims.id, 6); + assert_eq!(claims.sub, "6"); + } + Ok(None) => { + panic!("Expected Some(claims), got None"); + } + Err(e) => { + panic!("Error: {:?}", e); + } + } + } +} diff --git a/crates/rtss_api/src/lib.rs b/crates/rtss_api/src/lib.rs index b93cf3f..d13df9a 100644 --- a/crates/rtss_api/src/lib.rs +++ b/crates/rtss_api/src/lib.rs @@ -1,3 +1,9 @@ +mod jwt_auth; +mod server; +mod simulation; +mod simulation_operation; +pub use server::*; + pub fn add(left: u64, right: u64) -> u64 { left + right } diff --git a/crates/rtss_api/src/server.rs b/crates/rtss_api/src/server.rs new file mode 100644 index 0000000..0e9ca6e --- /dev/null +++ b/crates/rtss_api/src/server.rs @@ -0,0 +1,119 @@ +use std::ops::Deref; + +use async_graphql::*; +use async_graphql::{EmptySubscription, Schema}; +use async_graphql_axum::{GraphQLRequest, GraphQLResponse}; +use axum::extract::State; +use axum::http::HeaderMap; +use axum::{ + http::{HeaderValue, Method}, + response::{Html, IntoResponse}, + routing::get, + Router, +}; +use http::{playground_source, GraphQLPlaygroundConfig}; +use rtss_log::tracing::{debug, error, info}; +use rtss_sim_manage::SimulationManager; +use tokio::net::TcpListener; +use tokio::sync::Mutex; +use tower_http::cors::CorsLayer; + +use crate::{jwt_auth, simulation}; + +pub struct ServerConfig { + pub port: u16, +} + +impl Default for ServerConfig { + fn default() -> Self { + Self { port: 8080 } + } +} + +impl ServerConfig { + pub fn new(port: u16) -> Self { + Self { port } + } + + pub fn with_port(mut self, port: u16) -> Self { + self.port = port; + self + } + + pub fn to_socket_addr(&self) -> String { + format!("0.0.0.0:{}", self.port) + } +} + +pub async fn serve(config: ServerConfig) { + let schema = new_schema().await; + + let app = Router::new() + .route("/", get(graphiql).post(graphql_handler)) + .with_state(schema) + .layer( + CorsLayer::new() + .allow_origin("*".parse::().unwrap()) + .allow_headers(tower_http::cors::Any) + .allow_methods([Method::GET, Method::POST]), + ); + + debug!("Server started at http://{}", config.to_socket_addr()); + info!("GraphiQL IDE: http://localhost:{}", config.port); + axum::serve( + TcpListener::bind(config.to_socket_addr()).await.unwrap(), + app, + ) + .await + .unwrap(); +} + +async fn graphql_handler( + State(schema): State, + headers: HeaderMap, + req: GraphQLRequest, +) -> GraphQLResponse { + let mut req = req.into_inner(); + let token = jwt_auth::get_token_from_headers(headers); + match token { + Ok(token) => { + req = req.data(token); + } + Err(e) => { + error!("Error getting token from headers: {:?}", e); + } + } + schema.execute(req).await.into() +} + +async fn graphiql() -> impl IntoResponse { + Html(playground_source(GraphQLPlaygroundConfig::new("/"))) +} + +pub type SimulationSchema = Schema; + +#[derive(Default, MergedObject)] +pub struct Query(simulation::SimulationQuery); + +#[derive(Default, MergedObject)] +pub struct Mutation(simulation::SimulationMutation); + +pub struct MutexSimulationManager(Mutex); +impl Default for MutexSimulationManager { + fn default() -> Self { + Self(Mutex::new(SimulationManager::default())) + } +} +impl Deref for MutexSimulationManager { + type Target = Mutex; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +pub async fn new_schema() -> SimulationSchema { + Schema::build(Query::default(), Mutation::default(), EmptySubscription) + .data(MutexSimulationManager::default()) + .finish() +} diff --git a/crates/rtss_api/src/simulation.rs b/crates/rtss_api/src/simulation.rs new file mode 100644 index 0000000..9b993e7 --- /dev/null +++ b/crates/rtss_api/src/simulation.rs @@ -0,0 +1,106 @@ +use async_graphql::{Context, InputObject, Object}; +use rtss_log::tracing::info; +use rtss_sim_manage::{AvailablePlugins, SimulationBuilder}; + +use crate::{jwt_auth::Claims, simulation_operation::SimulationOperation, MutexSimulationManager}; + +#[derive(Default)] +pub struct SimulationQuery; + +#[Object] +impl SimulationQuery { + async fn simulations<'ctx>(&self, ctx: &Context<'ctx>) -> usize { + let sim = ctx.data::().unwrap(); + sim.lock().await.count() + } +} + +#[derive(Default)] +pub struct SimulationMutation; + +#[Object] +impl SimulationMutation { + async fn start_simulation<'ctx>( + &self, + ctx: &Context<'ctx>, + req: StartSimulationRequest, + ) -> async_graphql::Result { + let claims = ctx.data::>().unwrap(); + match claims { + Some(claims) => { + info!("User {claims:?} started simulation"); + } + _ => return Err("Unauthorized".into()), + } + let sim = ctx.data::().unwrap(); + let id = sim.lock().await.start_simulation( + SimulationBuilder::default() + .id(req.user_id) + .plugins(vec![AvailablePlugins::TrackSideEquipmentPlugin]), + )?; + Ok(id) + } + + async fn exit_simulation<'ctx>( + &self, + ctx: &Context<'ctx>, + id: String, + ) -> async_graphql::Result { + let sim = ctx.data::().unwrap(); + sim.lock().await.exit_simulation(id)?; + Ok(true) + } + + async fn pause_simulation<'ctx>( + &self, + ctx: &Context<'ctx>, + id: String, + ) -> async_graphql::Result { + let sim = ctx.data::().unwrap(); + sim.lock().await.pause_simulation(id)?; + Ok(true) + } + + async fn resume_simulation<'ctx>( + &self, + ctx: &Context<'ctx>, + id: String, + ) -> async_graphql::Result { + let sim = ctx.data::().unwrap(); + sim.lock().await.resume_simulation(id)?; + Ok(true) + } + + async fn update_simulation_speed<'ctx>( + &self, + ctx: &Context<'ctx>, + id: String, + speed: f32, + ) -> async_graphql::Result { + let sim = ctx.data::().unwrap(); + sim.lock().await.update_simulation_speed(id, speed)?; + Ok(true) + } + + async fn trigger_simulation_operation<'ctx>( + &self, + ctx: &Context<'ctx>, + id: String, + entity_uid: String, + operation: SimulationOperation, + ) -> async_graphql::Result { + let sim = ctx.data::().unwrap(); + sim.lock().await.trigger_entity_operation( + id, + entity_uid, + operation.to_operation_event(), + )?; + Ok(true) + } +} + +#[derive(InputObject)] +struct StartSimulationRequest { + user_id: String, + sim_def_id: String, +} diff --git a/crates/rtss_api/src/simulation_operation.rs b/crates/rtss_api/src/simulation_operation.rs new file mode 100644 index 0000000..0f82edc --- /dev/null +++ b/crates/rtss_api/src/simulation_operation.rs @@ -0,0 +1,17 @@ +use async_graphql::Enum; +use bevy_ecs::event::Event; + +#[derive(Enum, Copy, Clone, Eq, PartialEq, Debug)] +pub enum SimulationOperation { + TurnoutControlDC, + TurnoutControlFC, +} + +impl SimulationOperation { + pub fn to_operation_event(self) -> impl Event + Copy { + match self { + SimulationOperation::TurnoutControlDC => rtss_trackside::TurnoutControlEvent::DC, + SimulationOperation::TurnoutControlFC => rtss_trackside::TurnoutControlEvent::FC, + } + } +} diff --git a/crates/rtss_common/Cargo.toml b/crates/rtss_common/Cargo.toml new file mode 100644 index 0000000..2076315 --- /dev/null +++ b/crates/rtss_common/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "rtss_common" +version = "0.1.0" +edition = "2021" + +[dependencies] +bevy_ecs = {workspace = true} diff --git a/crates/rtss_common/src/lib.rs b/crates/rtss_common/src/lib.rs new file mode 100644 index 0000000..7acf0b5 --- /dev/null +++ b/crates/rtss_common/src/lib.rs @@ -0,0 +1,76 @@ +use std::{ + collections::HashMap, + sync::{Arc, Mutex}, +}; + +use bevy_ecs::{component::Component, entity::Entity, system::Resource}; + +/// 仿真公共资源 +pub struct SimulationResource { + id: String, + uid_entity_mapping: HashMap, +} + +impl SimulationResource { + pub fn new(id: String) -> Self { + SimulationResource { + id, + uid_entity_mapping: HashMap::new(), + } + } + + pub fn id(&self) -> &str { + &self.id + } + + pub fn get_entity(&self, uid: &str) -> Option { + self.uid_entity_mapping.get(uid).cloned() + } + + pub fn insert_entity(&mut self, uid: String, entity: Entity) { + self.uid_entity_mapping.insert(uid, entity); + } +} + +// 设备编号组件 +#[derive(Component, Debug, Clone, PartialEq, Eq)] +pub struct Uid(pub String); +impl Default for Uid { + fn default() -> Self { + Uid("".to_string()) + } +} + +#[derive(Resource)] +pub struct SharedSimulationResource(pub Arc>); + +impl SharedSimulationResource { + pub fn get_entity(&self, uid: &str) -> Option { + self.0.lock().unwrap().uid_entity_mapping.get(uid).cloned() + } + + pub fn insert_entity(&self, uid: String, entity: Entity) { + self.0 + .lock() + .unwrap() + .uid_entity_mapping + .insert(uid, entity); + } +} + +#[cfg(test)] +mod tests { + use bevy_ecs::world; + + use super::*; + + #[test] + fn it_works() { + let mut simulation_resource = SimulationResource::new("1".to_string()); + let mut world = world::World::default(); + let uid = Uid("1".to_string()); + let entity = world.spawn(uid.clone()).id(); + simulation_resource.insert_entity(uid.clone().0, entity); + assert_eq!(simulation_resource.get_entity(&uid.0), Some(entity)); + } +} diff --git a/crates/rtss_core/src/simulation.rs b/crates/rtss_core/src/simulation.rs deleted file mode 100644 index ca921be..0000000 --- a/crates/rtss_core/src/simulation.rs +++ /dev/null @@ -1,327 +0,0 @@ -use std::{ - collections::HashMap, - ops::{Deref, DerefMut}, - sync::mpsc, - time::{Duration, Instant}, -}; - -use bevy_app::{prelude::*, PluginsState}; -use bevy_ecs::{ - event::{Event, EventWriter}, - observer::Trigger, - system::{Res, ResMut, Resource}, -}; -use bevy_time::{prelude::*, TimePlugin}; -use rtss_log::tracing::{debug, error}; - -use crate::{add_needed_plugins, AvailablePlugins}; - -pub struct SimulationManager { - txs: HashMap>>, -} - -impl Default for SimulationManager { - fn default() -> Self { - Self::new() - } -} - -impl SimulationManager { - fn new() -> Self { - let tx = HashMap::new(); - SimulationManager { txs: tx } - } - - pub fn count(&self) -> usize { - self.txs.len() - } - - pub fn start_simulation(&mut self, builder: SimulationBuilder) { - let (tx, mut rx) = mpsc::channel(); - let id = builder.id.clone(); - - rayon::spawn(move || { - let wait = Some(builder.loop_duration); - let mut sim = crate::Simulation::new(builder); - sim.set_runner(move |mut app: App| { - let plugins_state = app.plugins_state(); - if plugins_state != PluginsState::Cleaned { - app.finish(); - app.cleanup(); - } - - loop { - match runner(&mut app, wait, &mut rx) { - Ok(Some(delay)) => std::thread::sleep(delay), - Ok(None) => continue, - Err(exit) => return exit, - } - } - }); - sim.run(); - }); - self.txs.insert(id, tx); - } - - pub fn exit_simulation(&mut self, id: String) { - debug!("exit simulation, id={}", id); - if let Some(tx) = self.txs.remove(&id) { - if let Err(e) = tx.send(Box::new(|app: &mut App| { - app.world_mut().trigger(SimulationControlEvent::Exit); - })) { - error!( - "Failed to send exit event to simulation, id={}, error={:?}", - id, e - ); - } - } - } - - pub fn pause_simulation(&mut self, id: String) { - if let Some(tx) = self.txs.get(&id) { - if let Err(e) = tx.send(Box::new(|app: &mut App| { - app.world_mut().trigger(SimulationControlEvent::Pause); - })) { - error!( - "Failed to send pause event to simulation, id={}, error={:?}", - id, e - ); - } - } - } - - pub fn resume_simulation(&mut self, id: String) { - if let Some(tx) = self.txs.get(&id) { - if let Err(e) = tx.send(Box::new(|app: &mut App| { - app.world_mut().trigger(SimulationControlEvent::Unpause); - })) { - error!( - "Failed to send resume event to simulation, id={}, error={:?}", - id, e - ); - } - } - } - - pub fn update_simulation_speed(&mut self, id: String, speed: f32) { - if let Some(tx) = self.txs.get(&id) { - if let Err(e) = tx.send(Box::new(move |app: &mut App| { - app.world_mut() - .trigger(SimulationControlEvent::UpdateSpeed(speed)); - })) { - error!( - "Failed to send update speed event to simulation, id={}, error={:?}", - id, e - ); - } - } - } -} - -fn runner( - app: &mut App, - wait: Option, - rx: &mut mpsc::Receiver>, -) -> Result, AppExit> { - let start_time = Instant::now(); - - if let Err(e) = rx.try_recv().map(|mut handle| handle(app)) { - match e { - mpsc::TryRecvError::Empty => {} - mpsc::TryRecvError::Disconnected => { - error!("Simulation handle channel disconnected"); - } - } - } - - app.update(); - - if let Some(exit) = app.should_exit() { - return Err(exit); - }; - - let end_time = Instant::now(); - - if let Some(wait) = wait { - let exe_time = end_time - start_time; - if exe_time < wait { - return Ok(Some(wait - exe_time)); - } - } - - Ok(None) -} - -pub struct SimulationBuilder { - /// 仿真ID - pub(crate) id: String, - /// 仿真主逻辑循环间隔,详细请查看 [`Time`](bevy_time::fixed::Fixed) - pub(crate) loop_duration: Duration, - /// 仿真所需插件 - pub(crate) plugins: Vec, -} - -impl Default for SimulationBuilder { - fn default() -> Self { - SimulationBuilder { - id: "default".to_string(), - loop_duration: Duration::from_millis(20), - plugins: Vec::new(), - } - } -} - -impl SimulationBuilder { - pub fn id(mut self, id: String) -> Self { - self.id = id; - self - } - - pub fn loop_duration(mut self, loop_duration: Duration) -> Self { - self.loop_duration = loop_duration; - self - } - - pub fn plugins(mut self, plugins: Vec) -> Self { - self.plugins = plugins; - self - } -} - -#[derive(Resource, Debug)] -pub struct SimulationId(String); - -impl SimulationId { - pub fn new(id: String) -> Self { - SimulationId(id) - } -} - -impl Deref for SimulationId { - type Target = String; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Resource, Debug)] -pub struct SimulationStatus { - // 仿真倍速 - pub speed: f32, - // 仿真是否暂停状态 - pub paused: bool, -} - -impl Default for SimulationStatus { - fn default() -> Self { - SimulationStatus { - speed: 1.0, - paused: true, - } - } -} - -/// 仿真控制事件 -#[derive(Event, Debug)] -pub enum SimulationControlEvent { - Pause, - Unpause, - UpdateSpeed(f32), - Exit, -} - -/// 仿真运行模式 -pub enum SimulationRunMode { - SingleSimulationMain, - SingleSimulationThread, - MultiSimulationThread, -} - -pub struct Simulation { - app: App, -} - -impl Deref for Simulation { - type Target = App; - - fn deref(&self) -> &Self::Target { - &self.app - } -} - -impl DerefMut for Simulation { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.app - } -} - -pub type SimulationHandle = dyn FnMut(&mut App) + Send; - -impl Simulation { - pub fn new(builder: SimulationBuilder) -> Self { - let mut app = App::new(); - // 初始化仿真App - app.add_plugins(TimePlugin) - .insert_resource(Time::::from_max_delta( - builder.loop_duration.mul_f32(2f32), - )) - .insert_resource(Time::::from_duration(builder.loop_duration)) - .insert_resource(SimulationId::new(builder.id)) - .insert_resource(SimulationStatus::default()) - .add_event::() - .observe(simulation_status_control); - // 添加仿真所需插件 - add_needed_plugins(&mut app, builder.plugins); - Simulation { app } - } -} - -pub fn simulation_status_control( - trigger: Trigger, - mut time: ResMut>, - sid: Res, - mut exit: EventWriter, -) { - match trigger.event() { - SimulationControlEvent::Pause => { - debug!("Pausing simulation"); - time.pause(); - } - SimulationControlEvent::Unpause => { - debug!("Unpausing simulation"); - time.unpause(); - } - SimulationControlEvent::UpdateSpeed(speed) => { - debug!("Update simulation speed to {}", speed); - time.set_relative_speed(*speed); - } - SimulationControlEvent::Exit => { - debug!("Exiting simulation, id={:?}", *sid); - exit.send(AppExit::Success); - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_simulation_manager() { - let mut manager = SimulationManager::default(); - assert_eq!(manager.count(), 0); - - manager.start_simulation(SimulationBuilder::default().id("0".to_string())); - assert_eq!(manager.count(), 1); - - manager.start_simulation(SimulationBuilder::default().id("1".to_string())); - assert_eq!(manager.count(), 2); - - manager.exit_simulation("0".to_string()); - assert_eq!(manager.count(), 1); - - manager.exit_simulation("1".to_string()); - assert_eq!(manager.count(), 0); - } -} diff --git a/crates/rtss_core/Cargo.toml b/crates/rtss_sim_manage/Cargo.toml similarity index 75% rename from crates/rtss_core/Cargo.toml rename to crates/rtss_sim_manage/Cargo.toml index 4c2fed7..673c3d9 100644 --- a/crates/rtss_core/Cargo.toml +++ b/crates/rtss_sim_manage/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "rtss_core" +name = "rtss_sim_manage" version = "0.1.0" edition = "2021" @@ -9,6 +9,8 @@ bevy_ecs = {workspace = true} bevy_app = {workspace = true} bevy_time = {workspace = true} rayon = {workspace = true} +thiserror = {workspace = true} rtss_log = { path = "../rtss_log" } +rtss_common = { path = "../rtss_common" } rtss_trackside = { path = "../rtss_trackside" } diff --git a/crates/rtss_core/src/config_plugins.rs b/crates/rtss_sim_manage/src/config_plugins.rs similarity index 100% rename from crates/rtss_core/src/config_plugins.rs rename to crates/rtss_sim_manage/src/config_plugins.rs diff --git a/crates/rtss_core/src/lib.rs b/crates/rtss_sim_manage/src/lib.rs similarity index 100% rename from crates/rtss_core/src/lib.rs rename to crates/rtss_sim_manage/src/lib.rs diff --git a/crates/rtss_sim_manage/src/simulation.rs b/crates/rtss_sim_manage/src/simulation.rs new file mode 100644 index 0000000..82a31c0 --- /dev/null +++ b/crates/rtss_sim_manage/src/simulation.rs @@ -0,0 +1,468 @@ +use std::{ + cell::RefCell, + collections::HashMap, + ops::Deref, + sync::{mpsc, Arc, Mutex}, + time::{Duration, Instant}, +}; + +use bevy_app::{prelude::*, PluginsState}; +use bevy_ecs::{ + event::{Event, EventWriter}, + observer::Trigger, + system::{Query, Res, ResMut, Resource}, + world::OnAdd, +}; +use bevy_time::{prelude::*, TimePlugin}; +use rtss_common::{SharedSimulationResource, SimulationResource, Uid}; +use rtss_log::tracing::{debug, error, warn}; +use thiserror::Error; + +use crate::{add_needed_plugins, AvailablePlugins}; + +/// 仿真管理器 +/// 非线程安全,若需要线程安全请使用类似 `Arc>` 的方式 +pub struct SimulationManager { + txs: RefCell>, +} + +impl Default for SimulationManager { + fn default() -> Self { + Self::new() + } +} + +#[derive(Error, Debug)] +pub enum SimulationControlError { + #[error("Unknown error")] + UnknownError, + #[error("Simulation not exist")] + SimulationNotExist, + #[error("Trigger event failed")] + TriggerEventFailed, + #[error("Simulation entity not exist")] + SimulationEntityNotExist, +} + +impl SimulationManager { + fn new() -> Self { + let txs = RefCell::new(HashMap::new()); + SimulationManager { txs } + } + + pub fn count(&self) -> usize { + self.txs.borrow().len() + } + + pub fn start_simulation( + &self, + builder: SimulationBuilder, + ) -> Result { + let id = builder.id.clone(); + let sim = Simulation::new(builder); + self.txs.borrow_mut().insert(id.clone(), sim); + Ok(id) + } + + pub fn exit_simulation(&self, id: String) -> Result<(), SimulationControlError> { + match self.txs.borrow_mut().remove(&id) { + Some(sim) => sim.exit_simulation(), + None => { + warn!("Simulation not exist, id={}", id); + Err(SimulationControlError::SimulationNotExist) + } + } + } + + pub fn pause_simulation(&self, id: String) -> Result<(), SimulationControlError> { + match self.txs.borrow().get(&id) { + Some(sim) => sim.pause_simulation(), + None => { + warn!("Simulation not exist, id={}", id); + Err(SimulationControlError::SimulationNotExist) + } + } + } + + pub fn resume_simulation(&self, id: String) -> Result<(), SimulationControlError> { + match self.txs.borrow().get(&id) { + Some(sim) => sim.resume_simulation(), + None => { + warn!("Simulation not exist, id={}", id); + Err(SimulationControlError::SimulationNotExist) + } + } + } + + pub fn update_simulation_speed( + &self, + id: String, + speed: f32, + ) -> Result<(), SimulationControlError> { + match self.txs.borrow().get(&id) { + Some(sim) => sim.update_simulation_speed(speed), + None => { + warn!("Simulation not exist, id={}", id); + Err(SimulationControlError::SimulationNotExist) + } + } + } + + pub fn trigger_operation(&self, id: String, event: E) -> Result<(), SimulationControlError> + where + E: Event + Copy, + { + match self.txs.borrow().get(&id) { + Some(sim) => sim.trigger_operation(event), + None => { + warn!("Simulation not exist, id={}", id); + Err(SimulationControlError::SimulationNotExist) + } + } + } + + pub fn trigger_entity_operation( + &self, + id: String, + entity_uid: String, + event: E, + ) -> Result<(), SimulationControlError> + where + E: Event + Copy, + { + match self.txs.borrow().get(&id) { + Some(sim) => sim.trigger_entity_operation(entity_uid, event), + None => { + warn!("Simulation not exist, id={}", id); + Err(SimulationControlError::SimulationNotExist) + } + } + } +} + +pub struct SimulationBuilder { + /// 仿真ID + pub(crate) id: String, + /// 仿真主逻辑循环间隔,详细请查看 [`Time`](bevy_time::fixed::Fixed) + pub(crate) loop_duration: Duration, + /// 仿真所需插件 + pub(crate) plugins: Vec, +} + +impl Default for SimulationBuilder { + fn default() -> Self { + SimulationBuilder { + id: "default".to_string(), + loop_duration: Duration::from_millis(500), + plugins: Vec::new(), + } + } +} + +impl SimulationBuilder { + pub fn id(mut self, id: String) -> Self { + self.id = id; + self + } + + pub fn loop_duration(mut self, loop_duration: Duration) -> Self { + self.loop_duration = loop_duration; + self + } + + pub fn plugins(mut self, plugins: Vec) -> Self { + self.plugins = plugins; + self + } +} + +#[derive(Resource, Debug)] +pub struct SimulationId(String); + +impl SimulationId { + pub fn new(id: String) -> Self { + SimulationId(id) + } +} + +impl Deref for SimulationId { + type Target = String; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +#[derive(Resource, Debug)] +pub struct SimulationStatus { + // 仿真倍速 + pub speed: f32, + // 仿真是否暂停状态 + pub paused: bool, +} + +impl Default for SimulationStatus { + fn default() -> Self { + SimulationStatus { + speed: 1.0, + paused: true, + } + } +} + +/// 仿真控制事件 +#[derive(Event, Debug, Clone, Copy)] +pub enum SimulationControlEvent { + Pause, + Unpause, + UpdateSpeed(f32), + Exit, +} + +pub struct Simulation { + tx: mpsc::Sender>, + resource: Arc>, +} + +pub type SimulationHandle = dyn FnMut(&mut App) + Send; + +impl Simulation { + pub fn new(builder: SimulationBuilder) -> Self { + let simulation_resource = Arc::new(Mutex::new(SimulationResource::new(builder.id.clone()))); + let cloned_resource = Arc::clone(&simulation_resource); + + let (tx, mut rx) = mpsc::channel(); + + rayon::spawn(move || { + let mut app = App::new(); + + let mut virtual_time = + Time::::from_max_delta(builder.loop_duration.mul_f32(2f32)); + virtual_time.pause(); + // 初始化仿真App + app.add_plugins(TimePlugin) + .insert_resource(virtual_time) + .insert_resource(Time::::from_duration(builder.loop_duration)) + .insert_resource(SimulationId::new(builder.id)) + .insert_resource(SimulationStatus::default()) + .insert_resource(SharedSimulationResource(Arc::clone(&cloned_resource))) + .add_event::() + .observe(simulation_status_control) + .observe(entity_observer); + // 添加仿真所需插件 + add_needed_plugins(&mut app, builder.plugins); + + let wait = Some(builder.loop_duration); + app.set_runner(move |mut app: App| { + let plugins_state = app.plugins_state(); + if plugins_state != PluginsState::Cleaned { + app.finish(); + app.cleanup(); + } + + loop { + match runner(&mut app, wait, &mut rx) { + Ok(Some(delay)) => std::thread::sleep(delay), + Ok(None) => continue, + Err(exit) => return exit, + } + } + }); + + app.run(); + }); + Simulation { + tx, + resource: simulation_resource, + } + } + + fn trigger_event(&self, event: SimulationControlEvent) -> Result<(), SimulationControlError> { + let id = self.resource.lock().unwrap().id().to_string(); + let result = self.tx.send(Box::new(move |app: &mut App| { + app.world_mut().trigger(event); + })); + match result { + Ok(_) => Ok(()), + Err(e) => { + error!( + "Failed to send event to simulation, id={}, error={:?}", + id, e + ); + Err(SimulationControlError::TriggerEventFailed) + } + } + } + + pub fn trigger_operation(&self, event: E) -> Result<(), SimulationControlError> + where + E: Event + Copy, + { + let id = self.resource.lock().unwrap().id().to_string(); + let result = self.tx.send(Box::new(move |app: &mut App| { + app.world_mut().trigger(event); + })); + match result { + Ok(_) => Ok(()), + Err(e) => { + error!( + "Failed to send event to simulation, id={}, error={:?}", + id, e + ); + Err(SimulationControlError::TriggerEventFailed) + } + } + } + + pub fn trigger_entity_operation( + &self, + entity_uid: String, + event: E, + ) -> Result<(), SimulationControlError> + where + E: Event + Copy, + { + let id = self.resource.lock().unwrap().id().to_string(); + match self.resource.lock().unwrap().get_entity(&entity_uid) { + Some(entity) => { + let result = self.tx.send(Box::new(move |app: &mut App| { + app.world_mut().trigger_targets(event, entity); + })); + match result { + Ok(_) => Ok(()), + Err(e) => { + error!( + "Failed to send event to simulation, id={}, error={:?}", + id, e + ); + Err(SimulationControlError::TriggerEventFailed) + } + } + } + None => { + error!("Entity not exist, id={}", entity_uid); + Err(SimulationControlError::SimulationEntityNotExist) + } + } + } + + pub fn exit_simulation(&self) -> Result<(), SimulationControlError> { + self.trigger_event(SimulationControlEvent::Exit) + } + + pub fn pause_simulation(&self) -> Result<(), SimulationControlError> { + self.trigger_event(SimulationControlEvent::Pause) + } + + pub fn resume_simulation(&self) -> Result<(), SimulationControlError> { + self.trigger_event(SimulationControlEvent::Unpause) + } + + pub fn update_simulation_speed(&self, speed: f32) -> Result<(), SimulationControlError> { + self.trigger_event(SimulationControlEvent::UpdateSpeed(speed)) + } +} + +pub fn entity_observer( + trigger: Trigger, + query: Query<&Uid>, + shared: ResMut, +) { + let entity = trigger.entity(); + match query.get(entity) { + Ok(uid) => { + shared.insert_entity(uid.0.clone(), entity); + debug!("添加uid实体映射, Uid: {:?}, Entity: {:?}", uid, entity); + } + Err(_) => { + warn!("Failed to get Uid from entity: {:?}", entity); + } + } +} + +pub fn simulation_status_control( + trigger: Trigger, + mut time: ResMut>, + sid: Res, + mut exit: EventWriter, +) { + match trigger.event() { + SimulationControlEvent::Pause => { + debug!("Pausing simulation"); + time.pause(); + } + SimulationControlEvent::Unpause => { + debug!("Unpausing simulation"); + time.unpause(); + } + SimulationControlEvent::UpdateSpeed(speed) => { + debug!("Update simulation speed to {}", speed); + time.set_relative_speed(*speed); + } + SimulationControlEvent::Exit => { + debug!("Exiting simulation, id={:?}", *sid); + exit.send(AppExit::Success); + } + } +} + +fn runner( + app: &mut App, + wait: Option, + rx: &mut mpsc::Receiver>, +) -> Result, AppExit> { + let start_time = Instant::now(); + + if let Err(e) = rx.try_recv().map(|mut handle| handle(app)) { + match e { + mpsc::TryRecvError::Empty => {} + mpsc::TryRecvError::Disconnected => { + error!("Simulation handle channel disconnected"); + } + } + } + + app.update(); + + if let Some(exit) = app.should_exit() { + return Err(exit); + }; + + let end_time = Instant::now(); + + if let Some(wait) = wait { + let exe_time = end_time - start_time; + if exe_time < wait { + return Ok(Some(wait - exe_time)); + } + } + + Ok(None) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_simulation_manager() { + let manager = SimulationManager::default(); + assert_eq!(manager.count(), 0); + + if let Ok(_) = manager.start_simulation(SimulationBuilder::default().id("0".to_string())) { + assert_eq!(manager.count(), 1); + } + + if let Ok(_) = manager.start_simulation(SimulationBuilder::default().id("1".to_string())) { + assert_eq!(manager.count(), 2); + } + + if let Ok(_) = manager.exit_simulation("0".to_string()) { + assert_eq!(manager.count(), 1); + } + + if let Ok(_) = manager.exit_simulation("1".to_string()) { + assert_eq!(manager.count(), 0); + } + } +} diff --git a/crates/rtss_trackside/Cargo.toml b/crates/rtss_trackside/Cargo.toml index da09a99..c5d4669 100644 --- a/crates/rtss_trackside/Cargo.toml +++ b/crates/rtss_trackside/Cargo.toml @@ -8,4 +8,6 @@ bevy_core = {workspace = true} bevy_ecs = {workspace = true} bevy_app = {workspace = true} bevy_time = {workspace = true} + rtss_log = { path = "../rtss_log" } +rtss_common = { path = "../rtss_common" } diff --git a/crates/rtss_trackside/src/components/equipment.rs b/crates/rtss_trackside/src/components/equipment.rs index ea66007..1db18d4 100644 --- a/crates/rtss_trackside/src/components/equipment.rs +++ b/crates/rtss_trackside/src/components/equipment.rs @@ -1,17 +1,9 @@ use bevy_ecs::{bundle::Bundle, component::Component}; - -// 设备编号组件 -#[derive(Component, Debug, Clone, PartialEq, Eq)] -pub struct Uid(pub String); -impl Default for Uid { - fn default() -> Self { - Uid("".to_string()) - } -} +use rtss_common::Uid; // 两常态位置转换组件,用于像道岔位置,屏蔽门位置等 #[derive(Component, Debug, Clone, PartialEq, Default)] -pub struct TwoNormalPositionsConversion { +pub struct TwoNormalPositionsTransform { // 当前实际位置,百分比值,0-100 pub position: i32, // 当前转换速度 @@ -36,5 +28,5 @@ pub struct TurnoutState { pub struct TurnoutBundle { pub uid: Uid, pub turnout_state: TurnoutState, - pub two_normal_positions_conversion: TwoNormalPositionsConversion, + pub two_normal_positions_conversion: TwoNormalPositionsTransform, } diff --git a/crates/rtss_trackside/src/events/equipment.rs b/crates/rtss_trackside/src/events/equipment.rs index 3872c32..87c8f4f 100644 --- a/crates/rtss_trackside/src/events/equipment.rs +++ b/crates/rtss_trackside/src/events/equipment.rs @@ -1,6 +1,6 @@ use bevy_ecs::event::Event; -#[derive(Event, Debug)] +#[derive(Event, Debug, Clone, Copy, Eq, PartialEq)] pub enum TurnoutControlEvent { // 道岔定操 DC, diff --git a/crates/rtss_trackside/src/plugin.rs b/crates/rtss_trackside/src/plugin.rs index 047053a..aae1dc0 100644 --- a/crates/rtss_trackside/src/plugin.rs +++ b/crates/rtss_trackside/src/plugin.rs @@ -3,7 +3,7 @@ use bevy_ecs::schedule::IntoSystemConfigs; use crate::{ handle_turnout_control, loading, turnout_state_update, two_normal_position_transform, - EquipmentUidEntityMapping, SimulationConfig, TurnoutControlEvent, + SimulationConfig, TurnoutControlEvent, }; #[derive(Default)] @@ -11,8 +11,7 @@ pub struct TrackSideEquipmentPlugin; impl Plugin for TrackSideEquipmentPlugin { fn build(&self, app: &mut bevy_app::App) { - app.insert_resource(EquipmentUidEntityMapping::default()) - .insert_resource(SimulationConfig::default()) + app.insert_resource(SimulationConfig::default()) .add_event::() .add_systems(Startup, loading) .add_systems( diff --git a/crates/rtss_trackside/src/resources/mod.rs b/crates/rtss_trackside/src/resources/mod.rs index f3c76bd..15903a5 100644 --- a/crates/rtss_trackside/src/resources/mod.rs +++ b/crates/rtss_trackside/src/resources/mod.rs @@ -1,12 +1,4 @@ -use std::collections::HashMap; - -use bevy_ecs::{entity::Entity, system::Resource}; - -// 用于存储设备编号与实体的映射关系的资源 -#[derive(Resource, Debug, Default)] -pub struct EquipmentUidEntityMapping { - pub turnout_mapping: HashMap, -} +use bevy_ecs::system::Resource; #[derive(Resource, Debug)] pub struct SimulationConfig { diff --git a/crates/rtss_trackside/src/systems/common.rs b/crates/rtss_trackside/src/systems/common.rs index d813c43..e2a6c52 100644 --- a/crates/rtss_trackside/src/systems/common.rs +++ b/crates/rtss_trackside/src/systems/common.rs @@ -1,31 +1,32 @@ use bevy_ecs::{entity::Entity, system::Query}; +use rtss_common::Uid; use rtss_log::tracing::debug; -use crate::{TwoNormalPositionsConversion, Uid}; +use crate::TwoNormalPositionsTransform; pub const TWO_NORMAL_POSITION_MIN: i32 = 0; pub const TWO_NORMAL_POSITION_MAX: i32 = 100; // 两常态位置转换系统 pub fn two_normal_position_transform( - mut query: Query<(Entity, &Uid, &mut TwoNormalPositionsConversion)>, + mut query: Query<(Entity, &Uid, &mut TwoNormalPositionsTransform)>, ) { - for (entity, uid, mut conversion) in &mut query { + for (entity, uid, mut transform) in &mut query { debug!( "Entity: {:?}, Uid: {:?}, Conversion: {:?}", - entity, uid, conversion + entity, uid, transform ); - if conversion.velocity == 0f32 { + if transform.velocity == 0f32 { continue; } - let p = conversion.position + conversion.velocity as i32; + let p = transform.position + transform.velocity as i32; if p > TWO_NORMAL_POSITION_MAX { - conversion.position = TWO_NORMAL_POSITION_MAX; - conversion.velocity = TWO_NORMAL_POSITION_MIN as f32; + transform.position = TWO_NORMAL_POSITION_MAX; + transform.velocity = TWO_NORMAL_POSITION_MIN as f32; } else if p < TWO_NORMAL_POSITION_MIN { - conversion.position = TWO_NORMAL_POSITION_MIN; - conversion.velocity = 0 as f32; + transform.position = TWO_NORMAL_POSITION_MIN; + transform.velocity = 0 as f32; } else { - conversion.position = p; + transform.position = p; } } } diff --git a/crates/rtss_trackside/src/systems/loading.rs b/crates/rtss_trackside/src/systems/loading.rs index 4a2e669..51f5510 100644 --- a/crates/rtss_trackside/src/systems/loading.rs +++ b/crates/rtss_trackside/src/systems/loading.rs @@ -1,14 +1,13 @@ use bevy_ecs::{prelude::Commands, system::ResMut}; +use rtss_common::{SharedSimulationResource, Uid}; -use crate::{components, EquipmentUidEntityMapping, Uid}; +use crate::components; -pub fn loading(mut commands: Commands, mut res_uid_mapping: ResMut) { +pub fn loading(mut commands: Commands, res_uid_mapping: ResMut) { let uid = Uid("1".to_string()); let et = commands.spawn(components::TurnoutBundle { uid: uid.clone(), ..Default::default() }); - res_uid_mapping - .turnout_mapping - .insert(uid.0.clone(), et.id()); + res_uid_mapping.insert_entity(uid.0, et.id()); } diff --git a/crates/rtss_trackside/src/systems/turnout.rs b/crates/rtss_trackside/src/systems/turnout.rs index f170ed9..f591fd6 100644 --- a/crates/rtss_trackside/src/systems/turnout.rs +++ b/crates/rtss_trackside/src/systems/turnout.rs @@ -3,10 +3,11 @@ use bevy_ecs::{ system::{Query, Res, ResMut}, }; use bevy_time::{Fixed, Time}; +use rtss_common::Uid; use rtss_log::tracing::debug; use crate::{ - events::TurnoutControlEvent, SimulationConfig, TurnoutState, TwoNormalPositionsConversion, Uid, + events::TurnoutControlEvent, SimulationConfig, TurnoutState, TwoNormalPositionsTransform, }; // 道岔控制事件处理系统 @@ -14,7 +15,7 @@ pub fn handle_turnout_control( trigger: Trigger, time: ResMut>, config: Res, - mut query: Query<(&Uid, &mut TurnoutState, &mut TwoNormalPositionsConversion)>, + mut query: Query<(&Uid, &mut TurnoutState, &mut TwoNormalPositionsTransform)>, ) { let (uid, mut state, mut conversion) = query .get_mut(trigger.entity()) @@ -42,7 +43,7 @@ pub fn handle_turnout_control( // 道岔状态更新系统 pub fn turnout_state_update( - mut query: Query<(&Uid, &mut TurnoutState, &mut TwoNormalPositionsConversion)>, + mut query: Query<(&Uid, &mut TurnoutState, &mut TwoNormalPositionsTransform)>, ) { for (uid, mut state, conversion) in &mut query { debug!( @@ -52,9 +53,11 @@ pub fn turnout_state_update( if conversion.position == 0 { state.db = true; state.fb = false; + state.dc = false; } else if conversion.position == 100 { state.db = false; state.fb = true; + state.fc = false; } else { state.db = false; state.fb = false; diff --git a/src/main.rs b/src/main.rs index 713aca4..d483313 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,41 +1,11 @@ -use std::{ - thread::{self}, - time::Duration, -}; +use rtss_api::ServerConfig; -use rtss_core::SimulationBuilder; - -fn main() { +#[tokio::main] +async fn main() { rtss_log::Logging { level: rtss_log::tracing::Level::DEBUG, ..Default::default() } .init(); - let mut manager = rtss_core::SimulationManager::default(); - // manager.start_simulation(SimulationBuilder::default().id("0".to_string())); - // thread::sleep(Duration::from_secs(3)); - // manager.exit_simulation("0".to_string()); - // let mut list: Vec = Vec::new(); - let max = 1; - for i in 0..max { - manager.start_simulation( - SimulationBuilder::default() - .id(i.to_string()) - .loop_duration(Duration::from_millis(500)) - .plugins(vec![rtss_core::AvailablePlugins::TrackSideEquipmentPlugin]), - ); - } - thread::sleep(Duration::from_secs(3)); - for i in 0..max { - manager.update_simulation_speed(i.to_string(), 2f32); - } - // thread::sleep(Duration::from_secs(3)); - // for i in 0..max { - // manager.resume_simulation(i.to_string()); - // } - thread::sleep(Duration::from_secs(3)); - for i in 0..max { - manager.exit_simulation(i.to_string()); - } - thread::sleep(Duration::from_secs(3)); + rtss_api::serve(ServerConfig::default()).await; }