From 8cfe3807843f7fd959404279cb7eb37802846272 Mon Sep 17 00:00:00 2001 From: jinmo <49105556+Jinmoli@users.noreply.github.com> Date: Tue, 4 Aug 2026 19:05:05 +0800 Subject: [PATCH] feat(mqtt): add MQTT broker connection support --- .github/scripts/database-issue-catalog.mjs | 1 + .github/scripts/label-issue-database.test.mjs | 2 + Cargo.lock | 301 ++- Cargo.toml | 4 +- apps/desktop/public/icons/database/mqtt.png | Bin 0 -> 15995 bytes apps/desktop/public/icons/database/mqtt.svg | 5 + .../connection/ConnectionDialog.vue | 174 +- .../src/components/icons/DatabaseIcon.vue | 1 + .../src/components/layout/ContentArea.vue | 7 + .../src/components/mqtt/MqttAdminConsole.vue | 246 ++ .../src/components/mqtt/MqttPublishDialog.vue | 352 +++ .../src/components/mqtt/TopicTreeNode.vue | 96 + .../sidebar/SidebarTreeRuntimeHost.vue | 6 + apps/desktop/src/i18n/locales/en.ts | 65 + apps/desktop/src/i18n/locales/es.ts | 65 + apps/desktop/src/i18n/locales/it.ts | 65 + apps/desktop/src/i18n/locales/ja.ts | 65 + apps/desktop/src/i18n/locales/pt-BR.ts | 65 + apps/desktop/src/i18n/locales/zh-CN.ts | 65 + apps/desktop/src/i18n/locales/zh-TW.ts | 65 + apps/desktop/src/lib/backend/api.ts | 10 + apps/desktop/src/lib/backend/http.ts | 1 + apps/desktop/src/lib/backend/mqtt-http.ts | 38 + apps/desktop/src/lib/backend/mqtt-tauri.ts | 33 + apps/desktop/src/lib/backend/tauri.ts | 1 + .../lib/database/databaseNamespaceCreation.ts | 1 + .../lib/database/databasePropertyEditing.ts | 1 + apps/desktop/src/lib/mqtt/mqttPayloadCodec.ts | 180 ++ apps/desktop/src/lib/sidebar/treeNodeIcon.ts | 1 + apps/desktop/src/stores/connectionStore.ts | 47 + apps/desktop/src/stores/queryStore.ts | 28 + apps/desktop/src/types/database.ts | 6 +- apps/desktop/src/types/mqtt.ts | 75 + crates/dbx-core/Cargo.toml | 3 +- crates/dbx-core/src/connection.rs | 50 +- crates/dbx-core/src/connection_secrets.rs | 286 +- crates/dbx-core/src/database_capabilities.rs | 1 + crates/dbx-core/src/lib.rs | 4 + crates/dbx-core/src/models/connection.rs | 18 + crates/dbx-core/src/mqtt/client.rs | 2295 +++++++++++++++++ crates/dbx-core/src/mqtt/mod.rs | 22 + crates/dbx-core/src/mqtt/service.rs | 71 + crates/dbx-core/src/mqtt/types.rs | 363 +++ crates/dbx-core/src/nanosleep_stub.rs | 38 + crates/dbx-core/src/query.rs | 6 + .../dbx-core/src/sql_dialect/ddl_profile.rs | 2 +- flake.nix | 2 +- package.json | 3 +- packages/app-tests/mqttPayloadCodec.test.ts | 56 + pnpm-lock.yaml | 155 +- src-tauri/src/commands/connection.rs | 11 + src-tauri/src/commands/mcp.rs | 2 + src-tauri/src/commands/mod.rs | 1 + src-tauri/src/commands/mqtt_cmd.rs | 103 + src-tauri/src/lib.rs | 8 + vendor/rumqttc/.cargo-ok | 1 + vendor/rumqttc/.cargo_vcs_info.json | 6 + vendor/rumqttc/CHANGELOG.md | 143 + vendor/rumqttc/Cargo.lock | 1430 ++++++++++ vendor/rumqttc/Cargo.toml | 179 ++ vendor/rumqttc/Cargo.toml.orig | 77 + vendor/rumqttc/README.md | 86 + vendor/rumqttc/certs/generate.sh | 23 + vendor/rumqttc/design.md | 273 ++ vendor/rumqttc/examples/async_manual_acks.rs | 86 + .../rumqttc/examples/async_manual_acks_v5.rs | 85 + vendor/rumqttc/examples/asyncpubsub.rs | 51 + vendor/rumqttc/examples/asyncpubsub_v5.rs | 52 + vendor/rumqttc/examples/serde.rs | 62 + vendor/rumqttc/examples/subscription_ids.rs | 82 + vendor/rumqttc/examples/syncpubsub.rs | 44 + vendor/rumqttc/examples/syncpubsub_v5.rs | 45 + vendor/rumqttc/examples/syncrecv.rs | 41 + vendor/rumqttc/examples/syncrecv_v5.rs | 42 + vendor/rumqttc/examples/tls.rs | 45 + vendor/rumqttc/examples/tls2.rs | 45 + vendor/rumqttc/examples/topic_alias.rs | 88 + vendor/rumqttc/examples/websocket.rs | 54 + vendor/rumqttc/examples/websocket_proxy.rs | 63 + vendor/rumqttc/src/client.rs | 523 ++++ vendor/rumqttc/src/eventloop.rs | 476 ++++ vendor/rumqttc/src/framed.rs | 121 + vendor/rumqttc/src/lib.rs | 1029 ++++++++ vendor/rumqttc/src/mqttbytes/mod.rs | 337 +++ vendor/rumqttc/src/mqttbytes/topic.rs | 214 ++ vendor/rumqttc/src/mqttbytes/v4/connack.rs | 124 + vendor/rumqttc/src/mqttbytes/v4/connect.rs | 444 ++++ vendor/rumqttc/src/mqttbytes/v4/disconnect.rs | 16 + vendor/rumqttc/src/mqttbytes/v4/mod.rs | 100 + vendor/rumqttc/src/mqttbytes/v4/ping.rs | 30 + vendor/rumqttc/src/mqttbytes/v4/puback.rs | 81 + vendor/rumqttc/src/mqttbytes/v4/pubcomp.rs | 51 + vendor/rumqttc/src/mqttbytes/v4/publish.rs | 274 ++ vendor/rumqttc/src/mqttbytes/v4/pubrec.rs | 51 + vendor/rumqttc/src/mqttbytes/v4/pubrel.rs | 51 + vendor/rumqttc/src/mqttbytes/v4/suback.rs | 118 + vendor/rumqttc/src/mqttbytes/v4/subscribe.rs | 242 ++ vendor/rumqttc/src/mqttbytes/v4/unsuback.rs | 38 + .../rumqttc/src/mqttbytes/v4/unsubscribe.rs | 61 + vendor/rumqttc/src/proxy.rs | 83 + vendor/rumqttc/src/state.rs | 940 +++++++ vendor/rumqttc/src/tls.rs | 187 ++ vendor/rumqttc/src/v5/client.rs | 871 +++++++ vendor/rumqttc/src/v5/eventloop.rs | 418 +++ vendor/rumqttc/src/v5/framed.rs | 132 + vendor/rumqttc/src/v5/mod.rs | 809 ++++++ vendor/rumqttc/src/v5/mqttbytes/mod.rs | 186 ++ vendor/rumqttc/src/v5/mqttbytes/v5/connack.rs | 530 ++++ vendor/rumqttc/src/v5/mqttbytes/v5/connect.rs | 687 +++++ .../rumqttc/src/v5/mqttbytes/v5/disconnect.rs | 470 ++++ vendor/rumqttc/src/v5/mqttbytes/v5/mod.rs | 495 ++++ vendor/rumqttc/src/v5/mqttbytes/v5/ping.rs | 22 + vendor/rumqttc/src/v5/mqttbytes/v5/puback.rs | 259 ++ vendor/rumqttc/src/v5/mqttbytes/v5/pubcomp.rs | 237 ++ vendor/rumqttc/src/v5/mqttbytes/v5/publish.rs | 340 +++ vendor/rumqttc/src/v5/mqttbytes/v5/pubrec.rs | 253 ++ vendor/rumqttc/src/v5/mqttbytes/v5/pubrel.rs | 238 ++ vendor/rumqttc/src/v5/mqttbytes/v5/suback.rs | 240 ++ .../rumqttc/src/v5/mqttbytes/v5/subscribe.rs | 305 +++ .../rumqttc/src/v5/mqttbytes/v5/unsuback.rs | 228 ++ .../src/v5/mqttbytes/v5/unsubscribe.rs | 176 ++ vendor/rumqttc/src/v5/state.rs | 1039 ++++++++ vendor/rumqttc/src/websockets.rs | 73 + vendor/rumqttc/tests/broker.rs | 306 +++ vendor/rumqttc/tests/reliability.rs | 583 +++++ 125 files changed, 23056 insertions(+), 107 deletions(-) create mode 100644 apps/desktop/public/icons/database/mqtt.png create mode 100644 apps/desktop/public/icons/database/mqtt.svg create mode 100644 apps/desktop/src/components/mqtt/MqttAdminConsole.vue create mode 100644 apps/desktop/src/components/mqtt/MqttPublishDialog.vue create mode 100644 apps/desktop/src/components/mqtt/TopicTreeNode.vue create mode 100644 apps/desktop/src/lib/backend/mqtt-http.ts create mode 100644 apps/desktop/src/lib/backend/mqtt-tauri.ts create mode 100644 apps/desktop/src/lib/mqtt/mqttPayloadCodec.ts create mode 100644 apps/desktop/src/types/mqtt.ts create mode 100644 crates/dbx-core/src/mqtt/client.rs create mode 100644 crates/dbx-core/src/mqtt/mod.rs create mode 100644 crates/dbx-core/src/mqtt/service.rs create mode 100644 crates/dbx-core/src/mqtt/types.rs create mode 100644 crates/dbx-core/src/nanosleep_stub.rs create mode 100644 packages/app-tests/mqttPayloadCodec.test.ts create mode 100644 src-tauri/src/commands/mqtt_cmd.rs create mode 100644 vendor/rumqttc/.cargo-ok create mode 100644 vendor/rumqttc/.cargo_vcs_info.json create mode 100644 vendor/rumqttc/CHANGELOG.md create mode 100644 vendor/rumqttc/Cargo.lock create mode 100644 vendor/rumqttc/Cargo.toml create mode 100644 vendor/rumqttc/Cargo.toml.orig create mode 100644 vendor/rumqttc/README.md create mode 100644 vendor/rumqttc/certs/generate.sh create mode 100644 vendor/rumqttc/design.md create mode 100644 vendor/rumqttc/examples/async_manual_acks.rs create mode 100644 vendor/rumqttc/examples/async_manual_acks_v5.rs create mode 100644 vendor/rumqttc/examples/asyncpubsub.rs create mode 100644 vendor/rumqttc/examples/asyncpubsub_v5.rs create mode 100644 vendor/rumqttc/examples/serde.rs create mode 100644 vendor/rumqttc/examples/subscription_ids.rs create mode 100644 vendor/rumqttc/examples/syncpubsub.rs create mode 100644 vendor/rumqttc/examples/syncpubsub_v5.rs create mode 100644 vendor/rumqttc/examples/syncrecv.rs create mode 100644 vendor/rumqttc/examples/syncrecv_v5.rs create mode 100644 vendor/rumqttc/examples/tls.rs create mode 100644 vendor/rumqttc/examples/tls2.rs create mode 100644 vendor/rumqttc/examples/topic_alias.rs create mode 100644 vendor/rumqttc/examples/websocket.rs create mode 100644 vendor/rumqttc/examples/websocket_proxy.rs create mode 100644 vendor/rumqttc/src/client.rs create mode 100644 vendor/rumqttc/src/eventloop.rs create mode 100644 vendor/rumqttc/src/framed.rs create mode 100644 vendor/rumqttc/src/lib.rs create mode 100644 vendor/rumqttc/src/mqttbytes/mod.rs create mode 100644 vendor/rumqttc/src/mqttbytes/topic.rs create mode 100644 vendor/rumqttc/src/mqttbytes/v4/connack.rs create mode 100644 vendor/rumqttc/src/mqttbytes/v4/connect.rs create mode 100644 vendor/rumqttc/src/mqttbytes/v4/disconnect.rs create mode 100644 vendor/rumqttc/src/mqttbytes/v4/mod.rs create mode 100644 vendor/rumqttc/src/mqttbytes/v4/ping.rs create mode 100644 vendor/rumqttc/src/mqttbytes/v4/puback.rs create mode 100644 vendor/rumqttc/src/mqttbytes/v4/pubcomp.rs create mode 100644 vendor/rumqttc/src/mqttbytes/v4/publish.rs create mode 100644 vendor/rumqttc/src/mqttbytes/v4/pubrec.rs create mode 100644 vendor/rumqttc/src/mqttbytes/v4/pubrel.rs create mode 100644 vendor/rumqttc/src/mqttbytes/v4/suback.rs create mode 100644 vendor/rumqttc/src/mqttbytes/v4/subscribe.rs create mode 100644 vendor/rumqttc/src/mqttbytes/v4/unsuback.rs create mode 100644 vendor/rumqttc/src/mqttbytes/v4/unsubscribe.rs create mode 100644 vendor/rumqttc/src/proxy.rs create mode 100644 vendor/rumqttc/src/state.rs create mode 100644 vendor/rumqttc/src/tls.rs create mode 100644 vendor/rumqttc/src/v5/client.rs create mode 100644 vendor/rumqttc/src/v5/eventloop.rs create mode 100644 vendor/rumqttc/src/v5/framed.rs create mode 100644 vendor/rumqttc/src/v5/mod.rs create mode 100644 vendor/rumqttc/src/v5/mqttbytes/mod.rs create mode 100644 vendor/rumqttc/src/v5/mqttbytes/v5/connack.rs create mode 100644 vendor/rumqttc/src/v5/mqttbytes/v5/connect.rs create mode 100644 vendor/rumqttc/src/v5/mqttbytes/v5/disconnect.rs create mode 100644 vendor/rumqttc/src/v5/mqttbytes/v5/mod.rs create mode 100644 vendor/rumqttc/src/v5/mqttbytes/v5/ping.rs create mode 100644 vendor/rumqttc/src/v5/mqttbytes/v5/puback.rs create mode 100644 vendor/rumqttc/src/v5/mqttbytes/v5/pubcomp.rs create mode 100644 vendor/rumqttc/src/v5/mqttbytes/v5/publish.rs create mode 100644 vendor/rumqttc/src/v5/mqttbytes/v5/pubrec.rs create mode 100644 vendor/rumqttc/src/v5/mqttbytes/v5/pubrel.rs create mode 100644 vendor/rumqttc/src/v5/mqttbytes/v5/suback.rs create mode 100644 vendor/rumqttc/src/v5/mqttbytes/v5/subscribe.rs create mode 100644 vendor/rumqttc/src/v5/mqttbytes/v5/unsuback.rs create mode 100644 vendor/rumqttc/src/v5/mqttbytes/v5/unsubscribe.rs create mode 100644 vendor/rumqttc/src/v5/state.rs create mode 100644 vendor/rumqttc/src/websockets.rs create mode 100644 vendor/rumqttc/tests/broker.rs create mode 100644 vendor/rumqttc/tests/reliability.rs diff --git a/.github/scripts/database-issue-catalog.mjs b/.github/scripts/database-issue-catalog.mjs index 402b4c1c4c..350d17d7ce 100644 --- a/.github/scripts/database-issue-catalog.mjs +++ b/.github/scripts/database-issue-catalog.mjs @@ -84,6 +84,7 @@ const supplementalDrivers = [ { dbType: "kafka", label: "Apache Kafka" }, { dbType: "rocketmq", label: "Apache RocketMQ" }, { dbType: "rabbitmq", label: "RabbitMQ" }, + { dbType: "mqtt", label: "MQTT", aliases: ["emqx", "hivemq", "mosquitto"] }, ]; const manifestUrl = new URL("../../crates/dbx-core/assets/database-drivers.manifest.json", import.meta.url); diff --git a/.github/scripts/label-issue-database.test.mjs b/.github/scripts/label-issue-database.test.mjs index 74f48a2d16..782eccf7c1 100644 --- a/.github/scripts/label-issue-database.test.mjs +++ b/.github/scripts/label-issue-database.test.mjs @@ -57,6 +57,8 @@ test("labels native and compatibility database products with their families", () ["Dremio", ["db/dremio", "db/jdbc"]], ["Apache Kafka", ["db/kafka", "db/mq"]], ["RabbitMQ", ["db/mq", "db/rabbitmq"]], + ["MQTT 5.0", ["db/mqtt"]], + ["EMQX 5.8", ["db/mqtt"]], ]; for (const [database, expected] of cases) { diff --git a/Cargo.lock b/Cargo.lock index 36dc614c3f..14987fa8de 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -41,9 +41,9 @@ dependencies = [ [[package]] name = "aes" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fc76eaeac4c9164506c466d4ffdd8ec9d0c5bf57ee97177c4d8eceb3a0e138" +checksum = "f8eb277bec05f56a0e0591f155a484cbd0f4f07ff2905051a48c72f004f7ed58" dependencies = [ "cipher 0.5.2", "cpubits", @@ -71,7 +71,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e22c0c90bbe8d4f77c3ca9ddabe41a1f8382d6fc1f7cea89459d0f320371f972" dependencies = [ "aead 0.6.0-rc.10", - "aes 0.9.1", + "aes 0.9.2", "cipher 0.5.2", "ctr 0.10.1", "ghash 0.6.0", @@ -256,9 +256,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.42" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79b3f8a79cccc2898f31920fc69f304859b3bd567490f75ebf51ae1c792a9ac" +checksum = "3976abdc8fe7d1133d43d304afd42abdf5bc3e1319d263d223bde07b5efc4be8" dependencies = [ "compression-codecs", "compression-core", @@ -395,6 +395,35 @@ dependencies = [ "syn 3.0.3", ] +[[package]] +name = "async-tungstenite" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cca750b12e02c389c1694d35c16539f88b8bbaa5945934fdc1b41a776688589" +dependencies = [ + "futures-io", + "futures-util", + "log", + "pin-project-lite", + "rustls-native-certs 0.7.3", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.25.0", + "tungstenite 0.21.0", +] + +[[package]] +name = "async_io_stream" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" +dependencies = [ + "futures", + "pharos", + "rustc_version", + "tokio", +] + [[package]] name = "asynchronous-codec" version = "0.6.2" @@ -897,9 +926,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.2.4" +version = "1.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f2d30e4173c4026932d51d31d6b0613b1fd3014bf3f9f8943d4ba139c437ba0" +checksum = "bb1307f12aa967b5a58416e87b3653360e0fd614a016b6e970db08fecbb1b80d" dependencies = [ "serde_core", ] @@ -1646,7 +1675,7 @@ dependencies = [ "reqwest 0.12.28", "russh", "rust_decimal", - "rustls 0.23.42", + "rustls 0.23.43", "semver", "serde", "serde_json", @@ -1726,10 +1755,11 @@ dependencies = [ "redis", "regex", "reqwest 0.12.28", + "rumqttc", "rusqlite", "russh", "rust_decimal", - "rustls 0.23.42", + "rustls 0.23.43", "rustls-pemfile 2.2.0", "serde", "serde_json", @@ -1767,7 +1797,7 @@ dependencies = [ "dirs", "reqwest 0.12.28", "rmcp", - "schemars 1.2.1", + "schemars 1.2.2", "serde", "serde_json", "tempfile", @@ -1792,7 +1822,7 @@ dependencies = [ "pbkdf2 0.12.2", "redis", "reqwest 0.12.28", - "rustls 0.23.42", + "rustls 0.23.43", "serde", "serde_json", "sha2 0.10.9", @@ -2021,13 +2051,13 @@ dependencies = [ [[package]] name = "displaydoc" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" +checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.3", ] [[package]] @@ -2234,7 +2264,7 @@ dependencies = [ "cc", "memchr", "rustc_version", - "toml 1.1.3+spec-1.1.0", + "toml 1.1.4+spec-1.1.0", "vswhom", "winreg", ] @@ -2344,11 +2374,10 @@ checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59" [[package]] name = "event-listener" -version = "5.4.1" +version = "5.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +checksum = "5a23add41df1562121a9393cb065eab5146a1242410f23a644851e90cfd669d2" dependencies = [ - "concurrent-queue", "parking", "pin-project-lite", ] @@ -2484,6 +2513,17 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ce81f49ae8a0482e4c55ea62ebbd7e5a686af544c00b9d090bba3ff9be97b3d" +[[package]] +name = "flume" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" +dependencies = [ + "futures-core", + "futures-sink", + "spin", +] + [[package]] name = "fnv" version = "1.0.7" @@ -3280,9 +3320,9 @@ dependencies = [ [[package]] name = "http" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6970f50e31d6fc17d3fa27329444bfa74e196cf62e95052a3f6fee181dba6425" +checksum = "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0" dependencies = [ "bytes", "itoa", @@ -3372,7 +3412,7 @@ dependencies = [ "http", "hyper", "hyper-util", - "rustls 0.23.42", + "rustls 0.23.43", "tokio", "tokio-rustls 0.26.4", "tower-service", @@ -4442,7 +4482,7 @@ dependencies = [ "percent-encoding", "rand 0.9.5", "rustc_version_runtime", - "rustls 0.23.42", + "rustls 0.23.43", "serde", "serde_bytes", "serde_with", @@ -4555,7 +4595,7 @@ dependencies = [ "mysql_common", "percent-encoding", "rand 0.10.2", - "rustls 0.23.42", + "rustls 0.23.43", "serde", "socket2", "thiserror 2.0.19", @@ -5438,6 +5478,16 @@ dependencies = [ "indexmap 2.14.0", ] +[[package]] +name = "pharos" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" +dependencies = [ + "futures", + "rustc_version", +] + [[package]] name = "phf" version = "0.13.1" @@ -5524,7 +5574,7 @@ version = "0.8.0-rc.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5a777c6e26664bc9504b3ce3f6133f8f20d9071f130a4f9fcbd3186959d8dd6" dependencies = [ - "aes 0.9.1", + "aes 0.9.2", "aes-gcm 0.11.0-rc.3", "cbc 0.2.1", "der 0.8.1", @@ -5922,7 +5972,7 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash", - "rustls 0.23.42", + "rustls 0.23.43", "socket2", "thiserror 2.0.19", "tokio", @@ -5943,7 +5993,7 @@ dependencies = [ "rand_pcg", "ring", "rustc-hash", - "rustls 0.23.42", + "rustls 0.23.43", "rustls-pki-types", "slab", "thiserror 2.0.19", @@ -6142,7 +6192,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "rand 0.9.5", - "rustls 0.23.42", + "rustls 0.23.43", "rustls-native-certs 0.8.4", "ryu", "sha1_smol", @@ -6257,7 +6307,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.42", + "rustls 0.23.43", "rustls-pki-types", "serde", "serde_json", @@ -6298,7 +6348,7 @@ dependencies = [ "log", "percent-encoding", "pin-project-lite", - "rustls 0.23.42", + "rustls 0.23.43", "rustls-pki-types", "rustls-platform-verifier", "serde", @@ -6413,7 +6463,7 @@ dependencies = [ "pastey", "pin-project-lite", "rmcp-macros", - "schemars 1.2.1", + "schemars 1.2.2", "serde", "serde_json", "thiserror 2.0.19", @@ -6455,6 +6505,25 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rumqttc" +version = "0.24.0" +dependencies = [ + "async-tungstenite", + "bytes", + "flume", + "futures-util", + "http", + "log", + "rustls-native-certs 0.7.3", + "rustls-pemfile 2.2.0", + "rustls-webpki 0.102.8", + "thiserror 1.0.69", + "tokio", + "tokio-rustls 0.25.0", + "ws_stream_tungstenite", +] + [[package]] name = "rusqlite" version = "0.32.1" @@ -6477,7 +6546,7 @@ checksum = "324b92f459d3e42da294e14e8eb150d2215fcfb7c966838bc1127cd68bc05a0d" dependencies = [ "aead 0.6.0-rc.10", "aes 0.8.4", - "aes 0.9.1", + "aes 0.9.2", "aes-gcm 0.11.0-rc.3", "aws-lc-rs", "bitflags 2.13.1", @@ -6676,9 +6745,23 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.42" +version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c54fcab019b409d04215d3a17cb438fd7fbf192ee61461f20f4fe18704bc138" +checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" +dependencies = [ + "log", + "ring", + "rustls-pki-types", + "rustls-webpki 0.102.8", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls" +version = "0.23.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0283386ce02abc0151e1761d08802dfe86c173b0b494af5cbc086574e453da06" dependencies = [ "aws-lc-rs", "log", @@ -6702,6 +6785,19 @@ dependencies = [ "security-framework 2.11.1", ] +[[package]] +name = "rustls-native-certs" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" +dependencies = [ + "openssl-probe 0.1.6", + "rustls-pemfile 2.2.0", + "rustls-pki-types", + "schannel", + "security-framework 2.11.1", +] + [[package]] name = "rustls-native-certs" version = "0.8.4" @@ -6753,7 +6849,7 @@ dependencies = [ "jni 0.22.4", "log", "once_cell", - "rustls 0.23.42", + "rustls 0.23.43", "rustls-native-certs 0.8.4", "rustls-platform-verifier-android", "rustls-webpki 0.103.13", @@ -6779,6 +6875,17 @@ dependencies = [ "untrusted 0.9.0", ] +[[package]] +name = "rustls-webpki" +version = "0.102.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted 0.9.0", +] + [[package]] name = "rustls-webpki" version = "0.103.13" @@ -6866,14 +6973,14 @@ dependencies = [ [[package]] name = "schemars" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" +checksum = "687274d293b6cdc6e73e0fee520bf2049650090d7164f87672d212a3c530cf4a" dependencies = [ "chrono", "dyn-clone", "ref-cast", - "schemars_derive 1.2.1", + "schemars_derive 1.2.2", "serde", "serde_json", ] @@ -6886,20 +6993,20 @@ checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" dependencies = [ "proc-macro2", "quote", - "serde_derive_internals", + "serde_derive_internals 0.29.1", "syn 2.0.119", ] [[package]] name = "schemars_derive" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d115b50f4aaeea07e79c1912f645c7513d81715d0420f8bc77a18c6260b307f" +checksum = "d98c67716b46af2f0b8cf752abc930f6f9aecfbf671ecfb531db8a31dbe4e2ba" dependencies = [ "proc-macro2", "quote", - "serde_derive_internals", - "syn 2.0.119", + "serde_derive_internals 0.30.0", + "syn 3.0.3", ] [[package]] @@ -7078,6 +7185,17 @@ dependencies = [ "syn 2.0.119", ] +[[package]] +name = "serde_derive_internals" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f852137cce035d6a4df67ccce505ff6b3e9fd3a10e3e52b24dc71e650bb1a9bd" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + [[package]] name = "serde_json" version = "1.0.151" @@ -7157,7 +7275,7 @@ dependencies = [ "indexmap 1.9.3", "indexmap 2.14.0", "schemars 0.9.0", - "schemars 1.2.1", + "schemars 1.2.2", "serde_core", "serde_json", "serde_with_macros", @@ -7491,6 +7609,9 @@ name = "spin" version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e" +dependencies = [ + "lock_api", +] [[package]] name = "spki" @@ -7814,9 +7935,9 @@ dependencies = [ [[package]] name = "tao-macros" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" +checksum = "5f7eeb6d99155545da6150a1795945f16ac9c178deb2a5f2e74d776107bd5849" dependencies = [ "proc-macro2", "quote", @@ -8049,7 +8170,7 @@ dependencies = [ "tauri-plugin", "tauri-utils", "thiserror 2.0.19", - "toml 1.1.3+spec-1.1.0", + "toml 1.1.4+spec-1.1.0", "url", ] @@ -8138,7 +8259,7 @@ dependencies = [ "osakit", "percent-encoding", "reqwest 0.13.4", - "rustls 0.23.42", + "rustls 0.23.43", "semver", "serde", "serde_json", @@ -8251,7 +8372,7 @@ dependencies = [ "serde_with", "swift-rs", "thiserror 2.0.19", - "toml 1.1.3+spec-1.1.0", + "toml 1.1.4+spec-1.1.0", "url", "urlpattern", "uuid", @@ -8266,7 +8387,7 @@ checksum = "cc65d45c68858bfe420dd29e834b5d15dbecf8a07a8a16cf4d532c7b1f69d4b6" dependencies = [ "dunce", "embed-resource", - "toml 1.1.3+spec-1.1.0", + "toml 1.1.4+spec-1.1.0", ] [[package]] @@ -8499,13 +8620,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.7.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6328af13490e73a9b4694030fafd93f8c8c6a9dede33e821c3fc63eddf8042ba" +checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.3", ] [[package]] @@ -8551,7 +8672,7 @@ checksum = "27d684bad428a0f2481f42241f821db42c54e2dc81d8c00db8536c506b0a0144" dependencies = [ "const-oid 0.9.6", "ring", - "rustls 0.23.42", + "rustls 0.23.43", "tokio", "tokio-postgres", "tokio-rustls 0.26.4", @@ -8568,13 +8689,24 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" +dependencies = [ + "rustls 0.22.4", + "rustls-pki-types", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ - "rustls 0.23.42", + "rustls 0.23.43", "tokio", ] @@ -8598,7 +8730,7 @@ dependencies = [ "futures-util", "log", "tokio", - "tungstenite", + "tungstenite 0.29.0", ] [[package]] @@ -8646,9 +8778,9 @@ dependencies = [ [[package]] name = "toml" -version = "1.1.3+spec-1.1.0" +version = "1.1.4+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53c96ecdfa941c8fc4fcaed14f99ada8ebed502eef533015095a07e3301d4c3c" +checksum = "3aace63f4bbcdfc2c965b059de67119c89c4017a70d633be6c104910f67056f5" dependencies = [ "indexmap 2.14.0", "serde_core", @@ -8724,9 +8856,9 @@ dependencies = [ [[package]] name = "toml_parser" -version = "1.1.2+spec-1.1.0" +version = "1.1.3+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56" dependencies = [ "winnow 1.0.4", ] @@ -8858,9 +8990,9 @@ dependencies = [ [[package]] name = "tray-icon" -version = "0.24.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65ba1e5f6b9ef9fd87e21b9c6f351554dbd717960089168fcfdef854686961dc" +checksum = "045979e3f037cd18ad1cb2a419dfda133c5c29c9f3453370079f2255d46c257e" dependencies = [ "crossbeam-channel", "dirs", @@ -8895,6 +9027,27 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "tungstenite" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand 0.8.7", + "rustls 0.22.4", + "rustls-pki-types", + "sha1 0.10.7", + "thiserror 1.0.69", + "url", + "utf-8", +] + [[package]] name = "tungstenite" version = "0.29.0" @@ -9121,6 +9274,12 @@ dependencies = [ "url", ] +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + [[package]] name = "utf8_iter" version = "1.0.4" @@ -10252,6 +10411,26 @@ dependencies = [ "x11-dl", ] +[[package]] +name = "ws_stream_tungstenite" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a198f414f083fb19fcc1bffcb0fa0cf46d33ccfa229adf248cac12c180e91609" +dependencies = [ + "async-tungstenite", + "async_io_stream", + "bitflags 2.13.1", + "futures-core", + "futures-io", + "futures-sink", + "futures-util", + "pharos", + "rustc_version", + "tokio", + "tracing", + "tungstenite 0.21.0", +] + [[package]] name = "wyz" version = "0.5.1" diff --git a/Cargo.toml b/Cargo.toml index d6672554f0..0b37b46816 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,14 @@ [workspace] resolver = "2" members = ["src-tauri", "crates/dbx-core", "crates/dbx-web", "crates/dbx-mcp", "crates/dbx-cli"] -exclude = ["vendor/ctor"] +exclude = ["vendor/ctor", "vendor/rumqttc"] [patch.crates-io] # Tauri 2.11 uses ctor 0.8, which excludes Rust's win7 vendor. This vendors # upstream rust-ctor#443 until tauri-utils moves to ctor 1.x. ctor = { path = "vendor/ctor" } +# rumqttc 0.24 hardcodes MQTT 3.1.1; this patch adds MQTT 3.1 CONNECT encoding. +rumqttc = { path = "vendor/rumqttc" } tokio-postgres = { git = "https://github.com/t8y2/tokio-postgres-gaussdb.git", rev = "115f9fef10f0fc3669b5337955e4eb461fc349a6" } postgres-types = { git = "https://github.com/t8y2/tokio-postgres-gaussdb.git", rev = "115f9fef10f0fc3669b5337955e4eb461fc349a6" } postgres-protocol = { git = "https://github.com/t8y2/tokio-postgres-gaussdb.git", rev = "115f9fef10f0fc3669b5337955e4eb461fc349a6" } diff --git a/apps/desktop/public/icons/database/mqtt.png b/apps/desktop/public/icons/database/mqtt.png new file mode 100644 index 0000000000000000000000000000000000000000..28b7223e14a63648ceb8ecf56744f99727507425 GIT binary patch literal 15995 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 + + + + \ No newline at end of file diff --git a/apps/desktop/src/components/connection/ConnectionDialog.vue b/apps/desktop/src/components/connection/ConnectionDialog.vue index 684d18acf4..526461d358 100644 --- a/apps/desktop/src/components/connection/ConnectionDialog.vue +++ b/apps/desktop/src/components/connection/ConnectionDialog.vue @@ -17,6 +17,7 @@ import { Switch } from "@/components/ui/switch"; import type { ConnectionConfig, ConnectionTestResult, DatabaseConnectionInfo, DatabaseType, HttpTunnelConfig, IdentifierCase, JdbcDriverInfo, JdbcLocalBundleInfo, JdbcMavenBundleInfo, ProxyTunnelConfig, SshConfigHostEntry, SshTunnelConfig, TransportLayerConfig } from "@/types/database"; import type { InfluxDbExternalConfig, InfluxDbVersion } from "@/types/influxdb"; import type { MqAdminConfig, MqAuth, MqSystemKind } from "@/types/mq"; +import type { MqttConnectionConfig } from "@/types/mqtt"; import type { NacosAdminConfig, NacosAuthConfig, NacosImplementation, NacosMetricsMode, NacosRNacosConsoleAuth, NacosVersionMode } from "@/types/nacos"; import { CONNECTION_ATTEMPT_CANCELLED_MESSAGE, useConnectionStore } from "@/stores/connectionStore"; import { useTunnelProfileStore } from "@/stores/tunnelProfileStore"; @@ -657,6 +658,23 @@ const nacosTlsSkipVerify = ref(false); const nacosMetricsMode = ref("auto"); const nacosMetricsUrl = ref(""); const nacosPageSize = ref(20); + +// --- MQTT-specific form fields --- +const mqttHost = ref("127.0.0.1"); +const mqttPort = ref(1883); +const mqttClientId = ref(""); +const mqttProtocolVersion = ref<"v3" | "v4" | "v5">("v5"); +const mqttTransportMode = ref<"tcp" | "websocket">("tcp"); +const mqttWsPath = ref("/mqtt"); +const mqttAuthKind = ref<"none" | "password">("none"); +const mqttUsername = ref(""); +const mqttPassword = ref(""); +const mqttTls = ref(false); +const mqttTlsSkipVerify = ref(false); +const mqttKeepAliveSecs = ref(60); +const mqttConnectTimeoutSecs = ref(30); +const mqttMaxPacketSizeBytes = ref(16 * 1024 * 1024); + const nacosPrimaryAddressLabel = computed(() => { if (nacosImplementation.value === "rnacos") return t("connection.nacosPrimaryAddressRNacos"); if (nacosVersionMode.value === "v2") return t("connection.nacosPrimaryAddressV2"); @@ -973,6 +991,7 @@ const driverProfiles: Record< rocketmq: { type: "mq", port: 9876, user: "", label: "Apache RocketMQ", icon: "rocketmq", host: "127.0.0.1" }, rabbitmq: { type: "mq", port: 5672, user: "", label: "RabbitMQ", icon: "rabbitmq", host: "127.0.0.1" }, nacos: { type: "nacos", port: 8848, user: "nacos", label: "Nacos", icon: "nacos", host: "127.0.0.1" }, + mqtt: { type: "mqtt", port: 1883, user: "", label: "MQTT", icon: "mqtt", host: "127.0.0.1" }, iris: { type: "iris", port: 1972, user: "_SYSTEM", label: "IRIS", icon: "iris" }, influxdb: { type: "influxdb", port: 8086, user: "", label: "InfluxDB", icon: "InfluxDB" }, custom_mysql: { @@ -1188,6 +1207,57 @@ function hydrateNacosFields(value: unknown) { resetNacosFields(value as Partial); } +function resetMqttFields(config?: Partial) { + mqttHost.value = config?.host?.trim() || "127.0.0.1"; + mqttPort.value = config?.port || 1883; + mqttClientId.value = config?.clientId || ""; + mqttProtocolVersion.value = config?.protocolVersion || "v5"; + mqttTransportMode.value = config?.transport || "tcp"; + mqttWsPath.value = config?.wsPath || "/mqtt"; + mqttTls.value = config?.tls || false; + mqttTlsSkipVerify.value = config?.tlsSkipVerify || false; + mqttKeepAliveSecs.value = Math.max(1, config?.keepAliveSecs || 60); + mqttConnectTimeoutSecs.value = Math.max(1, config?.connectTimeoutSecs || 30); + mqttMaxPacketSizeBytes.value = Math.min(268435455, Math.max(1024, config?.maxPacketSizeBytes || 16 * 1024 * 1024)); + const auth = config?.auth; + if (auth && auth.kind === "password") { + mqttAuthKind.value = "password"; + mqttUsername.value = auth.username || ""; + mqttPassword.value = auth.password || ""; + } else { + mqttAuthKind.value = "none"; + mqttUsername.value = ""; + mqttPassword.value = ""; + } +} + +function hydrateMqttFields(value: unknown) { + if (!value || typeof value !== "object") { + resetMqttFields(); + return; + } + resetMqttFields(value as Partial); +} + +function buildMqttExternalConfig(): MqttConnectionConfig { + const auth: MqttConnectionConfig["auth"] = mqttAuthKind.value === "password" ? { kind: "password", username: mqttUsername.value, password: mqttPassword.value } : { kind: "none" }; + + return { + host: mqttHost.value.trim(), + port: mqttPort.value, + clientId: mqttClientId.value.trim() || `dbx-${Math.random().toString(36).slice(2, 10)}`, + protocolVersion: mqttProtocolVersion.value, + transport: mqttTransportMode.value, + tls: mqttTls.value, + tlsSkipVerify: mqttTlsSkipVerify.value, + auth, + keepAliveSecs: Math.max(1, mqttKeepAliveSecs.value), + connectTimeoutSecs: Math.max(1, mqttConnectTimeoutSecs.value), + maxPacketSizeBytes: Math.min(268435455, Math.max(1024, mqttMaxPacketSizeBytes.value)), + wsPath: mqttTransportMode.value === "websocket" ? mqttWsPath.value || "/mqtt" : undefined, + }; +} + const influxDbVersion = ref("1"); const influxDbOrg = ref(""); @@ -1957,6 +2027,12 @@ function applyProfile(val: string, preserveConnectionFields = false) { form.value.connection_string = undefined; form.value.url_params = ""; } + if (profile.type === "mqtt") { + resetMqttFields(); + form.value.database = undefined; + form.value.connection_string = undefined; + form.value.url_params = ""; + } if (profile.type === "influxdb") { resetInfluxDbFields(); form.value.database = undefined; @@ -2060,6 +2136,11 @@ watch( } else { resetNacosFields(); } + if (config.db_type === "mqtt") { + hydrateMqttFields(config.external_config); + } else { + resetMqttFields(); + } if (config.db_type === "influxdb") { hydrateInfluxDbFields(config.external_config); } else { @@ -2304,6 +2385,7 @@ const iconTypeMap: Record = { rocketmq: "rocketmq", rabbitmq: "rabbitmq", nacos: "nacos", + mqtt: "mqtt", dm: "dm", h2: "h2", snowflake: "snowflake", @@ -2403,6 +2485,7 @@ const dbOptions: DbOption[] = [ { value: "kafka", label: "Apache Kafka" }, { value: "rocketmq", label: "Apache RocketMQ" }, { value: "rabbitmq", label: "RabbitMQ" }, + { value: "mqtt", label: "MQTT" }, { value: "nacos", label: "Nacos" }, { value: "influxdb", label: "InfluxDB" }, { value: "iris", label: "IRIS" }, @@ -2456,7 +2539,7 @@ const dbCategoryDefinitions: Array<{ { key: "mq", titleKey: "connection.databaseCategoryMq", - optionValues: ["mq", "kafka", "rocketmq", "rabbitmq"], + optionValues: ["mq", "kafka", "rocketmq", "rabbitmq", "mqtt"], }, { key: "registry_config", @@ -2864,6 +2947,7 @@ const hasRequiredConnectionTarget = computed(() => { return !!mqAdminUrl.value.trim(); } if (form.value.db_type === "zookeeper") return !!(form.value.host || form.value.connection_string || connectionUrlInput.value.trim()); + if (form.value.db_type === "mqtt") return !!mqttHost.value.trim() && mqttPort.value > 0; if (form.value.db_type === "nacos") return !!nacosServerAddr.value.trim(); if (isCloudflareD1Connection(form.value)) return hasCloudflareD1Credentials(form.value); if (isH2FileMode.value) return !!(form.value.host.trim() || h2FilePathFromJdbcUrl(form.value.connection_string)); @@ -3264,6 +3348,19 @@ function connectionConfigForSubmit(id: string, generatedName = ""): ConnectionCo config.database = nacosConfig.namespace || undefined; config.connection_string = undefined; config.url_params = ""; + } else if (config.db_type === "mqtt") { + const mqttConfig = buildMqttExternalConfig(); + config.external_config = mqttConfig; + config.driver_profile = "mqtt"; + config.driver_label = "MQTT"; + config.host = mqttConfig.host; + config.port = mqttConfig.port; + config.ssl = mqttConfig.tls; + config.username = ""; + config.password = ""; + config.database = undefined; + config.connection_string = undefined; + config.url_params = ""; } else if (config.db_type === "influxdb") { config.external_config = buildInfluxDbExternalConfig(); config.connection_string = undefined; @@ -5851,6 +5948,81 @@ function openExternalUrl(url: string) { + + + + +