From 505230b26c468730c0710241026e91037b410b3e Mon Sep 17 00:00:00 2001 From: soul-walker <31162815+soul-walker@users.noreply.github.com> Date: Thu, 31 Oct 2024 15:12:26 +0800 Subject: [PATCH] =?UTF-8?q?1=20=20=E9=87=8D=E6=9E=84rtsa=5Fmqtt=E5=BA=93?= =?UTF-8?q?=EF=BC=8C=E6=B7=BB=E5=8A=A0=E8=B7=AF=E7=94=B1=E8=AF=B7=E6=B1=82?= =?UTF-8?q?=E5=93=8D=E5=BA=94=E5=8A=9F=E8=83=BD=202=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E5=BA=93=E5=91=BD=E5=90=8Drtss->rtsa?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitea/workflows/cicd_local_test.yml | 8 +- .gitmodules | 4 +- .vscode/settings.json | 2 +- Cargo.lock | 65 +- Cargo.toml | 3 +- _typos.toml | 2 +- crates/{rtss_db => rtsa_db}/Cargo.toml | 6 +- crates/{rtss_db => rtsa_db}/src/common.rs | 0 .../src/db_access/draft_data.rs | 16 +- .../src/db_access/feature.rs | 14 +- .../{rtss_db => rtsa_db}/src/db_access/mod.rs | 22 +- .../src/db_access/release_data.rs | 30 +- .../src/db_access/user.rs | 12 +- crates/{rtss_db => rtsa_db}/src/error.rs | 0 crates/{rtss_db => rtsa_db}/src/lib.rs | 0 crates/{rtss_db => rtsa_db}/src/model.rs | 26 +- crates/{rtss_dto => rtsa_dto}/Cargo.toml | 2 +- crates/{rtss_dto => rtsa_dto}/build.rs | 14 +- crates/{rtss_dto => rtsa_dto}/src/lib.rs | 0 .../{rtss_dto => rtsa_dto}/src/pb/common.rs | 0 .../{rtss_dto => rtsa_dto}/src/pb/em_data.rs | 0 .../src/pb/iscs_graphic_data.rs | 0 crates/{rtss_dto => rtsa_dto}/src/pb/mod.rs | 0 .../src/pb/simulation.rs | 0 crates/{rtss_log => rtsa_log}/Cargo.toml | 2 +- crates/{rtss_log => rtsa_log}/src/lib.rs | 0 crates/{rtss_mqtt => rtsa_mqtt}/Cargo.toml | 5 +- crates/{rtss_mqtt => rtsa_mqtt}/src/error.rs | 2 + crates/rtsa_mqtt/src/lib.rs | 512 +++++++++++++ crates/rtsa_mqtt/src/service.rs | 247 ++++++ crates/rtss_mqtt/src/lib.rs | 702 ------------------ manager/Cargo.toml | 6 +- Dockerfile => manager/Dockerfile | 6 +- manager/conf/dev.toml | 2 +- manager/conf/local_test.toml | 2 +- .../crates/{rtss_api => rtsa_api}/Cargo.toml | 8 +- .../src/apis/data_options_def.rs | 6 +- .../src/apis/draft_data.rs | 52 +- .../src/apis/feature.rs | 30 +- .../src/apis/feature_config_def.rs | 0 .../{rtss_api => rtsa_api}/src/apis/mod.rs | 8 +- .../src/apis/release_data.rs | 46 +- .../src/apis/sys_info.rs | 0 .../{rtss_api => rtsa_api}/src/apis/user.rs | 20 +- .../crates/{rtss_api => rtsa_api}/src/lib.rs | 0 manager/crates/rtsa_api/src/loader/mod.rs | 10 + .../{rtss_api => rtsa_api}/src/server.rs | 26 +- .../src/user_auth/jwt_auth.rs | 2 +- .../src/user_auth/mod.rs | 10 +- manager/crates/rtss_api/src/loader/mod.rs | 10 - manager/src/app_config.rs | 8 +- manager/src/commands/cmd.rs | 10 +- manager/src/commands/db.rs | 2 +- migrations/20240830095636_init.down.sql | 2 +- migrations/20240830095636_init.up.sql | 180 ++--- rtss-proto-msg | 1 - simulation/Cargo.toml | 8 +- simulation/crates/rtss_ci/Cargo.toml | 6 - simulation/crates/rtss_ci/src/lib.rs | 14 - simulation/crates/rtss_common/Cargo.toml | 7 - simulation/crates/rtss_common/src/lib.rs | 76 -- simulation/crates/rtss_iscs/Cargo.toml | 6 - simulation/crates/rtss_iscs/src/lib.rs | 14 - simulation/crates/rtss_sim_manage/Cargo.toml | 16 - .../rtss_sim_manage/src/config_plugins.rs | 17 - simulation/crates/rtss_sim_manage/src/lib.rs | 19 - simulation/crates/rtss_sim_manage/src/main.rs | 4 - .../crates/rtss_sim_manage/src/simulation.rs | 468 ------------ simulation/crates/rtss_trackside/Cargo.toml | 13 - .../rtss_trackside/src/components/bundle.rs | 20 - .../src/components/equipment.rs | 42 -- .../rtss_trackside/src/components/mod.rs | 4 - .../rtss_trackside/src/events/equipment.rs | 9 - .../crates/rtss_trackside/src/events/mod.rs | 2 - simulation/crates/rtss_trackside/src/lib.rs | 10 - .../crates/rtss_trackside/src/plugin.rs | 23 - .../rtss_trackside/src/resources/mod.rs | 15 - .../rtss_trackside/src/systems/common.rs | 32 - .../rtss_trackside/src/systems/loading.rs | 13 - .../crates/rtss_trackside/src/systems/mod.rs | 6 - .../rtss_trackside/src/systems/turnout.rs | 78 -- simulation/src/app_config.rs | 8 +- simulation/src/commands/cmd.rs | 12 +- simulation/src/commands/db.rs | 2 +- simulation/src/components/mod.rs | 8 +- simulation/src/manage/data_loading_plugin.rs | 2 +- simulation/src/manage/simulation.rs | 24 +- .../src/manage/simulation_control_plugin.rs | 8 +- .../src/modules/trackside/systems/common.rs | 2 +- .../src/modules/trackside/systems/loading.rs | 2 +- .../src/modules/trackside/systems/turnout.rs | 2 +- 91 files changed, 1148 insertions(+), 1987 deletions(-) rename crates/{rtss_db => rtsa_db}/Cargo.toml (80%) rename crates/{rtss_db => rtsa_db}/src/common.rs (100%) rename crates/{rtss_db => rtsa_db}/src/db_access/draft_data.rs (98%) rename crates/{rtss_db => rtsa_db}/src/db_access/feature.rs (97%) rename crates/{rtss_db => rtsa_db}/src/db_access/mod.rs (78%) rename crates/{rtss_db => rtsa_db}/src/db_access/release_data.rs (97%) rename crates/{rtss_db => rtsa_db}/src/db_access/user.rs (98%) rename crates/{rtss_db => rtsa_db}/src/error.rs (100%) rename crates/{rtss_db => rtsa_db}/src/lib.rs (100%) rename crates/{rtss_db => rtsa_db}/src/model.rs (90%) rename crates/{rtss_dto => rtsa_dto}/Cargo.toml (93%) rename crates/{rtss_dto => rtsa_dto}/build.rs (76%) rename crates/{rtss_dto => rtsa_dto}/src/lib.rs (100%) rename crates/{rtss_dto => rtsa_dto}/src/pb/common.rs (100%) rename crates/{rtss_dto => rtsa_dto}/src/pb/em_data.rs (100%) rename crates/{rtss_dto => rtsa_dto}/src/pb/iscs_graphic_data.rs (100%) rename crates/{rtss_dto => rtsa_dto}/src/pb/mod.rs (100%) rename crates/{rtss_dto => rtsa_dto}/src/pb/simulation.rs (100%) rename crates/{rtss_log => rtsa_log}/Cargo.toml (94%) rename crates/{rtss_log => rtsa_log}/src/lib.rs (100%) rename crates/{rtss_mqtt => rtsa_mqtt}/Cargo.toml (77%) rename crates/{rtss_mqtt => rtsa_mqtt}/src/error.rs (87%) create mode 100644 crates/rtsa_mqtt/src/lib.rs create mode 100644 crates/rtsa_mqtt/src/service.rs delete mode 100644 crates/rtss_mqtt/src/lib.rs rename Dockerfile => manager/Dockerfile (69%) rename manager/crates/{rtss_api => rtsa_api}/Cargo.toml (81%) rename manager/crates/{rtss_api => rtsa_api}/src/apis/data_options_def.rs (93%) rename manager/crates/{rtss_api => rtsa_api}/src/apis/draft_data.rs (88%) rename manager/crates/{rtss_api => rtsa_api}/src/apis/feature.rs (89%) rename manager/crates/{rtss_api => rtsa_api}/src/apis/feature_config_def.rs (100%) rename manager/crates/{rtss_api => rtsa_api}/src/apis/mod.rs (90%) rename manager/crates/{rtss_api => rtsa_api}/src/apis/release_data.rs (90%) rename manager/crates/{rtss_api => rtsa_api}/src/apis/sys_info.rs (100%) rename manager/crates/{rtss_api => rtsa_api}/src/apis/user.rs (89%) rename manager/crates/{rtss_api => rtsa_api}/src/lib.rs (100%) create mode 100644 manager/crates/rtsa_api/src/loader/mod.rs rename manager/crates/{rtss_api => rtsa_api}/src/server.rs (85%) rename manager/crates/{rtss_api => rtsa_api}/src/user_auth/jwt_auth.rs (97%) rename manager/crates/{rtss_api => rtsa_api}/src/user_auth/mod.rs (97%) delete mode 100644 manager/crates/rtss_api/src/loader/mod.rs delete mode 160000 rtss-proto-msg delete mode 100644 simulation/crates/rtss_ci/Cargo.toml delete mode 100644 simulation/crates/rtss_ci/src/lib.rs delete mode 100644 simulation/crates/rtss_common/Cargo.toml delete mode 100644 simulation/crates/rtss_common/src/lib.rs delete mode 100644 simulation/crates/rtss_iscs/Cargo.toml delete mode 100644 simulation/crates/rtss_iscs/src/lib.rs delete mode 100644 simulation/crates/rtss_sim_manage/Cargo.toml delete mode 100644 simulation/crates/rtss_sim_manage/src/config_plugins.rs delete mode 100644 simulation/crates/rtss_sim_manage/src/lib.rs delete mode 100644 simulation/crates/rtss_sim_manage/src/main.rs delete mode 100644 simulation/crates/rtss_sim_manage/src/simulation.rs delete mode 100644 simulation/crates/rtss_trackside/Cargo.toml delete mode 100644 simulation/crates/rtss_trackside/src/components/bundle.rs delete mode 100644 simulation/crates/rtss_trackside/src/components/equipment.rs delete mode 100644 simulation/crates/rtss_trackside/src/components/mod.rs delete mode 100644 simulation/crates/rtss_trackside/src/events/equipment.rs delete mode 100644 simulation/crates/rtss_trackside/src/events/mod.rs delete mode 100644 simulation/crates/rtss_trackside/src/lib.rs delete mode 100644 simulation/crates/rtss_trackside/src/plugin.rs delete mode 100644 simulation/crates/rtss_trackside/src/resources/mod.rs delete mode 100644 simulation/crates/rtss_trackside/src/systems/common.rs delete mode 100644 simulation/crates/rtss_trackside/src/systems/loading.rs delete mode 100644 simulation/crates/rtss_trackside/src/systems/mod.rs delete mode 100644 simulation/crates/rtss_trackside/src/systems/turnout.rs diff --git a/.gitea/workflows/cicd_local_test.yml b/.gitea/workflows/cicd_local_test.yml index 14a0724..f6aa7d2 100644 --- a/.gitea/workflows/cicd_local_test.yml +++ b/.gitea/workflows/cicd_local_test.yml @@ -50,7 +50,7 @@ jobs: file: ./Dockerfile push: true tags: | - gitea.joylink.club/joylink/rtss-simulation:local-test + gitea.joylink.club/joylink/rtsam:lt - name: 发布到本地测试环境 uses: https://gitea.joylink.club/appleboy/ssh-action@v1.0.3 with: @@ -59,6 +59,6 @@ jobs: username: ${{ secrets.LOCAL_233_SSH_USER }} password: ${{ secrets.LOCAL_233_SSH_PASSWORD }} script: | - docker rm -f rtss-simulation || echo "rtss-simulation not exist" - docker pull gitea.joylink.club/joylink/rtss-simulation:local-test - docker run --name rtss-simulation --restart=always -e RUN_MODE=local_test --network jlnet --ip 10.11.11.11 -d -p 8765:8765 -v /usr/local/joylink/logs/simulation:/logs/simulation gitea.joylink.club/joylink/rtss-simulation:local-test + docker rm -f rtsa-simulation || echo "rtsa-simulation not exist" + docker pull gitea.joylink.club/joylink/rtsa-simulation:local-test + docker run --name rtsa-simulation --restart=always -e RUN_MODE=local_test --network jlnet --ip 10.11.11.11 -d -p 8765:8765 -v /usr/local/joylink/logs/simulation:/logs/simulation gitea.joylink.club/joylink/rtsa-simulation:local-test diff --git a/.gitmodules b/.gitmodules index b70e77c..069248f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ -[submodule "rtss-proto-msg"] - path = rtss-proto-msg +[submodule "rtsa-proto-msg"] + path = rtsa-proto-msg url = https://gitea.joylink.club/joylink/rtss-proto-msg.git diff --git a/.vscode/settings.json b/.vscode/settings.json index 2399fec..4faa377 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -27,7 +27,7 @@ "repr", "reqwest", "rtsa", - "rtss", + "rtsa", "rumqtt", "rumqttc", "sqlx", diff --git a/Cargo.lock b/Cargo.lock index ef449a3..82ff930 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -331,7 +331,7 @@ dependencies = [ "sync_wrapper 1.0.1", "tokio", "tokio-tungstenite", - "tower", + "tower 0.4.13", "tower-layer", "tower-service", "tracing", @@ -375,7 +375,7 @@ dependencies = [ "mime", "pin-project-lite", "serde", - "tower", + "tower 0.4.13", "tower-layer", "tower-service", "tracing", @@ -1448,7 +1448,7 @@ dependencies = [ "pin-project-lite", "socket2", "tokio", - "tower", + "tower 0.4.13", "tower-service", "tracing", ] @@ -1636,9 +1636,9 @@ dependencies = [ "clap", "config", "enum_dispatch", - "rtss_api", - "rtss_db", - "rtss_log", + "rtsa_api", + "rtsa_db", + "rtsa_log", "serde", "tokio", ] @@ -2400,7 +2400,7 @@ dependencies = [ ] [[package]] -name = "rtss_api" +name = "rtsa_api" version = "0.1.0" dependencies = [ "anyhow", @@ -2412,9 +2412,9 @@ dependencies = [ "chrono", "jsonwebtoken", "reqwest", - "rtss_db", - "rtss_dto", - "rtss_log", + "rtsa_db", + "rtsa_dto", + "rtsa_log", "serde", "serde_json", "sysinfo", @@ -2423,13 +2423,13 @@ dependencies = [ ] [[package]] -name = "rtss_db" +name = "rtsa_db" version = "0.1.0" dependencies = [ "anyhow", "lazy_static", - "rtss_dto", - "rtss_log", + "rtsa_dto", + "rtsa_log", "serde", "serde_json", "sqlx", @@ -2437,7 +2437,7 @@ dependencies = [ ] [[package]] -name = "rtss_dto" +name = "rtsa_dto" version = "0.1.0" dependencies = [ "async-graphql", @@ -2449,7 +2449,7 @@ dependencies = [ ] [[package]] -name = "rtss_log" +name = "rtsa_log" version = "0.1.0" dependencies = [ "tracing", @@ -2458,16 +2458,17 @@ dependencies = [ ] [[package]] -name = "rtss_mqtt" +name = "rtsa_mqtt" version = "0.1.0" dependencies = [ "async-trait", "bytes", "lazy_static", - "rtss_log", + "rtsa_log", "rumqttc", "thiserror", "tokio", + "tower 0.5.1", ] [[package]] @@ -2644,18 +2645,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.213" +version = "1.0.214" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ea7893ff5e2466df8d720bb615088341b295f849602c6956047f8f80f0e9bc1" +checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.213" +version = "1.0.214" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e85ad2009c50b58e87caa8cd6dac16bdf511bbfb7af6c33df902396aa480fa5" +checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" dependencies = [ "proc-macro2", "quote", @@ -2778,10 +2779,10 @@ dependencies = [ "enum_dispatch", "lazy_static", "rayon", - "rtss_db", - "rtss_dto", - "rtss_log", - "rtss_mqtt", + "rtsa_db", + "rtsa_dto", + "rtsa_log", + "rtsa_mqtt", "serde", "thiserror", "tokio", @@ -3391,6 +3392,20 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 0.1.2", + "tower-layer", + "tower-service", +] + [[package]] name = "tower-http" version = "0.6.0" diff --git a/Cargo.toml b/Cargo.toml index 37061c7..5287a86 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ sqlx = { version = "0.8", features = [ "json", "chrono", ] } -serde = { version = "1.0.213", features = ["derive"] } +serde = { version = "1.0.214", features = ["derive"] } serde_json = "1.0.132" anyhow = "1.0.91" async-trait = "0.1.83" @@ -26,3 +26,4 @@ lazy_static = "1.5.0" config = "0.14.1" clap = { version = "4.5.20", features = ["derive"] } enum_dispatch = "0.3" +tower = { version = "0.5.1", features = ["util"] } diff --git a/_typos.toml b/_typos.toml index 0b5b282..2092463 100644 --- a/_typos.toml +++ b/_typos.toml @@ -1,4 +1,4 @@ [default.extend-words] [files] -extend-exclude = ["README.md", "rtss-proto-msg/*"] +extend-exclude = ["README.md", "rtsa-proto-msg/*"] diff --git a/crates/rtss_db/Cargo.toml b/crates/rtsa_db/Cargo.toml similarity index 80% rename from crates/rtss_db/Cargo.toml rename to crates/rtsa_db/Cargo.toml index 27ebb7f..b345804 100644 --- a/crates/rtss_db/Cargo.toml +++ b/crates/rtsa_db/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "rtss_db" +name = "rtsa_db" version = "0.1.0" edition = "2021" @@ -19,5 +19,5 @@ sqlx = { workspace = true, features = [ thiserror = { workspace = true } lazy_static = { workspace = true } -rtss_dto = { path = "../rtss_dto" } -rtss_log = { path = "../rtss_log" } +rtsa_dto = { path = "../rtsa_dto" } +rtsa_log = { path = "../rtsa_log" } diff --git a/crates/rtss_db/src/common.rs b/crates/rtsa_db/src/common.rs similarity index 100% rename from crates/rtss_db/src/common.rs rename to crates/rtsa_db/src/common.rs diff --git a/crates/rtss_db/src/db_access/draft_data.rs b/crates/rtsa_db/src/db_access/draft_data.rs similarity index 98% rename from crates/rtss_db/src/db_access/draft_data.rs rename to crates/rtsa_db/src/db_access/draft_data.rs index dfe4b70..6a2fcb8 100644 --- a/crates/rtss_db/src/db_access/draft_data.rs +++ b/crates/rtsa_db/src/db_access/draft_data.rs @@ -1,7 +1,7 @@ use std::vec; -use rtss_dto::common::DataType; -use rtss_log::tracing::debug; +use rtsa_dto::common::DataType; +use rtsa_log::tracing::debug; use serde_json::Value; use crate::{ @@ -10,7 +10,7 @@ use crate::{ DbAccessError, }; -use super::RtssDbAccessor; +use super::RtsaDbAccessor; /// 草稿数据管理 #[allow(async_fn_in_trait)] @@ -205,7 +205,7 @@ impl CreateDraftData { } } -impl DraftDataAccessor for RtssDbAccessor { +impl DraftDataAccessor for RtsaDbAccessor { async fn paging_query_draft_data( &self, query: DraftDataQuery, @@ -436,8 +436,8 @@ mod tests { use crate::{SyncUserInfo, UserAccessor}; use super::*; - use rtss_dto::common::{IscsStyle, Role}; - use rtss_log::tracing::Level; + use rtsa_dto::common::{IscsStyle, Role}; + use rtsa_log::tracing::Level; use serde::{Deserialize, Serialize}; use sqlx::{types::chrono::Local, PgPool}; @@ -449,8 +449,8 @@ mod tests { // You could also do `use foo_crate::MIGRATOR` and just refer to it as `MIGRATOR` here. #[sqlx::test(migrator = "crate::MIGRATOR")] async fn basic_use_test(pool: PgPool) -> Result<(), DbAccessError> { - rtss_log::Logging::default().with_level(Level::DEBUG).init(); - let accessor = crate::db_access::RtssDbAccessor::new(pool); + rtsa_log::Logging::default().with_level(Level::DEBUG).init(); + let accessor = crate::db_access::RtsaDbAccessor::new(pool); // 同步10个用户 let mut users = vec![]; for i in 0..10 { diff --git a/crates/rtss_db/src/db_access/feature.rs b/crates/rtsa_db/src/db_access/feature.rs similarity index 97% rename from crates/rtss_db/src/db_access/feature.rs rename to crates/rtsa_db/src/db_access/feature.rs index 534c127..a48f7b4 100644 --- a/crates/rtss_db/src/db_access/feature.rs +++ b/crates/rtsa_db/src/db_access/feature.rs @@ -1,4 +1,4 @@ -use rtss_dto::common::FeatureType; +use rtsa_dto::common::FeatureType; use serde_json::Value; use crate::{ @@ -7,7 +7,7 @@ use crate::{ DbAccessError, }; -use super::RtssDbAccessor; +use super::RtsaDbAccessor; /// 功能特性管理 #[allow(async_fn_in_trait)] @@ -34,7 +34,7 @@ pub trait FeatureAccessor { async fn get_features(&self, ids: &[i32]) -> Result, DbAccessError>; } -impl FeatureAccessor for RtssDbAccessor { +impl FeatureAccessor for RtsaDbAccessor { async fn create_feature(&self, feature: &CreateFeature) -> Result { let table = FeatureColumn::Table.name(); let feature_type_column = FeatureColumn::FeatureType.name(); @@ -217,8 +217,8 @@ impl FeaturePagingFilter { #[cfg(test)] mod tests { - use rtss_dto::common::Role; - use rtss_log::tracing::Level; + use rtsa_dto::common::Role; + use rtsa_log::tracing::Level; use sqlx::{types::chrono::Local, PgPool}; use crate::{SyncUserInfo, UserAccessor}; @@ -227,8 +227,8 @@ mod tests { #[sqlx::test(migrator = "crate::MIGRATOR")] async fn test_basic_use(pool: PgPool) -> Result<(), DbAccessError> { - rtss_log::Logging::default().with_level(Level::DEBUG).init(); - let accessor = crate::db_access::RtssDbAccessor::new(pool); + rtsa_log::Logging::default().with_level(Level::DEBUG).init(); + let accessor = crate::db_access::RtsaDbAccessor::new(pool); // 同步10个用户 let mut users = vec![]; for i in 0..10 { diff --git a/crates/rtss_db/src/db_access/mod.rs b/crates/rtsa_db/src/db_access/mod.rs similarity index 78% rename from crates/rtss_db/src/db_access/mod.rs rename to crates/rtsa_db/src/db_access/mod.rs index 7566fd0..ea9e871 100644 --- a/crates/rtss_db/src/db_access/mod.rs +++ b/crates/rtsa_db/src/db_access/mod.rs @@ -5,7 +5,7 @@ pub use draft_data::*; mod release_data; pub use release_data::*; mod user; -use rtss_log::tracing::error; +use rtsa_log::tracing::error; pub use user::*; mod feature; pub use feature::*; @@ -14,7 +14,7 @@ use lazy_static::lazy_static; use crate::{model::MqttClientIdSeq, DbAccessError}; lazy_static! { - static ref RDA: Mutex> = Mutex::new(None); + static ref RDA: Mutex> = Mutex::new(None); } /// 初始化全局默认数据库访问器 @@ -29,7 +29,7 @@ pub async fn init_default_db_accessor(url: &str) { } /// 获取默认数据库访问器 -pub fn get_default_db_accessor() -> RtssDbAccessor { +pub fn get_default_db_accessor() -> RtsaDbAccessor { let rda = RDA.lock().unwrap(); if rda.is_none() { panic!("数据库访问器未初始化"); @@ -38,13 +38,13 @@ pub fn get_default_db_accessor() -> RtssDbAccessor { } #[derive(Clone)] -pub struct RtssDbAccessor { +pub struct RtsaDbAccessor { pool: sqlx::PgPool, } -impl RtssDbAccessor { +impl RtsaDbAccessor { pub fn new(pool: sqlx::PgPool) -> Self { - RtssDbAccessor { pool } + RtsaDbAccessor { pool } } pub async fn get_next_mqtt_client_id(&self) -> Result { @@ -56,22 +56,22 @@ impl RtssDbAccessor { } } -pub async fn get_db_accessor(url: &str) -> RtssDbAccessor { +pub async fn get_db_accessor(url: &str) -> RtsaDbAccessor { let pool = sqlx::PgPool::connect(url).await.expect("连接数据库失败"); - RtssDbAccessor::new(pool) + RtsaDbAccessor::new(pool) } #[cfg(test)] mod tests { use super::*; - use rtss_log::tracing::{self, Level}; + use rtsa_log::tracing::{self, Level}; use sqlx::PgPool; // You could also do `use foo_crate::MIGRATOR` and just refer to it as `MIGRATOR` here. #[sqlx::test(migrator = "crate::MIGRATOR")] async fn test_get_mqtt_client_id(pool: PgPool) -> Result<(), DbAccessError> { - rtss_log::Logging::default().with_level(Level::DEBUG).init(); - let accessor = crate::db_access::RtssDbAccessor::new(pool); + rtsa_log::Logging::default().with_level(Level::DEBUG).init(); + let accessor = crate::db_access::RtsaDbAccessor::new(pool); for _ in 0..10 { let id = accessor.get_next_mqtt_client_id().await?; tracing::info!("id = {}", id); diff --git a/crates/rtss_db/src/db_access/release_data.rs b/crates/rtsa_db/src/db_access/release_data.rs similarity index 97% rename from crates/rtss_db/src/db_access/release_data.rs rename to crates/rtsa_db/src/db_access/release_data.rs index 7fc727f..4785da2 100644 --- a/crates/rtss_db/src/db_access/release_data.rs +++ b/crates/rtsa_db/src/db_access/release_data.rs @@ -1,4 +1,4 @@ -use rtss_dto::common::DataType; +use rtsa_dto::common::DataType; use serde_json::Value; use sqlx::{types::chrono, Postgres}; @@ -11,7 +11,7 @@ use crate::{ DbAccessError, }; -use super::{CreateDraftData, DraftDataAccessor, RtssDbAccessor}; +use super::{CreateDraftData, DraftDataAccessor, RtsaDbAccessor}; #[allow(async_fn_in_trait)] pub trait ReleaseDataAccessor { @@ -109,7 +109,7 @@ pub struct ReleaseFromDraftResult { pub struct ReleaseDataQuery { pub name: Option, pub user_id: Option, - pub data_type: Option, + pub data_type: Option, pub options: Option, pub is_published: Option, } @@ -141,7 +141,7 @@ impl ReleaseDataQuery { self } - pub fn with_data_type(mut self, data_type: rtss_dto::common::DataType) -> Self { + pub fn with_data_type(mut self, data_type: rtsa_dto::common::DataType) -> Self { self.data_type = Some(data_type); self } @@ -202,7 +202,7 @@ pub struct CreateReleaseVersionData { pub user_id: i32, } -impl RtssDbAccessor { +impl RtsaDbAccessor { async fn insert_release_data_version<'e, 'c: 'e, E>( &self, data: CreateReleaseVersionData, @@ -237,7 +237,7 @@ impl RtssDbAccessor { } } -impl ReleaseDataAccessor for RtssDbAccessor { +impl ReleaseDataAccessor for RtsaDbAccessor { async fn release_new_from_draft( &self, draft_id: i32, @@ -645,12 +645,12 @@ impl ReleaseDataAccessor for RtssDbAccessor { #[cfg(test)] mod tests { - use crate::{CreateDraftData, DraftDataAccessor, RtssDbAccessor, SyncUserInfo, UserAccessor}; + use crate::{CreateDraftData, DraftDataAccessor, RtsaDbAccessor, SyncUserInfo, UserAccessor}; use super::*; use chrono::Local; - use rtss_dto::common::{IscsStyle, Role}; - use rtss_log::tracing::Level; + use rtsa_dto::common::{IscsStyle, Role}; + use rtsa_log::tracing::Level; use serde::{Deserialize, Serialize}; use sqlx::PgPool; @@ -695,8 +695,8 @@ mod tests { // You could also do `use foo_crate::MIGRATOR` and just refer to it as `MIGRATOR` here. #[sqlx::test(migrator = "crate::MIGRATOR")] async fn test_basic_use(pool: PgPool) -> Result<(), DbAccessError> { - rtss_log::Logging::default().with_level(Level::DEBUG).init(); - let accessor = RtssDbAccessor::new(pool); + rtsa_log::Logging::default().with_level(Level::DEBUG).init(); + let accessor = RtsaDbAccessor::new(pool); // 同步10个用户 let mut users = vec![]; for i in 0..10 { @@ -717,7 +717,7 @@ mod tests { let data = "test".as_bytes(); let draft = accessor .create_draft_data( - CreateDraftData::new("test", rtss_dto::common::DataType::Iscs, 1) + CreateDraftData::new("test", rtsa_dto::common::DataType::Iscs, 1) .with_options( serde_json::to_value(IscsDataOptions { style: IscsStyle::DaShiZhiNeng, @@ -767,7 +767,7 @@ mod tests { // name重复检查 let exist = accessor - .is_release_data_name_exist(rtss_dto::common::DataType::Iscs, name) + .is_release_data_name_exist(rtsa_dto::common::DataType::Iscs, name) .await?; assert!(exist); @@ -849,7 +849,7 @@ mod tests { let data = "test data".as_bytes(); let draft = accessor .create_draft_data( - CreateDraftData::new(&name, rtss_dto::common::DataType::Em, i).with_data(data), + CreateDraftData::new(&name, rtsa_dto::common::DataType::Em, i).with_data(data), ) .await?; let (release_data, _) = accessor @@ -883,7 +883,7 @@ mod tests { let page_result = accessor.paging_query_release_data_list(query, page).await?; assert_eq!(page_result.total, 2); // 分页查询发布数据,按数据类型过滤 - let query = ReleaseDataQuery::new().with_data_type(rtss_dto::common::DataType::Em); + let query = ReleaseDataQuery::new().with_data_type(rtsa_dto::common::DataType::Em); let page = PageQuery::new(1, 10); let page_result = accessor.paging_query_release_data_list(query, page).await?; assert_eq!(page_result.total, 8); diff --git a/crates/rtss_db/src/db_access/user.rs b/crates/rtsa_db/src/db_access/user.rs similarity index 98% rename from crates/rtss_db/src/db_access/user.rs rename to crates/rtsa_db/src/db_access/user.rs index ef473b3..07da088 100644 --- a/crates/rtss_db/src/db_access/user.rs +++ b/crates/rtsa_db/src/db_access/user.rs @@ -7,7 +7,7 @@ use crate::{ DbAccessError, }; -use super::RtssDbAccessor; +use super::RtsaDbAccessor; /// 草稿数据管理 #[allow(async_fn_in_trait)] @@ -96,7 +96,7 @@ pub struct SyncUserInfo { pub updated_at: Option>, } -impl RtssDbAccessor { +impl RtsaDbAccessor { /// 首次同步用户数据 async fn sync_new_users(&self, users: &[SyncUserInfo]) -> Result<(), DbAccessError> { let table = UserColumn::Table.name(); @@ -223,7 +223,7 @@ impl RtssDbAccessor { } } -impl UserAccessor for RtssDbAccessor { +impl UserAccessor for RtsaDbAccessor { async fn sync_user(&self, users: &[SyncUserInfo]) -> Result<(), DbAccessError> { self.check_and_sync_user(users).await } @@ -271,7 +271,7 @@ impl UserAccessor for RtssDbAccessor { mod tests { use std::time::Duration; - use rtss_log::tracing::Level; + use rtsa_log::tracing::Level; use serde::{Deserialize, Serialize}; use sqlx::PgPool; @@ -293,8 +293,8 @@ mod tests { #[sqlx::test(migrator = "crate::MIGRATOR")] async fn test_sync_user(pool: PgPool) -> Result<(), DbAccessError> { // 日志初始化 - rtss_log::Logging::default().with_level(Level::DEBUG).init(); - let accessor = RtssDbAccessor::new(pool); + rtsa_log::Logging::default().with_level(Level::DEBUG).init(); + let accessor = RtsaDbAccessor::new(pool); let users = vec![ SyncUserInfo { id: 1, diff --git a/crates/rtss_db/src/error.rs b/crates/rtsa_db/src/error.rs similarity index 100% rename from crates/rtss_db/src/error.rs rename to crates/rtsa_db/src/error.rs diff --git a/crates/rtss_db/src/lib.rs b/crates/rtsa_db/src/lib.rs similarity index 100% rename from crates/rtss_db/src/lib.rs rename to crates/rtsa_db/src/lib.rs diff --git a/crates/rtss_db/src/model.rs b/crates/rtsa_db/src/model.rs similarity index 90% rename from crates/rtss_db/src/model.rs rename to crates/rtsa_db/src/model.rs index 14377de..3b86283 100644 --- a/crates/rtss_db/src/model.rs +++ b/crates/rtsa_db/src/model.rs @@ -1,4 +1,4 @@ -use rtss_dto::common::{DataType, FeatureType, Role}; +use rtsa_dto::common::{DataType, FeatureType, Role}; use serde_json::Value; use sqlx::types::{ chrono::{DateTime, Local}, @@ -14,7 +14,7 @@ pub enum MqttClientIdSeq { impl MqttClientIdSeq { pub fn name(&self) -> &str { match self { - MqttClientIdSeq::Name => "rtss.mqtt_client_id_seq", + MqttClientIdSeq::Name => "rtsa.mqtt_client_id_seq", } } } @@ -46,7 +46,7 @@ pub struct UserModel { pub updated_at: DateTime, } -/// 数据库表 rtss.draft_data 列映射 +/// 数据库表 rtsa.draft_data 列映射 #[derive(Debug)] pub enum DraftDataColumn { Table, @@ -80,7 +80,7 @@ pub struct DraftDataModel { pub updated_at: DateTime, } -/// 数据库表 rtss.release_data 列映射 +/// 数据库表 rtsa.release_data 列映射 #[derive(Debug)] pub enum ReleaseDataColumn { Table, @@ -111,7 +111,7 @@ pub struct ReleaseDataModel { pub updated_at: DateTime, } -/// 数据库表 rtss.release_data_version 列映射 +/// 数据库表 rtsa.release_data_version 列映射 #[derive(Debug)] pub enum ReleaseDataVersionColumn { Table, @@ -137,7 +137,7 @@ pub struct ReleaseDataVersionModel { pub created_at: DateTime, } -/// 数据库表 rtss.feature 列映射 +/// 数据库表 rtsa.feature 列映射 #[derive(Debug)] #[allow(dead_code)] pub enum FeatureColumn { @@ -169,7 +169,7 @@ pub struct FeatureModel { pub updated_at: DateTime, } -/// 数据库表 rtss.user_config 列映射 +/// 数据库表 rtsa.user_config 列映射 #[derive(Debug)] #[allow(dead_code)] pub enum UserConfigColumn { @@ -195,7 +195,7 @@ pub struct UserConfigModel { impl TableColumn for UserColumn { fn name(&self) -> &str { match self { - UserColumn::Table => "rtss.user", + UserColumn::Table => "rtsa.user", UserColumn::Id => "id", UserColumn::Username => "username", UserColumn::Password => "password", @@ -211,7 +211,7 @@ impl TableColumn for UserColumn { impl TableColumn for DraftDataColumn { fn name(&self) -> &str { match self { - DraftDataColumn::Table => "rtss.draft_data", + DraftDataColumn::Table => "rtsa.draft_data", DraftDataColumn::Id => "id", DraftDataColumn::Name => "name", DraftDataColumn::DataType => "data_type", @@ -229,7 +229,7 @@ impl TableColumn for DraftDataColumn { impl TableColumn for ReleaseDataColumn { fn name(&self) -> &str { match self { - ReleaseDataColumn::Table => "rtss.release_data", + ReleaseDataColumn::Table => "rtsa.release_data", ReleaseDataColumn::Id => "id", ReleaseDataColumn::Name => "name", ReleaseDataColumn::DataType => "data_type", @@ -246,7 +246,7 @@ impl TableColumn for ReleaseDataColumn { impl TableColumn for ReleaseDataVersionColumn { fn name(&self) -> &str { match self { - ReleaseDataVersionColumn::Table => "rtss.release_data_version", + ReleaseDataVersionColumn::Table => "rtsa.release_data_version", ReleaseDataVersionColumn::Id => "id", ReleaseDataVersionColumn::ReleaseDataId => "release_data_id", ReleaseDataVersionColumn::Options => "options", @@ -261,7 +261,7 @@ impl TableColumn for ReleaseDataVersionColumn { impl TableColumn for FeatureColumn { fn name(&self) -> &str { match self { - FeatureColumn::Table => "rtss.feature", + FeatureColumn::Table => "rtsa.feature", FeatureColumn::Id => "id", FeatureColumn::FeatureType => "feature_type", FeatureColumn::Name => "name", @@ -279,7 +279,7 @@ impl TableColumn for FeatureColumn { impl TableColumn for UserConfigColumn { fn name(&self) -> &str { match self { - UserConfigColumn::Table => "rtss.user_config", + UserConfigColumn::Table => "rtsa.user_config", UserConfigColumn::Id => "id", UserConfigColumn::UserId => "user_id", UserConfigColumn::ConfigType => "config_type", diff --git a/crates/rtss_dto/Cargo.toml b/crates/rtsa_dto/Cargo.toml similarity index 93% rename from crates/rtss_dto/Cargo.toml rename to crates/rtsa_dto/Cargo.toml index 0f95f08..da3d05c 100644 --- a/crates/rtss_dto/Cargo.toml +++ b/crates/rtsa_dto/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "rtss_dto" +name = "rtsa_dto" version = "0.1.0" edition = "2021" diff --git a/crates/rtss_dto/build.rs b/crates/rtsa_dto/build.rs similarity index 76% rename from crates/rtss_dto/build.rs rename to crates/rtsa_dto/build.rs index 32d375e..9b9e224 100644 --- a/crates/rtss_dto/build.rs +++ b/crates/rtsa_dto/build.rs @@ -16,7 +16,7 @@ fn main() { { std::env::set_var( "PROTOC", - "../../rtss-proto-msg/protoc/protoc-27.4-win64/bin/protoc.exe", + "../../rtsa-proto-msg/protoc/protoc-27.4-win64/bin/protoc.exe", ); } Config::new() @@ -39,12 +39,12 @@ fn main() { ) .compile_protos( &[ - "../../rtss-proto-msg/src/em_data.proto", - "../../rtss-proto-msg/src/common.proto", - "../../rtss-proto-msg/src/iscs_graphic_data.proto", - "../../rtss-proto-msg/src/simulation.proto", + "../../rtsa-proto-msg/src/em_data.proto", + "../../rtsa-proto-msg/src/common.proto", + "../../rtsa-proto-msg/src/iscs_graphic_data.proto", + "../../rtsa-proto-msg/src/simulation.proto", ], - &["../../rtss-proto-msg/src/"], + &["../../rtsa-proto-msg/src/"], ) .unwrap(); @@ -52,5 +52,5 @@ fn main() { Command::new("cargo") .args(["fmt"]) .status() - .expect("Failed to run cargo fmt on rtss-dto"); + .expect("Failed to run cargo fmt on rtsa-dto"); } diff --git a/crates/rtss_dto/src/lib.rs b/crates/rtsa_dto/src/lib.rs similarity index 100% rename from crates/rtss_dto/src/lib.rs rename to crates/rtsa_dto/src/lib.rs diff --git a/crates/rtss_dto/src/pb/common.rs b/crates/rtsa_dto/src/pb/common.rs similarity index 100% rename from crates/rtss_dto/src/pb/common.rs rename to crates/rtsa_dto/src/pb/common.rs diff --git a/crates/rtss_dto/src/pb/em_data.rs b/crates/rtsa_dto/src/pb/em_data.rs similarity index 100% rename from crates/rtss_dto/src/pb/em_data.rs rename to crates/rtsa_dto/src/pb/em_data.rs diff --git a/crates/rtss_dto/src/pb/iscs_graphic_data.rs b/crates/rtsa_dto/src/pb/iscs_graphic_data.rs similarity index 100% rename from crates/rtss_dto/src/pb/iscs_graphic_data.rs rename to crates/rtsa_dto/src/pb/iscs_graphic_data.rs diff --git a/crates/rtss_dto/src/pb/mod.rs b/crates/rtsa_dto/src/pb/mod.rs similarity index 100% rename from crates/rtss_dto/src/pb/mod.rs rename to crates/rtsa_dto/src/pb/mod.rs diff --git a/crates/rtss_dto/src/pb/simulation.rs b/crates/rtsa_dto/src/pb/simulation.rs similarity index 100% rename from crates/rtss_dto/src/pb/simulation.rs rename to crates/rtsa_dto/src/pb/simulation.rs diff --git a/crates/rtss_log/Cargo.toml b/crates/rtsa_log/Cargo.toml similarity index 94% rename from crates/rtss_log/Cargo.toml rename to crates/rtsa_log/Cargo.toml index 801dce0..3eb3f13 100644 --- a/crates/rtss_log/Cargo.toml +++ b/crates/rtsa_log/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "rtss_log" +name = "rtsa_log" version = "0.1.0" edition = "2021" diff --git a/crates/rtss_log/src/lib.rs b/crates/rtsa_log/src/lib.rs similarity index 100% rename from crates/rtss_log/src/lib.rs rename to crates/rtsa_log/src/lib.rs diff --git a/crates/rtss_mqtt/Cargo.toml b/crates/rtsa_mqtt/Cargo.toml similarity index 77% rename from crates/rtss_mqtt/Cargo.toml rename to crates/rtsa_mqtt/Cargo.toml index 282ae0e..21b3b0a 100644 --- a/crates/rtss_mqtt/Cargo.toml +++ b/crates/rtsa_mqtt/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "rtss_mqtt" +name = "rtsa_mqtt" version = "0.1.0" edition = "2021" @@ -10,5 +10,6 @@ async-trait = { workspace = true } bytes = { workspace = true } lazy_static = { workspace = true } thiserror = { workspace = true } +tower = { workspace = true } -rtss_log = { path = "../rtss_log" } +rtsa_log = { path = "../rtsa_log" } diff --git a/crates/rtss_mqtt/src/error.rs b/crates/rtsa_mqtt/src/error.rs similarity index 87% rename from crates/rtss_mqtt/src/error.rs rename to crates/rtsa_mqtt/src/error.rs index 83b4c5f..1dc90d3 100644 --- a/crates/rtss_mqtt/src/error.rs +++ b/crates/rtsa_mqtt/src/error.rs @@ -11,4 +11,6 @@ pub enum MqttClientError { ClientError(#[from] ClientError), #[error("全局客户端未设置")] NoClient, + #[error("请求超时")] + RequestTimeout, } diff --git a/crates/rtsa_mqtt/src/lib.rs b/crates/rtsa_mqtt/src/lib.rs new file mode 100644 index 0000000..9e4b50c --- /dev/null +++ b/crates/rtsa_mqtt/src/lib.rs @@ -0,0 +1,512 @@ +use core::panic; +use std::{ + sync::{ + atomic::{AtomicU64, Ordering}, + Arc, Mutex, + }, + task::Waker, + time::Duration, +}; + +use bytes::Bytes; +use lazy_static::lazy_static; +use rtsa_log::tracing::{error, info, trace}; +use rumqttc::{ + v5::{ + mqttbytes::{ + v5::{Packet, Publish, PublishProperties}, + QoS, + }, + AsyncClient, Event, EventLoop, MqttOptions, + }, + Outgoing, +}; +use service::{Handler, MqttRequest, MqttRouter}; +use tokio::{sync::oneshot, time::timeout}; + +mod error; +use error::MqttClientError; +mod service; + +lazy_static! { +/// 全局静态MqttClient实例 +/// 使用注意事项: +/// 每次订阅/发布/请求时都通过get_global_mqtt_client获取新的实例,否则可能会出现死锁 +static ref MQTT_CLIENT: tokio::sync::Mutex> = tokio::sync::Mutex::new(None); +} + +/// 初始化全局MqttClient实例 +pub async fn init_global_mqtt_client( + mut options: MqttClientOptions, +) -> Result<(), MqttClientError> { + let client = options.build(); + set_global_mqtt_client(client).await +} + +/// 设置全局MqttClient实例 +pub async fn set_global_mqtt_client(client: MqttClient) -> Result<(), MqttClientError> { + let mut mqtt_client = MQTT_CLIENT.lock().await; + if mqtt_client.is_some() { + return Err(MqttClientError::AlreadySet); + } + *mqtt_client = Some(client); + Ok(()) +} + +/// 获取全局MqttClient实例 +pub async fn get_global_mqtt_client() -> MqttClient { + let mqtt_client = MQTT_CLIENT.lock().await; + if let Some(client) = mqtt_client.as_ref() { + return client.clone(); + } + panic!("MqttClient未初始化: 使用init_global_mqtt_client初始化,或者在main函数中调用set_global_mqtt_client设置"); +} + +pub struct MqttClientOptions { + id: String, + options: MqttOptions, + /// mqtt客户端请求队列的最大容量 + max_cap: usize, + request_timeout: Duration, +} + +impl MqttClientOptions { + pub fn new(id: &str, url: &str) -> Self { + Self { + id: id.to_string(), + options: MqttOptions::parse_url(format!("{}?client_id={}", url, id)) + .expect("解析mqtt url失败"), + max_cap: 30, + request_timeout: Duration::from_secs(5), + } + } + + pub fn set_max_cap(mut self, max_cap: usize) -> Self { + self.max_cap = max_cap; + self + } + + pub fn set_request_timeout(mut self, timeout: Duration) -> Self { + self.request_timeout = timeout; + self + } + + pub fn set_credentials(mut self, username: &str, password: &str) -> Self { + self.options.set_credentials(username, password); + self + } + + pub fn build(&mut self) -> MqttClient { + self.options.set_keep_alive(Duration::from_secs(10)); + let (client, eventloop) = AsyncClient::new(self.options.clone(), self.max_cap); + + let cli = MqttClient { + id: self.id.clone(), + request_timeout: self.request_timeout, + client, + request_id: Arc::new(AtomicU64::new(0)), + router: MqttRouter::new(), + }; + cli.run_async(eventloop); + cli + } +} + +/// MQTT客户端 +/// id: 客户端ID,从数据库的id序列中获取 +/// 客户端具有的功能: +/// 1. 启动 +/// 2. 订阅 +/// 3. 发布 +/// 4. 实现类似http的请求相应功能 +/// 5. 断开连接 +#[derive(Clone)] +pub struct MqttClient { + id: String, + /// 全局的请求超时时间 + request_timeout: Duration, + client: AsyncClient, + request_id: Arc, + router: MqttRouter, +} + +impl MqttClient { + pub async fn clear(&self) -> Result<(), MqttClientError> { + self.client.disconnect().await?; + // 清空订阅处理器 + self.router.clear(); + Ok(()) + } + + pub fn id(&self) -> &str { + &self.id + } + + pub async fn publish( + &self, + topic: &str, + qos: QoS, + payload: Vec, + ) -> Result<(), MqttClientError> { + self.client.publish(topic, qos, false, payload).await?; + Ok(()) + } + + pub async fn add_route(&self, topic: &str, handler: H, qos: QoS) + where + H: Handler + Send + Sync + 'static, + { + self.client.subscribe(topic, qos).await.unwrap(); + self.router.add_route(topic, handler); + } + + pub async fn remove_route(&self, topic: &str) { + self.client.unsubscribe(topic).await.unwrap(); + self.router.remove_route(topic); + } + + pub fn next_request_id(&self) -> u64 { + self.request_id.fetch_add(1, Ordering::Relaxed) + } + + pub async fn handle_request( + &self, + req: Request, + timeout: Duration, + ) -> Result { + // 订阅响应主题 + let response_topic = format!("{}/{}/resp/{}", self.id, req.topic, self.next_request_id()); + // 创建请求future + let response_future = MqttResponseFuture::new(&response_topic, timeout); + // 添加响应处理器 + self.add_route(&response_topic, response_future.clone(), QoS::ExactlyOnce) + .await; + // 发布请求 + let property = PublishProperties { + response_topic: Some(response_topic.clone()), + ..req.properties.unwrap_or_default() + }; + self.client + .publish_with_properties(req.topic, req.qos, false, req.payload, property) + .await?; + // 等待响应 + let resp = response_future.await; + // 注销响应处理器并取消订阅 + self.remove_route(&response_topic).await; + if resp.is_timeout() { + return Err(MqttClientError::RequestTimeout); + } + Ok(resp) + } + + /// 发送请求并等待响应 + pub async fn request(&self, req: Request) -> Result { + self.handle_request(req, self.request_timeout).await + } + + /// 发送请求并等待响应,指定响应超时时间 + /// 响应超时时间为0时表示永不超时 + pub async fn request_with_timeout( + &self, + req: Request, + timeout: Duration, + ) -> Result { + self.handle_request(req, timeout).await + } + + fn run_async(&self, eventloop: EventLoop) { + let cli = self.clone(); + tokio::spawn(async move { + cli.run(eventloop).await; + }); + } + + async fn run(&self, mut eventloop: EventLoop) { + while let Ok(notification) = eventloop.poll().await { + match notification { + Event::Incoming(Packet::Publish(publish)) => { + trace!("Received message: {:?}", publish); + let this = self.clone(); + let router = self.router.clone(); + tokio::spawn(async move { + let response_topic = publish + .properties + .clone() + .and_then(|p| p.response_topic.clone()); + if let Some(resp) = router.handle_request(MqttRequest::new(publish)).await { + if let Some(r_topic) = response_topic { + this.publish(&r_topic, QoS::AtMostOnce, resp.payload.to_vec()) + .await + .unwrap(); + } + } + }); + } + Event::Outgoing(Outgoing::Disconnect) => { + info!("Disconnected to the broker"); + break; + } + Event::Incoming(Packet::Disconnect(disconnect)) => { + info!("Disconnected from the broker: {:?}", disconnect); + break; + } + _ => { + trace!("Unhandled event: {:?}", notification); + } + } + } + } +} + +pub struct Request { + topic: String, + qos: QoS, + payload: Bytes, + properties: Option, +} + +impl Request { + pub fn new(topic: &str, payload: Bytes) -> Self { + Self { + topic: topic.to_string(), + qos: QoS::AtMostOnce, + payload, + properties: None, + } + } + + pub fn with_qos(mut self, qos: QoS) -> Self { + self.qos = qos; + self + } + + pub fn with_properties(mut self, properties: PublishProperties) -> Self { + self.properties = Some(properties); + self + } +} + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum MqttResponseState { + Waiting, + Received, + Timeout, +} + +/// MQTT请求响应 +#[derive(Clone, Debug)] +pub struct Response { + state: Arc>, + response: Arc>, +} + +impl Default for Response { + fn default() -> Self { + Self::new() + } +} + +impl Response { + pub fn new() -> Self { + Self { + state: Arc::new(Mutex::new(MqttResponseState::Waiting)), + response: Arc::new(Mutex::new(Publish::default())), + } + } + + pub fn is_waiting(&self) -> bool { + *self.state.lock().unwrap() == MqttResponseState::Waiting + } + + pub fn is_received(&self) -> bool { + *self.state.lock().unwrap() == MqttResponseState::Received + } + + pub fn is_timeout(&self) -> bool { + *self.state.lock().unwrap() == MqttResponseState::Timeout + } + + pub fn set_timeout(&self) { + *self.state.lock().unwrap() = MqttResponseState::Timeout; + } + + pub fn set(&self, response: Publish) { + *self.state.lock().unwrap() = MqttResponseState::Received; + *self.response.lock().unwrap() = response; + } + + pub fn get(&self) -> Publish { + self.response.lock().unwrap().clone() + } +} + +/// MQTT响应Future +#[derive(Clone)] +pub struct MqttResponseFuture { + pub start_time: std::time::Instant, + timeout: Duration, + tx: Arc>>>, + waker: Arc>>, + response_topic: String, + response: Response, +} + +impl MqttResponseFuture { + pub fn new(response_topic: &str, timeout: Duration) -> Self { + let (tx, rx) = oneshot::channel(); + let r = Self { + start_time: std::time::Instant::now(), + timeout, + tx: Arc::new(Mutex::new(Some(tx))), + waker: Arc::new(Mutex::new(None)), + response_topic: response_topic.to_string(), + response: Response::new(), + }; + // 启动超时检查 + r.start_timeout_monitor(rx); + + r + } + + /// 启动超时监控任务逻辑 + fn start_timeout_monitor(&self, rx: oneshot::Receiver<()>) { + if self.timeout.as_millis() == 0 { + return; + } + let response = self.response.clone(); + let response_topic = self.response_topic.clone(); + let duration = self.timeout; + let waker = self.waker.clone(); + tokio::spawn(async move { + if (timeout(duration, rx).await).is_err() { + error!("Mqtt response timeout: {:?}", response_topic); + response.set_timeout(); + if let Some(waker) = waker.lock().unwrap().take() { + waker.wake(); + } + } + }); + } +} + +impl Handler for MqttResponseFuture { + fn handle( + &self, + req: MqttRequest, + ) -> std::pin::Pin> + Send>> + { + let topic = req.topic(); + trace!("MqttResponseFuture handle: {:?}", topic); + if topic == self.response_topic { + self.response.set(req.get()); + if let Some(tx) = self.tx.lock().unwrap().take() { + tx.send(()) + .expect("Send Mqtt response timeout signal failed"); + } + if let Some(waker) = self.waker.lock().unwrap().take() { + waker.wake(); + } + } + Box::pin(async { None }) + } +} + +impl std::future::Future for MqttResponseFuture { + type Output = Response; + + fn poll( + self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll { + if self.response.is_waiting() { + trace!( + "topic={} Response future poll waiting...", + self.response_topic + ); + self.waker.lock().unwrap().replace(cx.waker().clone()); + std::task::Poll::Pending + } else { + trace!( + "topic={} Response future poll ready: {:?}", + self.response_topic, + self.response + ); + std::task::Poll::Ready(self.response.clone()) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use rtsa_log::tracing::Level; + + use tokio::time::Duration; + + fn create_mqtt_options() -> MqttClientOptions { + MqttClientOptions::new("rtsa_test1", "tcp://localhost:1883") + .set_credentials("rtsa", "Joylink@0503") + } + + #[tokio::test] + async fn test_mqtt_client_initialization() { + let options = create_mqtt_options(); + let result = init_global_mqtt_client(options).await; + assert!(result.is_ok()); + } + + #[tokio::test] + async fn test_mqtt_client_publish() { + let options = create_mqtt_options(); + init_global_mqtt_client(options).await.unwrap(); + let mqtt_client = get_global_mqtt_client().await; + let result = mqtt_client + .publish("test/topic", QoS::AtLeastOnce, b"Hello, MQTT!".to_vec()) + .await; + assert!(result.is_ok()); + } + + #[tokio::test] + async fn test_mqtt_client_request_response() { + rtsa_log::Logging::default().with_level(Level::TRACE).init(); + let options = create_mqtt_options(); + init_global_mqtt_client(options).await.unwrap(); + let mqtt_client = get_global_mqtt_client().await; + + struct EchoHandler; + impl Handler for EchoHandler { + fn handle( + &self, + req: MqttRequest, + ) -> std::pin::Pin< + Box> + Send>, + > { + let payload = req.payload(); + Box::pin(async move { Some(service::MqttResponse::new(payload)) }) + } + } + mqtt_client + .add_route("test/echo", EchoHandler, QoS::AtLeastOnce) + .await; + + let request = Request::new("test/echo", Bytes::from("Echo message")); + let response = mqtt_client.request(request).await.unwrap(); + assert_eq!(response.get().payload, Bytes::from("Echo message")); + + mqtt_client.remove_route("test/echo").await; + } + + #[tokio::test] + async fn test_mqtt_client_timeout() { + let options = create_mqtt_options(); + init_global_mqtt_client(options).await.unwrap(); + let mqtt_client = get_global_mqtt_client().await; + + let request = + Request::new("test/timeout", Bytes::from("Timeout test")).with_qos(QoS::ExactlyOnce); + let result = mqtt_client + .request_with_timeout(request, Duration::from_secs(1)) + .await; + assert!(result.is_err()); + } +} diff --git a/crates/rtsa_mqtt/src/service.rs b/crates/rtsa_mqtt/src/service.rs new file mode 100644 index 0000000..c96d320 --- /dev/null +++ b/crates/rtsa_mqtt/src/service.rs @@ -0,0 +1,247 @@ +use std::{ + collections::HashMap, + future::Future, + pin::Pin, + sync::{Arc, Mutex}, +}; + +use bytes::Bytes; +use rumqttc::v5::mqttbytes::v5::{Publish, PublishProperties}; + +pub struct MqttRequest { + publish: Publish, +} + +impl MqttRequest { + pub fn new(publish: Publish) -> Self { + MqttRequest { publish } + } + + pub fn topic(&self) -> String { + String::from_utf8_lossy(&self.publish.topic).to_string() + } + + pub fn payload(&self) -> Bytes { + self.publish.payload.clone() + } + + pub fn get(&self) -> Publish { + self.publish.clone() + } +} + +pub struct MqttResponse { + pub properties: Option, + pub payload: Bytes, +} + +impl MqttResponse { + pub fn new(payload: Bytes) -> Self { + MqttResponse { + properties: None, + payload, + } + } + + pub fn with_properties(payload: Bytes, properties: PublishProperties) -> Self { + MqttResponse { + properties: Some(properties), + payload, + } + } +} + +pub trait Handler: Send + Sync + 'static { + fn handle( + &self, + req: MqttRequest, + ) -> Pin> + Send>>; +} + +impl Handler for F +where + F: Fn(MqttRequest) -> Fut + Send + Sync + 'static, + Fut: Future> + Send + 'static, +{ + fn handle( + &self, + req: MqttRequest, + ) -> Pin> + Send>> { + Box::pin((self)(req)) + } +} + +#[derive(Clone)] +pub struct MqttRouter { + routes: Arc>>>, +} + +impl MqttRouter { + pub fn new() -> Self { + MqttRouter { + routes: Arc::new(Mutex::new(HashMap::new())), + } + } + + pub fn add_route(&self, topic: &str, handler: H) + where + H: Handler + Send + Sync + 'static, + { + self.routes + .lock() + .unwrap() + .insert(topic.to_string(), Arc::new(handler)); + } + + pub fn remove_route(&self, topic: &str) { + self.routes.lock().unwrap().remove(topic); + } + + fn get_handler(&self, topic: &str) -> Option> { + let routes = self.routes.lock().unwrap(); + routes.get(topic).cloned() + } + + pub fn clear(&self) { + self.routes.lock().unwrap().clear(); + } + + pub async fn handle_request(&self, req: MqttRequest) -> Option { + if let Some(handler) = self.get_handler(&req.topic()) { + handler.handle(req).await + } else { + None + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use bytes::Bytes; + use rumqttc::v5::mqttbytes::v5::Publish; + + // Helper function to create a Publish message + fn create_publish(topic: &str, payload: &[u8]) -> Publish { + Publish { + topic: topic.as_bytes().to_vec().into(), + payload: Bytes::from(payload.to_vec()), + dup: false, + qos: rumqttc::v5::mqttbytes::QoS::AtMostOnce, + retain: false, + pkid: 0, + properties: None, + } + } + + // Sample handler that echoes the payload back + async fn echo_handler(req: MqttRequest) -> Option { + Some(MqttResponse { + properties: None, + payload: req.payload(), + }) + } + + // Sample handler that returns None + async fn none_handler(_req: MqttRequest) -> Option { + None + } + + #[tokio::test] + async fn test_add_and_get_handler() { + let router = MqttRouter::new(); + router.add_route("test/topic", echo_handler); + + assert!(router.get_handler("test/topic").is_some()); + assert!(router.get_handler("invalid/topic").is_none()); + } + + #[tokio::test] + async fn test_handle_request_with_existing_route() { + let router = MqttRouter::new(); + router.add_route("test/topic", echo_handler); + + let publish = create_publish("test/topic", b"hello"); + let req = MqttRequest::new(publish); + + let response = router.handle_request(req).await; + + assert!(response.is_some()); + assert_eq!(response.unwrap().payload, Bytes::from("hello")); + } + + #[tokio::test] + async fn test_handle_request_with_nonexistent_route() { + let router = MqttRouter::new(); + + let publish = create_publish("invalid/topic", b"hello"); + let req = MqttRequest::new(publish); + + let response = router.handle_request(req).await; + + assert!(response.is_none()); + } + + #[tokio::test] + async fn test_handler_returning_none() { + let router = MqttRouter::new(); + router.add_route("test/topic", none_handler); + + let publish = create_publish("test/topic", b"hello"); + let req = MqttRequest::new(publish); + + let response = router.handle_request(req).await; + + assert!(response.is_none()); + } + + #[tokio::test] + async fn test_multiple_routes() { + let router = MqttRouter::new(); + router.add_route("topic/one", echo_handler); + router.add_route("topic/two", none_handler); + + let publish_one = create_publish("topic/one", b"payload1"); + let req_one = MqttRequest::new(publish_one); + let response_one = router.handle_request(req_one).await; + assert!(response_one.is_some()); + assert_eq!(response_one.unwrap().payload, Bytes::from("payload1")); + + let publish_two = create_publish("topic/two", b"payload2"); + let req_two = MqttRequest::new(publish_two); + let response_two = router.handle_request(req_two).await; + assert!(response_two.is_none()); + } + + #[tokio::test] + async fn test_concurrent_access() { + use std::sync::Arc; + use tokio::sync::Barrier; + + let router = Arc::new(MqttRouter::new()); + router.add_route("test/topic", echo_handler); + + let barrier = Arc::new(Barrier::new(10)); + let mut handles = Vec::new(); + + for _ in 0..10 { + let router_cloned = router.clone(); + let barrier_cloned = barrier.clone(); + + let handle = tokio::spawn(async move { + let publish = create_publish("test/topic", b"concurrent"); + let req = MqttRequest::new(publish); + + barrier_cloned.wait().await; + let response = router_cloned.handle_request(req).await; + assert!(response.is_some()); + assert_eq!(response.unwrap().payload, Bytes::from("concurrent")); + }); + handles.push(handle); + } + + for handle in handles { + handle.await.unwrap(); + } + } +} diff --git a/crates/rtss_mqtt/src/lib.rs b/crates/rtss_mqtt/src/lib.rs deleted file mode 100644 index aa7f8d6..0000000 --- a/crates/rtss_mqtt/src/lib.rs +++ /dev/null @@ -1,702 +0,0 @@ -use core::panic; -use std::{ - any::TypeId, - collections::HashMap, - sync::{ - atomic::{AtomicU64, Ordering}, - Arc, Mutex, - }, - task::Waker, - time::Duration, -}; - -use bytes::Bytes; -use lazy_static::lazy_static; -use rtss_log::tracing::{debug, error, info, trace}; -use rumqttc::{ - v5::{ - mqttbytes::{ - v5::{Packet, Publish, PublishProperties}, - QoS, - }, - AsyncClient, Event, EventLoop, MqttOptions, - }, - Outgoing, -}; -use tokio::{sync::oneshot, time::timeout}; - -mod error; -use error::MqttClientError; - -lazy_static! { -/// 全局静态MqttClient实例 -/// 使用注意事项: -/// 每次订阅/发布/请求时都通过get_global_mqtt_client获取新的实例,否则可能会出现死锁 -static ref MQTT_CLIENT: tokio::sync::Mutex> = tokio::sync::Mutex::new(None); -} - -/// 初始化全局MqttClient实例 -pub async fn init_global_mqtt_client( - mut options: MqttClientOptions, -) -> Result<(), MqttClientError> { - let client = options.build(); - set_global_mqtt_client(client).await -} - -/// 设置全局MqttClient实例 -pub async fn set_global_mqtt_client(client: MqttClient) -> Result<(), MqttClientError> { - let mut mqtt_client = MQTT_CLIENT.lock().await; - if mqtt_client.is_some() { - return Err(MqttClientError::AlreadySet); - } - *mqtt_client = Some(client); - Ok(()) -} - -/// 获取全局MqttClient实例 -pub async fn get_global_mqtt_client() -> MqttClient { - let mqtt_client = MQTT_CLIENT.lock().await; - if let Some(client) = mqtt_client.as_ref() { - return client.clone(); - } - panic!("MqttClient未初始化: 使用init_global_mqtt_client初始化,或者在main函数中调用set_global_mqtt_client设置"); -} - -pub struct MqttClientOptions { - id: String, - options: MqttOptions, - /// mqtt客户端请求队列的最大容量 - max_cap: usize, - request_timeout: Duration, -} - -impl MqttClientOptions { - pub fn new(id: &str, url: &str) -> Self { - Self { - id: id.to_string(), - options: MqttOptions::parse_url(format!("{}?client_id={}", url, id)) - .expect("解析mqtt url失败"), - max_cap: 30, - request_timeout: Duration::from_secs(5), - } - } - - pub fn set_max_cap(mut self, max_cap: usize) -> Self { - self.max_cap = max_cap; - self - } - - pub fn set_request_timeout(mut self, timeout: Duration) -> Self { - self.request_timeout = timeout; - self - } - - pub fn set_credentials(mut self, username: &str, password: &str) -> Self { - self.options.set_credentials(username, password); - self - } - - pub fn build(&mut self) -> MqttClient { - self.options.set_keep_alive(Duration::from_secs(10)); - let (client, eventloop) = AsyncClient::new(self.options.clone(), self.max_cap); - - let subscriptions = SubscribeHandlerMap::new(); - let cli = MqttClient { - id: self.id.clone(), - request_timeout: self.request_timeout, - client, - request_id: Arc::new(AtomicU64::new(0)), - subscriptions, - }; - cli.run_async(eventloop); - cli - } -} - -/// MQTT客户端 -/// id: 客户端ID,从数据库的id序列中获取 -/// 客户端具有的功能: -/// 1. 启动 -/// 2. 订阅 -/// 3. 发布 -/// 4. 实现类似http的请求相应功能 -/// 5. 断开连接 -#[derive(Clone)] -pub struct MqttClient { - id: String, - /// 全局的请求超时时间 - request_timeout: Duration, - client: AsyncClient, - request_id: Arc, - subscriptions: SubscribeHandlerMap, -} - -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct HandlerId(TypeId); - -#[derive(Clone)] -pub struct SubscribeHandlerMap { - sub_handlers: Arc>>, -} - -impl SubscribeHandlerMap { - fn new() -> Self { - Self { - sub_handlers: Arc::new(Mutex::new(HashMap::new())), - } - } - - fn insert( - &self, - topic: &str, - handler_id: HandlerId, - handler: Arc, - ) -> HandlerId { - self.sub_handlers - .lock() - .unwrap() - .entry(topic.to_string()) - .or_insert_with(MessageHandlerMap::new) - .insert(handler_id, handler); - handler_id - } - - fn remove(&self, topic: &str, handler_id: HandlerId) { - if let Some(topic_handlers) = self.sub_handlers.lock().unwrap().get_mut(topic) { - topic_handlers.remove(handler_id); - } - } - - #[allow(dead_code)] - fn remove_all(&self, topic: &str) { - if let Some(topic_handlers) = self.sub_handlers.lock().unwrap().get_mut(topic) { - topic_handlers.remove_all(); - } - } - - fn get_handlers(&self, topic: &str) -> Option>> { - self.sub_handlers - .lock() - .unwrap() - .get(topic) - .map(|handlers| handlers.values()) - } - - #[allow(dead_code)] - fn get_mut(&self, topic: &str) -> Option { - self.sub_handlers.lock().unwrap().get(topic).cloned() - } - - #[allow(dead_code)] - fn is_topic_empty(&self, topic: &str) -> bool { - if let Some(topic_handlers) = self.sub_handlers.lock().unwrap().get(topic) { - topic_handlers.is_empty() - } else { - true - } - } - - #[allow(dead_code)] - fn is_empty(&self) -> bool { - self.sub_handlers.lock().unwrap().is_empty() - } - - fn clear(&self) { - self.sub_handlers.lock().unwrap().clear(); - } -} - -#[derive(Clone)] -struct MessageHandlerMap { - handlers: Arc>>>, -} - -impl MessageHandlerMap { - fn new() -> Self { - Self { - handlers: Arc::new(Mutex::new(HashMap::new())), - } - } - - fn insert(&self, handler_id: HandlerId, handler: Arc) { - self.handlers.lock().unwrap().insert(handler_id, handler); - } - - /// 移除处理器,返回剩余处理器数量 - fn remove(&self, handler_id: HandlerId) -> Option> { - self.handlers.lock().unwrap().remove(&handler_id) - } - - #[allow(dead_code)] - fn remove_all(&self) { - self.handlers.lock().unwrap().clear(); - } - - fn values(&self) -> Vec> { - self.handlers.lock().unwrap().values().cloned().collect() - } - - #[allow(dead_code)] - fn is_empty(&self) -> bool { - self.handlers.lock().unwrap().is_empty() - } -} - -#[must_use = "this `SubscribeTopicHandler` implements `Drop`, which will unregister the handler"] -#[derive(Clone)] -pub struct SubscribeTopicHandler { - topic: String, - handler_id: HandlerId, - handler_map: SubscribeHandlerMap, -} - -impl SubscribeTopicHandler { - pub fn new(topic: &str, handler_id: HandlerId, handler_map: SubscribeHandlerMap) -> Self { - Self { - topic: topic.to_string(), - handler_id, - handler_map, - } - } - - pub fn unregister(&self) { - self.handler_map.remove(&self.topic, self.handler_id); - } -} - -/// 订阅消息处理器 -#[async_trait::async_trait] -pub trait MessageHandler: Send + Sync { - async fn handle(&self, publish: Publish); -} - -/// 为闭包实现消息处理器 -#[async_trait::async_trait] -impl MessageHandler for F -where - F: Fn(Publish) + Sync + Send, -{ - async fn handle(&self, publish: Publish) { - self(publish); - } -} - -impl MqttClient { - pub async fn clear(&self) -> Result<(), MqttClientError> { - self.client.disconnect().await?; - // 清空订阅处理器 - self.subscriptions.clear(); - Ok(()) - } - - pub fn id(&self) -> &str { - &self.id - } - - pub async fn subscribe(&self, topic: &str, qos: QoS) -> Result<(), MqttClientError> { - self.client.subscribe(topic, qos).await?; - Ok(()) - } - - pub async fn unsubscribe(&self, topic: &str) -> Result<(), MqttClientError> { - self.client.unsubscribe(topic).await?; - Ok(()) - } - - pub fn register_topic_handler(&self, topic: &str, handler: H) -> SubscribeTopicHandler - where - H: MessageHandler + 'static, - { - let handler_id = HandlerId(TypeId::of::()); - self.subscriptions - .insert(topic, handler_id, Arc::new(handler)); - SubscribeTopicHandler::new(topic, handler_id, self.subscriptions.clone()) - } - - pub fn unregister_topic(&self, topic: &str) { - self.subscriptions.remove_all(topic); - } - - pub fn topic_handler_count(&self, topic: &str) -> usize { - if let Some(topic_handlers) = self.subscriptions.get_handlers(topic) { - topic_handlers.len() - } else { - 0 - } - } - - pub async fn publish( - &self, - topic: &str, - qos: QoS, - payload: Vec, - ) -> Result<(), MqttClientError> { - self.client.publish(topic, qos, false, payload).await?; - Ok(()) - } - - pub fn next_request_id(&self) -> u64 { - self.request_id.fetch_add(1, Ordering::Relaxed) - } - - /// 发送请求并等待响应 - /// TODO: 需要测试中请求时的并发情况(多个请求同时等待,以及在请求时订阅和发布是否受影响) - pub async fn request( - &self, - topic: &str, - qos: QoS, - payload: Vec, - ) -> Result { - // 订阅响应主题 - let response_topic = format!("{}/{}/resp/{}", self.id, topic, self.next_request_id()); - self.subscribe(&response_topic, QoS::ExactlyOnce).await?; - // 创建请求future - let response_future = MqttResponseFuture::new(&response_topic, self.request_timeout); - // 注册响应处理器 - let response_handler = - self.register_topic_handler(&response_topic, response_future.clone()); - // 发布请求 - let property = PublishProperties { - response_topic: Some(response_topic.clone()), - ..Default::default() - }; - self.client - .publish_with_properties(topic, qos, false, payload, property) - .await?; - // 等待响应 - let resp = response_future.await; - // 注销响应处理器并取消订阅 - response_handler.unregister(); - self.unsubscribe(&response_topic).await?; - Ok(resp) - } - - /// 发送请求并等待响应,指定响应超时时间 - /// 响应超时时间为0时表示永不超时 - pub async fn request_with_timeout( - &self, - topic: &str, - qos: QoS, - payload: Vec, - timeout: Duration, - ) -> Result { - let response_topic = format!("{}/{}/resp/{}", self.id, topic, self.next_request_id()); - self.subscribe(&response_topic, QoS::ExactlyOnce).await?; - let response_future = MqttResponseFuture::new(&response_topic, timeout); - let response_handler = - self.register_topic_handler(&response_topic, response_future.clone()); - let property = PublishProperties { - response_topic: Some(response_topic.clone()), - ..Default::default() - }; - self.client - .publish_with_properties(topic, qos, false, payload, property) - .await?; - let resp = response_future.await; - response_handler.unregister(); - self.unsubscribe(&response_topic).await?; - Ok(resp) - } - - fn run_async(&self, eventloop: EventLoop) { - let cli = self.clone(); - tokio::spawn(async move { - cli.run(eventloop).await; - }); - } - - async fn run(&self, mut eventloop: EventLoop) { - while let Ok(notification) = eventloop.poll().await { - match notification { - Event::Incoming(Packet::Publish(publish)) => { - trace!("Received message: {:?}", publish); - let topic: String = String::from_utf8_lossy(&publish.topic).to_string(); - - if let Some(topic_handlers) = self.subscriptions.get_handlers(&topic) { - for handler in topic_handlers { - let handler = handler.clone(); - let p = publish.clone(); - tokio::spawn(async move { - handler.handle(p).await; - }); - } - } - } - Event::Outgoing(Outgoing::Disconnect) => { - info!("Disconnected to the broker"); - break; - } - Event::Incoming(Packet::Disconnect(disconnect)) => { - info!("Disconnected from the broker: {:?}", disconnect); - break; - } - _ => { - trace!("Unhandled event: {:?}", notification); - } - } - } - } -} - -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub enum MqttResponseState { - Waiting, - Received, - Timeout, -} - -/// MQTT请求响应 -#[derive(Clone, Debug)] -pub struct MqttResponse { - state: Arc>, - response: Arc>, -} - -impl Default for MqttResponse { - fn default() -> Self { - Self::new() - } -} - -impl MqttResponse { - pub fn new() -> Self { - Self { - state: Arc::new(Mutex::new(MqttResponseState::Waiting)), - response: Arc::new(Mutex::new(Bytes::new())), - } - } - - pub fn is_waiting(&self) -> bool { - *self.state.lock().unwrap() == MqttResponseState::Waiting - } - - pub fn is_received(&self) -> bool { - *self.state.lock().unwrap() == MqttResponseState::Received - } - - pub fn is_timeout(&self) -> bool { - *self.state.lock().unwrap() == MqttResponseState::Timeout - } - - pub fn set_timeout(&self) { - *self.state.lock().unwrap() = MqttResponseState::Timeout; - } - - pub fn set(&self, response: Bytes) { - *self.state.lock().unwrap() = MqttResponseState::Received; - *self.response.lock().unwrap() = response; - } - - pub fn get(&self) -> Bytes { - self.response.lock().unwrap().clone() - } -} - -/// MQTT响应Future -#[derive(Clone)] -pub struct MqttResponseFuture { - pub start_time: std::time::Instant, - timeout: Duration, - tx: Arc>>>, - waker: Arc>>, - response_topic: String, - response: MqttResponse, -} - -impl MqttResponseFuture { - pub fn new(response_topic: &str, timeout: Duration) -> Self { - let (tx, rx) = oneshot::channel(); - let r = Self { - start_time: std::time::Instant::now(), - timeout, - tx: Arc::new(Mutex::new(Some(tx))), - waker: Arc::new(Mutex::new(None)), - response_topic: response_topic.to_string(), - response: MqttResponse::new(), - }; - // 启动超时检查 - r.start_timeout_monitor(rx); - - r - } - - /// 启动超时监控任务逻辑 - fn start_timeout_monitor(&self, rx: oneshot::Receiver<()>) { - if self.timeout.as_millis() == 0 { - return; - } - let response = self.response.clone(); - let response_topic = self.response_topic.clone(); - let duration = self.timeout; - let waker = self.waker.clone(); - tokio::spawn(async move { - if (timeout(duration, rx).await).is_err() { - error!("Mqtt response timeout: {:?}", response_topic); - response.set_timeout(); - if let Some(waker) = waker.lock().unwrap().take() { - waker.wake(); - } - } - }); - } -} - -#[async_trait::async_trait] -impl MessageHandler for MqttResponseFuture { - async fn handle(&self, publish: Publish) { - if publish.topic == self.response_topic { - self.response.set(publish.payload); - if let Some(tx) = self.tx.lock().unwrap().take() { - tx.send(()) - .expect("Send Mqtt response timeout signal failed"); - } - if let Some(waker) = self.waker.lock().unwrap().take() { - waker.wake(); - } - } - } -} - -impl std::future::Future for MqttResponseFuture { - type Output = MqttResponse; - - fn poll( - self: std::pin::Pin<&mut Self>, - cx: &mut std::task::Context<'_>, - ) -> std::task::Poll { - if self.response.is_waiting() { - debug!( - "topic={} Response future poll waiting...", - self.response_topic - ); - self.waker.lock().unwrap().replace(cx.waker().clone()); - std::task::Poll::Pending - } else { - debug!( - "topic={} Response future poll ready: {:?}", - self.response_topic, self.response - ); - std::task::Poll::Ready(self.response.clone()) - } - } -} - -pub fn get_publish_response_topic(publish: Option) -> Option { - publish.and_then(|p| p.response_topic.clone()) -} - -#[cfg(test)] -mod tests { - use super::*; - use rtss_log::tracing::{info, Level}; - - use tokio::{ - sync::broadcast, - time::{sleep, Duration}, - }; - - fn create_mqtt_options() -> MqttClientOptions { - MqttClientOptions::new("rtss_test1", "tcp://localhost:1883") - .set_credentials("rtsa", "Joylink@0503") - } - - #[tokio::test] - async fn test_subscribe_and_publish() { - rtss_log::Logging::default().with_level(Level::TRACE).init(); - let client = create_mqtt_options().build(); - - client - .subscribe("test/topic", QoS::AtMostOnce) - .await - .unwrap(); - let handler1 = client.register_topic_handler("test/topic", |publish: Publish| { - info!( - "Handler 1 received: topic={}, payload={:?}", - String::from_utf8_lossy(&publish.topic), - String::from_utf8_lossy(&publish.payload) - ); - }); - let _ = client.register_topic_handler("test/topic", |publish: Publish| { - info!( - "Handler 2 received: topic={}, payload={:?}", - String::from_utf8_lossy(&publish.topic), - String::from_utf8_lossy(&publish.payload) - ); - }); - - assert_eq!(client.topic_handler_count("test/topic"), 2); - client - .publish("test/topic", QoS::AtMostOnce, b"Hello, MQTT!".to_vec()) - .await - .unwrap(); - - // Wait for a moment to allow handlers to process the message - sleep(Duration::from_millis(200)).await; - - // Test remove_handler - client.unsubscribe("test/topic").await.unwrap(); - handler1.unregister(); - assert_eq!(client.topic_handler_count("test/topic"), 1); - - sleep(Duration::from_millis(200)).await; - // Test clear - client.clear().await.unwrap(); - - assert_eq!(client.topic_handler_count("test/topic"), 0); - } - - #[tokio::test] - async fn test_request() { - rtss_log::Logging::default().with_level(Level::DEBUG).init(); - init_global_mqtt_client(create_mqtt_options()) - .await - .unwrap(); - - let c = get_global_mqtt_client().await; - c.subscribe("test/request", QoS::AtMostOnce).await.unwrap(); - let handler = |p: Publish| { - info!( - "Request handler received: topic={}, payload={:?}", - String::from_utf8_lossy(&p.topic), - String::from_utf8_lossy(&p.payload) - ); - let response = Bytes::from("Hello, response!"); - let resp_topic = get_publish_response_topic(p.properties.clone()); - if let Some(r_topic) = resp_topic { - tokio::spawn(async move { - // 此处需要使用全局MqttClient实例,否则会出现死锁 - let c = get_global_mqtt_client().await; - c.publish(&r_topic, QoS::AtMostOnce, response.to_vec()) - .await - .unwrap(); - }); - } - }; - let _ = c.register_topic_handler("test/request", handler); - - let response = c - .request("test/request", QoS::AtMostOnce, b"Hello, request!".to_vec()) - .await - .unwrap(); - info!("Request response: {:?}", response); - } - - #[tokio::test] - async fn test_async_broadcast() { - let (tx, mut rx1) = broadcast::channel(16); - let mut rx2 = tx.subscribe(); - - tokio::spawn(async move { - assert_eq!(rx1.recv().await.unwrap(), 10); - assert_eq!(rx1.recv().await.unwrap(), 20); - }); - - tokio::spawn(async move { - assert_eq!(rx2.recv().await.unwrap(), 10); - assert_eq!(rx2.recv().await.unwrap(), 20); - }); - - tx.send(10).unwrap(); - tx.send(20).unwrap(); - } -} diff --git a/manager/Cargo.toml b/manager/Cargo.toml index acb9982..bb6c07f 100644 --- a/manager/Cargo.toml +++ b/manager/Cargo.toml @@ -5,9 +5,9 @@ edition = "2021" [dependencies] tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } -rtss_log = { path = "../crates/rtss_log" } -rtss_api = { path = "crates/rtss_api" } -rtss_db = { path = "../crates/rtss_db" } +rtsa_log = { path = "../crates/rtsa_log" } +rtsa_api = { path = "crates/rtsa_api" } +rtsa_db = { path = "../crates/rtsa_db" } serde = { workspace = true } config = { workspace = true } clap = { workspace = true, features = ["derive"] } diff --git a/Dockerfile b/manager/Dockerfile similarity index 69% rename from Dockerfile rename to manager/Dockerfile index 51a1089..9485a0a 100644 --- a/Dockerfile +++ b/manager/Dockerfile @@ -11,11 +11,11 @@ ENV TZ=Asia/Shanghai # 复制时区信息到系统时区目录 RUN cp /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone -WORKDIR /rtss_sim -COPY ./target/x86_64-unknown-linux-musl/release/rtss_simulation ./rtss_sim +WORKDIR /rtsa +COPY ./target/x86_64-unknown-linux-musl/release/manager ./rtsa_m COPY ./conf/* ./conf/ COPY ./migrations/* ./migrations/ EXPOSE 8765 -CMD ["sh", "-c", "./rtss_sim db migrate && ./rtss_sim serve"] +CMD ["sh", "-c", "./rtsa_m db migrate && ./rtsa_m serve"] diff --git a/manager/conf/dev.toml b/manager/conf/dev.toml index 839879b..2a3d22a 100644 --- a/manager/conf/dev.toml +++ b/manager/conf/dev.toml @@ -2,4 +2,4 @@ url = "postgresql://joylink:Joylink@0503@localhost:5432/joylink" [sso] -base_url = "http://192.168.33.233/rtss-server" +base_url = "http://192.168.33.233/rtsa-server" diff --git a/manager/conf/local_test.toml b/manager/conf/local_test.toml index c876abf..b452e50 100644 --- a/manager/conf/local_test.toml +++ b/manager/conf/local_test.toml @@ -5,4 +5,4 @@ url = "postgresql://joylink:Joylink@0503@10.11.11.2:5432/joylink" level = "debug" [sso] -base_url = "http://192.168.33.233/rtss-server" +base_url = "http://192.168.33.233/rtsa-server" diff --git a/manager/crates/rtss_api/Cargo.toml b/manager/crates/rtsa_api/Cargo.toml similarity index 81% rename from manager/crates/rtss_api/Cargo.toml rename to manager/crates/rtsa_api/Cargo.toml index c2b8815..c196377 100644 --- a/manager/crates/rtss_api/Cargo.toml +++ b/manager/crates/rtsa_api/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "rtss_api" +name = "rtsa_api" version = "0.1.0" edition = "2021" @@ -19,6 +19,6 @@ base64 = "0.22.1" sysinfo = "0.31.3" reqwest = { version = "0.12.7", default-features = false, features = ["rustls-tls", "json"] } -rtss_log = { path = "../../../crates/rtss_log" } -rtss_db = { path = "../../../crates/rtss_db" } -rtss_dto = { path = "../../../crates/rtss_dto" } +rtsa_log = { path = "../../../crates/rtsa_log" } +rtsa_db = { path = "../../../crates/rtsa_db" } +rtsa_dto = { path = "../../../crates/rtsa_dto" } diff --git a/manager/crates/rtss_api/src/apis/data_options_def.rs b/manager/crates/rtsa_api/src/apis/data_options_def.rs similarity index 93% rename from manager/crates/rtss_api/src/apis/data_options_def.rs rename to manager/crates/rtsa_api/src/apis/data_options_def.rs index b0ea32b..9a21c95 100644 --- a/manager/crates/rtss_api/src/apis/data_options_def.rs +++ b/manager/crates/rtsa_api/src/apis/data_options_def.rs @@ -1,6 +1,6 @@ use async_graphql::{InputObject, InputType, OutputType, SimpleObject}; -use rtss_db::{common::TableColumn, model::DraftDataColumn}; -use rtss_dto::common::IscsStyle; +use rtsa_db::{common::TableColumn, model::DraftDataColumn}; +use rtsa_dto::common::IscsStyle; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde_json::Value; @@ -36,7 +36,7 @@ mod tests { #[test] fn test_iscs_data_options_serialize() { - rtss_log::Logging::default().init(); + rtsa_log::Logging::default().init(); let options = IscsDataOptions { style: IscsStyle::DaShiZhiNeng, }; diff --git a/manager/crates/rtss_api/src/apis/draft_data.rs b/manager/crates/rtsa_api/src/apis/draft_data.rs similarity index 88% rename from manager/crates/rtss_api/src/apis/draft_data.rs rename to manager/crates/rtsa_api/src/apis/draft_data.rs index bd826b2..457fb3b 100644 --- a/manager/crates/rtss_api/src/apis/draft_data.rs +++ b/manager/crates/rtsa_api/src/apis/draft_data.rs @@ -3,13 +3,13 @@ use async_graphql::{ComplexObject, Context, InputObject, Object, SimpleObject}; use base64::prelude::*; use base64::Engine; use chrono::NaiveDateTime; -use rtss_db::DraftDataAccessor; -use rtss_db::RtssDbAccessor; -use rtss_dto::common::{DataType, Role}; +use rtsa_db::DraftDataAccessor; +use rtsa_db::RtsaDbAccessor; +use rtsa_dto::common::{DataType, Role}; use serde_json::Value; use crate::apis::{PageDto, PageQueryDto}; -use crate::loader::RtssDbLoader; +use crate::loader::RtsaDbLoader; use super::data_options_def::{DataOptions, IscsDataOptions}; use super::release_data::ReleaseDataId; @@ -33,7 +33,7 @@ impl DraftDataQuery { paging: PageQueryDto, query: DraftDataFilterDto, ) -> async_graphql::Result> { - let db_accessor = ctx.data::()?; + let db_accessor = ctx.data::()?; let paging_result = db_accessor .paging_query_draft_data(query.into(), paging.into()) .await?; @@ -53,7 +53,7 @@ impl DraftDataQuery { .await?; query.user_id = user.id_i32(); query.data_type = Some(DataType::Iscs); - let db_accessor = ctx.data::()?; + let db_accessor = ctx.data::()?; let paging_result = db_accessor .paging_query_draft_data(query.into(), paging.into()) .await?; @@ -67,7 +67,7 @@ impl DraftDataQuery { paging: PageQueryDto, mut query: DraftDataFilterDto, ) -> async_graphql::Result> { - let db_accessor = ctx.data::()?; + let db_accessor = ctx.data::()?; query.data_type = Some(DataType::Iscs); let paging_result = db_accessor .paging_query_draft_data(query.into(), paging.into()) @@ -77,7 +77,7 @@ impl DraftDataQuery { /// 根据id获取草稿数据 #[graphql(guard = "RoleGuard::new(Role::User)")] async fn draft_data(&self, ctx: &Context<'_>, id: i32) -> async_graphql::Result { - let db_accessor = ctx.data::()?; + let db_accessor = ctx.data::()?; let draft_data = db_accessor.query_draft_data_by_id(id).await?; Ok(draft_data.into()) } @@ -94,7 +94,7 @@ impl DraftDataQuery { .query_user(&ctx.data::()?.0) .await?; let user_id = user.id_i32(); - let db_accessor = ctx.data::()?; + let db_accessor = ctx.data::()?; let exist = db_accessor .is_draft_data_exist(user_id, &data_type, &name) .await?; @@ -116,7 +116,7 @@ impl DraftDataMutation { .query_user(&ctx.data::()?.0) .await?; input = input.with_data_type_and_user_id(DataType::Iscs, user.id_i32()); - let db_accessor = ctx.data::()?; + let db_accessor = ctx.data::()?; let draft_data = db_accessor.create_draft_data(input.into()).await?; Ok(draft_data.into()) } @@ -128,7 +128,7 @@ impl DraftDataMutation { id: i32, name: String, ) -> async_graphql::Result { - let db_accessor = ctx.data::()?; + let db_accessor = ctx.data::()?; let draft_data = db_accessor.update_draft_data_name(id, &name).await?; Ok(draft_data.into()) } @@ -141,7 +141,7 @@ impl DraftDataMutation { id: i32, data: String, // base64编码的数据 ) -> async_graphql::Result { - let db_accessor = ctx.data::()?; + let db_accessor = ctx.data::()?; let bytes = BASE64_STANDARD .decode(data) .map_err(|e| async_graphql::Error::new(format!("base64 decode error: {}", e)))?; @@ -156,7 +156,7 @@ impl DraftDataMutation { id: i32, is_shared: bool, ) -> async_graphql::Result { - let db_accessor = ctx.data::()?; + let db_accessor = ctx.data::()?; let draft_data = db_accessor.set_draft_data_shared(id, is_shared).await?; Ok(draft_data.into()) } @@ -167,7 +167,7 @@ impl DraftDataMutation { ctx: &Context<'_>, id: Vec, ) -> async_graphql::Result { - let db_accessor = ctx.data::()?; + let db_accessor = ctx.data::()?; db_accessor.delete_draft_data(id.as_slice()).await?; Ok(true) } @@ -179,7 +179,7 @@ impl DraftDataMutation { id: i32, release_data_id: i32, ) -> async_graphql::Result { - let db_accessor = ctx.data::()?; + let db_accessor = ctx.data::()?; let draft_data = db_accessor .set_default_release_data_id(id, release_data_id) .await?; @@ -198,7 +198,7 @@ impl DraftDataMutation { .query_user(&ctx.data::()?.0) .await?; let user_id = user.id_i32(); - let db_accessor = ctx.data::()?; + let db_accessor = ctx.data::()?; let draft_data = db_accessor.save_as_new_draft(id, &name, user_id).await?; Ok(draft_data.into()) } @@ -223,7 +223,7 @@ impl CreateDraftDataDto { } } -impl From> for rtss_db::CreateDraftData { +impl From> for rtsa_db::CreateDraftData { fn from(value: CreateDraftDataDto) -> Self { let cdd = Self::new( &value.name, @@ -246,12 +246,12 @@ pub struct UserDraftDataFilterDto { pub user_id: i32, pub name: Option, /// 数据类型,在某个具体类型查询时不传,传了也不生效 - pub data_type: Option, + pub data_type: Option, pub options: Option, pub is_shared: Option, } -impl From> for rtss_db::DraftDataQuery { +impl From> for rtsa_db::DraftDataQuery { fn from(value: UserDraftDataFilterDto) -> Self { Self { user_id: Some(value.user_id), @@ -277,7 +277,7 @@ pub struct DraftDataFilterDto { pub options: Option, } -impl From> for rtss_db::DraftDataQuery { +impl From> for rtsa_db::DraftDataQuery { fn from(value: DraftDataFilterDto) -> Self { Self { user_id: value.user_id, @@ -313,7 +313,7 @@ impl DraftDataDto { ctx: &Context<'_>, ) -> async_graphql::Result> { if let Some(version_id) = self.default_release_data_id { - let loader = ctx.data_unchecked::>(); + let loader = ctx.data_unchecked::>(); let name = loader.load_one(ReleaseDataId::new(version_id)).await?; Ok(name) } else { @@ -323,14 +323,14 @@ impl DraftDataDto { /// 获取用户name async fn user_name(&self, ctx: &Context<'_>) -> async_graphql::Result> { - let loader = ctx.data_unchecked::>(); + let loader = ctx.data_unchecked::>(); let name = loader.load_one(UserId::new(self.user_id)).await?; Ok(name) } } -impl From for DraftDataDto { - fn from(value: rtss_db::model::DraftDataModel) -> Self { +impl From for DraftDataDto { + fn from(value: rtsa_db::model::DraftDataModel) -> Self { Self { id: value.id, name: value.name, @@ -354,8 +354,8 @@ pub struct DraftIscsDataDto { pub options: Option, } -impl From for DraftIscsDataDto { - fn from(value: rtss_db::model::DraftDataModel) -> Self { +impl From for DraftIscsDataDto { + fn from(value: rtsa_db::model::DraftDataModel) -> Self { Self { options: value .options diff --git a/manager/crates/rtss_api/src/apis/feature.rs b/manager/crates/rtsa_api/src/apis/feature.rs similarity index 89% rename from manager/crates/rtss_api/src/apis/feature.rs rename to manager/crates/rtsa_api/src/apis/feature.rs index ba597aa..beeb5ac 100644 --- a/manager/crates/rtss_api/src/apis/feature.rs +++ b/manager/crates/rtsa_api/src/apis/feature.rs @@ -1,15 +1,15 @@ use crate::{ apis::{PageDto, PageQueryDto}, - loader::RtssDbLoader, + loader::RtsaDbLoader, user_auth::{RoleGuard, Token, UserAuthCache}, }; use async_graphql::{ dataloader::DataLoader, ComplexObject, Context, InputObject, Object, SimpleObject, }; use chrono::NaiveDateTime; -use rtss_db::{CreateFeature, FeatureAccessor, RtssDbAccessor, UpdateFeature}; -use rtss_dto::common::FeatureType; -use rtss_dto::common::Role; +use rtsa_db::{CreateFeature, FeatureAccessor, RtsaDbAccessor, UpdateFeature}; +use rtsa_dto::common::FeatureType; +use rtsa_dto::common::Role; use serde_json::Value; use super::{ @@ -33,7 +33,7 @@ impl FeatureQuery { page: PageQueryDto, query: FeatureQueryDto, ) -> async_graphql::Result> { - let dba = ctx.data::()?; + let dba = ctx.data::()?; let paging = dba .paging_query_features(page.into(), &query.into()) .await?; @@ -43,7 +43,7 @@ impl FeatureQuery { /// id获取功能feature #[graphql(guard = "RoleGuard::new(Role::User)")] async fn feature(&self, ctx: &Context<'_>, id: i32) -> async_graphql::Result { - let dba = ctx.data::()?; + let dba = ctx.data::()?; let feature = dba.get_feature(id).await?; Ok(feature.into()) } @@ -55,7 +55,7 @@ impl FeatureQuery { ctx: &Context<'_>, ids: Vec, ) -> async_graphql::Result> { - let dba = ctx.data::()?; + let dba = ctx.data::()?; let features = dba.get_features(ids.as_slice()).await?; Ok(features.into_iter().map(|f| f.into()).collect()) } @@ -71,7 +71,7 @@ impl FeatureMutation { id: i32, is_published: bool, ) -> async_graphql::Result { - let dba = ctx.data::()?; + let dba = ctx.data::()?; let feature = dba.set_feature_published(id, is_published).await?; Ok(feature.into()) } @@ -83,7 +83,7 @@ impl FeatureMutation { ctx: &Context<'_>, mut input: CreateFeatureDto, ) -> async_graphql::Result { - let dba = ctx.data::()?; + let dba = ctx.data::()?; let user = ctx .data::()? .query_user(&ctx.data::()?.0) @@ -100,7 +100,7 @@ impl FeatureMutation { ctx: &Context<'_>, input: UpdateFeatureDto, ) -> async_graphql::Result { - let dba = ctx.data::()?; + let dba = ctx.data::()?; let feature = dba.update_feature(&input.into()).await?; Ok(feature.into()) } @@ -168,7 +168,7 @@ pub struct FeatureQueryDto { pub is_published: Option, } -impl From for rtss_db::FeaturePagingFilter { +impl From for rtsa_db::FeaturePagingFilter { fn from(value: FeatureQueryDto) -> Self { Self { name: value.name, @@ -197,21 +197,21 @@ pub struct FeatureDto { impl FeatureDto { /// 创建用户name async fn creator_name(&self, ctx: &Context<'_>) -> async_graphql::Result> { - let loader = ctx.data_unchecked::>(); + let loader = ctx.data_unchecked::>(); let name = loader.load_one(UserId::new(self.creator_id)).await?; Ok(name) } /// 更新用户name async fn updater_name(&self, ctx: &Context<'_>) -> async_graphql::Result> { - let loader = ctx.data_unchecked::>(); + let loader = ctx.data_unchecked::>(); let name = loader.load_one(UserId::new(self.updater_id)).await?; Ok(name) } } -impl From for FeatureDto { - fn from(value: rtss_db::model::FeatureModel) -> Self { +impl From for FeatureDto { + fn from(value: rtsa_db::model::FeatureModel) -> Self { Self { id: value.id, feature_type: value.feature_type, diff --git a/manager/crates/rtss_api/src/apis/feature_config_def.rs b/manager/crates/rtsa_api/src/apis/feature_config_def.rs similarity index 100% rename from manager/crates/rtss_api/src/apis/feature_config_def.rs rename to manager/crates/rtsa_api/src/apis/feature_config_def.rs diff --git a/manager/crates/rtss_api/src/apis/mod.rs b/manager/crates/rtsa_api/src/apis/mod.rs similarity index 90% rename from manager/crates/rtss_api/src/apis/mod.rs rename to manager/crates/rtsa_api/src/apis/mod.rs index 0cc599f..ed4ef19 100644 --- a/manager/crates/rtss_api/src/apis/mod.rs +++ b/manager/crates/rtsa_api/src/apis/mod.rs @@ -25,7 +25,7 @@ pub struct Mutation( ); #[derive(Enum, Copy, Clone, Default, Eq, PartialEq, Debug)] -#[graphql(remote = "rtss_db::common::SortOrder")] +#[graphql(remote = "rtsa_db::common::SortOrder")] pub enum SortOrder { #[default] Asc, @@ -40,7 +40,7 @@ pub struct PageQueryDto { pub items_per_page: i32, } -impl From for rtss_db::common::PageQuery { +impl From for rtsa_db::common::PageQuery { fn from(value: PageQueryDto) -> Self { Self { page: value.page, @@ -74,8 +74,8 @@ impl PageDto { } } -impl> From> for PageDto { - fn from(value: rtss_db::common::PageResult) -> Self { +impl> From> for PageDto { + fn from(value: rtsa_db::common::PageResult) -> Self { Self::new( value.total, value.data.into_iter().map(|m| m.into()).collect(), diff --git a/manager/crates/rtss_api/src/apis/release_data.rs b/manager/crates/rtsa_api/src/apis/release_data.rs similarity index 90% rename from manager/crates/rtss_api/src/apis/release_data.rs rename to manager/crates/rtsa_api/src/apis/release_data.rs index 442ee7c..7a4f066 100644 --- a/manager/crates/rtss_api/src/apis/release_data.rs +++ b/manager/crates/rtsa_api/src/apis/release_data.rs @@ -5,14 +5,14 @@ use async_graphql::dataloader::*; use async_graphql::{ComplexObject, Context, InputObject, Object, SimpleObject}; use base64::prelude::*; use chrono::NaiveDateTime; -use rtss_db::model::*; -use rtss_db::prelude::*; -use rtss_db::{model::ReleaseDataModel, ReleaseDataAccessor, RtssDbAccessor}; -use rtss_dto::common::{DataType, Role}; +use rtsa_db::model::*; +use rtsa_db::prelude::*; +use rtsa_db::{model::ReleaseDataModel, ReleaseDataAccessor, RtsaDbAccessor}; +use rtsa_dto::common::{DataType, Role}; use serde_json::Value; use crate::apis::draft_data::DraftDataDto; -use crate::loader::RtssDbLoader; +use crate::loader::RtsaDbLoader; use super::data_options_def::{DataOptions, IscsDataOptions}; use super::user::UserId; @@ -36,7 +36,7 @@ impl ReleaseDataQuery { page: PageQueryDto, query: ReleaseTypedDataFilterDto, ) -> async_graphql::Result> { - let db_accessor = ctx.data::()?; + let db_accessor = ctx.data::()?; let paging = db_accessor .paging_query_release_data_list(query.into(), page.into()) .await?; @@ -51,7 +51,7 @@ impl ReleaseDataQuery { page: PageQueryDto, mut query: ReleaseTypedDataFilterDto, ) -> async_graphql::Result> { - let db_accessor = ctx.data::()?; + let db_accessor = ctx.data::()?; query.data_type = Some(DataType::Iscs); let paging = db_accessor .paging_query_release_data_list(query.into(), page.into()) @@ -66,7 +66,7 @@ impl ReleaseDataQuery { ctx: &Context<'_>, id: i32, ) -> async_graphql::Result { - let db_accessor = ctx.data::()?; + let db_accessor = ctx.data::()?; let model = db_accessor.query_release_data_with_used_version(id).await?; Ok(model.into()) } @@ -79,7 +79,7 @@ impl ReleaseDataQuery { data_type: DataType, name: String, ) -> async_graphql::Result { - let db_accessor = ctx.data::()?; + let db_accessor = ctx.data::()?; let result = db_accessor .is_release_data_name_exist(data_type, &name) .await?; @@ -94,7 +94,7 @@ impl ReleaseDataQuery { data_id: i32, page: PageQueryDto, ) -> async_graphql::Result> { - let db_accessor = ctx.data::()?; + let db_accessor = ctx.data::()?; let paging = db_accessor .paging_query_release_data_version_list(data_id, page.into()) .await?; @@ -108,7 +108,7 @@ impl ReleaseDataQuery { ctx: &Context<'_>, version_id: i32, ) -> async_graphql::Result { - let db_accessor = ctx.data::()?; + let db_accessor = ctx.data::()?; let model = db_accessor .query_release_data_version_by_id(version_id) .await?; @@ -132,7 +132,7 @@ impl ReleaseDataMutation { .query_user(&ctx.data::()?.0) .await?; let user_id = user.id_i32(); - let db_accessor = ctx.data::()?; + let db_accessor = ctx.data::()?; let result = db_accessor .release_new_from_draft(draft_id, &name, &description, Some(user_id)) .await?; @@ -152,7 +152,7 @@ impl ReleaseDataMutation { .query_user(&ctx.data::()?.0) .await?; let user_id = user.id_i32(); - let db_accessor = ctx.data::()?; + let db_accessor = ctx.data::()?; let result = db_accessor .release_to_existing(draft_id, &description, Some(user_id)) .await?; @@ -167,7 +167,7 @@ impl ReleaseDataMutation { id: i32, name: String, ) -> async_graphql::Result { - let db_accessor = ctx.data::()?; + let db_accessor = ctx.data::()?; let result = db_accessor.update_release_data_name(id, &name).await?; Ok(result.into()) } @@ -180,7 +180,7 @@ impl ReleaseDataMutation { id: i32, is_published: bool, ) -> async_graphql::Result { - let db_accessor = ctx.data::()?; + let db_accessor = ctx.data::()?; let result = db_accessor .set_release_data_published(id, is_published) .await?; @@ -195,7 +195,7 @@ impl ReleaseDataMutation { id: i32, version_id: i32, ) -> async_graphql::Result { - let db_accessor = ctx.data::()?; + let db_accessor = ctx.data::()?; let result = db_accessor .set_release_data_used_version(id, version_id) .await?; @@ -214,7 +214,7 @@ impl ReleaseDataMutation { .query_user(&ctx.data::()?.0) .await?; let user_id = user.id_i32(); - let db_accessor = ctx.data::()?; + let db_accessor = ctx.data::()?; let result = db_accessor .create_draft_from_release_version(version_id, user_id) .await?; @@ -235,7 +235,7 @@ pub struct ReleaseTypedDataFilterDto { pub is_published: Option, } -impl From> for rtss_db::ReleaseDataQuery { +impl From> for rtsa_db::ReleaseDataQuery { fn from(value: ReleaseTypedDataFilterDto) -> Self { Self { name: value.name, @@ -265,7 +265,7 @@ pub struct ReleaseDataDto { impl ReleaseDataDto { async fn description(&self, ctx: &Context<'_>) -> async_graphql::Result> { if let Some(version_id) = self.used_version_id { - let loader = ctx.data_unchecked::>(); + let loader = ctx.data_unchecked::>(); let description = loader .load_one(ReleaseDataVersionId::new(version_id)) .await?; @@ -277,7 +277,7 @@ impl ReleaseDataDto { /// 获取用户name async fn user_name(&self, ctx: &Context<'_>) -> async_graphql::Result> { - let loader = ctx.data_unchecked::>(); + let loader = ctx.data_unchecked::>(); let name = loader.load_one(UserId::new(self.user_id)).await?; Ok(name) } @@ -294,7 +294,7 @@ impl ReleaseDataId { } } -impl Loader for RtssDbLoader { +impl Loader for RtsaDbLoader { type Value = String; type Error = Arc; @@ -326,7 +326,7 @@ impl ReleaseDataVersionId { } } -impl Loader for RtssDbLoader { +impl Loader for RtsaDbLoader { type Value = String; type Error = Arc; @@ -388,7 +388,7 @@ pub struct ReleaseDataVersionDto { impl ReleaseDataVersionDto { /// 获取用户name async fn user_name(&self, ctx: &Context<'_>) -> async_graphql::Result> { - let loader = ctx.data_unchecked::>(); + let loader = ctx.data_unchecked::>(); let name = loader.load_one(UserId::new(self.user_id)).await?; Ok(name) } diff --git a/manager/crates/rtss_api/src/apis/sys_info.rs b/manager/crates/rtsa_api/src/apis/sys_info.rs similarity index 100% rename from manager/crates/rtss_api/src/apis/sys_info.rs rename to manager/crates/rtsa_api/src/apis/sys_info.rs diff --git a/manager/crates/rtss_api/src/apis/user.rs b/manager/crates/rtsa_api/src/apis/user.rs similarity index 89% rename from manager/crates/rtss_api/src/apis/user.rs rename to manager/crates/rtsa_api/src/apis/user.rs index 2170d71..b9e240c 100644 --- a/manager/crates/rtss_api/src/apis/user.rs +++ b/manager/crates/rtsa_api/src/apis/user.rs @@ -2,14 +2,14 @@ use std::{collections::HashMap, sync::Arc}; use async_graphql::{dataloader::Loader, Context, InputObject, Object, SimpleObject}; use chrono::NaiveDateTime; -use rtss_db::{DbAccessError, RtssDbAccessor, UserAccessor}; +use rtsa_db::{DbAccessError, RtsaDbAccessor, UserAccessor}; use crate::{ - loader::RtssDbLoader, + loader::RtsaDbLoader, user_auth::{build_jwt, Claims, RoleGuard, Token, UserAuthCache, UserInfoDto}, UserAuthClient, }; -use rtss_dto::common::Role; +use rtsa_dto::common::Role; use super::{PageDto, PageQueryDto}; @@ -47,7 +47,7 @@ impl UserQuery { page: PageQueryDto, query: UserQueryDto, ) -> async_graphql::Result> { - let dba = ctx.data::()?; + let dba = ctx.data::()?; let paging = dba.query_user_page(page.into(), query.into()).await?; Ok(paging.into()) } @@ -63,12 +63,12 @@ impl UserMutation { async fn sync_user(&self, ctx: &Context<'_>) -> async_graphql::Result { let http_client = ctx.data::()?; let users = http_client.query_all_users(ctx.data::()?).await?; - let dba = ctx.data::()?; + let dba = ctx.data::()?; dba.sync_user( users .into_iter() .map(|u| u.into()) - .collect::>() + .collect::>() .as_slice(), ) .await?; @@ -85,7 +85,7 @@ pub struct UserQueryDto { pub roles: Option>, } -impl From for rtss_db::UserPageFilter { +impl From for rtsa_db::UserPageFilter { fn from(value: UserQueryDto) -> Self { Self { id: value.id, @@ -122,8 +122,8 @@ impl From for UserDto { } } -impl From for UserDto { - fn from(value: rtss_db::model::UserModel) -> Self { +impl From for UserDto { + fn from(value: rtsa_db::model::UserModel) -> Self { Self { id: value.id, name: value.username, @@ -147,7 +147,7 @@ impl UserId { } } -impl Loader for RtssDbLoader { +impl Loader for RtsaDbLoader { type Value = String; type Error = Arc; diff --git a/manager/crates/rtss_api/src/lib.rs b/manager/crates/rtsa_api/src/lib.rs similarity index 100% rename from manager/crates/rtss_api/src/lib.rs rename to manager/crates/rtsa_api/src/lib.rs diff --git a/manager/crates/rtsa_api/src/loader/mod.rs b/manager/crates/rtsa_api/src/loader/mod.rs new file mode 100644 index 0000000..877d7ff --- /dev/null +++ b/manager/crates/rtsa_api/src/loader/mod.rs @@ -0,0 +1,10 @@ +/// 数据库加载器 +pub struct RtsaDbLoader { + pub(crate) db_accessor: rtsa_db::RtsaDbAccessor, +} + +impl RtsaDbLoader { + pub fn new(db_accessor: rtsa_db::RtsaDbAccessor) -> Self { + Self { db_accessor } + } +} diff --git a/manager/crates/rtss_api/src/server.rs b/manager/crates/rtsa_api/src/server.rs similarity index 85% rename from manager/crates/rtss_api/src/server.rs rename to manager/crates/rtsa_api/src/server.rs index a1dbe69..6da2201 100644 --- a/manager/crates/rtss_api/src/server.rs +++ b/manager/crates/rtsa_api/src/server.rs @@ -10,13 +10,13 @@ use axum::{ }; use dataloader::DataLoader; use http::{playground_source, GraphQLPlaygroundConfig}; -use rtss_db::RtssDbAccessor; -use rtss_log::tracing::{debug, info}; +use rtsa_db::RtsaDbAccessor; +use rtsa_log::tracing::{debug, info}; use tokio::net::TcpListener; use tower_http::cors::CorsLayer; use crate::apis::{Mutation, Query}; -use crate::loader::RtssDbLoader; +use crate::loader::RtsaDbLoader; use crate::user_auth; pub use crate::user_auth::UserAuthClient; @@ -52,7 +52,7 @@ pub async fn serve(config: ServerConfig) -> anyhow::Result<()> { .user_auth_client .clone() .expect("user auth client not configured"); - let dba = rtss_db::get_db_accessor(&config.database_url).await; + let dba = rtsa_db::get_db_accessor(&config.database_url).await; let schema = new_schema(SchemaOptions::new(client, dba)); let app = Router::new() @@ -76,7 +76,7 @@ pub async fn serve(config: ServerConfig) -> anyhow::Result<()> { } async fn graphql_handler( - State(schema): State, + State(schema): State, headers: HeaderMap, req: GraphQLRequest, ) -> GraphQLResponse { @@ -92,31 +92,31 @@ async fn graphiql() -> impl IntoResponse { Html(playground_source(GraphQLPlaygroundConfig::new("/"))) } -pub type RtssAppSchema = Schema; +pub type RtsaAppSchema = Schema; pub struct SchemaOptions { pub user_auth_client: UserAuthClient, pub user_info_cache: user_auth::UserAuthCache, - pub rtss_dba: RtssDbAccessor, + pub rtsa_dba: RtsaDbAccessor, } impl SchemaOptions { - pub fn new(user_auth_client: UserAuthClient, rtss_dba: RtssDbAccessor) -> Self { + pub fn new(user_auth_client: UserAuthClient, rtsa_dba: RtsaDbAccessor) -> Self { let user_info_cache = user_auth::UserAuthCache::new(user_auth_client.clone()); Self { user_auth_client, user_info_cache, - rtss_dba, + rtsa_dba, } } } -pub fn new_schema(options: SchemaOptions) -> RtssAppSchema { - let loader = RtssDbLoader::new(options.rtss_dba.clone()); +pub fn new_schema(options: SchemaOptions) -> RtsaAppSchema { + let loader = RtsaDbLoader::new(options.rtsa_dba.clone()); Schema::build(Query::default(), Mutation::default(), EmptySubscription) .data(options.user_auth_client) .data(options.user_info_cache) - .data(options.rtss_dba) + .data(options.rtsa_dba) .data(DataLoader::new(loader, tokio::spawn)) // .data(MutexSimulationManager::default()) .finish() @@ -129,7 +129,7 @@ mod tests { #[tokio::test] async fn test_new_schema() { let dba = - rtss_db::get_db_accessor("postgresql://joylink:Joylink@0503@localhost:5432/joylink") + rtsa_db::get_db_accessor("postgresql://joylink:Joylink@0503@localhost:5432/joylink") .await; let _ = new_schema(SchemaOptions::new( crate::UserAuthClient { diff --git a/manager/crates/rtss_api/src/user_auth/jwt_auth.rs b/manager/crates/rtsa_api/src/user_auth/jwt_auth.rs similarity index 97% rename from manager/crates/rtss_api/src/user_auth/jwt_auth.rs rename to manager/crates/rtsa_api/src/user_auth/jwt_auth.rs index b0d144c..e49ba48 100644 --- a/manager/crates/rtss_api/src/user_auth/jwt_auth.rs +++ b/manager/crates/rtsa_api/src/user_auth/jwt_auth.rs @@ -70,7 +70,7 @@ mod tests { #[test] fn test_jwt() { - rtss_log::Logging::default().init(); + rtsa_log::Logging::default().init(); let claim = Claims::new(5); let jwt = build_jwt(claim).unwrap(); println!("jwt: {}", jwt.0); diff --git a/manager/crates/rtss_api/src/user_auth/mod.rs b/manager/crates/rtsa_api/src/user_auth/mod.rs similarity index 97% rename from manager/crates/rtss_api/src/user_auth/mod.rs rename to manager/crates/rtsa_api/src/user_auth/mod.rs index cb8d4ca..854757c 100644 --- a/manager/crates/rtss_api/src/user_auth/mod.rs +++ b/manager/crates/rtsa_api/src/user_auth/mod.rs @@ -6,8 +6,8 @@ use std::{ use async_graphql::Guard; use axum::http::HeaderMap; use chrono::{DateTime, Local}; -use rtss_dto::common::Role; -use rtss_log::tracing::error; +use rtsa_dto::common::Role; +use rtsa_log::tracing::error; use serde::{Deserialize, Serialize}; mod jwt_auth; @@ -225,7 +225,7 @@ fn parse_to_date_time(s: &str) -> chrono::DateTime { .unwrap() } -impl From for rtss_db::SyncUserInfo { +impl From for rtsa_db::SyncUserInfo { fn from(user_info: UserInfoDto) -> Self { Self { id: user_info.id_i32(), @@ -301,9 +301,9 @@ mod tests { // #[tokio::test] // async fn test_user_auth_cache() -> anyhow::Result<()> { - // rtss_log::Logging::default().with_level(Level::DEBUG).init(); + // rtsa_log::Logging::default().with_level(Level::DEBUG).init(); // let client = UserAuthClient { - // base_url: "http://192.168.33.233/rtss-server".to_string(), + // base_url: "http://192.168.33.233/rtsa-server".to_string(), // login_url: "/api/login".to_string(), // logout_url: "/api/login/logout".to_string(), // user_info_url: "/api/login/getUserInfo".to_string(), diff --git a/manager/crates/rtss_api/src/loader/mod.rs b/manager/crates/rtss_api/src/loader/mod.rs deleted file mode 100644 index 693c098..0000000 --- a/manager/crates/rtss_api/src/loader/mod.rs +++ /dev/null @@ -1,10 +0,0 @@ -/// 数据库加载器 -pub struct RtssDbLoader { - pub(crate) db_accessor: rtss_db::RtssDbAccessor, -} - -impl RtssDbLoader { - pub fn new(db_accessor: rtss_db::RtssDbAccessor) -> Self { - Self { db_accessor } - } -} diff --git a/manager/src/app_config.rs b/manager/src/app_config.rs index 305d1f2..3b10d4b 100644 --- a/manager/src/app_config.rs +++ b/manager/src/app_config.rs @@ -20,9 +20,9 @@ pub struct Log { level: String, } -impl From for rtss_log::Logging { +impl From for rtsa_log::Logging { fn from(log: Log) -> Self { - rtss_log::Logging { + rtsa_log::Logging { level: log.level.parse().unwrap(), ..Default::default() } @@ -69,9 +69,9 @@ impl AppConfig { // Default to 'dev' env // Note that this file is _optional_ .add_source(File::with_name(&format!("{dir}/{run_mode}")).required(true)) - // Add in settings from the environment (with a prefix of RTSS_SIM) + // Add in settings from the environment (with a prefix of rtsa_SIM) // Eg.. `APP_DEBUG=1 ./target/app` would set the `debug` key - .add_source(Environment::with_prefix("RTSS_SIM").separator("_")) + .add_source(Environment::with_prefix("rtsa_SIM").separator("_")) // You may also programmatically change settings // .set_override("database.url", "postgres://")? // build the configuration diff --git a/manager/src/commands/cmd.rs b/manager/src/commands/cmd.rs index a78f6ea..fc2583a 100644 --- a/manager/src/commands/cmd.rs +++ b/manager/src/commands/cmd.rs @@ -6,7 +6,7 @@ use crate::{app_config, CmdExecutor}; use super::DbSubCommand; #[derive(Parser, Debug)] -#[command(name = "rtss-sim", version, author, about, long_about = None)] +#[command(name = "rtsa-sim", version, author, about, long_about = None)] pub struct Cmd { #[command(subcommand)] pub cmd: SubCommand, @@ -31,11 +31,11 @@ impl CmdExecutor for ServerOpts { async fn execute(&self) -> anyhow::Result<()> { let app_config = app_config::AppConfig::new(&self.config_path).expect("Failed to load app config"); - let log: rtss_log::Logging = app_config.log.into(); + let log: rtsa_log::Logging = app_config.log.into(); log.init(); - rtss_api::serve( - rtss_api::ServerConfig::new(&app_config.database.url, app_config.server.port) - .with_user_auth_client(rtss_api::UserAuthClient { + rtsa_api::serve( + rtsa_api::ServerConfig::new(&app_config.database.url, app_config.server.port) + .with_user_auth_client(rtsa_api::UserAuthClient { base_url: app_config.sso.base_url, login_url: app_config.sso.login_url, logout_url: app_config.sso.logout_url, diff --git a/manager/src/commands/db.rs b/manager/src/commands/db.rs index 9026b87..c2e0844 100644 --- a/manager/src/commands/db.rs +++ b/manager/src/commands/db.rs @@ -22,6 +22,6 @@ impl CmdExecutor for MigrateOpts { async fn execute(&self) -> anyhow::Result<()> { let app_config = app_config::AppConfig::new(&self.config_path).expect("Failed to load app config"); - rtss_db::run_migrations(&app_config.database.url).await + rtsa_db::run_migrations(&app_config.database.url).await } } diff --git a/migrations/20240830095636_init.down.sql b/migrations/20240830095636_init.down.sql index 852f357..c5fc754 100644 --- a/migrations/20240830095636_init.down.sql +++ b/migrations/20240830095636_init.down.sql @@ -1 +1 @@ -DROP SCHEMA rtss CASCADE; +DROP SCHEMA rtsa CASCADE; diff --git a/migrations/20240830095636_init.up.sql b/migrations/20240830095636_init.up.sql index 0191bd9..975a313 100644 --- a/migrations/20240830095636_init.up.sql +++ b/migrations/20240830095636_init.up.sql @@ -1,12 +1,12 @@ --- 初始化数据库SCHEMA(所有轨道交通信号系统仿真的表、类型等都在rtss SCHEMA下) -CREATE SCHEMA rtss; +-- 初始化数据库SCHEMA(所有轨道交通信号系统仿真的表、类型等都在rtsa SCHEMA下) +CREATE SCHEMA rtsa; -- 创建mqtt客户端id序列 -CREATE SEQUENCE rtss.mqtt_client_id_seq; +CREATE SEQUENCE rtsa.mqtt_client_id_seq; -- 创建用户表 CREATE TABLE - rtss.user ( + rtsa.user ( id SERIAL PRIMARY KEY, -- id 自增主键 username VARCHAR(128) NOT NULL, -- 用户名 password VARCHAR(128) NOT NULL, -- 密码 @@ -18,40 +18,40 @@ CREATE TABLE ); -- 创建用户名称索引 -CREATE INDEX ON rtss.user (username); +CREATE INDEX ON rtsa.user (username); -- 创建用户邮箱索引 -CREATE INDEX ON rtss.user (email); +CREATE INDEX ON rtsa.user (email); -- 创建用户手机号索引 -CREATE INDEX ON rtss.user (mobile); +CREATE INDEX ON rtsa.user (mobile); -- 创建用户角色索引 -CREATE INDEX ON rtss.user USING GIN (roles); +CREATE INDEX ON rtsa.user USING GIN (roles); -- 注释用户表 -COMMENT ON TABLE rtss.user IS '用户表'; +COMMENT ON TABLE rtsa.user IS '用户表'; -- 注释用户表字段 -COMMENT ON COLUMN rtss.user.id IS 'id 自增主键'; +COMMENT ON COLUMN rtsa.user.id IS 'id 自增主键'; -COMMENT ON COLUMN rtss.user.username IS '用户名'; +COMMENT ON COLUMN rtsa.user.username IS '用户名'; -COMMENT ON COLUMN rtss.user.password IS '密码'; +COMMENT ON COLUMN rtsa.user.password IS '密码'; -COMMENT ON COLUMN rtss.user.email IS '邮箱'; +COMMENT ON COLUMN rtsa.user.email IS '邮箱'; -COMMENT ON COLUMN rtss.user.mobile IS '手机号'; +COMMENT ON COLUMN rtsa.user.mobile IS '手机号'; -COMMENT ON COLUMN rtss.user.roles IS '角色列表'; +COMMENT ON COLUMN rtsa.user.roles IS '角色列表'; -COMMENT ON COLUMN rtss.user.created_at IS '创建时间'; +COMMENT ON COLUMN rtsa.user.created_at IS '创建时间'; -COMMENT ON COLUMN rtss.user.updated_at IS '更新时间'; +COMMENT ON COLUMN rtsa.user.updated_at IS '更新时间'; -- 创建草稿数据表 CREATE TABLE - rtss.draft_data ( + rtsa.draft_data ( id SERIAL PRIMARY KEY, -- id 自增主键 name VARCHAR(128) NOT NULL, -- 草稿名称 data_type INT NOT NULL, -- 数据类型 @@ -62,44 +62,44 @@ CREATE TABLE is_shared BOOLEAN NOT NULL DEFAULT FALSE, -- 是否共享 created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间 updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 更新时间 - FOREIGN KEY (user_id) REFERENCES rtss.user (id) ON DELETE CASCADE, -- 用户外键 + FOREIGN KEY (user_id) REFERENCES rtsa.user (id) ON DELETE CASCADE, -- 用户外键 UNIQUE (name, data_type, user_id) -- 一个用户的某个类型的草稿名称唯一 ); -- 创建草稿数据用户索引 -CREATE INDEX ON rtss.draft_data (user_id); +CREATE INDEX ON rtsa.draft_data (user_id); -- 创建草稿数据类型索引 -CREATE INDEX ON rtss.draft_data (data_type); +CREATE INDEX ON rtsa.draft_data (data_type); -- 创建草稿数据配置项索引 -CREATE INDEX ON rtss.draft_data USING GIN (options); +CREATE INDEX ON rtsa.draft_data USING GIN (options); -- 注释草稿数据表 -COMMENT ON TABLE rtss.draft_data IS '草稿数据表'; +COMMENT ON TABLE rtsa.draft_data IS '草稿数据表'; -- 注释草稿数据表字段 -COMMENT ON COLUMN rtss.draft_data.id IS 'id 自增主键'; +COMMENT ON COLUMN rtsa.draft_data.id IS 'id 自增主键'; -COMMENT ON COLUMN rtss.draft_data.name IS '草稿名称'; +COMMENT ON COLUMN rtsa.draft_data.name IS '草稿名称'; -COMMENT ON COLUMN rtss.draft_data.data_type IS '数据类型'; +COMMENT ON COLUMN rtsa.draft_data.data_type IS '数据类型'; -COMMENT ON COLUMN rtss.draft_data.options IS '数据相关的参数项或配置项'; +COMMENT ON COLUMN rtsa.draft_data.options IS '数据相关的参数项或配置项'; -COMMENT ON COLUMN rtss.draft_data.data IS '草稿数据'; +COMMENT ON COLUMN rtsa.draft_data.data IS '草稿数据'; -COMMENT ON COLUMN rtss.draft_data.user_id IS '创建用户id'; +COMMENT ON COLUMN rtsa.draft_data.user_id IS '创建用户id'; -COMMENT ON COLUMN rtss.draft_data.is_shared IS '是否共享'; +COMMENT ON COLUMN rtsa.draft_data.is_shared IS '是否共享'; -COMMENT ON COLUMN rtss.draft_data.created_at IS '创建时间'; +COMMENT ON COLUMN rtsa.draft_data.created_at IS '创建时间'; -COMMENT ON COLUMN rtss.draft_data.updated_at IS '更新时间'; +COMMENT ON COLUMN rtsa.draft_data.updated_at IS '更新时间'; -- 创建发布数据表 CREATE TABLE - rtss.release_data ( + rtsa.release_data ( id SERIAL PRIMARY KEY, -- id 自增主键 name VARCHAR(128) NOT NULL, -- 发布数据名称(数据唯一标识) data_type INT NOT NULL, -- 数据类型 @@ -109,47 +109,47 @@ CREATE TABLE is_published BOOLEAN NOT NULL DEFAULT TRUE, -- 是否上架 created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间 updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 更新时间 - FOREIGN KEY (user_id) REFERENCES rtss.user (id) ON DELETE CASCADE, -- 用户外键 + FOREIGN KEY (user_id) REFERENCES rtsa.user (id) ON DELETE CASCADE, -- 用户外键 UNIQUE(data_type, name) -- 数据类型和名称唯一 ); -- 创建发布数据名称索引 -CREATE INDEX ON rtss.release_data (name); +CREATE INDEX ON rtsa.release_data (name); -- 创建发布数据用户索引 -CREATE INDEX ON rtss.release_data (user_id); +CREATE INDEX ON rtsa.release_data (user_id); -- 创建发布数据类型索引 -CREATE INDEX ON rtss.release_data (data_type); +CREATE INDEX ON rtsa.release_data (data_type); -- 创建发布数据配置项索引 -CREATE INDEX ON rtss.release_data USING GIN (options); +CREATE INDEX ON rtsa.release_data USING GIN (options); -- 注释发布数据表 -COMMENT ON TABLE rtss.release_data IS '发布数据表'; +COMMENT ON TABLE rtsa.release_data IS '发布数据表'; -- 注释发布数据表字段 -COMMENT ON COLUMN rtss.release_data.id IS 'id 自增主键'; +COMMENT ON COLUMN rtsa.release_data.id IS 'id 自增主键'; -COMMENT ON COLUMN rtss.release_data.name IS '发布数据名称(数据唯一标识)'; +COMMENT ON COLUMN rtsa.release_data.name IS '发布数据名称(数据唯一标识)'; -COMMENT ON COLUMN rtss.release_data.data_type IS '数据类型'; +COMMENT ON COLUMN rtsa.release_data.data_type IS '数据类型'; -COMMENT ON COLUMN rtss.release_data.options IS '数据相关的参数项或配置项'; +COMMENT ON COLUMN rtsa.release_data.options IS '数据相关的参数项或配置项'; -COMMENT ON COLUMN rtss.release_data.used_version_id IS '使用的版本数据id'; +COMMENT ON COLUMN rtsa.release_data.used_version_id IS '使用的版本数据id'; -COMMENT ON COLUMN rtss.release_data.user_id IS '发布/更新用户id'; +COMMENT ON COLUMN rtsa.release_data.user_id IS '发布/更新用户id'; -COMMENT ON COLUMN rtss.release_data.is_published IS '是否上架'; +COMMENT ON COLUMN rtsa.release_data.is_published IS '是否上架'; -COMMENT ON COLUMN rtss.release_data.created_at IS '创建时间'; +COMMENT ON COLUMN rtsa.release_data.created_at IS '创建时间'; -COMMENT ON COLUMN rtss.release_data.updated_at IS '更新时间'; +COMMENT ON COLUMN rtsa.release_data.updated_at IS '更新时间'; -- 创建发布数据版本表 CREATE TABLE - rtss.release_data_version ( + rtsa.release_data_version ( id SERIAL PRIMARY KEY, -- id 自增主键 release_data_id INT NOT NULL, -- 发布数据id options JSONB NULL, -- 数据相关的参数项或配置项 @@ -157,46 +157,46 @@ CREATE TABLE description TEXT NOT NULL, -- 版本描述 user_id INT NOT NULL, -- 发布用户id created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间 - FOREIGN KEY (user_id) REFERENCES rtss.user (id) ON DELETE CASCADE, -- 用户外键 - FOREIGN KEY (release_data_id) REFERENCES rtss.release_data (id) ON DELETE CASCADE + FOREIGN KEY (user_id) REFERENCES rtsa.user (id) ON DELETE CASCADE, -- 用户外键 + FOREIGN KEY (release_data_id) REFERENCES rtsa.release_data (id) ON DELETE CASCADE ); -- 创建发布数据版本发布数据索引 -CREATE INDEX ON rtss.release_data_version (release_data_id); +CREATE INDEX ON rtsa.release_data_version (release_data_id); -- 创建发布数据版本用户索引 -CREATE INDEX ON rtss.release_data_version (user_id); +CREATE INDEX ON rtsa.release_data_version (user_id); -- 创建发布数据版本配置项索引 -CREATE INDEX ON rtss.release_data_version USING GIN (options); +CREATE INDEX ON rtsa.release_data_version USING GIN (options); -- 创建发布数据当前版本外键 -ALTER TABLE rtss.release_data ADD FOREIGN KEY (used_version_id) REFERENCES rtss.release_data_version (id) ON DELETE SET NULL; +ALTER TABLE rtsa.release_data ADD FOREIGN KEY (used_version_id) REFERENCES rtsa.release_data_version (id) ON DELETE SET NULL; -- 创建草稿数据默认发布数据外键 -ALTER TABLE rtss.draft_data ADD FOREIGN KEY (default_release_data_id) REFERENCES rtss.release_data (id) ON DELETE SET NULL; +ALTER TABLE rtsa.draft_data ADD FOREIGN KEY (default_release_data_id) REFERENCES rtsa.release_data (id) ON DELETE SET NULL; -- 注释发布数据版本表 -COMMENT ON TABLE rtss.release_data_version IS '发布数据版本表'; +COMMENT ON TABLE rtsa.release_data_version IS '发布数据版本表'; -- 注释发布数据版本表字段 -COMMENT ON COLUMN rtss.release_data_version.id IS 'id 自增主键'; +COMMENT ON COLUMN rtsa.release_data_version.id IS 'id 自增主键'; -COMMENT ON COLUMN rtss.release_data_version.release_data_id IS '发布数据id'; +COMMENT ON COLUMN rtsa.release_data_version.release_data_id IS '发布数据id'; -COMMENT ON COLUMN rtss.release_data_version.options IS '数据相关的参数项或配置项'; +COMMENT ON COLUMN rtsa.release_data_version.options IS '数据相关的参数项或配置项'; -COMMENT ON COLUMN rtss.release_data_version.data IS '数据'; +COMMENT ON COLUMN rtsa.release_data_version.data IS '数据'; -COMMENT ON COLUMN rtss.release_data_version.description IS '版本描述'; +COMMENT ON COLUMN rtsa.release_data_version.description IS '版本描述'; -COMMENT ON COLUMN rtss.release_data_version.user_id IS '发布用户id'; +COMMENT ON COLUMN rtsa.release_data_version.user_id IS '发布用户id'; -COMMENT ON COLUMN rtss.release_data_version.created_at IS '创建时间'; +COMMENT ON COLUMN rtsa.release_data_version.created_at IS '创建时间'; -- 创建feature表 CREATE TABLE - rtss.feature ( + rtsa.feature ( id SERIAL PRIMARY KEY, -- id 自增主键 feature_type INT NOT NULL, -- feature类型 name VARCHAR(128) NOT NULL UNIQUE, -- feature名称 @@ -207,68 +207,68 @@ CREATE TABLE updater_id INT NOT NULL, -- 更新用户id created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间 updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 更新时间 - FOREIGN KEY (creator_id) REFERENCES rtss.user (id) ON DELETE CASCADE, -- 用户外键 - FOREIGN KEY (updater_id) REFERENCES rtss.user (id) ON DELETE CASCADE -- 用户外键 + FOREIGN KEY (creator_id) REFERENCES rtsa.user (id) ON DELETE CASCADE, -- 用户外键 + FOREIGN KEY (updater_id) REFERENCES rtsa.user (id) ON DELETE CASCADE -- 用户外键 ); -- 创建feature类型索引 -CREATE INDEX ON rtss.feature (feature_type); +CREATE INDEX ON rtsa.feature (feature_type); -- 创建feature名称索引 -CREATE INDEX ON rtss.feature (name); +CREATE INDEX ON rtsa.feature (name); -- 注释仿真feature表 -COMMENT ON TABLE rtss.feature IS 'feature表'; +COMMENT ON TABLE rtsa.feature IS 'feature表'; -- 注释仿真feature表字段 -COMMENT ON COLUMN rtss.feature.id IS 'id 自增主键'; +COMMENT ON COLUMN rtsa.feature.id IS 'id 自增主键'; -COMMENT ON COLUMN rtss.feature.feature_type IS 'feature类型'; +COMMENT ON COLUMN rtsa.feature.feature_type IS 'feature类型'; -COMMENT ON COLUMN rtss.feature.name IS 'feature名称'; +COMMENT ON COLUMN rtsa.feature.name IS 'feature名称'; -COMMENT ON COLUMN rtss.feature.description IS 'feature描述'; +COMMENT ON COLUMN rtsa.feature.description IS 'feature描述'; -COMMENT ON COLUMN rtss.feature.config IS 'feature配置'; +COMMENT ON COLUMN rtsa.feature.config IS 'feature配置'; -COMMENT ON COLUMN rtss.feature.is_published IS '是否上架'; +COMMENT ON COLUMN rtsa.feature.is_published IS '是否上架'; -COMMENT ON COLUMN rtss.feature.creator_id IS '创建用户id'; +COMMENT ON COLUMN rtsa.feature.creator_id IS '创建用户id'; -COMMENT ON COLUMN rtss.feature.created_at IS '创建时间'; +COMMENT ON COLUMN rtsa.feature.created_at IS '创建时间'; -COMMENT ON COLUMN rtss.feature.updated_at IS '更新时间'; +COMMENT ON COLUMN rtsa.feature.updated_at IS '更新时间'; -- 创建用户配置表 CREATE TABLE - rtss.user_config ( + rtsa.user_config ( id SERIAL PRIMARY KEY, -- id 自增主键 user_id INT NOT NULL, -- 用户id config_type INT NOT NULL, -- 配置类型 config BYTEA NOT NULL, -- 配置 created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间 updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 更新时间 - FOREIGN KEY (user_id) REFERENCES rtss.user (id) ON DELETE CASCADE -- 用户外键 + FOREIGN KEY (user_id) REFERENCES rtsa.user (id) ON DELETE CASCADE -- 用户外键 ); -- 创建用户配置用户索引 -CREATE INDEX ON rtss.user_config (user_id); +CREATE INDEX ON rtsa.user_config (user_id); -- 创建用户配置类型索引 -CREATE INDEX ON rtss.user_config (config_type); +CREATE INDEX ON rtsa.user_config (config_type); -- 注释用户feature配置表 -COMMENT ON TABLE rtss.user_config IS '用户feature配置表'; +COMMENT ON TABLE rtsa.user_config IS '用户feature配置表'; -- 注释用户feature配置表字段 -COMMENT ON COLUMN rtss.user_config.id IS 'id 自增主键'; +COMMENT ON COLUMN rtsa.user_config.id IS 'id 自增主键'; -COMMENT ON COLUMN rtss.user_config.user_id IS '用户id'; +COMMENT ON COLUMN rtsa.user_config.user_id IS '用户id'; -COMMENT ON COLUMN rtss.user_config.config_type IS '配置类型'; +COMMENT ON COLUMN rtsa.user_config.config_type IS '配置类型'; -COMMENT ON COLUMN rtss.user_config.config IS '配置'; +COMMENT ON COLUMN rtsa.user_config.config IS '配置'; -COMMENT ON COLUMN rtss.user_config.created_at IS '创建时间'; +COMMENT ON COLUMN rtsa.user_config.created_at IS '创建时间'; -COMMENT ON COLUMN rtss.user_config.updated_at IS '更新时间'; +COMMENT ON COLUMN rtsa.user_config.updated_at IS '更新时间'; diff --git a/rtss-proto-msg b/rtss-proto-msg deleted file mode 160000 index 1f53057..0000000 --- a/rtss-proto-msg +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 1f53057b3f87790ef27c91399a5bb7e890f05549 diff --git a/simulation/Cargo.toml b/simulation/Cargo.toml index 8f5ed71..a59b6d4 100644 --- a/simulation/Cargo.toml +++ b/simulation/Cargo.toml @@ -18,7 +18,7 @@ clap = { workspace = true, features = ["derive"] } enum_dispatch = { workspace = true } anyhow = { workspace = true } -rtss_log = { path = "../crates/rtss_log" } -rtss_dto = { path = "../crates/rtss_dto" } -rtss_db = { path = "../crates/rtss_db" } -rtss_mqtt = { path = "../crates/rtss_mqtt" } +rtsa_log = { path = "../crates/rtsa_log" } +rtsa_dto = { path = "../crates/rtsa_dto" } +rtsa_db = { path = "../crates/rtsa_db" } +rtsa_mqtt = { path = "../crates/rtsa_mqtt" } diff --git a/simulation/crates/rtss_ci/Cargo.toml b/simulation/crates/rtss_ci/Cargo.toml deleted file mode 100644 index 48a78bd..0000000 --- a/simulation/crates/rtss_ci/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "rtss_ci" -version = "0.1.0" -edition = "2021" - -[dependencies] diff --git a/simulation/crates/rtss_ci/src/lib.rs b/simulation/crates/rtss_ci/src/lib.rs deleted file mode 100644 index b93cf3f..0000000 --- a/simulation/crates/rtss_ci/src/lib.rs +++ /dev/null @@ -1,14 +0,0 @@ -pub fn add(left: u64, right: u64) -> u64 { - left + right -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); - } -} diff --git a/simulation/crates/rtss_common/Cargo.toml b/simulation/crates/rtss_common/Cargo.toml deleted file mode 100644 index 2076315..0000000 --- a/simulation/crates/rtss_common/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "rtss_common" -version = "0.1.0" -edition = "2021" - -[dependencies] -bevy_ecs = {workspace = true} diff --git a/simulation/crates/rtss_common/src/lib.rs b/simulation/crates/rtss_common/src/lib.rs deleted file mode 100644 index 7acf0b5..0000000 --- a/simulation/crates/rtss_common/src/lib.rs +++ /dev/null @@ -1,76 +0,0 @@ -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/simulation/crates/rtss_iscs/Cargo.toml b/simulation/crates/rtss_iscs/Cargo.toml deleted file mode 100644 index a99cf7b..0000000 --- a/simulation/crates/rtss_iscs/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "rtss_iscs" -version = "0.1.0" -edition = "2021" - -[dependencies] diff --git a/simulation/crates/rtss_iscs/src/lib.rs b/simulation/crates/rtss_iscs/src/lib.rs deleted file mode 100644 index b93cf3f..0000000 --- a/simulation/crates/rtss_iscs/src/lib.rs +++ /dev/null @@ -1,14 +0,0 @@ -pub fn add(left: u64, right: u64) -> u64 { - left + right -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); - } -} diff --git a/simulation/crates/rtss_sim_manage/Cargo.toml b/simulation/crates/rtss_sim_manage/Cargo.toml deleted file mode 100644 index 1e4a19b..0000000 --- a/simulation/crates/rtss_sim_manage/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "rtss_sim_manage" -version = "0.1.0" -edition = "2021" - -[dependencies] -bevy_core = {workspace = true} -bevy_ecs = {workspace = true} -bevy_app = {workspace = true} -bevy_time = {workspace = true} -rayon = {workspace = true} -thiserror = {workspace = true} - -rtss_log = { path = "../../crates/rtss_log" } -rtss_common = { path = "../rtss_common" } -rtss_trackside = { path = "../rtss_trackside" } diff --git a/simulation/crates/rtss_sim_manage/src/config_plugins.rs b/simulation/crates/rtss_sim_manage/src/config_plugins.rs deleted file mode 100644 index 25cbe1c..0000000 --- a/simulation/crates/rtss_sim_manage/src/config_plugins.rs +++ /dev/null @@ -1,17 +0,0 @@ -use bevy_app::App; -use rtss_trackside::TrackSideEquipmentPlugin; - -#[derive(Debug)] -pub enum AvailablePlugins { - TrackSideEquipmentPlugin, -} - -pub(crate) fn add_needed_plugins(app: &mut App, plugins: Vec) { - for plugin in plugins { - match plugin { - AvailablePlugins::TrackSideEquipmentPlugin => { - app.add_plugins(TrackSideEquipmentPlugin); - } - } - } -} diff --git a/simulation/crates/rtss_sim_manage/src/lib.rs b/simulation/crates/rtss_sim_manage/src/lib.rs deleted file mode 100644 index 71fe151..0000000 --- a/simulation/crates/rtss_sim_manage/src/lib.rs +++ /dev/null @@ -1,19 +0,0 @@ -mod config_plugins; -mod simulation; -pub use config_plugins::*; -pub use simulation::*; - -pub fn add(left: u64, right: u64) -> u64 { - left + right -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); - } -} diff --git a/simulation/crates/rtss_sim_manage/src/main.rs b/simulation/crates/rtss_sim_manage/src/main.rs deleted file mode 100644 index 7da3a48..0000000 --- a/simulation/crates/rtss_sim_manage/src/main.rs +++ /dev/null @@ -1,4 +0,0 @@ - -fn main() { - println!("Hello, world!"); -} diff --git a/simulation/crates/rtss_sim_manage/src/simulation.rs b/simulation/crates/rtss_sim_manage/src/simulation.rs deleted file mode 100644 index 82a31c0..0000000 --- a/simulation/crates/rtss_sim_manage/src/simulation.rs +++ /dev/null @@ -1,468 +0,0 @@ -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/simulation/crates/rtss_trackside/Cargo.toml b/simulation/crates/rtss_trackside/Cargo.toml deleted file mode 100644 index 8cb7829..0000000 --- a/simulation/crates/rtss_trackside/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "rtss_trackside" -version = "0.1.0" -edition = "2021" - -[dependencies] -bevy_core = {workspace = true} -bevy_ecs = {workspace = true} -bevy_app = {workspace = true} -bevy_time = {workspace = true} - -rtss_log = { path = "../../crates/rtss_log" } -rtss_common = { path = "../rtss_common" } diff --git a/simulation/crates/rtss_trackside/src/components/bundle.rs b/simulation/crates/rtss_trackside/src/components/bundle.rs deleted file mode 100644 index 5afb354..0000000 --- a/simulation/crates/rtss_trackside/src/components/bundle.rs +++ /dev/null @@ -1,20 +0,0 @@ -use bevy_ecs::bundle::Bundle; -use rtss_common::Uid; - -use super::{PsdState, TurnoutState, TwoNormalPositionsTransform}; - -// 道岔设备组件包 -#[derive(Bundle, Default)] -pub struct TurnoutBundle { - pub uid: Uid, - pub turnout_state: TurnoutState, - pub two_normal_positions_conversion: TwoNormalPositionsTransform, -} - -/// 屏蔽门设备组件包 -#[derive(Bundle, Default)] -pub struct PsdBundle { - pub uid: Uid, - pub psd_state: PsdState, - pub two_normal_positions_conversion: TwoNormalPositionsTransform, -} diff --git a/simulation/crates/rtss_trackside/src/components/equipment.rs b/simulation/crates/rtss_trackside/src/components/equipment.rs deleted file mode 100644 index d96c1e2..0000000 --- a/simulation/crates/rtss_trackside/src/components/equipment.rs +++ /dev/null @@ -1,42 +0,0 @@ -use bevy_ecs::component::Component; - -/// 两常态位置转换组件,用于像道岔位置,屏蔽门位置等 -#[derive(Component, Debug, Clone, PartialEq, Default)] -pub struct TwoNormalPositionsTransform { - // 当前实际位置,百分比值,0-100 - pub position: f32, - // 当前转换速度 - pub velocity: f32, -} - -/// 道岔设备状态组件 -#[derive(Component, Debug, Clone, PartialEq, Eq, Default)] -pub struct TurnoutState { - // 定位表示继电器状态 - pub dbj: bool, - // 反位表示继电器状态 - pub fbj: bool, - // 是否定位 - pub dw: bool, - // 是否反位 - pub fw: bool, - // 定操继电器状态 - pub dcj: bool, - // 反操继电器状态 - pub fcj: bool, -} - -pub struct SignalState {} - -/// 屏蔽门设备状态组件 -#[derive(Component, Debug, Clone, PartialEq, Eq, Default)] -pub struct PsdState { - // 门关继电器状态 - pub mgj: bool, - // 关门继电器状态 - pub gmj: bool, - // 开门继电器状态 - pub kmj: bool, - // 门旁路继电器状态(互锁解除) - pub mplj: bool, -} diff --git a/simulation/crates/rtss_trackside/src/components/mod.rs b/simulation/crates/rtss_trackside/src/components/mod.rs deleted file mode 100644 index ce5489b..0000000 --- a/simulation/crates/rtss_trackside/src/components/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -mod bundle; -mod equipment; -pub use bundle::*; -pub use equipment::*; diff --git a/simulation/crates/rtss_trackside/src/events/equipment.rs b/simulation/crates/rtss_trackside/src/events/equipment.rs deleted file mode 100644 index 87c8f4f..0000000 --- a/simulation/crates/rtss_trackside/src/events/equipment.rs +++ /dev/null @@ -1,9 +0,0 @@ -use bevy_ecs::event::Event; - -#[derive(Event, Debug, Clone, Copy, Eq, PartialEq)] -pub enum TurnoutControlEvent { - // 道岔定操 - DC, - // 道岔反操 - FC, -} diff --git a/simulation/crates/rtss_trackside/src/events/mod.rs b/simulation/crates/rtss_trackside/src/events/mod.rs deleted file mode 100644 index 3d75eaa..0000000 --- a/simulation/crates/rtss_trackside/src/events/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -mod equipment; -pub use equipment::*; diff --git a/simulation/crates/rtss_trackside/src/lib.rs b/simulation/crates/rtss_trackside/src/lib.rs deleted file mode 100644 index 28529c4..0000000 --- a/simulation/crates/rtss_trackside/src/lib.rs +++ /dev/null @@ -1,10 +0,0 @@ -mod components; -mod events; -mod plugin; -mod resources; -mod systems; -pub use components::*; -pub use events::*; -pub use plugin::*; -pub use resources::*; -pub use systems::*; diff --git a/simulation/crates/rtss_trackside/src/plugin.rs b/simulation/crates/rtss_trackside/src/plugin.rs deleted file mode 100644 index aae1dc0..0000000 --- a/simulation/crates/rtss_trackside/src/plugin.rs +++ /dev/null @@ -1,23 +0,0 @@ -use bevy_app::{FixedUpdate, Plugin, Startup}; -use bevy_ecs::schedule::IntoSystemConfigs; - -use crate::{ - handle_turnout_control, loading, turnout_state_update, two_normal_position_transform, - SimulationConfig, TurnoutControlEvent, -}; - -#[derive(Default)] -pub struct TrackSideEquipmentPlugin; - -impl Plugin for TrackSideEquipmentPlugin { - fn build(&self, app: &mut bevy_app::App) { - app.insert_resource(SimulationConfig::default()) - .add_event::() - .add_systems(Startup, loading) - .add_systems( - FixedUpdate, - (two_normal_position_transform, turnout_state_update).chain(), - ) - .observe(handle_turnout_control); - } -} diff --git a/simulation/crates/rtss_trackside/src/resources/mod.rs b/simulation/crates/rtss_trackside/src/resources/mod.rs deleted file mode 100644 index 15903a5..0000000 --- a/simulation/crates/rtss_trackside/src/resources/mod.rs +++ /dev/null @@ -1,15 +0,0 @@ -use bevy_ecs::system::Resource; - -#[derive(Resource, Debug)] -pub struct SimulationConfig { - // 道岔转换总时间,单位ms - pub turnout_transform_time: i32, -} - -impl Default for SimulationConfig { - fn default() -> Self { - SimulationConfig { - turnout_transform_time: 3500, - } - } -} diff --git a/simulation/crates/rtss_trackside/src/systems/common.rs b/simulation/crates/rtss_trackside/src/systems/common.rs deleted file mode 100644 index b8d45f2..0000000 --- a/simulation/crates/rtss_trackside/src/systems/common.rs +++ /dev/null @@ -1,32 +0,0 @@ -use bevy_ecs::{entity::Entity, system::Query}; -use rtss_common::Uid; -use rtss_log::tracing::debug; - -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 TwoNormalPositionsTransform)>, -) { - for (entity, uid, mut transform) in &mut query { - debug!( - "Entity: {:?}, Uid: {:?}, Conversion: {:?}", - entity, uid, transform - ); - if transform.velocity == 0f32 { - continue; - } - let p = transform.position + transform.velocity; - if p >= TWO_NORMAL_POSITION_MAX as f32 { - transform.position = TWO_NORMAL_POSITION_MAX as f32; - transform.velocity = TWO_NORMAL_POSITION_MIN as f32; - } else if p <= TWO_NORMAL_POSITION_MIN as f32 { - transform.position = TWO_NORMAL_POSITION_MIN as f32; - transform.velocity = 0 as f32; - } else { - transform.position = p; - } - } -} diff --git a/simulation/crates/rtss_trackside/src/systems/loading.rs b/simulation/crates/rtss_trackside/src/systems/loading.rs deleted file mode 100644 index 51f5510..0000000 --- a/simulation/crates/rtss_trackside/src/systems/loading.rs +++ /dev/null @@ -1,13 +0,0 @@ -use bevy_ecs::{prelude::Commands, system::ResMut}; -use rtss_common::{SharedSimulationResource, Uid}; - -use crate::components; - -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.insert_entity(uid.0, et.id()); -} diff --git a/simulation/crates/rtss_trackside/src/systems/mod.rs b/simulation/crates/rtss_trackside/src/systems/mod.rs deleted file mode 100644 index 25919fa..0000000 --- a/simulation/crates/rtss_trackside/src/systems/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -mod common; -mod loading; -mod turnout; -pub use common::*; -pub use loading::*; -pub use turnout::*; diff --git a/simulation/crates/rtss_trackside/src/systems/turnout.rs b/simulation/crates/rtss_trackside/src/systems/turnout.rs deleted file mode 100644 index e6fbed0..0000000 --- a/simulation/crates/rtss_trackside/src/systems/turnout.rs +++ /dev/null @@ -1,78 +0,0 @@ -use bevy_ecs::{ - observer::Trigger, - system::{Query, Res, ResMut}, -}; -use bevy_time::{Fixed, Time}; -use rtss_common::Uid; -use rtss_log::tracing::debug; - -use crate::{ - events::TurnoutControlEvent, SimulationConfig, TurnoutState, TwoNormalPositionsTransform, - TWO_NORMAL_POSITION_MAX, TWO_NORMAL_POSITION_MIN, -}; - -// 道岔控制事件处理系统 -pub fn handle_turnout_control( - trigger: Trigger, - time: ResMut>, - config: Res, - mut query: Query<(&Uid, &mut TurnoutState, &mut TwoNormalPositionsTransform)>, -) { - let (uid, mut state, mut conversion) = query - .get_mut(trigger.entity()) - .expect("通过entity获取道岔异常"); - let v = calculate_avg_velocity( - crate::TWO_NORMAL_POSITION_MAX as f32, - config.turnout_transform_time as f32, - time.timestep().as_millis() as f32, - ); - match trigger.event() { - TurnoutControlEvent::DC => { - state.dcj = true; - state.fcj = false; - conversion.velocity = -v; - debug!("道岔定操处理:{:?}", uid); - } - TurnoutControlEvent::FC => { - state.dcj = false; - state.fcj = true; - conversion.velocity = v; - debug!("道岔反操处理:uid={:?}, conversion={:?}", uid, conversion); - } - } -} - -// 道岔状态更新系统 -pub fn turnout_state_update( - mut query: Query<(&Uid, &mut TurnoutState, &mut TwoNormalPositionsTransform)>, -) { - for (uid, mut state, conversion) in &mut query { - debug!( - "更新道岔状态:Uid={:?}, State={:?}, Conversion={:?}", - uid, state, conversion - ); - if conversion.position as i32 == TWO_NORMAL_POSITION_MIN { - state.dw = true; - state.fw = false; - state.dbj = true; - state.fbj = false; - state.dcj = false; - } else if conversion.position as i32 == TWO_NORMAL_POSITION_MAX { - state.fw = true; - state.dw = false; - state.dbj = false; - state.fbj = true; - state.fcj = false; - } else { - state.dw = false; - state.fw = false; - state.dbj = false; - state.fbj = false; - } - } -} - -// 计算平均速度 -fn calculate_avg_velocity(total_distance: f32, total_time: f32, time_step: f32) -> f32 { - total_distance / (total_time / time_step) -} diff --git a/simulation/src/app_config.rs b/simulation/src/app_config.rs index afea059..67dca23 100644 --- a/simulation/src/app_config.rs +++ b/simulation/src/app_config.rs @@ -15,9 +15,9 @@ pub struct Log { level: String, } -impl From for rtss_log::Logging { +impl From for rtsa_log::Logging { fn from(log: Log) -> Self { - rtss_log::Logging { + rtsa_log::Logging { level: log.level.parse().unwrap(), ..Default::default() } @@ -61,9 +61,9 @@ impl AppConfig { // Default to 'dev' env // Note that this file is _optional_ .add_source(File::with_name(&format!("{dir}/{run_mode}")).required(true)) - // Add in settings from the environment (with a prefix of RTSS_SIM) + // Add in settings from the environment (with a prefix of rtsa_SIM) // Eg.. `APP_DEBUG=1 ./target/app` would set the `debug` key - .add_source(Environment::with_prefix("RTSS_SIM").separator("_")) + .add_source(Environment::with_prefix("rtsa_SIM").separator("_")) // You may also programmatically change settings // .set_override("database.url", "postgres://")? // build the configuration diff --git a/simulation/src/commands/cmd.rs b/simulation/src/commands/cmd.rs index b3fde03..87f380c 100644 --- a/simulation/src/commands/cmd.rs +++ b/simulation/src/commands/cmd.rs @@ -6,7 +6,7 @@ use crate::app_config; use super::{CmdExecutor, DbSubCommand}; #[derive(Parser, Debug)] -#[command(name = "rtss-sim", version, author, about, long_about = None)] +#[command(name = "rtsa-sim", version, author, about, long_about = None)] pub struct Cmd { #[command(subcommand)] pub cmd: SubCommand, @@ -31,18 +31,18 @@ impl CmdExecutor for ServerOpts { async fn execute(&self) -> anyhow::Result<()> { let app_config = app_config::AppConfig::new(&self.config_path).expect("Failed to load app config"); - let log: rtss_log::Logging = app_config.log.into(); + let log: rtsa_log::Logging = app_config.log.into(); log.init(); // 数据库访问器初始化 - rtss_db::init_default_db_accessor(&app_config.database.url).await; + rtsa_db::init_default_db_accessor(&app_config.database.url).await; // mqtt客户端初始化 - let cli_id = rtss_db::get_default_db_accessor() + let cli_id = rtsa_db::get_default_db_accessor() .get_next_mqtt_client_id() .await?; let mqtt_cli_options = - rtss_mqtt::MqttClientOptions::new(&format!("rtsa{}", cli_id), &app_config.mqtt.url) + rtsa_mqtt::MqttClientOptions::new(&format!("rtsa{}", cli_id), &app_config.mqtt.url) .set_credentials(&app_config.mqtt.username, &app_config.mqtt.password); - rtss_mqtt::init_global_mqtt_client(mqtt_cli_options).await?; + rtsa_mqtt::init_global_mqtt_client(mqtt_cli_options).await?; Ok(()) } } diff --git a/simulation/src/commands/db.rs b/simulation/src/commands/db.rs index 044abed..37fad47 100644 --- a/simulation/src/commands/db.rs +++ b/simulation/src/commands/db.rs @@ -24,6 +24,6 @@ impl CmdExecutor for MigrateOpts { async fn execute(&self) -> anyhow::Result<()> { let app_config = app_config::AppConfig::new(&self.config_path).expect("Failed to load app config"); - rtss_db::run_migrations(&app_config.database.url).await + rtsa_db::run_migrations(&app_config.database.url).await } } diff --git a/simulation/src/components/mod.rs b/simulation/src/components/mod.rs index 6272b8b..b0fcfd4 100644 --- a/simulation/src/components/mod.rs +++ b/simulation/src/components/mod.rs @@ -52,8 +52,8 @@ impl SimulationUidEntityMapResource { #[derive(Resource, Debug)] pub struct TxResource { - tx: broadcast::Sender, - rx: Option>, + tx: broadcast::Sender, + rx: Option>, } impl TxResource { @@ -62,11 +62,11 @@ impl TxResource { TxResource { tx, rx: Some(rx) } } - pub fn get_tx(&self) -> broadcast::Sender { + pub fn get_tx(&self) -> broadcast::Sender { self.tx.clone() } - pub fn subscribe(&mut self) -> broadcast::Receiver { + pub fn subscribe(&mut self) -> broadcast::Receiver { let rx = self.tx.subscribe(); if self.rx.is_some() { std::mem::take(&mut self.rx); diff --git a/simulation/src/manage/data_loading_plugin.rs b/simulation/src/manage/data_loading_plugin.rs index 25dda15..43ddc1e 100644 --- a/simulation/src/manage/data_loading_plugin.rs +++ b/simulation/src/manage/data_loading_plugin.rs @@ -1,6 +1,6 @@ use bevy_app::{Plugin, Startup}; use bevy_ecs::system::Res; -use rtss_log::tracing::debug; +use rtsa_log::tracing::debug; use crate::components::SimulationInfo; diff --git a/simulation/src/manage/simulation.rs b/simulation/src/manage/simulation.rs index 0caa324..94cc9ff 100644 --- a/simulation/src/manage/simulation.rs +++ b/simulation/src/manage/simulation.rs @@ -12,7 +12,7 @@ use bevy_ecs::{ system::ResMut, }; use bevy_time::{Fixed, Time, TimePlugin, Virtual}; -use rtss_log::tracing::{debug, error, info}; +use rtsa_log::tracing::{debug, error, info}; use tokio::sync::broadcast; use crate::{ @@ -52,7 +52,7 @@ impl SimulationOptions { #[derive(Debug, Clone)] pub struct Simulation { app: Arc>, - tx: broadcast::Sender, + tx: broadcast::Sender, } impl Simulation { @@ -95,7 +95,7 @@ impl Simulation { }) } - pub fn send_operation(&self, op: rtss_dto::simulation::Operation) { + pub fn send_operation(&self, op: rtsa_dto::simulation::Operation) { if let Err(e) = self.tx.send(op) { error!("send operation error: {}", e); } @@ -117,31 +117,31 @@ mod tests { use super::*; - use rtss_dto::simulation::OperationType; - use rtss_log::tracing::Level; + use rtsa_dto::simulation::OperationType; + use rtsa_log::tracing::Level; #[test] fn test_new_simulation() { - rtss_log::Logging::default().with_level(Level::DEBUG).init(); + rtsa_log::Logging::default().with_level(Level::DEBUG).init(); let simulation1 = Simulation::new(SimulationOptions::new("1", "1")).unwrap(); assert!(simulation1.app.lock().unwrap().update_schedule.is_some()); - simulation1.send_operation(rtss_dto::simulation::Operation { - otype: rtss_dto::simulation::OperationType::SetSpeed as i32, - param: Some(rtss_dto::simulation::operation::Param::SetSpeedParam( - rtss_dto::simulation::SetSpeedParam { speed: 2.0 }, + simulation1.send_operation(rtsa_dto::simulation::Operation { + otype: rtsa_dto::simulation::OperationType::SetSpeed as i32, + param: Some(rtsa_dto::simulation::operation::Param::SetSpeedParam( + rtsa_dto::simulation::SetSpeedParam { speed: 2.0 }, )), }); let clone2 = simulation1.clone(); thread::spawn(move || { sleep(Duration::from_millis(100)); info!("send pause"); - clone2.send_operation(rtss_dto::simulation::Operation { + clone2.send_operation(rtsa_dto::simulation::Operation { otype: OperationType::Pause as i32, param: None, }); sleep(Duration::from_millis(200)); info!("send unpause"); - clone2.send_operation(rtss_dto::simulation::Operation { + clone2.send_operation(rtsa_dto::simulation::Operation { otype: OperationType::Unpause as i32, param: None, }); diff --git a/simulation/src/manage/simulation_control_plugin.rs b/simulation/src/manage/simulation_control_plugin.rs index d9d9abf..5644394 100644 --- a/simulation/src/manage/simulation_control_plugin.rs +++ b/simulation/src/manage/simulation_control_plugin.rs @@ -1,8 +1,8 @@ use bevy_app::prelude::*; use bevy_ecs::prelude::*; use bevy_time::prelude::*; -use rtss_dto::simulation::{operation, OperationType, SetSpeedParam}; -use rtss_log::tracing::debug; +use rtsa_dto::simulation::{operation, OperationType, SetSpeedParam}; +use rtsa_log::tracing::debug; use tokio::sync::broadcast; use crate::components::{SimulationInfo, TxResource}; @@ -23,10 +23,10 @@ fn init_rx_resource(mut commands: Commands, mut tx: ResMut) { } #[derive(Resource, Debug)] -struct RxResource(pub broadcast::Receiver); +struct RxResource(pub broadcast::Receiver); impl RxResource { - fn new(rx: broadcast::Receiver) -> Self { + fn new(rx: broadcast::Receiver) -> Self { RxResource(rx) } } diff --git a/simulation/src/modules/trackside/systems/common.rs b/simulation/src/modules/trackside/systems/common.rs index 312c35b..7d4b47e 100644 --- a/simulation/src/modules/trackside/systems/common.rs +++ b/simulation/src/modules/trackside/systems/common.rs @@ -1,5 +1,5 @@ use bevy_ecs::{entity::Entity, system::Query}; -use rtss_log::tracing::debug; +use rtsa_log::tracing::debug; use crate::{components::Uid, modules::trackside::components::TwoNormalPositionsTransform}; diff --git a/simulation/src/modules/trackside/systems/loading.rs b/simulation/src/modules/trackside/systems/loading.rs index b50958f..c5bc434 100644 --- a/simulation/src/modules/trackside/systems/loading.rs +++ b/simulation/src/modules/trackside/systems/loading.rs @@ -1,5 +1,5 @@ use bevy_ecs::{prelude::Commands, system::ResMut}; -use rtss_log::tracing::debug; +use rtsa_log::tracing::debug; use crate::{ components::{SimulationUidEntityMapResource, Uid}, diff --git a/simulation/src/modules/trackside/systems/turnout.rs b/simulation/src/modules/trackside/systems/turnout.rs index 1efae81..ca65384 100644 --- a/simulation/src/modules/trackside/systems/turnout.rs +++ b/simulation/src/modules/trackside/systems/turnout.rs @@ -3,7 +3,7 @@ use bevy_ecs::{ system::{Query, Res, ResMut}, }; use bevy_time::{Fixed, Time}; -use rtss_log::tracing::debug; +use rtsa_log::tracing::debug; use crate::{ components::Uid,