From 6e3f855350e64c4e69cea0f93e44df00999f78be Mon Sep 17 00:00:00 2001 From: Daniel Boros Date: Sun, 17 May 2026 14:31:36 +0200 Subject: [PATCH 01/11] refactor: road to support wasm --- Cargo.lock | 4237 +++++++- Cargo.toml | 34 + crates/rsql-core/Cargo.toml | 31 + .../rsql-core/src/common/mod.rs | 1 - .../rsql-core}/src/common/pgsql.rs | 0 .../rsql-core}/src/drivers/mod.rs | 0 .../src/drivers/pgsql/commands/admin.rs | 110 +- .../src/drivers/pgsql/commands/connection.rs | 35 + .../src/drivers/pgsql/commands/metadata.rs | 189 + .../src/drivers/pgsql/commands/mod.rs | 11 + .../src/drivers/pgsql/commands/object_info.rs | 50 + .../drivers/pgsql/commands/pool_helpers.rs | 93 + .../src/drivers/pgsql/commands/pubsub.rs | 32 + .../src/drivers/pgsql/commands/query.rs | 115 +- .../pgsql/commands/snapshot_persistence.rs | 33 +- .../src/drivers/pgsql/commands/statistics.rs | 92 + .../src/drivers/pgsql/ddl_generation.rs | 2 +- .../src/drivers/pgsql/extensions.rs | 2 +- .../src/drivers/pgsql/metadata_schema.rs | 2 +- .../drivers/pgsql/metadata_views_functions.rs | 2 +- .../rsql-core}/src/drivers/pgsql/mod.rs | 25 +- .../drivers/pgsql/query_execution/helpers.rs | 6 +- .../src/drivers/pgsql/query_execution/mod.rs | 3 +- .../drivers/pgsql/query_execution/simple.rs | 2 +- .../pgsql/query_execution/virtual_cache.rs | 2 +- .../pgsql/roles_schema_objects/csv_import.rs | 2 +- .../drivers/pgsql/roles_schema_objects/mod.rs | 0 .../roles_schema_objects/roles_grants.rs | 2 +- .../roles_schema_objects/schema_objects.rs | 2 +- .../pgsql/statistics_activity/database.rs | 2 +- .../drivers/pgsql/statistics_activity/mod.rs | 0 .../pgsql/statistics_activity/objects.rs | 2 +- .../enums.rs => crates/rsql-core/src/error.rs | 6 +- crates/rsql-core/src/lib.rs | 11 + {src-tauri => crates/rsql-core}/src/ssh.rs | 0 crates/rsql-core/src/state/mod.rs | 24 + .../rsql-core/src/state}/project.rs | 34 +- .../rsql-core/src/state}/query.rs | 32 +- .../rsql-core/src/state}/workspace.rs | 31 +- crates/rsql-core/src/utils/diff.rs | 80 + crates/rsql-core/src/utils/mod.rs | 132 + crates/rsql-core/tests/state_smoke.rs | 104 + {src-tauri => crates/rsql-tauri}/.gitignore | 0 crates/rsql-tauri/Cargo.toml | 42 + {src-tauri => crates/rsql-tauri}/build.rs | 0 .../rsql-tauri}/capabilities/default.json | 0 .../rsql-tauri}/icons/128x128.png | Bin .../rsql-tauri}/icons/128x128@2x.png | Bin .../rsql-tauri}/icons/32x32.png | Bin .../rsql-tauri}/icons/Square107x107Logo.png | Bin .../rsql-tauri}/icons/Square142x142Logo.png | Bin .../rsql-tauri}/icons/Square150x150Logo.png | Bin .../rsql-tauri}/icons/Square284x284Logo.png | Bin .../rsql-tauri}/icons/Square30x30Logo.png | Bin .../rsql-tauri}/icons/Square310x310Logo.png | Bin .../rsql-tauri}/icons/Square44x44Logo.png | Bin .../rsql-tauri}/icons/Square71x71Logo.png | Bin .../rsql-tauri}/icons/Square89x89Logo.png | Bin .../rsql-tauri}/icons/StoreLogo.png | Bin .../rsql-tauri}/icons/icon.icns | Bin .../rsql-tauri}/icons/icon.ico | Bin .../rsql-tauri}/icons/icon.png | Bin .../rsql-tauri}/src/app_setup.rs | 3 +- crates/rsql-tauri/src/commands.rs | 81 + crates/rsql-tauri/src/drivers/mod.rs | 1 + .../drivers/pgsql/commands/admin_commands.rs | 118 + .../pgsql/commands/metadata_commands.rs | 151 + .../src/drivers/pgsql/commands/mod.rs | 4 - .../pgsql/commands/object_info_commands.rs | 47 + .../drivers/pgsql/commands/pool_connection.rs | 140 +- .../drivers/pgsql/commands/pubsub_commands.rs | 41 +- .../drivers/pgsql/commands/query_commands.rs | 95 + .../pgsql/commands/statistics_commands.rs | 90 + crates/rsql-tauri/src/drivers/pgsql/mod.rs | 4 + .../src/drivers/pgsql}/streaming.rs | 7 +- {src-tauri => crates/rsql-tauri}/src/lib.rs | 0 {src-tauri => crates/rsql-tauri}/src/main.rs | 38 +- .../rsql-tauri}/src/terminal.rs | 0 crates/rsql-tauri/src/utils.rs | 33 + .../rsql-tauri}/tauri.conf.json | 2 +- package.json | 2 +- scripts/check-rsql-core-purity.sh | 18 + src-tauri/Cargo.lock | 8571 ----------------- src-tauri/Cargo.toml | 45 - src-tauri/src/dbs/mod.rs | 3 - .../pgsql/commands/metadata_commands.rs | 219 - .../pgsql/commands/object_info_commands.rs | 61 - .../pgsql/commands/statistics_commands.rs | 117 - src-tauri/src/utils.rs | 243 - vite.config.ts | 3 +- 90 files changed, 5623 insertions(+), 10129 deletions(-) create mode 100644 Cargo.toml create mode 100644 crates/rsql-core/Cargo.toml rename src-tauri/src/common.rs => crates/rsql-core/src/common/mod.rs (87%) rename {src-tauri => crates/rsql-core}/src/common/pgsql.rs (100%) rename {src-tauri => crates/rsql-core}/src/drivers/mod.rs (100%) rename src-tauri/src/drivers/pgsql/commands/admin_commands.rs => crates/rsql-core/src/drivers/pgsql/commands/admin.rs (56%) create mode 100644 crates/rsql-core/src/drivers/pgsql/commands/connection.rs create mode 100644 crates/rsql-core/src/drivers/pgsql/commands/metadata.rs create mode 100644 crates/rsql-core/src/drivers/pgsql/commands/mod.rs create mode 100644 crates/rsql-core/src/drivers/pgsql/commands/object_info.rs create mode 100644 crates/rsql-core/src/drivers/pgsql/commands/pool_helpers.rs create mode 100644 crates/rsql-core/src/drivers/pgsql/commands/pubsub.rs rename src-tauri/src/drivers/pgsql/commands/query_commands.rs => crates/rsql-core/src/drivers/pgsql/commands/query.rs (57%) rename {src-tauri => crates/rsql-core}/src/drivers/pgsql/commands/snapshot_persistence.rs (91%) create mode 100644 crates/rsql-core/src/drivers/pgsql/commands/statistics.rs rename {src-tauri => crates/rsql-core}/src/drivers/pgsql/ddl_generation.rs (99%) rename {src-tauri => crates/rsql-core}/src/drivers/pgsql/extensions.rs (98%) rename {src-tauri => crates/rsql-core}/src/drivers/pgsql/metadata_schema.rs (99%) rename {src-tauri => crates/rsql-core}/src/drivers/pgsql/metadata_views_functions.rs (99%) rename {src-tauri => crates/rsql-core}/src/drivers/pgsql/mod.rs (85%) rename {src-tauri => crates/rsql-core}/src/drivers/pgsql/query_execution/helpers.rs (95%) rename {src-tauri => crates/rsql-core}/src/drivers/pgsql/query_execution/mod.rs (70%) rename {src-tauri => crates/rsql-core}/src/drivers/pgsql/query_execution/simple.rs (98%) rename {src-tauri => crates/rsql-core}/src/drivers/pgsql/query_execution/virtual_cache.rs (98%) rename {src-tauri => crates/rsql-core}/src/drivers/pgsql/roles_schema_objects/csv_import.rs (98%) rename {src-tauri => crates/rsql-core}/src/drivers/pgsql/roles_schema_objects/mod.rs (100%) rename {src-tauri => crates/rsql-core}/src/drivers/pgsql/roles_schema_objects/roles_grants.rs (99%) rename {src-tauri => crates/rsql-core}/src/drivers/pgsql/roles_schema_objects/schema_objects.rs (99%) rename {src-tauri => crates/rsql-core}/src/drivers/pgsql/statistics_activity/database.rs (99%) rename {src-tauri => crates/rsql-core}/src/drivers/pgsql/statistics_activity/mod.rs (100%) rename {src-tauri => crates/rsql-core}/src/drivers/pgsql/statistics_activity/objects.rs (99%) rename src-tauri/src/common/enums.rs => crates/rsql-core/src/error.rs (88%) create mode 100644 crates/rsql-core/src/lib.rs rename {src-tauri => crates/rsql-core}/src/ssh.rs (100%) create mode 100644 crates/rsql-core/src/state/mod.rs rename {src-tauri/src/dbs => crates/rsql-core/src/state}/project.rs (83%) rename {src-tauri/src/dbs => crates/rsql-core/src/state}/query.rs (65%) rename {src-tauri/src/dbs => crates/rsql-core/src/state}/workspace.rs (67%) create mode 100644 crates/rsql-core/src/utils/diff.rs create mode 100644 crates/rsql-core/src/utils/mod.rs create mode 100644 crates/rsql-core/tests/state_smoke.rs rename {src-tauri => crates/rsql-tauri}/.gitignore (100%) create mode 100644 crates/rsql-tauri/Cargo.toml rename {src-tauri => crates/rsql-tauri}/build.rs (100%) rename {src-tauri => crates/rsql-tauri}/capabilities/default.json (100%) rename {src-tauri => crates/rsql-tauri}/icons/128x128.png (100%) rename {src-tauri => crates/rsql-tauri}/icons/128x128@2x.png (100%) rename {src-tauri => crates/rsql-tauri}/icons/32x32.png (100%) rename {src-tauri => crates/rsql-tauri}/icons/Square107x107Logo.png (100%) rename {src-tauri => crates/rsql-tauri}/icons/Square142x142Logo.png (100%) rename {src-tauri => crates/rsql-tauri}/icons/Square150x150Logo.png (100%) rename {src-tauri => crates/rsql-tauri}/icons/Square284x284Logo.png (100%) rename {src-tauri => crates/rsql-tauri}/icons/Square30x30Logo.png (100%) rename {src-tauri => crates/rsql-tauri}/icons/Square310x310Logo.png (100%) rename {src-tauri => crates/rsql-tauri}/icons/Square44x44Logo.png (100%) rename {src-tauri => crates/rsql-tauri}/icons/Square71x71Logo.png (100%) rename {src-tauri => crates/rsql-tauri}/icons/Square89x89Logo.png (100%) rename {src-tauri => crates/rsql-tauri}/icons/StoreLogo.png (100%) rename {src-tauri => crates/rsql-tauri}/icons/icon.icns (100%) rename {src-tauri => crates/rsql-tauri}/icons/icon.ico (100%) rename {src-tauri => crates/rsql-tauri}/icons/icon.png (100%) rename {src-tauri => crates/rsql-tauri}/src/app_setup.rs (98%) create mode 100644 crates/rsql-tauri/src/commands.rs create mode 100644 crates/rsql-tauri/src/drivers/mod.rs create mode 100644 crates/rsql-tauri/src/drivers/pgsql/commands/admin_commands.rs create mode 100644 crates/rsql-tauri/src/drivers/pgsql/commands/metadata_commands.rs rename {src-tauri => crates/rsql-tauri}/src/drivers/pgsql/commands/mod.rs (75%) create mode 100644 crates/rsql-tauri/src/drivers/pgsql/commands/object_info_commands.rs rename {src-tauri => crates/rsql-tauri}/src/drivers/pgsql/commands/pool_connection.rs (58%) rename {src-tauri => crates/rsql-tauri}/src/drivers/pgsql/commands/pubsub_commands.rs (84%) create mode 100644 crates/rsql-tauri/src/drivers/pgsql/commands/query_commands.rs create mode 100644 crates/rsql-tauri/src/drivers/pgsql/commands/statistics_commands.rs create mode 100644 crates/rsql-tauri/src/drivers/pgsql/mod.rs rename {src-tauri/src/drivers/pgsql/query_execution => crates/rsql-tauri/src/drivers/pgsql}/streaming.rs (97%) rename {src-tauri => crates/rsql-tauri}/src/lib.rs (100%) rename {src-tauri => crates/rsql-tauri}/src/main.rs (76%) rename {src-tauri => crates/rsql-tauri}/src/terminal.rs (100%) create mode 100644 crates/rsql-tauri/src/utils.rs rename {src-tauri => crates/rsql-tauri}/tauri.conf.json (96%) create mode 100755 scripts/check-rsql-core-purity.sh delete mode 100644 src-tauri/Cargo.lock delete mode 100644 src-tauri/Cargo.toml delete mode 100644 src-tauri/src/dbs/mod.rs delete mode 100644 src-tauri/src/drivers/pgsql/commands/metadata_commands.rs delete mode 100644 src-tauri/src/drivers/pgsql/commands/object_info_commands.rs delete mode 100644 src-tauri/src/drivers/pgsql/commands/statistics_commands.rs delete mode 100644 src-tauri/src/utils.rs diff --git a/Cargo.lock b/Cargo.lock index 91a59ed..f7c9dc7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,54 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common 0.1.6", + "generic-array 0.14.7", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "getrandom 0.3.3", + "once_cell", + "version_check", + "zerocopy 0.8.27", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -41,6 +89,12 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -56,6 +110,169 @@ version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" +dependencies = [ + "derive_arbitrary", +] + +[[package]] +name = "argon2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" +dependencies = [ + "base64ct", + "blake2", + "cpufeatures", + "password-hash", +] + +[[package]] +name = "async-broadcast" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" +dependencies = [ + "event-listener", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-channel" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-executor" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "pin-project-lite", + "slab", +] + +[[package]] +name = "async-io" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19634d6336019ef220f09fd31168ce5c184b295cbf80345437cc36094ef223ca" +dependencies = [ + "async-lock", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite", + "parking", + "polling", + "rustix 1.1.2", + "slab", + "windows-sys 0.60.2", +] + +[[package]] +name = "async-lock" +version = "3.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-process" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65daa13722ad51e6ab1a1b9c01299142bc75135b337923cfa10e79bbbd669f00" +dependencies = [ + "async-channel", + "async-io", + "async-lock", + "async-signal", + "async-task", + "blocking", + "cfg-if", + "event-listener", + "futures-lite", + "rustix 1.1.2", +] + +[[package]] +name = "async-recursion" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "async-signal" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f567af260ef69e1d52c2b560ce0ea230763e6fbb9214a85d768760a920e3e3c1" +dependencies = [ + "async-io", + "async-lock", + "atomic-waker", + "cfg-if", + "futures-core", + "futures-io", + "rustix 1.1.2", + "signal-hook-registry", + "slab", + "windows-sys 0.60.2", +] + +[[package]] +name = "async-stream" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + [[package]] name = "async-trait" version = "0.1.89" @@ -103,22 +320,71 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] -name = "backend" -version = "1.0.0" +name = "aws-lc-rs" +version = "1.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94bffc006df10ac2a68c83692d734a465f8ee6c5b384d8545a636f81d858f4bf" dependencies = [ - "bincode", - "chrono", - "common", - "serde_json", - "sled", - "tauri", - "tauri-build", - "tauri-plugin-fs", - "tauri-plugin-shell", - "tokio", - "tokio-postgres", - "tracing", - "tracing-subscriber", + "aws-lc-sys", + "untrusted 0.7.1", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4321e568ed89bb5a7d291a7f37997c2c0df89809d7b6d12062c81ddb54aa782e" +dependencies = [ + "cc", + "cmake", + "dunce", + "fs_extra", +] + +[[package]] +name = "axum" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" +dependencies = [ + "async-trait", + "axum-core", + "bitflags 1.3.2", + "bytes", + "futures-util", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.32", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "sync_wrapper 0.1.2", + "tower 0.4.13", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http 0.2.12", + "http-body 0.4.6", + "mime", + "rustversion", + "tower-layer", + "tower-service", ] [[package]] @@ -136,6 +402,18 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base16ct" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd307490d624467aa6f74b0eabb77633d1f758a7b25f12bceb0b22e08d9726f6" + [[package]] name = "base64" version = "0.21.7" @@ -148,6 +426,23 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + +[[package]] +name = "bcrypt-pbkdf" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aeac2e1fe888769f34f05ac343bbef98b14d1ffb292ab69d4608b3abc86f2a2" +dependencies = [ + "blowfish", + "pbkdf2", + "sha2 0.10.9", +] + [[package]] name = "bincode" version = "1.3.3" @@ -157,6 +452,29 @@ dependencies = [ "serde", ] +[[package]] +name = "bindgen" +version = "0.66.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b84e06fc203107bfbad243f4aba2af864eb7db3b1cf46ea0a023b0b433d2a7" +dependencies = [ + "bitflags 2.9.4", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.106", + "which", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -172,13 +490,40 @@ dependencies = [ "serde", ] +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest 0.10.7", +] + [[package]] name = "block-buffer" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array", + "generic-array 0.14.7", +] + +[[package]] +name = "block-buffer" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "block-padding" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" +dependencies = [ + "generic-array 0.14.7", ] [[package]] @@ -199,6 +544,29 @@ dependencies = [ "objc2 0.6.2", ] +[[package]] +name = "blocking" +version = "1.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" +dependencies = [ + "async-channel", + "async-task", + "futures-io", + "futures-lite", + "piper", +] + +[[package]] +name = "blowfish" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e412e2cd0f2b2d93e02543ceae7917b3c70331573df19ee046bcbc35e45e87d7" +dependencies = [ + "byteorder", + "cipher", +] + [[package]] name = "brotli" version = "8.0.2" @@ -314,13 +682,24 @@ dependencies = [ "toml 0.9.5", ] +[[package]] +name = "cbc" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" +dependencies = [ + "cipher", +] + [[package]] name = "cc" -version = "1.2.36" +version = "1.2.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5252b3d2648e5eedbc1a6f501e3c795e07025c1e93bbf8bbdd6eef7f447a6d54" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" dependencies = [ "find-msvc-tools", + "jobserver", + "libc", "shlex", ] @@ -330,6 +709,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + [[package]] name = "cfb" version = "0.7.3" @@ -357,12 +745,29 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + [[package]] name = "cfg_aliases" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "chacha20" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + [[package]] name = "chrono" version = "0.4.42" @@ -377,6 +782,42 @@ dependencies = [ "windows-link 0.2.0", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common 0.1.6", + "inout", +] + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading 0.8.9", +] + +[[package]] +name = "cmake" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" +dependencies = [ + "cc", +] + +[[package]] +name = "cmov" +version = "0.5.0-pre.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5417da527aa9bf6a1e10a781231effd1edd3ee82f27d5f8529ac9b279babce96" + [[package]] name = "combine" version = "4.6.7" @@ -388,12 +829,26 @@ dependencies = [ ] [[package]] -name = "common" -version = "1.0.0" +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" dependencies = [ - "serde", + "crossbeam-utils", ] +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + [[package]] name = "convert_case" version = "0.4.0" @@ -410,6 +865,16 @@ dependencies = [ "version_check", ] +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation" version = "0.10.1" @@ -433,9 +898,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" dependencies = [ "bitflags 2.9.4", - "core-foundation", + "core-foundation 0.10.1", + "core-graphics-types", + "foreign-types 0.5.0", + "libc", +] + +[[package]] +name = "core-graphics" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "064badf302c3194842cf2c5d61f56cc88e54a759313879cdf03abdd27d0c3b97" +dependencies = [ + "bitflags 2.9.4", + "core-foundation 0.10.1", "core-graphics-types", - "foreign-types", + "foreign-types 0.5.0", "libc", ] @@ -446,10 +924,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ "bitflags 2.9.4", - "core-foundation", + "core-foundation 0.10.1", "libc", ] +[[package]] +name = "core-models" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0940496e5c83c54f3b753d5317daec82e8edac71c33aaa1f666d76f518de2444" +dependencies = [ + "hax-lib", + "pastey", + "rand 0.9.2", +] + [[package]] name = "cpufeatures" version = "0.2.17" @@ -477,6 +966,16 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + [[package]] name = "crossbeam-epoch" version = "0.9.18" @@ -492,16 +991,61 @@ version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array 0.14.7", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-bigint" +version = "0.7.0-rc.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37387ceb32048ff590f2cbd24d8b05fffe63c3f69a5cfa089d4f722ca4385a19" +dependencies = [ + "ctutils", + "num-traits", + "rand_core 0.10.0-rc-3", + "serdect", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array", + "generic-array 0.14.7", "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "crypto-primes" +version = "0.7.0-pre.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79c98a281f9441200b24e3151407a629bfbe720399186e50516da939195e482" +dependencies = [ + "crypto-bigint 0.7.0-rc.18", + "libm", + "rand_core 0.10.0-rc-3", +] + [[package]] name = "cssparser" version = "0.29.6" @@ -529,6 +1073,27 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "csv" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52cd9d68cf7efc6ddfaaee42e7288d3a99d613d4b50f76ce9827ae0c6e14f938" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde_core", +] + +[[package]] +name = "csv-core" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704a3c26996a80471189265814dbc2c257598b96b8a7feae2d31ace646bb9782" +dependencies = [ + "memchr", +] + [[package]] name = "ctor" version = "0.2.9" @@ -539,6 +1104,51 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "ctutils" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "758e5ed90be3c8abff7f9a6f37ab7f6d8c59c2210d448b81f3f508134aec84e4" +dependencies = [ + "cmov", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + [[package]] name = "darling" version = "0.20.11" @@ -574,6 +1184,80 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "data-encoding" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" + +[[package]] +name = "deadpool" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0be2b1d1d6ec8d846f05e137292d0b89133caf95ef33695424c09568bdd39b1b" +dependencies = [ + "deadpool-runtime", + "lazy_static", + "num_cpus", + "tokio", +] + +[[package]] +name = "deadpool-postgres" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d697d376cbfa018c23eb4caab1fd1883dd9c906a8c034e8d9a3cb06a7e0bef9" +dependencies = [ + "async-trait", + "deadpool", + "getrandom 0.2.16", + "tokio", + "tokio-postgres", + "tracing", +] + +[[package]] +name = "deadpool-runtime" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "092966b41edc516079bdf31ec78a2e0588d1d0c08f78b91d8307215928642b2b" +dependencies = [ + "tokio", +] + +[[package]] +name = "delegate" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "780eb241654bf097afb00fc5f054a09b687dad862e485fdcf8399bb056565370" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid 0.9.6", + "pem-rfc7468 0.7.0", + "zeroize", +] + +[[package]] +name = "der" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fd89660b2dc699704064e59e9dba0147b903e85319429e131620d022be411b" +dependencies = [ + "const-oid 0.10.2", + "pem-rfc7468 1.0.0", + "zeroize", +] + [[package]] name = "deranged" version = "0.5.3" @@ -584,6 +1268,17 @@ dependencies = [ "serde", ] +[[package]] +name = "derive_arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + [[package]] name = "derive_more" version = "0.99.20" @@ -603,11 +1298,23 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", - "crypto-common", + "block-buffer 0.10.4", + "const-oid 0.9.6", + "crypto-common 0.1.6", "subtle", ] +[[package]] +name = "digest" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "285743a676ccb6b3e116bc14cc69319b957867930ae9c4822f8e0f54509d7243" +dependencies = [ + "block-buffer 0.12.0", + "const-oid 0.10.2", + "crypto-common 0.2.1", +] + [[package]] name = "dirs" version = "6.0.0" @@ -629,12 +1336,6 @@ dependencies = [ "windows-sys 0.61.0", ] -[[package]] -name = "dispatch" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" - [[package]] name = "dispatch2" version = "0.3.0" @@ -642,6 +1343,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" dependencies = [ "bitflags 2.9.4", + "block2 0.6.1", + "libc", "objc2 0.6.2", ] @@ -679,6 +1382,12 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + [[package]] name = "dpi" version = "0.1.2" @@ -715,6 +1424,72 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der 0.7.10", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "signature 2.2.0", + "spki 0.7.3", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8 0.10.2", + "signature 2.2.0", +] + +[[package]] +name = "ed25519-dalek" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" +dependencies = [ + "curve25519-dalek", + "ed25519", + "rand_core 0.6.4", + "serde", + "sha2 0.10.9", + "subtle", + "zeroize", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct 0.2.0", + "crypto-bigint 0.5.5", + "digest 0.10.7", + "ff", + "generic-array 0.14.7", + "group", + "hkdf", + "pem-rfc7468 0.7.0", + "pkcs8 0.10.2", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "embed-resource" version = "3.0.5" @@ -726,7 +1501,7 @@ dependencies = [ "rustc_version", "toml 0.9.5", "vswhom", - "winreg", + "winreg 0.55.0", ] [[package]] @@ -745,27 +1520,127 @@ dependencies = [ ] [[package]] -name = "equivalent" -version = "1.0.2" +name = "endi" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf" [[package]] -name = "erased-serde" -version = "0.4.6" +name = "enum_dispatch" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e004d887f51fcb9fef17317a2f3525c887d8aa3f4f50fed920816a688284a5b7" +checksum = "aa18ce2bc66555b3218614519ac839ddb759a7d6720732f979ef8d13be147ecd" dependencies = [ - "serde", - "typeid", -] - + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "enumflags2" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" +dependencies = [ + "enumflags2_derive", + "serde", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "erased-serde" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e004d887f51fcb9fef17317a2f3525c887d8aa3f4f50fed920816a688284a5b7" +dependencies = [ + "serde", + "typeid", +] + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.0", +] + +[[package]] +name = "event-listener" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + [[package]] name = "fallible-iterator" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "faststr" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ca7d44d22004409a61c393afb3369c8f7bb74abcae49fe249ee01dcc3002113" +dependencies = [ + "bytes", + "rkyv", + "serde", + "simdutf8", +] + [[package]] name = "fdeflate" version = "0.3.7" @@ -775,6 +1650,22 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + [[package]] name = "field-offset" version = "0.3.6" @@ -785,11 +1676,33 @@ dependencies = [ "rustc_version", ] +[[package]] +name = "filedescriptor" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e40758ed24c9b2eeb76c35fb0aebc66c626084edd827e07e1552279814c6682d" +dependencies = [ + "libc", + "thiserror 1.0.69", + "winapi", +] + +[[package]] +name = "filetime" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db" +dependencies = [ + "cfg-if", + "libc", + "libredox", +] + [[package]] name = "find-msvc-tools" -version = "0.1.1" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" [[package]] name = "flate2" @@ -807,6 +1720,15 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared 0.1.1", +] + [[package]] name = "foreign-types" version = "0.5.0" @@ -814,7 +1736,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" dependencies = [ "foreign-types-macros", - "foreign-types-shared", + "foreign-types-shared 0.3.1", ] [[package]] @@ -828,6 +1750,12 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "foreign-types-shared" version = "0.3.1" @@ -844,14 +1772,10 @@ dependencies = [ ] [[package]] -name = "fs2" -version = "0.4.3" +name = "fs_extra" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" -dependencies = [ - "libc", - "winapi", -] +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" [[package]] name = "futf" @@ -863,6 +1787,21 @@ dependencies = [ "new_debug_unreachable", ] +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.31" @@ -896,6 +1835,19 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +[[package]] +name = "futures-lite" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + [[package]] name = "futures-macro" version = "0.3.31" @@ -925,6 +1877,7 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ + "futures-channel", "futures-core", "futures-io", "futures-macro", @@ -1052,6 +2005,18 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", +] + +[[package]] +name = "generic-array" +version = "1.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaf57c49a95fd1fe24b90b3033bee6dc7e8f1288d51494cb44e627c295e38542" +dependencies = [ + "generic-array 0.14.7", + "rustversion", + "typenum", ] [[package]] @@ -1072,8 +2037,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi 0.11.1+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] @@ -1088,6 +2055,16 @@ dependencies = [ "wasi 0.14.5+wasi-0.2.4", ] +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug", + "polyval", +] + [[package]] name = "gimli" version = "0.31.1" @@ -1156,7 +2133,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc" dependencies = [ "heck 0.4.1", - "proc-macro-crate 2.0.2", + "proc-macro-crate 2.0.0", "proc-macro-error", "proc-macro2", "quote", @@ -1190,6 +2167,17 @@ dependencies = [ "system-deps", ] +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "gtk" version = "0.18.2" @@ -1242,18 +2230,99 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "h2" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.12", + "indexmap 2.11.1", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", +] + [[package]] name = "hashbrown" version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "hashlink" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +dependencies = [ + "hashbrown 0.14.5", +] + +[[package]] +name = "hax-lib" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d9ba66d1739c68e0219b2b2238b5c4145f491ebf181b9c6ab561a19352ae86" +dependencies = [ + "hax-lib-macros", + "num-bigint", + "num-traits", +] + +[[package]] +name = "hax-lib-macros" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24ba777a231a58d1bce1d68313fa6b6afcc7966adef23d60f45b8a2b9b688bf1" +dependencies = [ + "hax-lib-macros-types", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "hax-lib-macros-types" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "867e19177d7425140b417cd27c2e05320e727ee682e98368f88b7194e80ad515" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "serde_json", + "uuid", +] + [[package]] name = "heck" version = "0.4.1" @@ -1266,19 +2335,49 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + [[package]] name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + [[package]] name = "hmac" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest", + "digest 0.10.7", +] + +[[package]] +name = "home" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" +dependencies = [ + "windows-sys 0.61.0", ] [[package]] @@ -1295,9 +2394,9 @@ dependencies = [ [[package]] name = "http" -version = "1.3.1" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", @@ -1305,34 +2404,101 @@ dependencies = [ ] [[package]] -name = "http-body" -version = "1.0.1" +name = "http" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" dependencies = [ "bytes", - "http", + "fnv", + "itoa", ] [[package]] -name = "http-body-util" +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.3.1", +] + +[[package]] +name = "http-body-util" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http", - "http-body", + "http 1.3.1", + "http-body 1.0.1", "pin-project-lite", ] +[[package]] +name = "http-range-header" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" + [[package]] name = "httparse" version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hybrid-array" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1b229d73f5803b562cc26e4da0396c8610a4ee209f4fac8fa4f8d709166dc45" +dependencies = [ + "typenum", +] + +[[package]] +name = "hyper" +version = "0.14.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http 0.2.12", + "http-body 0.4.6", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.5.10", + "tokio", + "tower-service", + "tracing", + "want", +] + [[package]] name = "hyper" version = "1.7.0" @@ -1343,8 +2509,8 @@ dependencies = [ "bytes", "futures-channel", "futures-core", - "http", - "http-body", + "http 1.3.1", + "http-body 1.0.1", "httparse", "itoa", "pin-project-lite", @@ -1354,6 +2520,52 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-rustls" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "399c78f9338483cb7e630c8474b07268983c6bd5acee012e4211f9f7bb21b070" +dependencies = [ + "futures-util", + "http 0.2.12", + "hyper 0.14.32", + "log", + "rustls 0.22.4", + "rustls-native-certs 0.7.3", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.25.0", + "webpki-roots 0.26.11", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +dependencies = [ + "http 1.3.1", + "hyper 1.7.0", + "hyper-util", + "rustls 0.23.37", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.26.4", + "tower-service", +] + +[[package]] +name = "hyper-timeout" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" +dependencies = [ + "hyper 0.14.32", + "pin-project-lite", + "tokio", + "tokio-io-timeout", +] + [[package]] name = "hyper-util" version = "0.1.16" @@ -1365,9 +2577,9 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "http", - "http-body", - "hyper", + "http 1.3.1", + "http-body 1.0.1", + "hyper 1.7.0", "ipnet", "libc", "percent-encoding", @@ -1390,7 +2602,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core", + "windows-core 0.61.2", ] [[package]] @@ -1404,9 +2616,9 @@ dependencies = [ [[package]] name = "ico" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc50b891e4acf8fe0e71ef88ec43ad82ee07b3810ad09de10f1d01f072ed4b98" +checksum = "3e795dff5605e0f04bff85ca41b51a96b83e80b281e96231bcaaf1ac35103371" dependencies = [ "byteorder", "png", @@ -1557,12 +2769,44 @@ dependencies = [ ] [[package]] -name = "instant" -version = "0.1.13" +name = "inout" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" dependencies = [ - "cfg-if", + "block-padding", + "generic-array 0.14.7", +] + +[[package]] +name = "internal-russh-forked-ssh-key" +version = "0.6.16+upstream-0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe44f2bbd99fcb302e246e2d6bcf51aeda346d02a365f80296a07a8c711b6da6" +dependencies = [ + "argon2", + "bcrypt-pbkdf", + "digest 0.11.1", + "ecdsa", + "ed25519-dalek", + "hex", + "hmac", + "num-bigint-dig", + "p256", + "p384", + "p521", + "rand_core 0.6.4", + "rsa", + "sec1", + "sha1 0.10.6", + "sha1 0.11.0-rc.5", + "sha2 0.10.9", + "signature 2.2.0", + "signature 3.0.0-rc.6", + "ssh-cipher", + "ssh-encoding", + "subtle", + "zeroize", ] [[package]] @@ -1611,6 +2855,15 @@ dependencies = [ "once_cell", ] +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.15" @@ -1662,11 +2915,21 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.3", + "libc", +] + [[package]] name = "js-sys" -version = "0.3.78" +version = "0.3.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0b063578492ceec17683ef2f8c5e89121fbd0b172cbc280635ab7567db2738" +checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" dependencies = [ "once_cell", "wasm-bindgen", @@ -1722,6 +2985,15 @@ name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libappindicator" @@ -1743,7 +3015,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf" dependencies = [ "gtk-sys", - "libloading", + "libloading 0.7.4", "once_cell", ] @@ -1753,6 +3025,72 @@ version = "0.2.175" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" +[[package]] +name = "libcrux-intrinsics" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc9ee7ef66569dd7516454fe26de4e401c0c62073929803486b96744594b9632" +dependencies = [ + "core-models", + "hax-lib", +] + +[[package]] +name = "libcrux-ml-kem" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bb6a88086bf11bd2ec90926c749c4a427f2e59841437dbdede8cde8a96334ab" +dependencies = [ + "hax-lib", + "libcrux-intrinsics", + "libcrux-platform", + "libcrux-secrets", + "libcrux-sha3", + "libcrux-traits", + "rand 0.9.2", + "tls_codec", +] + +[[package]] +name = "libcrux-platform" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db82d058aa76ea315a3b2092f69dfbd67ddb0e462038a206e1dcd73f058c0778" +dependencies = [ + "libc", +] + +[[package]] +name = "libcrux-secrets" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e4dbbf6bc9f2bc0f20dc3bea3e5c99adff3bdccf6d2a40488963da69e2ec307" +dependencies = [ + "hax-lib", +] + +[[package]] +name = "libcrux-sha3" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2400bec764d1c75b8a496d5747cffe32f1fb864a12577f0aca2f55a92021c962" +dependencies = [ + "hax-lib", + "libcrux-intrinsics", + "libcrux-platform", + "libcrux-traits", +] + +[[package]] +name = "libcrux-traits" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9adfd58e79d860f6b9e40e35127bfae9e5bd3ade33201d1347459011a2add034" +dependencies = [ + "libcrux-secrets", + "rand 0.9.2", +] + [[package]] name = "libloading" version = "0.7.4" @@ -1763,6 +3101,22 @@ dependencies = [ "winapi", ] +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link 0.2.0", +] + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + [[package]] name = "libredox" version = "0.1.9" @@ -1771,9 +3125,157 @@ checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3" dependencies = [ "bitflags 2.9.4", "libc", - "redox_syscall 0.5.17", + "redox_syscall", +] + +[[package]] +name = "libsql" +version = "0.9.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2329faffc510cc3c6b4f00169a39177cc7099d3ed7647fc92f7cf26e53a8d976" +dependencies = [ + "anyhow", + "async-stream", + "async-trait", + "base64 0.21.7", + "bincode", + "bitflags 2.9.4", + "bytes", + "chrono", + "crc32fast", + "fallible-iterator 0.3.0", + "futures", + "http 0.2.12", + "hyper 0.14.32", + "hyper-rustls 0.25.0", + "libsql-hrana", + "libsql-sqlite3-parser", + "libsql-sys", + "libsql_replication", + "parking_lot", + "serde", + "serde_json", + "thiserror 1.0.69", + "tokio", + "tokio-stream", + "tokio-util", + "tonic", + "tonic-web", + "tower 0.4.13", + "tower-http 0.4.4", + "tracing", + "uuid", + "zerocopy 0.7.35", +] + +[[package]] +name = "libsql-ffi" +version = "0.9.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cd1c1662822495393327856774f6803be25d85bfdcd5b9d4af35458f5daaf75" +dependencies = [ + "bindgen", + "cc", + "cmake", + "glob", +] + +[[package]] +name = "libsql-hrana" +version = "0.9.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "646d0aa75e412769018422f0da798f72e93bd51964f0b2ddad4317aa779ae444" +dependencies = [ + "base64 0.21.7", + "bytes", + "prost", + "serde", +] + +[[package]] +name = "libsql-rusqlite" +version = "0.9.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a4ce3a78c6e3c2b23b02ab6272df8340e1c53380497979d456882254f348d5f" +dependencies = [ + "bitflags 2.9.4", + "fallible-iterator 0.2.0", + "fallible-streaming-iterator", + "hashlink", + "libsql-ffi", + "smallvec", +] + +[[package]] +name = "libsql-sqlite3-parser" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15a90128c708356af8f7d767c9ac2946692c9112b4f74f07b99a01a60680e413" +dependencies = [ + "bitflags 2.9.4", + "cc", + "fallible-iterator 0.3.0", + "indexmap 2.11.1", + "log", + "memchr", + "phf 0.11.3", + "phf_codegen 0.11.3", + "phf_shared 0.11.3", + "uncased", +] + +[[package]] +name = "libsql-sys" +version = "0.9.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a3c326fcfc36fe7578238d5ee6b58c529f8c76372acd61ec50267529cdaff95" +dependencies = [ + "bytes", + "libsql-ffi", + "libsql-rusqlite", + "once_cell", + "tracing", + "zerocopy 0.7.35", +] + +[[package]] +name = "libsql_replication" +version = "0.9.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d9a2e469ac8400659bd31f81a745908bcc5cb6b40be2f2ff8de90b15bec5501" +dependencies = [ + "aes", + "async-stream", + "async-trait", + "bytes", + "cbc", + "libsql-rusqlite", + "libsql-sys", + "parking_lot", + "prost", + "serde", + "thiserror 1.0.69", + "tokio", + "tokio-stream", + "tokio-util", + "tonic", + "tracing", + "uuid", + "zerocopy 0.7.35", ] +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + [[package]] name = "litemap" version = "0.8.0" @@ -1833,6 +3335,12 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" +[[package]] +name = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + [[package]] name = "md-5" version = "0.10.6" @@ -1840,9 +3348,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ "cfg-if", - "digest", + "digest 0.10.7", ] +[[package]] +name = "md5" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" + [[package]] name = "memchr" version = "2.7.5" @@ -1864,6 +3378,18 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "minisign-verify" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22f9645cb765ea72b8111f36c522475d2daa0d22c957a9826437e97534bc4e9e" + [[package]] name = "miniz_oxide" version = "0.8.9" @@ -1907,12 +3433,49 @@ dependencies = [ ] [[package]] -name = "ndk" -version = "0.9.0" +name = "munge" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" +checksum = "5e17401f259eba956ca16491461b6e8f72913a0a114e39736ce404410f915a0c" dependencies = [ - "bitflags 2.9.4", + "munge_macro", +] + +[[package]] +name = "munge_macro" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4568f25ccbd45ab5d5603dc34318c1ec56b117531781260002151b8530a9f931" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "native-tls" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe 0.1.6", + "openssl-sys", + "schannel", + "security-framework 2.11.1", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "ndk" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" +dependencies = [ + "bitflags 2.9.4", "jni-sys", "log", "ndk-sys", @@ -1942,12 +3505,68 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" +[[package]] +name = "nix" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" +dependencies = [ + "bitflags 2.9.4", + "cfg-if", + "cfg_aliases 0.1.1", + "libc", +] + +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.9.4", + "cfg-if", + "cfg_aliases 0.2.1", + "libc", +] + +[[package]] +name = "nix" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" +dependencies = [ + "bitflags 2.9.4", + "cfg-if", + "cfg_aliases 0.2.1", + "libc", + "memoffset", +] + [[package]] name = "nodrop" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "ntapi" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3b335231dfd352ffb0f8017f3b6027a4917f7df785ea2143d8af2adc66980ae" +dependencies = [ + "winapi", +] + [[package]] name = "nu-ansi-term" version = "0.50.1" @@ -1957,12 +3576,59 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "num-bigint-dig" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" +dependencies = [ + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand 0.8.5", + "serde", + "smallvec", +] + [[package]] name = "num-conv" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -1972,6 +3638,16 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num_cpus" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" +dependencies = [ + "hermit-abi", + "libc", +] + [[package]] name = "num_enum" version = "0.7.4" @@ -1988,7 +3664,7 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" dependencies = [ - "proc-macro-crate 2.0.2", + "proc-macro-crate 3.3.0", "proc-macro2", "quote", "syn 2.0.106", @@ -2028,36 +3704,8 @@ checksum = "e6f29f568bec459b0ddff777cec4fe3fd8666d82d5a40ebd0ff7e66134f89bcc" dependencies = [ "bitflags 2.9.4", "block2 0.6.1", - "libc", "objc2 0.6.2", - "objc2-cloud-kit", - "objc2-core-data", "objc2-core-foundation", - "objc2-core-graphics", - "objc2-core-image", - "objc2-foundation 0.3.1", - "objc2-quartz-core 0.3.1", -] - -[[package]] -name = "objc2-cloud-kit" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17614fdcd9b411e6ff1117dfb1d0150f908ba83a7df81b1f118005fe0a8ea15d" -dependencies = [ - "bitflags 2.9.4", - "objc2 0.6.2", - "objc2-foundation 0.3.1", -] - -[[package]] -name = "objc2-core-data" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291fbbf7d29287518e8686417cf7239c74700fd4b607623140a7d4a3c834329d" -dependencies = [ - "bitflags 2.9.4", - "objc2 0.6.2", "objc2-foundation 0.3.1", ] @@ -2079,20 +3727,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "989c6c68c13021b5c2d6b71456ebb0f9dc78d752e86a98da7c716f4f9470f5a4" dependencies = [ "bitflags 2.9.4", - "dispatch2", - "objc2 0.6.2", "objc2-core-foundation", - "objc2-io-surface", -] - -[[package]] -name = "objc2-core-image" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79b3dc0cc4386b6ccf21c157591b34a7f44c8e75b064f85502901ab2188c007e" -dependencies = [ - "objc2 0.6.2", - "objc2-foundation 0.3.1", ] [[package]] @@ -2136,23 +3771,12 @@ dependencies = [ ] [[package]] -name = "objc2-io-surface" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7282e9ac92529fa3457ce90ebb15f4ecbc383e8338060960760fa2cf75420c3c" -dependencies = [ - "bitflags 2.9.4", - "objc2 0.6.2", - "objc2-core-foundation", -] - -[[package]] -name = "objc2-javascript-core" +name = "objc2-io-kit" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9052cb1bb50a4c161d934befcf879526fb87ae9a68858f241e693ca46225cf5a" +checksum = "71c1c64d6120e51cd86033f67176b1cb66780c2efe34dec55176f77befd93c0a" dependencies = [ - "objc2 0.6.2", + "libc", "objc2-core-foundation", ] @@ -2169,38 +3793,28 @@ dependencies = [ ] [[package]] -name = "objc2-quartz-core" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" -dependencies = [ - "bitflags 2.9.4", - "block2 0.5.1", - "objc2 0.5.2", - "objc2-foundation 0.2.2", - "objc2-metal", -] - -[[package]] -name = "objc2-quartz-core" +name = "objc2-osa-kit" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ffb6a0cd5f182dc964334388560b12a57f7b74b3e2dec5e2722aa2dfb2ccd5" +checksum = "26bb88504b5a050dbba515d2414607bf5e57dd56b107bc5f0351197a3e7bdc5d" dependencies = [ "bitflags 2.9.4", "objc2 0.6.2", + "objc2-app-kit", "objc2-foundation 0.3.1", ] [[package]] -name = "objc2-security" -version = "0.3.1" +name = "objc2-quartz-core" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1f8e0ef3ab66b08c42644dcb34dba6ec0a574bbd8adbb8bdbdc7a2779731a44" +checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ "bitflags 2.9.4", - "objc2 0.6.2", - "objc2-core-foundation", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", + "objc2-metal", ] [[package]] @@ -2227,8 +3841,6 @@ dependencies = [ "objc2-app-kit", "objc2-core-foundation", "objc2-foundation 0.3.1", - "objc2-javascript-core", - "objc2-security", ] [[package]] @@ -2246,6 +3858,12 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + [[package]] name = "open" version = "5.3.2" @@ -2258,12 +3876,72 @@ dependencies = [ "pathdiff", ] +[[package]] +name = "openssl" +version = "0.10.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24ad14dd45412269e1a30f52ad8f0664f0f4f4a89ee8fe28c3b3527021ebb654" +dependencies = [ + "bitflags 2.9.4", + "cfg-if", + "foreign-types 0.3.2", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + +[[package]] +name = "openssl-sys" +version = "0.9.110" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a9f0075ba3c21b09f8e8b2026584b1d18d49388648f2fbbf3c97ea8deced8e2" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "option-ext" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +[[package]] +name = "ordered-stream" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" +dependencies = [ + "futures-core", + "pin-project-lite", +] + [[package]] name = "os_pipe" version = "1.2.2" @@ -2274,6 +3952,77 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "osakit" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "732c71caeaa72c065bb69d7ea08717bd3f4863a4f451402fc9513e29dbd5261b" +dependencies = [ + "objc2 0.6.2", + "objc2-foundation 0.3.1", + "objc2-osa-kit", + "serde", + "serde_json", + "thiserror 2.0.16", +] + +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2 0.10.9", +] + +[[package]] +name = "p384" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2 0.10.9", +] + +[[package]] +name = "p521" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc9e2161f1f215afdfce23677034ae137bbd45016a880c2eb3ba8eb95f085b2" +dependencies = [ + "base16ct 0.2.0", + "ecdsa", + "elliptic-curve", + "primeorder", + "rand_core 0.6.4", + "sha2 0.10.9", +] + +[[package]] +name = "pageant" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b537f975f6d8dcf48db368d7ec209d583b015713b5df0f5d92d2631e4ff5595" +dependencies = [ + "byteorder", + "bytes", + "delegate", + "futures", + "log", + "rand 0.8.5", + "sha2 0.10.9", + "thiserror 1.0.69", + "tokio", + "windows 0.62.1", + "windows-strings 0.5.0", +] + [[package]] name = "pango" version = "0.18.3" @@ -2300,15 +4049,10 @@ dependencies = [ ] [[package]] -name = "parking_lot" -version = "0.11.2" +name = "parking" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.6", -] +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" @@ -2317,42 +4061,79 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" dependencies = [ "lock_api", - "parking_lot_core 0.9.11", + "parking_lot_core", ] [[package]] name = "parking_lot_core" -version = "0.8.6" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", - "instant", "libc", - "redox_syscall 0.2.16", + "redox_syscall", "smallvec", - "winapi", + "windows-targets 0.52.6", ] [[package]] -name = "parking_lot_core" -version = "0.9.11" +name = "password-hash" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" dependencies = [ - "cfg-if", - "libc", - "redox_syscall 0.5.17", - "smallvec", - "windows-targets 0.52.6", + "base64ct", + "rand_core 0.6.4", + "subtle", ] +[[package]] +name = "pastey" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec" + [[package]] name = "pathdiff" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest 0.10.7", + "hmac", +] + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "pem-rfc7468" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6305423e0e7738146434843d1694d621cce767262b2a86910beab705e4493d9" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" version = "2.3.2" @@ -2389,6 +4170,16 @@ dependencies = [ "phf_shared 0.11.3", ] +[[package]] +name = "phf" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" +dependencies = [ + "phf_shared 0.13.1", + "serde", +] + [[package]] name = "phf_codegen" version = "0.8.0" @@ -2491,6 +4282,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" dependencies = [ "siphasher 1.0.1", + "uncased", +] + +[[package]] +name = "phf_shared" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" +dependencies = [ + "siphasher 1.0.1", +] + +[[package]] +name = "pin-project" +version = "1.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", ] [[package]] @@ -2505,6 +4326,64 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "piper" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" +dependencies = [ + "atomic-waker", + "fastrand", + "futures-io", +] + +[[package]] +name = "pkcs1" +version = "0.8.0-rc.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "986d2e952779af96ea048f160fd9194e1751b4faea78bcf3ceb456efe008088e" +dependencies = [ + "der 0.8.0", + "spki 0.8.0-rc.4", +] + +[[package]] +name = "pkcs5" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e847e2c91a18bfa887dd028ec33f2fe6f25db77db3619024764914affe8b69a6" +dependencies = [ + "aes", + "cbc", + "der 0.7.10", + "pbkdf2", + "scrypt", + "sha2 0.10.9", + "spki 0.7.3", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der 0.7.10", + "pkcs5", + "rand_core 0.6.4", + "spki 0.7.3", +] + +[[package]] +name = "pkcs8" +version = "0.11.0-rc.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12922b6296c06eb741b02d7b5161e3aaa22864af38dfa025a1a3ba3f68c84577" +dependencies = [ + "der 0.8.0", + "spki 0.8.0-rc.4", +] + [[package]] name = "pkg-config" version = "0.3.32" @@ -2537,32 +4416,102 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "polling" +version = "3.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5bd19146350fe804f7cb2669c851c03d69da628803dab0d98018142aaa5d829" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi", + "pin-project-lite", + "rustix 1.1.2", + "windows-sys 0.60.2", +] + +[[package]] +name = "poly1305" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" +dependencies = [ + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "portable-pty" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4a596a2b3d2752d94f51fac2d4a96737b8705dddd311a32b9af47211f08671e" +dependencies = [ + "anyhow", + "bitflags 1.3.2", + "downcast-rs", + "filedescriptor", + "lazy_static", + "libc", + "log", + "nix 0.28.0", + "serial2", + "shared_library", + "shell-words", + "winapi", + "winreg 0.10.1", +] + +[[package]] +name = "postgres-native-tls" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac73153d92e4bde922bd6f1dfba7f1ab8132266c031153b55e20a1521cd36d49" +dependencies = [ + "native-tls", + "tokio", + "tokio-native-tls", + "tokio-postgres", +] + [[package]] name = "postgres-protocol" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76ff0abab4a9b844b93ef7b81f1efc0a366062aaef2cd702c76256b5dc075c54" +checksum = "fbef655056b916eb868048276cfd5d6a7dea4f81560dfd047f97c8c6fe3fcfd4" dependencies = [ "base64 0.22.1", "byteorder", "bytes", - "fallible-iterator", + "fallible-iterator 0.2.0", "hmac", "md-5", "memchr", "rand 0.9.2", - "sha2", + "sha2 0.10.9", "stringprep", ] [[package]] name = "postgres-types" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613283563cd90e1dfc3518d548caee47e0e725455ed619881f5cf21f36de4b48" +checksum = "ef4605b7c057056dd35baeb6ac0c0338e4975b1f2bef0f65da953285eb007095" dependencies = [ "bytes", - "fallible-iterator", + "fallible-iterator 0.2.0", "postgres-protocol", ] @@ -2587,7 +4536,7 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "zerocopy", + "zerocopy 0.8.27", ] [[package]] @@ -2596,6 +4545,25 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.106", +] + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + [[package]] name = "proc-macro-crate" version = "1.3.1" @@ -2608,12 +4576,20 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "2.0.2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" +checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" dependencies = [ - "toml_datetime 0.6.3", - "toml_edit 0.20.2", + "toml_edit 0.20.7", +] + +[[package]] +name = "proc-macro-crate" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" +dependencies = [ + "toml_edit 0.22.27", ] [[package]] @@ -2640,6 +4616,28 @@ dependencies = [ "version_check", ] +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.106", +] + [[package]] name = "proc-macro-hack" version = "0.5.20+deprecated" @@ -2656,8 +4654,42 @@ dependencies = [ ] [[package]] -name = "proc-macros" -version = "1.0.0" +name = "prost" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-derive" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "ptr_meta" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9a0cf95a1196af61d4f1cbdab967179516d9a4a4312af1f31948f8f6224a79" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7347867d0a7e1208d93b46767be83e2b8f978c3dad35f775ac8d8847551d6fe1" dependencies = [ "proc-macro2", "quote", @@ -2688,6 +4720,15 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "rancor" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a063ea72381527c2a0561da9c80000ef822bdd7c3241b1cc1b12100e3df081ee" +dependencies = [ + "ptr_meta", +] + [[package]] name = "rand" version = "0.7.3" @@ -2780,6 +4821,12 @@ dependencies = [ "getrandom 0.3.3", ] +[[package]] +name = "rand_core" +version = "0.10.0-rc-3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f66ee92bc15280519ef199a274fe0cafff4245d31bc39aaa31c011ad56cb1f05" + [[package]] name = "rand_hc" version = "0.2.0" @@ -2805,12 +4852,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" [[package]] -name = "redox_syscall" -version = "0.2.16" +name = "rayon" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" dependencies = [ - "bitflags 1.3.2", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", ] [[package]] @@ -2859,77 +4917,478 @@ version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" + +[[package]] +name = "rend" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cadadef317c2f20755a64d7fdc48f9e7178ee6b0e1f7fce33fa60f1d68a276e6" + +[[package]] +name = "reqwest" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-core", + "futures-util", + "http 1.3.1", + "http-body 1.0.1", + "http-body-util", + "hyper 1.7.0", + "hyper-rustls 0.27.7", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "rustls 0.23.37", + "rustls-pki-types", + "rustls-platform-verifier", + "serde", + "serde_json", + "sync_wrapper 1.0.2", + "tokio", + "tokio-rustls 0.26.4", + "tokio-util", + "tower 0.5.2", + "tower-http 0.6.8", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "rfd" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15ad77d9e70a92437d8f74c35d99b4e4691128df018833e99f90bcd36152672" +dependencies = [ + "block2 0.6.1", + "dispatch2", + "glib-sys", + "gobject-sys", + "gtk-sys", + "js-sys", + "log", + "objc2 0.6.2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation 0.3.1", + "raw-window-handle", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-sys 0.60.2", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.16", + "libc", + "untrusted 0.9.0", + "windows-sys 0.52.0", +] + +[[package]] +name = "rkyv" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a30e631b7f4a03dee9056b8ef6982e8ba371dd5bedb74d3ec86df4499132c70" +dependencies = [ + "bytes", + "hashbrown 0.16.1", + "indexmap 2.11.1", + "munge", + "ptr_meta", + "rancor", + "rend", + "rkyv_derive", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8100bb34c0a1d0f907143db3149e6b4eea3c33b9ee8b189720168e818303986f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "rsa" +version = "0.10.0-rc.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9a2b1eacbc34fbaf77f6f1db1385518446008d49b9f9f59dc9d1340fce4ca9e" +dependencies = [ + "const-oid 0.10.2", + "crypto-bigint 0.7.0-rc.18", + "crypto-primes", + "digest 0.11.1", + "pkcs1", + "pkcs8 0.11.0-rc.11", + "rand_core 0.10.0-rc-3", + "sha2 0.11.0-rc.5", + "signature 3.0.0-rc.6", + "spki 0.8.0-rc.4", + "zeroize", +] + +[[package]] +name = "rsql" +version = "1.1.5" +dependencies = [ + "csv", + "deadpool-postgres", + "futures-util", + "libsql", + "native-tls", + "portable-pty", + "postgres-native-tls", + "rayon", + "rsql-core", + "russh", + "serde", + "serde_json", + "sonic-rs", + "sysinfo", + "tauri", + "tauri-build", + "tauri-plugin-dialog", + "tauri-plugin-fs", + "tauri-plugin-opener", + "tauri-plugin-process", + "tauri-plugin-shell", + "tauri-plugin-updater", + "thiserror 2.0.16", + "tokio", + "tokio-postgres", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "rsql-core" +version = "1.1.5" +dependencies = [ + "csv", + "deadpool-postgres", + "futures-util", + "libsql", + "native-tls", + "portable-pty", + "postgres-native-tls", + "rayon", + "russh", + "serde", + "serde_json", + "sonic-rs", + "sysinfo", + "thiserror 2.0.16", + "tokio", + "tokio-postgres", + "tracing", +] + +[[package]] +name = "russh" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afe62631a04a1f4d71a14b99505483b95ff97c503b67d876c042fce659186956" +dependencies = [ + "aes", + "aws-lc-rs", + "bitflags 2.9.4", + "block-padding", + "byteorder", + "bytes", + "cbc", + "ctr", + "curve25519-dalek", + "data-encoding", + "delegate", + "der 0.7.10", + "digest 0.10.7", + "ecdsa", + "ed25519-dalek", + "elliptic-curve", + "enum_dispatch", + "flate2", + "futures", + "generic-array 1.3.5", + "getrandom 0.2.16", + "hex-literal", + "hmac", + "home", + "inout", + "internal-russh-forked-ssh-key", + "libcrux-ml-kem", + "log", + "md5", + "num-bigint", + "p256", + "p384", + "p521", + "pageant", + "pbkdf2", + "pkcs1", + "pkcs5", + "pkcs8 0.10.2", + "rand 0.9.2", + "rand_core 0.10.0-rc-3", + "rsa", + "russh-cryptovec", + "russh-util", + "sec1", + "sha1 0.10.6", + "sha2 0.10.9", + "signature 2.2.0", + "spki 0.7.3", + "ssh-encoding", + "subtle", + "thiserror 1.0.69", + "tokio", + "typenum", + "zeroize", +] + +[[package]] +name = "russh-cryptovec" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb0ed583ff0f6b4aa44c7867dd7108df01b30571ee9423e250b4cc939f8c6cf" +dependencies = [ + "libc", + "log", + "nix 0.29.0", + "ssh-encoding", + "winapi", +] + +[[package]] +name = "russh-util" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "668424a5dde0bcb45b55ba7de8476b93831b4aa2fa6947e145f3b053e22c60b6" +dependencies = [ + "chrono", + "tokio", + "wasm-bindgen", + "wasm-bindgen-futures", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags 2.9.4", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustix" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +dependencies = [ + "bitflags 2.9.4", + "errno", + "libc", + "linux-raw-sys 0.11.0", + "windows-sys 0.61.0", +] + +[[package]] +name = "rustls" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" +dependencies = [ + "log", + "ring", + "rustls-pki-types", + "rustls-webpki 0.102.8", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls" +version = "0.23.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki 0.103.9", + "subtle", + "zeroize", +] + +[[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", + "rustls-pki-types", + "schannel", + "security-framework 2.11.1", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +dependencies = [ + "openssl-probe 0.2.1", + "rustls-pki-types", + "schannel", + "security-framework 3.5.1", ] [[package]] -name = "regex-automata" -version = "0.4.10" +name = "rustls-pemfile" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", + "rustls-pki-types", ] [[package]] -name = "regex-syntax" -version = "0.8.6" +name = "rustls-pki-types" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +dependencies = [ + "zeroize", +] [[package]] -name = "reqwest" -version = "0.12.23" +name = "rustls-platform-verifier" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d429f34c8092b2d42c7c93cec323bb4adeb7c67698f70839adec842ec10c7ceb" +checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" dependencies = [ - "base64 0.22.1", - "bytes", - "futures-core", - "futures-util", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-util", - "js-sys", + "core-foundation 0.10.1", + "core-foundation-sys", + "jni", "log", - "percent-encoding", - "pin-project-lite", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "tokio", - "tokio-util", - "tower", - "tower-http", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-streams", - "web-sys", + "once_cell", + "rustls 0.23.37", + "rustls-native-certs 0.8.3", + "rustls-platform-verifier-android", + "rustls-webpki 0.103.9", + "security-framework 3.5.1", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.61.0", ] [[package]] -name = "rustc-demangle" -version = "0.1.26" +name = "rustls-platform-verifier-android" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] -name = "rustc_version" -version = "0.4.1" +name = "rustls-webpki" +version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ - "semver", + "ring", + "rustls-pki-types", + "untrusted 0.9.0", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted 0.9.0", ] [[package]] @@ -2940,9 +5399,18 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" -version = "1.0.20" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "salsa20" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher", +] [[package]] name = "same-file" @@ -2953,6 +5421,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +dependencies = [ + "windows-sys 0.61.0", +] + [[package]] name = "schemars" version = "0.8.22" @@ -3010,6 +5487,67 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "scrypt" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f" +dependencies = [ + "pbkdf2", + "salsa20", + "sha2 0.10.9", +] + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct 0.2.0", + "der 0.7.10", + "generic-array 0.14.7", + "pkcs8 0.10.2", + "subtle", + "zeroize", +] + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.9.4", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework" +version = "3.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" +dependencies = [ + "bitflags 2.9.4", + "core-foundation 0.10.1", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "selectors" version = "0.24.0" @@ -3039,10 +5577,11 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ + "serde_core", "serde_derive", ] @@ -3057,11 +5596,20 @@ dependencies = [ "typeid", ] +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -3081,14 +5629,15 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.143" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", "memchr", - "ryu", "serde", + "serde_core", + "zmij", ] [[package]] @@ -3120,18 +5669,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - [[package]] name = "serde_with" version = "3.14.0" @@ -3164,6 +5701,27 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "serdect" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9af4a3e75ebd5599b30d4de5768e00b5095d518a79fefc3ecbaf77e665d1ec06" +dependencies = [ + "base16ct 1.0.0", + "serde", +] + +[[package]] +name = "serial2" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1401f562d358cdfdbdf8946e51a7871ede1db68bd0fd99bedc79e400241550" +dependencies = [ + "cfg-if", + "libc", + "winapi", +] + [[package]] name = "serialize-to-javascript" version = "0.1.2" @@ -3196,6 +5754,28 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha1" +version = "0.11.0-rc.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b167252f3c126be0d8926639c4c4706950f01445900c4b3db0fd7e89fcb750a" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.11.1", +] + [[package]] name = "sha2" version = "0.10.9" @@ -3204,7 +5784,18 @@ checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", - "digest", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.11.0-rc.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c5f3b1e2dc8aad28310d8410bd4d7e180eca65fca176c52ab00d364475d0024" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.11.1", ] [[package]] @@ -3227,6 +5818,22 @@ dependencies = [ "windows-sys 0.60.2", ] +[[package]] +name = "shared_library" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a9e7e0f2bfae24d8a5b5a66c5b257a83c7412304311512a0c054cd5e619da11" +dependencies = [ + "lazy_static", + "libc", +] + +[[package]] +name = "shell-words" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc6fe69c597f9c37bfeeeeeb33da3530379845f10be461a66d16d03eca2ded77" + [[package]] name = "shlex" version = "1.3.0" @@ -3263,12 +5870,38 @@ dependencies = [ "libc", ] +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + +[[package]] +name = "signature" +version = "3.0.0-rc.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a96996ccff7dfa16f052bd995b4cecc72af22c35138738dc029f0ead6608d" +dependencies = [ + "digest 0.11.1", + "rand_core 0.10.0-rc-3", +] + [[package]] name = "simd-adler32" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + [[package]] name = "siphasher" version = "0.3.11" @@ -3287,22 +5920,6 @@ version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" -[[package]] -name = "sled" -version = "0.34.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f96b4737c2ce5987354855aed3797279def4ebf734436c6aa4552cf8e169935" -dependencies = [ - "crc32fast", - "crossbeam-epoch", - "crossbeam-utils", - "fs2", - "fxhash", - "libc", - "log", - "parking_lot 0.11.2", -] - [[package]] name = "smallvec" version = "1.15.1" @@ -3336,45 +5953,139 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18051cdd562e792cad055119e0cdb2cfc137e44e3987532e0f9659a77931bb08" dependencies = [ "bytemuck", - "cfg_aliases", - "core-graphics", - "foreign-types", + "cfg_aliases 0.2.1", + "core-graphics 0.24.0", + "foreign-types 0.5.0", "js-sys", "log", "objc2 0.5.2", "objc2-foundation 0.2.2", - "objc2-quartz-core 0.2.2", + "objc2-quartz-core", "raw-window-handle", - "redox_syscall 0.5.17", + "redox_syscall", "wasm-bindgen", "web-sys", "windows-sys 0.59.0", ] [[package]] -name = "soup3" -version = "0.5.0" +name = "sonic-number" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5661364b38abad49cf1ade6631fcc35d2ccf882a7d68616b4228b7717feb5fba" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "sonic-rs" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e16b39f36452a4fa6f14a481b02e9ba5c6842c6a44d0545da967eca122f2eed9" +dependencies = [ + "ahash", + "bumpalo", + "bytes", + "cfg-if", + "faststr", + "itoa", + "ref-cast", + "serde", + "simdutf8", + "sonic-number", + "sonic-simd", + "thiserror 2.0.16", + "zmij", +] + +[[package]] +name = "sonic-simd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9f944718c33623919878cf74b4c9361eb3024f635733922b26722b14cd3f8cc" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "soup3" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "471f924a40f31251afc77450e781cb26d55c0b650842efafc9c6cbd2f7cc4f9f" +dependencies = [ + "futures-channel", + "gio", + "glib", + "libc", + "soup3-sys", +] + +[[package]] +name = "soup3-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebe8950a680a12f24f15ebe1bf70db7af98ad242d9db43596ad3108aab86c27" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der 0.7.10", +] + +[[package]] +name = "spki" +version = "0.8.0-rc.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8baeff88f34ed0691978ec34440140e1572b68c7dd4a495fd14a3dc1944daa80" +dependencies = [ + "base64ct", + "der 0.8.0", +] + +[[package]] +name = "ssh-cipher" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "471f924a40f31251afc77450e781cb26d55c0b650842efafc9c6cbd2f7cc4f9f" +checksum = "caac132742f0d33c3af65bfcde7f6aa8f62f0e991d80db99149eb9d44708784f" dependencies = [ - "futures-channel", - "gio", - "glib", - "libc", - "soup3-sys", + "aes", + "aes-gcm", + "cbc", + "chacha20", + "cipher", + "ctr", + "poly1305", + "ssh-encoding", + "subtle", ] [[package]] -name = "soup3-sys" -version = "0.5.0" +name = "ssh-encoding" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ebe8950a680a12f24f15ebe1bf70db7af98ad242d9db43596ad3108aab86c27" +checksum = "eb9242b9ef4108a78e8cd1a2c98e193ef372437f8c22be363075233321dd4a15" dependencies = [ - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "system-deps", + "base64ct", + "bytes", + "pem-rfc7468 0.7.0", + "sha2 0.10.9", ] [[package]] @@ -3383,6 +6094,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "string_cache" version = "0.8.9" @@ -3390,7 +6107,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" dependencies = [ "new_debug_unreachable", - "parking_lot 0.12.4", + "parking_lot", "phf_shared 0.11.3", "precomputed-hash", "serde", @@ -3464,6 +6181,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + [[package]] name = "sync_wrapper" version = "1.0.2" @@ -3484,6 +6207,20 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "sysinfo" +version = "0.38.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d03c61d2a49c649a15c407338afe7accafde9dac869995dccb73e5f7ef7d9034" +dependencies = [ + "libc", + "memchr", + "ntapi", + "objc2-core-foundation", + "objc2-io-kit", + "windows 0.62.1", +] + [[package]] name = "system-deps" version = "6.2.2" @@ -3493,29 +6230,28 @@ dependencies = [ "cfg-expr", "heck 0.5.0", "pkg-config", - "toml 0.8.2", + "toml 0.8.23", "version-compare", ] [[package]] name = "tao" -version = "0.34.3" +version = "0.34.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "959469667dbcea91e5485fc48ba7dd6023face91bb0f1a14681a70f99847c3f7" +checksum = "6e06d52c379e63da659a483a958110bbde891695a0ecb53e48cc7786d5eda7bb" dependencies = [ "bitflags 2.9.4", "block2 0.6.1", - "core-foundation", - "core-graphics", + "core-foundation 0.10.1", + "core-graphics 0.25.0", "crossbeam-channel", - "dispatch", + "dispatch2", "dlopen2", "dpi", "gdkwayland-sys", "gdkx11-sys", "gtk", "jni", - "lazy_static", "libc", "log", "ndk", @@ -3525,14 +6261,13 @@ dependencies = [ "objc2-app-kit", "objc2-foundation 0.3.1", "once_cell", - "parking_lot 0.12.4", + "parking_lot", "raw-window-handle", - "scopeguard", "tao-macros", "unicode-segmentation", "url", - "windows", - "windows-core", + "windows 0.61.3", + "windows-core 0.61.2", "windows-version", "x11-dl", ] @@ -3548,6 +6283,17 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "tar" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" +dependencies = [ + "filetime", + "libc", + "xattr", +] + [[package]] name = "target-lexicon" version = "0.12.16" @@ -3556,9 +6302,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tauri" -version = "2.8.5" +version = "2.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d1d3b3dc4c101ac989fd7db77e045cc6d91a25349cd410455cb5c57d510c1c" +checksum = "da77cc00fb9028caf5b5d4650f75e31f1ef3693459dfca7f7e506d1ecef0ba2d" dependencies = [ "anyhow", "bytes", @@ -3570,7 +6316,7 @@ dependencies = [ "glob", "gtk", "heck 0.5.0", - "http", + "http 1.3.1", "jni", "libc", "log", @@ -3599,18 +6345,17 @@ dependencies = [ "tokio", "tray-icon", "url", - "urlpattern", "webkit2gtk", "webview2-com", "window-vibrancy", - "windows", + "windows 0.61.3", ] [[package]] name = "tauri-build" -version = "2.4.1" +version = "2.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c432ccc9ff661803dab74c6cd78de11026a578a9307610bbc39d3c55be7943f" +checksum = "4bbc990d1dbf57a8e1c7fa2327f2a614d8b757805603c1b9ba5c81bade09fd4d" dependencies = [ "anyhow", "cargo_toml", @@ -3630,9 +6375,9 @@ dependencies = [ [[package]] name = "tauri-codegen" -version = "2.4.0" +version = "2.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ab3a62cf2e6253936a8b267c2e95839674e7439f104fa96ad0025e149d54d8a" +checksum = "d4a24476afd977c5d5d169f72425868613d82747916dd29e0a357c84c4bd6d29" dependencies = [ "base64 0.22.1", "brotli", @@ -3645,7 +6390,7 @@ dependencies = [ "semver", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "syn 2.0.106", "tauri-utils", "thiserror 2.0.16", @@ -3657,9 +6402,9 @@ dependencies = [ [[package]] name = "tauri-macros" -version = "2.4.0" +version = "2.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4368ea8094e7045217edb690f493b55b30caf9f3e61f79b4c24b6db91f07995e" +checksum = "d39b349a98dadaffebb73f0a40dcd1f23c999211e5a2e744403db384d0c33de7" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -3671,9 +6416,9 @@ dependencies = [ [[package]] name = "tauri-plugin" -version = "2.4.0" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9946a3cede302eac0c6eb6c6070ac47b1768e326092d32efbb91f21ed58d978f" +checksum = "ddde7d51c907b940fb573006cdda9a642d6a7c8153657e88f8a5c3c9290cd4aa" dependencies = [ "anyhow", "glob", @@ -3686,11 +6431,29 @@ dependencies = [ "walkdir", ] +[[package]] +name = "tauri-plugin-dialog" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9204b425d9be8d12aa60c2a83a289cf7d1caae40f57f336ed1155b3a5c0e359b" +dependencies = [ + "log", + "raw-window-handle", + "rfd", + "serde", + "serde_json", + "tauri", + "tauri-plugin", + "tauri-plugin-fs", + "thiserror 2.0.16", + "url", +] + [[package]] name = "tauri-plugin-fs" -version = "2.4.2" +version = "2.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "315784ec4be45e90a987687bae7235e6be3d6e9e350d2b75c16b8a4bf22c1db7" +checksum = "ed390cc669f937afeb8b28032ce837bac8ea023d975a2e207375ec05afaf1804" dependencies = [ "anyhow", "dunce", @@ -3708,6 +6471,38 @@ dependencies = [ "url", ] +[[package]] +name = "tauri-plugin-opener" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "786156aa8e89e03d271fbd3fe642207da8e65f3c961baa9e2930f332bf80a1f5" +dependencies = [ + "dunce", + "glob", + "objc2-app-kit", + "objc2-foundation 0.3.1", + "open", + "schemars 0.8.22", + "serde", + "serde_json", + "tauri", + "tauri-plugin", + "thiserror 2.0.16", + "url", + "windows 0.61.3", + "zbus", +] + +[[package]] +name = "tauri-plugin-process" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d55511a7bf6cd70c8767b02c97bf8134fa434daf3926cfc1be0a0f94132d165a" +dependencies = [ + "tauri", + "tauri-plugin", +] + [[package]] name = "tauri-plugin-shell" version = "2.3.1" @@ -3729,16 +6524,49 @@ dependencies = [ "tokio", ] +[[package]] +name = "tauri-plugin-updater" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fe8e9bebd88fc222938ffdfbdcfa0307081423bd01e3252fc337d8bde81fc61" +dependencies = [ + "base64 0.22.1", + "dirs", + "flate2", + "futures-util", + "http 1.3.1", + "infer", + "log", + "minisign-verify", + "osakit", + "percent-encoding", + "reqwest", + "rustls 0.23.37", + "semver", + "serde", + "serde_json", + "tar", + "tauri", + "tauri-plugin", + "tempfile", + "thiserror 2.0.16", + "time", + "tokio", + "url", + "windows-sys 0.60.2", + "zip", +] + [[package]] name = "tauri-runtime" -version = "2.8.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4cfc9ad45b487d3fded5a4731a567872a4812e9552e3964161b08edabf93846" +checksum = "2826d79a3297ed08cd6ea7f412644ef58e32969504bc4fbd8d7dbeabc4445ea2" dependencies = [ "cookie", "dpi", "gtk", - "http", + "http 1.3.1", "jni", "objc2 0.6.2", "objc2-ui-kit", @@ -3751,22 +6579,21 @@ dependencies = [ "url", "webkit2gtk", "webview2-com", - "windows", + "windows 0.61.3", ] [[package]] name = "tauri-runtime-wry" -version = "2.8.1" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1fe9d48bd122ff002064e88cfcd7027090d789c4302714e68fcccba0f4b7807" +checksum = "e11ea2e6f801d275fdd890d6c9603736012742a1c33b96d0db788c9cdebf7f9e" dependencies = [ "gtk", - "http", + "http 1.3.1", "jni", "log", "objc2 0.6.2", "objc2-app-kit", - "objc2-foundation 0.3.1", "once_cell", "percent-encoding", "raw-window-handle", @@ -3777,15 +6604,15 @@ dependencies = [ "url", "webkit2gtk", "webview2-com", - "windows", + "windows 0.61.3", "wry", ] [[package]] name = "tauri-utils" -version = "2.7.0" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41a3852fdf9a4f8fbeaa63dc3e9a85284dd6ef7200751f0bd66ceee30c93f212" +checksum = "219a1f983a2af3653f75b5747f76733b0da7ff03069c7a41901a5eb3ace4557d" dependencies = [ "anyhow", "brotli", @@ -3794,7 +6621,7 @@ dependencies = [ "dunce", "glob", "html5ever", - "http", + "http 1.3.1", "infer", "json-patch", "kuchikiki", @@ -3829,6 +6656,19 @@ dependencies = [ "toml 0.9.5", ] +[[package]] +name = "tempfile" +version = "3.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84fa4d11fadde498443cca10fd3ac23c951f0dc59e080e9f4b93d4df4e4eea53" +dependencies = [ + "fastrand", + "getrandom 0.3.3", + "once_cell", + "rustix 1.1.2", + "windows-sys 0.61.0", +] + [[package]] name = "tendril" version = "0.4.3" @@ -3944,6 +6784,27 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +[[package]] +name = "tls_codec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de2e01245e2bb89d6f05801c564fa27624dbd7b1846859876c7dad82e90bf6b" +dependencies = [ + "tls_codec_derive", + "zeroize", +] + +[[package]] +name = "tls_codec_derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d2e76690929402faae40aebdda620a2c0e25dd6d3b9afe48867dfd95991f4bd" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + [[package]] name = "tokio" version = "1.47.1" @@ -3955,38 +6816,104 @@ dependencies = [ "io-uring", "libc", "mio", + "parking_lot", "pin-project-lite", + "signal-hook-registry", "slab", "socket2 0.6.0", + "tokio-macros", "windows-sys 0.59.0", ] +[[package]] +name = "tokio-io-timeout" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bd86198d9ee903fedd2f9a2e72014287c0d9167e4ae43b5853007205dda1b76" +dependencies = [ + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-macros" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + [[package]] name = "tokio-postgres" -version = "0.7.13" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c95d533c83082bb6490e0189acaa0bbeef9084e60471b696ca6988cd0541fb0" +checksum = "2b40d66d9b2cfe04b628173409368e58247e8eddbbd3b0e6c6ba1d09f20f6c9e" dependencies = [ "async-trait", "byteorder", "bytes", - "fallible-iterator", + "fallible-iterator 0.2.0", "futures-channel", "futures-util", "log", - "parking_lot 0.12.4", + "parking_lot", "percent-encoding", - "phf 0.11.3", + "phf 0.13.1", "pin-project-lite", "postgres-protocol", "postgres-types", "rand 0.9.2", - "socket2 0.5.10", + "socket2 0.6.0", "tokio", "tokio-util", "whoami", ] +[[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.37", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + [[package]] name = "tokio-util" version = "0.7.16" @@ -4002,14 +6929,14 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.2" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", "serde_spanned 0.6.9", - "toml_datetime 0.6.3", - "toml_edit 0.20.2", + "toml_datetime 0.6.11", + "toml_edit 0.22.27", ] [[package]] @@ -4029,9 +6956,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.3" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" dependencies = [ "serde", ] @@ -4052,21 +6979,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ "indexmap 2.11.1", - "toml_datetime 0.6.3", + "toml_datetime 0.6.11", "winnow 0.5.40", ] [[package]] name = "toml_edit" -version = "0.20.2" +version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" +dependencies = [ + "indexmap 2.11.1", + "toml_datetime 0.6.11", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap 2.11.1", "serde", "serde_spanned 0.6.9", - "toml_datetime 0.6.3", - "winnow 0.5.40", + "toml_datetime 0.6.11", + "winnow 0.7.13", ] [[package]] @@ -4084,35 +7022,122 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64" +[[package]] +name = "tonic" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76c4eb7a4e9ef9d4763600161f12f5070b92a578e1b634db88a6887844c91a13" +dependencies = [ + "async-stream", + "async-trait", + "axum", + "base64 0.21.7", + "bytes", + "h2", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.32", + "hyper-timeout", + "percent-encoding", + "pin-project", + "prost", + "tokio", + "tokio-stream", + "tower 0.4.13", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tonic-web" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc3b0e1cedbf19fdfb78ef3d672cb9928e0a91a9cb4629cc0c916e8cff8aaaa1" +dependencies = [ + "base64 0.21.7", + "bytes", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.32", + "pin-project", + "tokio-stream", + "tonic", + "tower-http 0.4.4", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "indexmap 1.9.3", + "pin-project", + "pin-project-lite", + "rand 0.8.5", + "slab", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "tower" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 1.0.2", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" dependencies = [ + "bitflags 2.9.4", + "bytes", "futures-core", "futures-util", + "http 0.2.12", + "http-body 0.4.6", + "http-range-header", "pin-project-lite", - "sync_wrapper", - "tokio", + "tower 0.4.13", "tower-layer", "tower-service", + "tracing", ] [[package]] name = "tower-http" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ "bitflags 2.9.4", "bytes", "futures-util", - "http", - "http-body", + "http 1.3.1", + "http-body 1.0.1", "iri-string", "pin-project-lite", - "tower", + "tower 0.5.2", "tower-layer", "tower-service", ] @@ -4135,6 +7160,7 @@ version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -4222,9 +7248,29 @@ checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" [[package]] name = "typenum" -version = "1.18.0" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "uds_windows" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9" +dependencies = [ + "memoffset", + "tempfile", + "winapi", +] + +[[package]] +name = "uncased" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +checksum = "e1b88fcfe09e89d3866a5c11019378088af2d24c3fbd4f0543f96b479ec90697" +dependencies = [ + "version_check", +] [[package]] name = "unic-char-property" @@ -4300,6 +7346,28 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common 0.1.6", + "subtle", +] + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" version = "2.5.7" @@ -4354,6 +7422,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version-compare" version = "0.2.0" @@ -4443,9 +7517,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.101" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e14915cadd45b529bb8d1f343c4ed0ac1de926144b746e2710f9cd05df6603b" +checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" dependencies = [ "cfg-if", "once_cell", @@ -4454,27 +7528,14 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.101" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28d1ba982ca7923fd01448d5c30c6864d0a14109560296a162f80f305fb93bb" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.106", - "wasm-bindgen-shared", -] - [[package]] name = "wasm-bindgen-futures" -version = "0.4.51" +version = "0.4.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca85039a9b469b38336411d6d6ced91f3fc87109a2a27b0c197663f5144dffe" +checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8" dependencies = [ "cfg-if", + "futures-util", "js-sys", "once_cell", "wasm-bindgen", @@ -4483,9 +7544,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.101" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c3d463ae3eff775b0c45df9da45d68837702ac35af998361e2c84e7c5ec1b0d" +checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4493,31 +7554,31 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.101" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bb4ce89b08211f923caf51d527662b75bdc9c9c7aab40f86dcb9fb85ac552aa" +checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" dependencies = [ + "bumpalo", "proc-macro2", "quote", "syn 2.0.106", - "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.101" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f143854a3b13752c6950862c906306adb27c7e839f7414cec8fea35beab624c1" +checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" dependencies = [ "unicode-ident", ] [[package]] name = "wasm-streams" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" +checksum = "9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb" dependencies = [ "futures-util", "js-sys", @@ -4528,9 +7589,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.78" +version = "0.3.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77e4b637749ff0d92b8fad63aa1f7cff3cbe125fd49c175cd6345e7272638b12" +checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9" dependencies = [ "js-sys", "wasm-bindgen", @@ -4538,9 +7599,9 @@ dependencies = [ [[package]] name = "webkit2gtk" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76b1bc1e54c581da1e9f179d0b38512ba358fb1af2d634a1affe42e37172361a" +checksum = "a1027150013530fb2eaf806408df88461ae4815a45c541c8975e61d6f2fc4793" dependencies = [ "bitflags 1.3.2", "cairo-rs", @@ -4562,9 +7623,9 @@ dependencies = [ [[package]] name = "webkit2gtk-sys" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62daa38afc514d1f8f12b8693d30d5993ff77ced33ce30cd04deebc267a6d57c" +checksum = "916a5f65c2ef0dfe12fff695960a2ec3d4565359fdbb2e9943c974e06c734ea5" dependencies = [ "bitflags 1.3.2", "cairo-sys-rs", @@ -4580,6 +7641,33 @@ dependencies = [ "system-deps", ] +[[package]] +name = "webpki-root-certs" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "804f18a4ac2676ffb4e8b5b5fa9ae38af06df08162314f96a68d2a363e21a8ca" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "webpki-roots" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.6", +] + +[[package]] +name = "webpki-roots" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "webview2-com" version = "0.38.0" @@ -4588,8 +7676,8 @@ checksum = "d4ba622a989277ef3886dd5afb3e280e3dd6d974b766118950a08f8f678ad6a4" dependencies = [ "webview2-com-macros", "webview2-com-sys", - "windows", - "windows-core", + "windows 0.61.3", + "windows-core 0.61.2", "windows-implement", "windows-interface", ] @@ -4612,8 +7700,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "36695906a1b53a3bf5c4289621efedac12b73eeb0b89e7e1a89b517302d5d75c" dependencies = [ "thiserror 2.0.16", - "windows", - "windows-core", + "windows 0.61.3", + "windows-core 0.61.2", +] + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix 0.38.44", ] [[package]] @@ -4679,11 +7779,23 @@ version = "0.61.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" dependencies = [ - "windows-collections", - "windows-core", - "windows-future", + "windows-collections 0.2.0", + "windows-core 0.61.2", + "windows-future 0.2.1", "windows-link 0.1.3", - "windows-numerics", + "windows-numerics 0.2.0", +] + +[[package]] +name = "windows" +version = "0.62.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49e6c4a1f363c8210c6f77ba24f645c61c6fb941eccf013da691f7e09515b8ac" +dependencies = [ + "windows-collections 0.3.1", + "windows-core 0.62.1", + "windows-future 0.3.1", + "windows-numerics 0.3.0", ] [[package]] @@ -4692,7 +7804,16 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" dependencies = [ - "windows-core", + "windows-core 0.61.2", +] + +[[package]] +name = "windows-collections" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "123e712f464a8a60ce1a13f4c446d2d43ab06464cb5842ff68f5c71b6fb7852e" +dependencies = [ + "windows-core 0.62.1", ] [[package]] @@ -4704,8 +7825,21 @@ dependencies = [ "windows-implement", "windows-interface", "windows-link 0.1.3", - "windows-result", - "windows-strings", + "windows-result 0.3.4", + "windows-strings 0.4.2", +] + +[[package]] +name = "windows-core" +version = "0.62.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6844ee5416b285084d3d3fffd743b925a6c9385455f64f6d4fa3031c4c2749a9" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.2.0", + "windows-result 0.4.0", + "windows-strings 0.5.0", ] [[package]] @@ -4714,16 +7848,27 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" dependencies = [ - "windows-core", + "windows-core 0.61.2", "windows-link 0.1.3", - "windows-threading", + "windows-threading 0.1.0", +] + +[[package]] +name = "windows-future" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f3db6b24b120200d649cd4811b4947188ed3a8d2626f7075146c5d178a9a4a" +dependencies = [ + "windows-core 0.62.1", + "windows-link 0.2.0", + "windows-threading 0.2.0", ] [[package]] name = "windows-implement" -version = "0.60.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", @@ -4732,9 +7877,9 @@ dependencies = [ [[package]] name = "windows-interface" -version = "0.59.1" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", @@ -4759,10 +7904,20 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" dependencies = [ - "windows-core", + "windows-core 0.61.2", "windows-link 0.1.3", ] +[[package]] +name = "windows-numerics" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ce3498fe0aba81e62e477408383196b4b0363db5e0c27646f932676283b43d8" +dependencies = [ + "windows-core 0.62.1", + "windows-link 0.2.0", +] + [[package]] name = "windows-result" version = "0.3.4" @@ -4772,6 +7927,15 @@ dependencies = [ "windows-link 0.1.3", ] +[[package]] +name = "windows-result" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f" +dependencies = [ + "windows-link 0.2.0", +] + [[package]] name = "windows-strings" version = "0.4.2" @@ -4781,6 +7945,15 @@ dependencies = [ "windows-link 0.1.3", ] +[[package]] +name = "windows-strings" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda" +dependencies = [ + "windows-link 0.2.0", +] + [[package]] name = "windows-sys" version = "0.45.0" @@ -4883,6 +8056,15 @@ dependencies = [ "windows-link 0.1.3", ] +[[package]] +name = "windows-threading" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab47f085ad6932defa48855254c758cdd0e2f2d48e62a34118a268d8f345e118" +dependencies = [ + "windows-link 0.2.0", +] + [[package]] name = "windows-version" version = "0.1.5" @@ -5044,6 +8226,18 @@ name = "winnow" version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] [[package]] name = "winreg" @@ -5069,9 +8263,9 @@ checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" [[package]] name = "wry" -version = "0.53.3" +version = "0.54.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f0e9642a0d061f6236c54ccae64c2722a7879ad4ec7dff59bd376d446d8e90" +checksum = "bb26159b420aa77684589a744ae9a9461a95395b848764ad12290a14d960a11a" dependencies = [ "base64 0.22.1", "block2 0.6.1", @@ -5083,7 +8277,7 @@ dependencies = [ "gdkx11", "gtk", "html5ever", - "http", + "http 1.3.1", "javascriptcore-rs", "jni", "kuchikiki", @@ -5098,7 +8292,7 @@ dependencies = [ "once_cell", "percent-encoding", "raw-window-handle", - "sha2", + "sha2 0.10.9", "soup3", "tao-macros", "thiserror 2.0.16", @@ -5106,8 +8300,8 @@ dependencies = [ "webkit2gtk", "webkit2gtk-sys", "webview2-com", - "windows", - "windows-core", + "windows 0.61.3", + "windows-core 0.61.2", "windows-version", "x11-dl", ] @@ -5133,6 +8327,16 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "xattr" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" +dependencies = [ + "libc", + "rustix 1.1.2", +] + [[package]] name = "yoke" version = "0.8.0" @@ -5157,13 +8361,94 @@ dependencies = [ "synstructure", ] +[[package]] +name = "zbus" +version = "5.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d07e46d035fb8e375b2ce63ba4e4ff90a7f73cf2ffb0138b29e1158d2eaadf7" +dependencies = [ + "async-broadcast", + "async-executor", + "async-io", + "async-lock", + "async-process", + "async-recursion", + "async-task", + "async-trait", + "blocking", + "enumflags2", + "event-listener", + "futures-core", + "futures-lite", + "hex", + "nix 0.30.1", + "ordered-stream", + "serde", + "serde_repr", + "tracing", + "uds_windows", + "windows-sys 0.60.2", + "winnow 0.7.13", + "zbus_macros", + "zbus_names", + "zvariant", +] + +[[package]] +name = "zbus_macros" +version = "5.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57e797a9c847ed3ccc5b6254e8bcce056494b375b511b3d6edcec0aeb4defaca" +dependencies = [ + "proc-macro-crate 3.3.0", + "proc-macro2", + "quote", + "syn 2.0.106", + "zbus_names", + "zvariant", + "zvariant_utils", +] + +[[package]] +name = "zbus_names" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7be68e64bf6ce8db94f63e72f0c7eb9a60d733f7e0499e628dfab0f84d6bcb97" +dependencies = [ + "serde", + "static_assertions", + "winnow 0.7.13", + "zvariant", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive 0.7.35", +] + [[package]] name = "zerocopy" version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" dependencies = [ - "zerocopy-derive", + "zerocopy-derive 0.8.27", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", ] [[package]] @@ -5198,6 +8483,26 @@ dependencies = [ "synstructure", ] +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + [[package]] name = "zerotrie" version = "0.2.2" @@ -5230,3 +8535,61 @@ dependencies = [ "quote", "syn 2.0.106", ] + +[[package]] +name = "zip" +version = "4.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caa8cd6af31c3b31c6631b8f483848b91589021b28fffe50adada48d4f4d2ed1" +dependencies = [ + "arbitrary", + "crc32fast", + "indexmap 2.11.1", + "memchr", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" + +[[package]] +name = "zvariant" +version = "5.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "999dd3be73c52b1fccd109a4a81e4fcd20fab1d3599c8121b38d04e1419498db" +dependencies = [ + "endi", + "enumflags2", + "serde", + "winnow 0.7.13", + "zvariant_derive", + "zvariant_utils", +] + +[[package]] +name = "zvariant_derive" +version = "5.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6643fd0b26a46d226bd90d3f07c1b5321fe9bb7f04673cb37ac6d6883885b68e" +dependencies = [ + "proc-macro-crate 3.3.0", + "proc-macro2", + "quote", + "syn 2.0.106", + "zvariant_utils", +] + +[[package]] +name = "zvariant_utils" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6949d142f89f6916deca2232cf26a8afacf2b9fdc35ce766105e104478be599" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "syn 2.0.106", + "winnow 0.7.13", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..7b9635b --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,34 @@ +[workspace] +members = ["crates/rsql-tauri", "crates/rsql-core"] +resolver = "3" + +[workspace.package] +version = "1.1.5" +edition = "2024" +authors = ["rust-dd"] +description = "Modern SQL Client" + +[workspace.dependencies] +serde = { version = "1", features = ["derive"] } +serde_json = "1" +sonic-rs = "0.5" +tokio = "1.47.1" +tokio-postgres = "0.7.13" +deadpool-postgres = "0.14.1" +postgres-native-tls = "0.5" +native-tls = "0.2" +tracing = "0.1.41" +tracing-subscriber = { version = "0.3.20", features = ["fmt"] } +libsql = "0.9.29" +thiserror = "2" +portable-pty = "0.9.0" +rayon = "1.11.0" +sysinfo = "0.38.3" +csv = "1.3" +futures-util = "0.3" +russh = "0.57" + +[profile.release] +codegen-units = 1 +lto = true +strip = "symbols" diff --git a/crates/rsql-core/Cargo.toml b/crates/rsql-core/Cargo.toml new file mode 100644 index 0000000..9bbfefd --- /dev/null +++ b/crates/rsql-core/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "rsql-core" +version.workspace = true +edition.workspace = true +authors.workspace = true +description = "Shared core for the rsql desktop and proxy builds" + +[lib] +path = "src/lib.rs" + +[dependencies] +serde.workspace = true +serde_json.workspace = true +sonic-rs.workspace = true +tokio.workspace = true +tokio-postgres.workspace = true +deadpool-postgres.workspace = true +postgres-native-tls.workspace = true +native-tls.workspace = true +tracing.workspace = true +libsql.workspace = true +thiserror.workspace = true +portable-pty.workspace = true +rayon.workspace = true +sysinfo.workspace = true +csv.workspace = true +futures-util.workspace = true +russh.workspace = true + +[dev-dependencies] +tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } diff --git a/src-tauri/src/common.rs b/crates/rsql-core/src/common/mod.rs similarity index 87% rename from src-tauri/src/common.rs rename to crates/rsql-core/src/common/mod.rs index 498856f..3431b55 100644 --- a/src-tauri/src/common.rs +++ b/crates/rsql-core/src/common/mod.rs @@ -1,6 +1,5 @@ use std::collections::BTreeMap; -pub mod enums; pub mod pgsql; pub type BTreeVecStore = BTreeMap>; diff --git a/src-tauri/src/common/pgsql.rs b/crates/rsql-core/src/common/pgsql.rs similarity index 100% rename from src-tauri/src/common/pgsql.rs rename to crates/rsql-core/src/common/pgsql.rs diff --git a/src-tauri/src/drivers/mod.rs b/crates/rsql-core/src/drivers/mod.rs similarity index 100% rename from src-tauri/src/drivers/mod.rs rename to crates/rsql-core/src/drivers/mod.rs diff --git a/src-tauri/src/drivers/pgsql/commands/admin_commands.rs b/crates/rsql-core/src/drivers/pgsql/commands/admin.rs similarity index 56% rename from src-tauri/src/drivers/pgsql/commands/admin_commands.rs rename to crates/rsql-core/src/drivers/pgsql/commands/admin.rs index 60889df..86f9e56 100644 --- a/src-tauri/src/drivers/pgsql/commands/admin_commands.rs +++ b/crates/rsql-core/src/drivers/pgsql/commands/admin.rs @@ -1,123 +1,104 @@ use crate::AppState; -use crate::common::enums::AppError; -use crate::drivers::pgsql::{ - DbGrant, PgRole, SchemaObject, TableGrant, execute_query, extract_schema_objects, - import_csv_to_table, load_available_extensions, load_database_grants, load_enum_types, - load_extensions, load_pg_settings, load_roles, load_table_grants, parse_csv_preview, +use crate::drivers::pgsql::extensions::{ + load_available_extensions, load_enum_types, load_extensions, load_pg_settings, }; +use crate::drivers::pgsql::query_execution::execute_query; +use crate::drivers::pgsql::roles_schema_objects::{ + DbGrant, PgRole, SchemaObject, TableGrant, extract_schema_objects, import_csv_to_table, + load_database_grants, load_roles, load_table_grants, parse_csv_preview, +}; +use crate::error::AppError; -use tauri::ipc::Response; -use tauri::{Result, State}; - -use super::pool_connection::acquire_client; +use super::pool_helpers::acquire_client; -#[tauri::command(rename_all = "snake_case")] -pub async fn pgsql_csv_preview(file_path: &str) -> Result<(Vec, Vec>)> { - parse_csv_preview(file_path, 5).await.map_err(Into::into) +pub async fn pgsql_csv_preview( + file_path: &str, +) -> Result<(Vec, Vec>), AppError> { + parse_csv_preview(file_path, 5).await } -#[tauri::command(rename_all = "snake_case")] pub async fn pgsql_csv_import( + app_state: &AppState, project_id: &str, file_path: &str, schema: &str, table: &str, column_mapping: Vec<(usize, String)>, - app_state: State<'_, AppState>, -) -> Result { +) -> Result { let client = acquire_client(&app_state.clients, project_id).await?; - import_csv_to_table(&client, file_path, schema, table, &column_mapping) - .await - .map_err(Into::into) + import_csv_to_table(&client, file_path, schema, table, &column_mapping).await } -#[tauri::command(rename_all = "snake_case")] pub async fn pgsql_load_roles( + app_state: &AppState, project_id: &str, - app_state: State<'_, AppState>, -) -> Result> { +) -> Result, AppError> { let client = acquire_client(&app_state.meta_clients, project_id).await?; - load_roles(&client).await.map_err(Into::into) + load_roles(&client).await } -#[tauri::command(rename_all = "snake_case")] pub async fn pgsql_load_table_grants( + app_state: &AppState, project_id: &str, role_name: &str, - app_state: State<'_, AppState>, -) -> Result> { +) -> Result, AppError> { let client = acquire_client(&app_state.meta_clients, project_id).await?; - load_table_grants(&client, role_name) - .await - .map_err(Into::into) + load_table_grants(&client, role_name).await } -#[tauri::command(rename_all = "snake_case")] pub async fn pgsql_load_database_grants( + app_state: &AppState, project_id: &str, role_name: &str, - app_state: State<'_, AppState>, -) -> Result> { +) -> Result, AppError> { let client = acquire_client(&app_state.meta_clients, project_id).await?; - load_database_grants(&client, role_name) - .await - .map_err(Into::into) + load_database_grants(&client, role_name).await } -#[tauri::command(rename_all = "snake_case")] pub async fn pgsql_extract_schema_objects( + app_state: &AppState, project_id: &str, schema: &str, - app_state: State<'_, AppState>, -) -> Result> { +) -> Result, AppError> { let client = acquire_client(&app_state.meta_clients, project_id).await?; - extract_schema_objects(&client, schema) - .await - .map_err(Into::into) + extract_schema_objects(&client, schema).await } -#[tauri::command(rename_all = "snake_case")] pub async fn pgsql_load_extensions( + app_state: &AppState, project_id: &str, - app_state: State<'_, AppState>, -) -> Result { +) -> Result { let client = acquire_client(&app_state.meta_clients, project_id).await?; let result = load_extensions(&client).await?; - let json = sonic_rs::to_string(&result).map_err(|e| AppError::QueryFailed(e.to_string()))?; - Ok(Response::new(json)) + sonic_rs::to_string(&result).map_err(|e| AppError::QueryFailed(e.to_string())) } -#[tauri::command(rename_all = "snake_case")] pub async fn pgsql_load_available_extensions( + app_state: &AppState, project_id: &str, - app_state: State<'_, AppState>, -) -> Result { +) -> Result { let client = acquire_client(&app_state.meta_clients, project_id).await?; let result = load_available_extensions(&client).await?; - let json = sonic_rs::to_string(&result).map_err(|e| AppError::QueryFailed(e.to_string()))?; - Ok(Response::new(json)) + sonic_rs::to_string(&result).map_err(|e| AppError::QueryFailed(e.to_string())) } -#[tauri::command(rename_all = "snake_case")] pub async fn pgsql_load_enum_types( + app_state: &AppState, project_id: &str, - app_state: State<'_, AppState>, -) -> Result { +) -> Result { let client = acquire_client(&app_state.meta_clients, project_id).await?; let result = load_enum_types(&client).await?; - let json = sonic_rs::to_string(&result).map_err(|e| AppError::QueryFailed(e.to_string()))?; - Ok(Response::new(json)) + sonic_rs::to_string(&result).map_err(|e| AppError::QueryFailed(e.to_string())) } -#[tauri::command(rename_all = "snake_case")] pub async fn pgsql_table_action( + app_state: &AppState, project_id: &str, action: &str, schema: &str, table: &str, object_type: &str, - app_state: State<'_, AppState>, -) -> Result { +) -> Result { let client = acquire_client(&app_state.clients, project_id).await?; fn qi(name: &str) -> String { @@ -148,23 +129,20 @@ pub async fn pgsql_table_action( return Err(AppError::QueryFailed(format!( "Unknown action '{}' for object type '{}'", action, object_type - )) - .into()); + ))); } }; - execute_query(&client, &sql).await.map_err(|e| e)?; + execute_query(&client, &sql).await?; Ok(format!("{action} completed successfully.")) } -#[tauri::command(rename_all = "snake_case")] pub async fn pgsql_load_pg_settings( + app_state: &AppState, project_id: &str, - app_state: State<'_, AppState>, -) -> Result { +) -> Result { let client = acquire_client(&app_state.meta_clients, project_id).await?; let result = load_pg_settings(&client).await?; - let json = sonic_rs::to_string(&result).map_err(|e| AppError::QueryFailed(e.to_string()))?; - Ok(Response::new(json)) + sonic_rs::to_string(&result).map_err(|e| AppError::QueryFailed(e.to_string())) } diff --git a/crates/rsql-core/src/drivers/pgsql/commands/connection.rs b/crates/rsql-core/src/drivers/pgsql/commands/connection.rs new file mode 100644 index 0000000..90861be --- /dev/null +++ b/crates/rsql-core/src/drivers/pgsql/commands/connection.rs @@ -0,0 +1,35 @@ +use tokio_postgres::Config; + +use crate::error::AppError; + +use super::pool_helpers::{create_pg_pool, full_error_chain}; + +pub async fn pgsql_test_connection(key: [&str; 6]) -> Result { + let user = key[0]; + let password = key[1]; + let database = key[2]; + let host = key[3]; + let port: u16 = key[4].parse().unwrap_or(5432); + let use_ssl = key[5] == "true"; + + let mut cfg = Config::new(); + cfg.user(user) + .password(password) + .dbname(database) + .host(host) + .port(port); + + let pool = create_pg_pool(&cfg, use_ssl, 1)?; + let client = pool + .get() + .await + .map_err(|e| AppError::ConnectionFailed(full_error_chain(&e)))?; + + let row = client + .query_one("SELECT version()", &[]) + .await + .map_err(|e| AppError::ConnectionFailed(e.to_string()))?; + + let version: String = row.get(0); + Ok(version) +} diff --git a/crates/rsql-core/src/drivers/pgsql/commands/metadata.rs b/crates/rsql-core/src/drivers/pgsql/commands/metadata.rs new file mode 100644 index 0000000..740eea1 --- /dev/null +++ b/crates/rsql-core/src/drivers/pgsql/commands/metadata.rs @@ -0,0 +1,189 @@ +use crate::AppState; +use crate::common::pgsql::{PgsqlLoadColumns, PgsqlLoadSchemas, PgsqlLoadTables}; +use crate::drivers::pgsql::metadata_schema::{ + load_column_details, load_columns, load_constraints, load_databases, load_indexes, + load_policies, load_rules, load_schemas, load_tables, load_tablespaces, load_triggers, +}; +use crate::drivers::pgsql::metadata_views_functions::{ + load_functions, load_materialized_views, load_trigger_functions, load_views, +}; +use crate::drivers::pgsql::{ + ColumnDetail, ConstraintDetail, FunctionInfo, IndexDetail, PolicyDetail, RuleDetail, + TriggerDetail, get_pool, +}; +use crate::error::AppError; + +use super::pool_helpers::acquire_client; + +pub async fn pgsql_load_databases( + app_state: &AppState, + project_id: &str, +) -> Result, AppError> { + let pool = { + let pools = app_state.meta_clients.lock().await; + get_pool(&pools, project_id)? + }; + load_databases(&pool).await +} + +pub async fn pgsql_load_tablespaces( + app_state: &AppState, + project_id: &str, +) -> Result, AppError> { + let pool = { + let pools = app_state.meta_clients.lock().await; + get_pool(&pools, project_id)? + }; + load_tablespaces(&pool).await +} + +pub async fn pgsql_load_schemas( + app_state: &AppState, + project_id: &str, +) -> Result { + let client = acquire_client(&app_state.meta_clients, project_id).await?; + + load_schemas( + &client, + r#"SELECT schema_name FROM information_schema.schemata + WHERE schema_name NOT IN ('pg_catalog', 'information_schema') + ORDER BY schema_name"#, + ) + .await +} + +pub async fn pgsql_load_tables( + app_state: &AppState, + project_id: &str, + schema: &str, +) -> Result { + let client = acquire_client(&app_state.meta_clients, project_id).await?; + + load_tables( + &client, + r#"SELECT table_name, + pg_size_pretty(pg_total_relation_size('"' || table_schema || '"."' || table_name || '"')) AS size + FROM information_schema.tables + WHERE table_schema = $1 + ORDER BY table_name"#, + schema, + ) + .await +} + +pub async fn pgsql_load_columns( + app_state: &AppState, + project_id: &str, + schema: &str, + table: &str, +) -> Result { + let client = acquire_client(&app_state.meta_clients, project_id).await?; + + load_columns(&client, schema, table).await +} + +pub async fn pgsql_load_column_details( + app_state: &AppState, + project_id: &str, + schema: &str, + table: &str, +) -> Result, AppError> { + let client = acquire_client(&app_state.meta_clients, project_id).await?; + + load_column_details(&client, schema, table).await +} + +pub async fn pgsql_load_indexes( + app_state: &AppState, + project_id: &str, + schema: &str, + table: &str, +) -> Result, AppError> { + let client = acquire_client(&app_state.meta_clients, project_id).await?; + + load_indexes(&client, schema, table).await +} + +pub async fn pgsql_load_constraints( + app_state: &AppState, + project_id: &str, + schema: &str, + table: &str, +) -> Result, AppError> { + let client = acquire_client(&app_state.meta_clients, project_id).await?; + + load_constraints(&client, schema, table).await +} + +pub async fn pgsql_load_triggers( + app_state: &AppState, + project_id: &str, + schema: &str, + table: &str, +) -> Result, AppError> { + let client = acquire_client(&app_state.meta_clients, project_id).await?; + + load_triggers(&client, schema, table).await +} + +pub async fn pgsql_load_rules( + app_state: &AppState, + project_id: &str, + schema: &str, + table: &str, +) -> Result, AppError> { + let client = acquire_client(&app_state.meta_clients, project_id).await?; + + load_rules(&client, schema, table).await +} + +pub async fn pgsql_load_policies( + app_state: &AppState, + project_id: &str, + schema: &str, + table: &str, +) -> Result, AppError> { + let client = acquire_client(&app_state.meta_clients, project_id).await?; + + load_policies(&client, schema, table).await +} + +pub async fn pgsql_load_views( + app_state: &AppState, + project_id: &str, + schema: &str, +) -> Result, AppError> { + let client = acquire_client(&app_state.meta_clients, project_id).await?; + + load_views(&client, schema).await +} + +pub async fn pgsql_load_materialized_views( + app_state: &AppState, + project_id: &str, + schema: &str, +) -> Result, AppError> { + let client = acquire_client(&app_state.meta_clients, project_id).await?; + + load_materialized_views(&client, schema).await +} + +pub async fn pgsql_load_functions( + app_state: &AppState, + project_id: &str, + schema: &str, +) -> Result, AppError> { + let client = acquire_client(&app_state.meta_clients, project_id).await?; + + load_functions(&client, schema).await +} + +pub async fn pgsql_load_trigger_functions( + app_state: &AppState, + project_id: &str, + schema: &str, +) -> Result, AppError> { + let client = acquire_client(&app_state.meta_clients, project_id).await?; + + load_trigger_functions(&client, schema).await +} diff --git a/crates/rsql-core/src/drivers/pgsql/commands/mod.rs b/crates/rsql-core/src/drivers/pgsql/commands/mod.rs new file mode 100644 index 0000000..5ad1793 --- /dev/null +++ b/crates/rsql-core/src/drivers/pgsql/commands/mod.rs @@ -0,0 +1,11 @@ +pub(crate) const SNAPSHOT_PAGE_WRITE_RETRIES: usize = 3; + +pub mod admin; +pub mod connection; +pub mod metadata; +pub mod object_info; +pub mod pool_helpers; +pub mod pubsub; +pub mod query; +pub mod snapshot_persistence; +pub mod statistics; diff --git a/crates/rsql-core/src/drivers/pgsql/commands/object_info.rs b/crates/rsql-core/src/drivers/pgsql/commands/object_info.rs new file mode 100644 index 0000000..2533262 --- /dev/null +++ b/crates/rsql-core/src/drivers/pgsql/commands/object_info.rs @@ -0,0 +1,50 @@ +use crate::AppState; +use crate::drivers::pgsql::ddl_generation::generate_full_ddl; +use crate::drivers::pgsql::metadata_views_functions::{ + load_function_info, load_matview_info, load_view_info, +}; +use crate::drivers::pgsql::ObjectStats; +use crate::error::AppError; + +use super::pool_helpers::acquire_client; + +pub async fn pgsql_view_info( + app_state: &AppState, + project_id: &str, + schema: &str, + view: &str, +) -> Result { + let client = acquire_client(&app_state.meta_clients, project_id).await?; + load_view_info(&client, schema, view).await +} + +pub async fn pgsql_matview_info( + app_state: &AppState, + project_id: &str, + schema: &str, + matview: &str, +) -> Result { + let client = acquire_client(&app_state.meta_clients, project_id).await?; + load_matview_info(&client, schema, matview).await +} + +pub async fn pgsql_function_info( + app_state: &AppState, + project_id: &str, + schema: &str, + func_name: &str, +) -> Result { + let client = acquire_client(&app_state.meta_clients, project_id).await?; + load_function_info(&client, schema, func_name).await +} + +pub async fn pgsql_generate_ddl( + app_state: &AppState, + project_id: &str, + schema: &str, + name: &str, + object_type: &str, +) -> Result { + let client = acquire_client(&app_state.meta_clients, project_id).await?; + generate_full_ddl(&client, schema, name, object_type).await +} diff --git a/crates/rsql-core/src/drivers/pgsql/commands/pool_helpers.rs b/crates/rsql-core/src/drivers/pgsql/commands/pool_helpers.rs new file mode 100644 index 0000000..6f42027 --- /dev/null +++ b/crates/rsql-core/src/drivers/pgsql/commands/pool_helpers.rs @@ -0,0 +1,93 @@ +use std::{collections::BTreeMap, sync::Arc}; + +use deadpool_postgres::{Manager as PgManager, ManagerConfig, Pool, RecyclingMethod}; +use native_tls::TlsConnector; +use postgres_native_tls::MakeTlsConnector; +use tokio_postgres::{CancelToken, Config, NoTls}; + +use crate::AppState; +use crate::drivers::pgsql::get_pool; +use crate::error::AppError; + +pub fn is_sqlite_lock_error(message: &str) -> bool { + let lower = message.to_ascii_lowercase(); + lower.contains("database is locked") || lower.contains("database busy") +} + +pub fn full_error_chain(e: &dyn std::error::Error) -> String { + let mut msg = e.to_string(); + let mut src = e.source(); + while let Some(cause) = src { + msg.push_str(": "); + msg.push_str(&cause.to_string()); + src = cause.source(); + } + msg +} + +pub fn create_pg_pool( + cfg: &Config, + use_ssl: bool, + max_size: usize, +) -> std::result::Result { + let manager_config = ManagerConfig { + recycling_method: RecyclingMethod::Custom("ROLLBACK".into()), + }; + + if use_ssl { + let tls_connector = TlsConnector::builder() + .build() + .map_err(|e| AppError::ConnectionFailed(e.to_string()))?; + let tls = MakeTlsConnector::new(tls_connector); + let manager = PgManager::from_config(cfg.clone(), tls, manager_config); + Pool::builder(manager) + .max_size(max_size) + .build() + .map_err(|e| AppError::ConnectionFailed(e.to_string())) + } else { + let manager = PgManager::from_config(cfg.clone(), NoTls, manager_config); + Pool::builder(manager) + .max_size(max_size) + .build() + .map_err(|e| AppError::ConnectionFailed(e.to_string())) + } +} + +pub async fn acquire_client( + pools_mutex: &tokio::sync::Mutex>>, + project_id: &str, +) -> std::result::Result { + let pool = { + let pools = pools_mutex.lock().await; + get_pool(&pools, project_id)? + }; + + pool.get() + .await + .map_err(|e| AppError::ConnectionFailed(e.to_string())) +} + +pub async fn apply_statement_timeout(client: &deadpool_postgres::Client, timeout_ms: u32) { + if timeout_ms > 0 { + client + .simple_query(&format!("SET statement_timeout = {}", timeout_ms)) + .await + .ok(); + } +} + +pub async fn reset_statement_timeout(client: &deadpool_postgres::Client, timeout_ms: u32) { + if timeout_ms > 0 { + client.simple_query("RESET statement_timeout").await.ok(); + } +} + +pub async fn set_cancel_token( + app_state: &AppState, + project_id: &str, + token: CancelToken, +) -> std::result::Result<(), AppError> { + let mut cancel_tokens = app_state.cancel_tokens.lock().await; + cancel_tokens.insert(project_id.to_string(), token); + Ok(()) +} diff --git a/crates/rsql-core/src/drivers/pgsql/commands/pubsub.rs b/crates/rsql-core/src/drivers/pgsql/commands/pubsub.rs new file mode 100644 index 0000000..3a9c814 --- /dev/null +++ b/crates/rsql-core/src/drivers/pgsql/commands/pubsub.rs @@ -0,0 +1,32 @@ +use crate::AppState; +use crate::drivers::pgsql::roles_schema_objects::discover_notify_channels; +use crate::error::AppError; + +use super::pool_helpers::acquire_client; + +pub async fn pgsql_notify_send( + app_state: &AppState, + project_id: &str, + channel: &str, + payload: &str, +) -> Result { + let client = acquire_client(&app_state.clients, project_id).await?; + let sql = format!( + "SELECT pg_notify('{}', '{}')", + channel.replace('\'', "''"), + payload.replace('\'', "''"), + ); + client + .batch_execute(&sql) + .await + .map_err(|e| AppError::QueryFailed(e.to_string()))?; + Ok(true) +} + +pub async fn pgsql_discover_channels( + app_state: &AppState, + project_id: &str, +) -> Result, AppError> { + let client = acquire_client(&app_state.meta_clients, project_id).await?; + discover_notify_channels(&client).await +} diff --git a/src-tauri/src/drivers/pgsql/commands/query_commands.rs b/crates/rsql-core/src/drivers/pgsql/commands/query.rs similarity index 57% rename from src-tauri/src/drivers/pgsql/commands/query_commands.rs rename to crates/rsql-core/src/drivers/pgsql/commands/query.rs index 20b019b..29a344c 100644 --- a/src-tauri/src/drivers/pgsql/commands/query_commands.rs +++ b/crates/rsql-core/src/drivers/pgsql/commands/query.rs @@ -1,18 +1,15 @@ -use crate::AppState; -use crate::common::enums::AppError; -use crate::drivers::pgsql::{ - close_virtual, execute_query, execute_query_packed, execute_query_streamed, execute_virtual, - fetch_virtual_page, -}; - use native_tls::TlsConnector; use postgres_native_tls::MakeTlsConnector; -use tauri::ipc::Response; -use tauri::{AppHandle, Manager, Result, State}; use tokio_postgres::NoTls; -use super::CELL_SEP; -use super::pool_connection::{ +use crate::AppState; +use crate::drivers::pgsql::CELL_SEP; +use crate::drivers::pgsql::query_execution::{ + close_virtual, execute_query, execute_query_packed, execute_virtual, fetch_virtual_page, +}; +use crate::error::AppError; + +use super::pool_helpers::{ acquire_client, apply_statement_timeout, reset_statement_timeout, set_cancel_token, }; use super::snapshot_persistence::{ @@ -20,22 +17,22 @@ use super::snapshot_persistence::{ snapshot_upsert_metadata, }; -#[tauri::command(rename_all = "snake_case")] pub async fn pgsql_run_query( + app_state: &AppState, project_id: &str, sql: &str, - app_state: State<'_, AppState>, -) -> Result { +) -> Result { let client = acquire_client(&app_state.clients, project_id).await?; - set_cancel_token(&app_state, project_id, client.cancel_token()).await?; + set_cancel_token(app_state, project_id, client.cancel_token()).await?; let result = execute_query(&client, sql).await?; - let json = sonic_rs::to_string(&result).map_err(|e| AppError::QueryFailed(e.to_string()))?; - Ok(Response::new(json)) + sonic_rs::to_string(&result).map_err(|e| AppError::QueryFailed(e.to_string())) } -#[tauri::command(rename_all = "snake_case")] -pub async fn pgsql_cancel_query(project_id: &str, app_state: State<'_, AppState>) -> Result { +pub async fn pgsql_cancel_query( + app_state: &AppState, + project_id: &str, +) -> Result { let cancel_token = { let cancel_tokens = app_state.cancel_tokens.lock().await; cancel_tokens @@ -68,15 +65,14 @@ pub async fn pgsql_cancel_query(project_id: &str, app_state: State<'_, AppState> Ok(true) } -#[tauri::command(rename_all = "snake_case")] pub async fn pgsql_run_query_packed( + app_state: &AppState, project_id: &str, sql: &str, timeout_ms: Option, - app_state: State<'_, AppState>, -) -> Result { +) -> Result { let client = acquire_client(&app_state.clients, project_id).await?; - set_cancel_token(&app_state, project_id, client.cancel_token()).await?; + set_cancel_token(app_state, project_id, client.cancel_token()).await?; let timeout = timeout_ms.unwrap_or(0); apply_statement_timeout(&client, timeout).await; @@ -84,41 +80,24 @@ pub async fn pgsql_run_query_packed( reset_statement_timeout(&client, timeout).await; let result = result?; - let json = sonic_rs::to_string(&result).map_err(|e| AppError::QueryFailed(e.to_string()))?; - Ok(Response::new(json)) + sonic_rs::to_string(&result).map_err(|e| AppError::QueryFailed(e.to_string())) } -#[tauri::command(rename_all = "snake_case")] -pub async fn pgsql_run_query_streamed( - project_id: &str, - sql: &str, - stream_id: &str, - app: AppHandle, -) -> Result<()> { - let app_state = app.state::(); - let client = acquire_client(&app_state.clients, project_id).await?; - set_cancel_token(&app_state, project_id, client.cancel_token()).await?; - - execute_query_streamed(&client, sql, stream_id, &app) - .await - .map_err(Into::into) -} - -#[tauri::command(rename_all = "snake_case")] pub async fn pgsql_execute_virtual( + app_state: &AppState, project_id: &str, sql: &str, query_id: &str, page_size: usize, timeout_ms: Option, - app_state: State<'_, AppState>, -) -> Result { +) -> Result { let client = acquire_client(&app_state.clients, project_id).await?; - set_cancel_token(&app_state, project_id, client.cancel_token()).await?; + set_cancel_token(app_state, project_id, client.cancel_token()).await?; let timeout = timeout_ms.unwrap_or(0); apply_statement_timeout(&client, timeout).await; - let result = execute_virtual(&client, &app_state.virtual_cache, sql, query_id, page_size).await; + let result = + execute_virtual(&client, &app_state.virtual_cache, sql, query_id, page_size).await; reset_statement_timeout(&client, timeout).await; let result = result?; @@ -128,7 +107,7 @@ pub async fn pgsql_execute_virtual( result.0.split(CELL_SEP).count() }; if let Err(e) = snapshot_upsert_metadata( - &app_state, project_id, query_id, sql, &result.0, result.1, page_size, col_count, + app_state, project_id, query_id, sql, &result.0, result.1, page_size, col_count, ) .await { @@ -138,7 +117,7 @@ pub async fn pgsql_execute_virtual( e ); } - if let Err(e) = snapshot_store_page(&app_state, query_id, 0, &result.2).await { + if let Err(e) = snapshot_store_page(app_state, query_id, 0, &result.2).await { tracing::warn!( "Failed to persist virtual snapshot first page for {}: {:?}", query_id, @@ -146,28 +125,25 @@ pub async fn pgsql_execute_virtual( ); } - let json = sonic_rs::to_string(&result).map_err(|e| AppError::QueryFailed(e.to_string()))?; - Ok(Response::new(json)) + sonic_rs::to_string(&result).map_err(|e| AppError::QueryFailed(e.to_string())) } -#[tauri::command(rename_all = "snake_case")] pub async fn pgsql_fetch_page( + app_state: &AppState, query_id: &str, col_count: usize, offset: usize, limit: usize, - app_state: State<'_, AppState>, -) -> Result { +) -> Result { let page_index = if limit == 0 { 0 } else { offset / limit }; match fetch_virtual_page(&app_state.virtual_cache, query_id, col_count, offset, limit).await { Ok(packed) => { - if let Err(e) = snapshot_store_page(&app_state, query_id, page_index, &packed).await { + if let Err(e) = snapshot_store_page(app_state, query_id, page_index, &packed).await { tracing::warn!("Failed to persist fetched page for {}: {:?}", query_id, e); } - let json = - sonic_rs::to_string(&packed).map_err(|e| AppError::QueryFailed(e.to_string()))?; - return Ok(Response::new(json)); + return sonic_rs::to_string(&packed) + .map_err(|e| AppError::QueryFailed(e.to_string())); } Err(err) => { tracing::debug!( @@ -178,17 +154,15 @@ pub async fn pgsql_fetch_page( } } - if let Some(packed) = snapshot_load_page(&app_state, query_id, page_index).await? { - let json = - sonic_rs::to_string(&packed).map_err(|e| AppError::QueryFailed(e.to_string()))?; - return Ok(Response::new(json)); + if let Some(packed) = snapshot_load_page(app_state, query_id, page_index).await? { + return sonic_rs::to_string(&packed).map_err(|e| AppError::QueryFailed(e.to_string())); } - if restore_virtual_from_snapshot(&app_state, query_id).await? { + if restore_virtual_from_snapshot(app_state, query_id).await? { let packed = fetch_virtual_page(&app_state.virtual_cache, query_id, col_count, offset, limit) .await?; - if let Err(e) = snapshot_store_page(&app_state, query_id, page_index, &packed).await { + if let Err(e) = snapshot_store_page(app_state, query_id, page_index, &packed).await { tracing::warn!( "Failed to persist restored page for {} (page {}): {:?}", query_id, @@ -196,22 +170,21 @@ pub async fn pgsql_fetch_page( e ); } - let json = - sonic_rs::to_string(&packed).map_err(|e| AppError::QueryFailed(e.to_string()))?; - return Ok(Response::new(json)); + return sonic_rs::to_string(&packed).map_err(|e| AppError::QueryFailed(e.to_string())); } Err(AppError::QueryFailed(format!( "Virtual query {} not found in memory and no snapshot available", query_id - )) - .into()) + ))) } -#[tauri::command(rename_all = "snake_case")] -pub async fn pgsql_close_virtual(query_id: &str, app_state: State<'_, AppState>) -> Result<()> { +pub async fn pgsql_close_virtual( + app_state: &AppState, + query_id: &str, +) -> Result<(), AppError> { close_virtual(&app_state.virtual_cache, query_id).await?; - if let Err(e) = snapshot_cleanup_query(&app_state, query_id).await { + if let Err(e) = snapshot_cleanup_query(app_state, query_id).await { tracing::warn!( "Failed to cleanup virtual snapshot for {}: {:?}", query_id, diff --git a/src-tauri/src/drivers/pgsql/commands/snapshot_persistence.rs b/crates/rsql-core/src/drivers/pgsql/commands/snapshot_persistence.rs similarity index 91% rename from src-tauri/src/drivers/pgsql/commands/snapshot_persistence.rs rename to crates/rsql-core/src/drivers/pgsql/commands/snapshot_persistence.rs index 3edccf5..ac442cc 100644 --- a/src-tauri/src/drivers/pgsql/commands/snapshot_persistence.rs +++ b/crates/rsql-core/src/drivers/pgsql/commands/snapshot_persistence.rs @@ -1,30 +1,31 @@ use std::time::{SystemTime, UNIX_EPOCH}; use crate::AppState; -use crate::common::enums::AppError; -use crate::drivers::pgsql::execute_virtual; +use crate::drivers::pgsql::CELL_SEP; +use crate::drivers::pgsql::query_execution::execute_virtual; +use crate::error::AppError; use tokio::time::{Duration, sleep}; -use super::pool_connection::{acquire_client, is_sqlite_lock_error, set_cancel_token}; -use super::{CELL_SEP, SNAPSHOT_PAGE_WRITE_RETRIES}; +use super::SNAPSHOT_PAGE_WRITE_RETRIES; +use super::pool_helpers::{acquire_client, is_sqlite_lock_error, set_cancel_token}; #[derive(Clone)] -pub(crate) struct VirtualSnapshotMeta { - pub(crate) project_id: String, - pub(crate) sql: String, - pub(crate) page_size: usize, - pub(crate) col_count: usize, +pub struct VirtualSnapshotMeta { + pub project_id: String, + pub sql: String, + pub page_size: usize, + pub col_count: usize, } -pub(crate) fn now_unix_secs() -> i64 { +pub fn now_unix_secs() -> i64 { SystemTime::now() .duration_since(UNIX_EPOCH) .map(|d| d.as_secs() as i64) .unwrap_or_default() } -pub(crate) async fn snapshot_upsert_metadata( +pub async fn snapshot_upsert_metadata( app_state: &AppState, project_id: &str, query_id: &str, @@ -60,7 +61,7 @@ pub(crate) async fn snapshot_upsert_metadata( Ok(()) } -pub(crate) async fn snapshot_store_page( +pub async fn snapshot_store_page( app_state: &AppState, query_id: &str, page_index: usize, @@ -108,7 +109,7 @@ pub(crate) async fn snapshot_store_page( Ok(()) } -pub(crate) async fn snapshot_load_page( +pub async fn snapshot_load_page( app_state: &AppState, query_id: &str, page_index: usize, @@ -143,7 +144,7 @@ pub(crate) async fn snapshot_load_page( } } -pub(crate) async fn snapshot_load_metadata( +pub async fn snapshot_load_metadata( app_state: &AppState, query_id: &str, ) -> std::result::Result, AppError> { @@ -197,7 +198,7 @@ pub(crate) async fn snapshot_load_metadata( })) } -pub(crate) async fn snapshot_cleanup_query( +pub async fn snapshot_cleanup_query( app_state: &AppState, query_id: &str, ) -> std::result::Result<(), AppError> { @@ -223,7 +224,7 @@ pub(crate) async fn snapshot_cleanup_query( Ok(()) } -pub(crate) async fn restore_virtual_from_snapshot( +pub async fn restore_virtual_from_snapshot( app_state: &AppState, query_id: &str, ) -> std::result::Result { diff --git a/crates/rsql-core/src/drivers/pgsql/commands/statistics.rs b/crates/rsql-core/src/drivers/pgsql/commands/statistics.rs new file mode 100644 index 0000000..e5e4c02 --- /dev/null +++ b/crates/rsql-core/src/drivers/pgsql/commands/statistics.rs @@ -0,0 +1,92 @@ +use crate::AppState; +use crate::drivers::pgsql::statistics_activity::{ + load_active_locks, load_activity, load_database_stats, load_fk_details, load_foreign_keys, + load_index_usage, load_table_bloat, load_table_statistics, load_table_stats, +}; +use crate::drivers::pgsql::{DbStat, FKDetail, ForeignKeyInfo, ObjectStats}; +use crate::error::AppError; + +use super::pool_helpers::acquire_client; + +pub async fn pgsql_load_activity( + app_state: &AppState, + project_id: &str, +) -> Result { + let client = acquire_client(&app_state.meta_clients, project_id).await?; + let result = load_activity(&client).await?; + sonic_rs::to_string(&result).map_err(|e| AppError::QueryFailed(e.to_string())) +} + +pub async fn pgsql_load_database_stats( + app_state: &AppState, + project_id: &str, +) -> Result, AppError> { + let client = acquire_client(&app_state.meta_clients, project_id).await?; + load_database_stats(&client).await +} + +pub async fn pgsql_load_table_stats( + app_state: &AppState, + project_id: &str, +) -> Result { + let client = acquire_client(&app_state.meta_clients, project_id).await?; + let result = load_table_stats(&client).await?; + sonic_rs::to_string(&result).map_err(|e| AppError::QueryFailed(e.to_string())) +} + +pub async fn pgsql_load_foreign_keys( + app_state: &AppState, + project_id: &str, + schema: &str, +) -> Result, AppError> { + let client = acquire_client(&app_state.meta_clients, project_id).await?; + load_foreign_keys(&client, schema).await +} + +pub async fn pgsql_table_statistics( + app_state: &AppState, + project_id: &str, + schema: &str, + table: &str, +) -> Result { + let client = acquire_client(&app_state.meta_clients, project_id).await?; + load_table_statistics(&client, schema, table).await +} + +pub async fn pgsql_fk_details( + app_state: &AppState, + project_id: &str, + schema: &str, + table: &str, + direction: &str, +) -> Result, AppError> { + let client = acquire_client(&app_state.meta_clients, project_id).await?; + load_fk_details(&client, schema, table, direction).await +} + +pub async fn pgsql_load_locks( + app_state: &AppState, + project_id: &str, +) -> Result { + let client = acquire_client(&app_state.meta_clients, project_id).await?; + let result = load_active_locks(&client).await?; + sonic_rs::to_string(&result).map_err(|e| AppError::QueryFailed(e.to_string())) +} + +pub async fn pgsql_load_index_usage( + app_state: &AppState, + project_id: &str, +) -> Result { + let client = acquire_client(&app_state.meta_clients, project_id).await?; + let result = load_index_usage(&client).await?; + sonic_rs::to_string(&result).map_err(|e| AppError::QueryFailed(e.to_string())) +} + +pub async fn pgsql_load_table_bloat( + app_state: &AppState, + project_id: &str, +) -> Result { + let client = acquire_client(&app_state.meta_clients, project_id).await?; + let result = load_table_bloat(&client).await?; + sonic_rs::to_string(&result).map_err(|e| AppError::QueryFailed(e.to_string())) +} diff --git a/src-tauri/src/drivers/pgsql/ddl_generation.rs b/crates/rsql-core/src/drivers/pgsql/ddl_generation.rs similarity index 99% rename from src-tauri/src/drivers/pgsql/ddl_generation.rs rename to crates/rsql-core/src/drivers/pgsql/ddl_generation.rs index 841d8b5..c627d3d 100644 --- a/src-tauri/src/drivers/pgsql/ddl_generation.rs +++ b/crates/rsql-core/src/drivers/pgsql/ddl_generation.rs @@ -1,6 +1,6 @@ use tokio_postgres::{Client, SimpleQueryMessage}; -use crate::common::enums::AppError; +use crate::error::AppError; pub async fn generate_full_ddl( client: &Client, diff --git a/src-tauri/src/drivers/pgsql/extensions.rs b/crates/rsql-core/src/drivers/pgsql/extensions.rs similarity index 98% rename from src-tauri/src/drivers/pgsql/extensions.rs rename to crates/rsql-core/src/drivers/pgsql/extensions.rs index e720263..83b8832 100644 --- a/src-tauri/src/drivers/pgsql/extensions.rs +++ b/crates/rsql-core/src/drivers/pgsql/extensions.rs @@ -1,4 +1,4 @@ -use crate::common::enums::AppError; +use crate::error::AppError; pub async fn load_extensions( client: &deadpool_postgres::Client, diff --git a/src-tauri/src/drivers/pgsql/metadata_schema.rs b/crates/rsql-core/src/drivers/pgsql/metadata_schema.rs similarity index 99% rename from src-tauri/src/drivers/pgsql/metadata_schema.rs rename to crates/rsql-core/src/drivers/pgsql/metadata_schema.rs index f48a373..d5ec126 100644 --- a/src-tauri/src/drivers/pgsql/metadata_schema.rs +++ b/crates/rsql-core/src/drivers/pgsql/metadata_schema.rs @@ -2,8 +2,8 @@ use deadpool_postgres::Pool; use tokio::time as tokio_time; use tokio_postgres::Client; -use crate::common::enums::AppError; use crate::common::pgsql::{PgsqlLoadColumns, PgsqlLoadSchemas, PgsqlLoadTables}; +use crate::error::AppError; use super::{ColumnDetail, ConstraintDetail, IndexDetail, PolicyDetail, RuleDetail, TriggerDetail}; diff --git a/src-tauri/src/drivers/pgsql/metadata_views_functions.rs b/crates/rsql-core/src/drivers/pgsql/metadata_views_functions.rs similarity index 99% rename from src-tauri/src/drivers/pgsql/metadata_views_functions.rs rename to crates/rsql-core/src/drivers/pgsql/metadata_views_functions.rs index e3f6a88..24fb5d1 100644 --- a/src-tauri/src/drivers/pgsql/metadata_views_functions.rs +++ b/crates/rsql-core/src/drivers/pgsql/metadata_views_functions.rs @@ -1,6 +1,6 @@ use tokio_postgres::Client; -use crate::common::enums::AppError; +use crate::error::AppError; use super::{FunctionInfo, ObjectStats}; diff --git a/src-tauri/src/drivers/pgsql/mod.rs b/crates/rsql-core/src/drivers/pgsql/mod.rs similarity index 85% rename from src-tauri/src/drivers/pgsql/mod.rs rename to crates/rsql-core/src/drivers/pgsql/mod.rs index 7dcff7d..ae7ed91 100644 --- a/src-tauri/src/drivers/pgsql/mod.rs +++ b/crates/rsql-core/src/drivers/pgsql/mod.rs @@ -1,8 +1,3 @@ -use deadpool_postgres::Pool; -use std::sync::Arc; - -use crate::common::enums::AppError; - pub mod commands; pub mod ddl_generation; pub mod extensions; @@ -12,14 +7,10 @@ pub mod query_execution; pub mod roles_schema_objects; pub mod statistics_activity; -pub use commands::*; -pub use ddl_generation::*; -pub use extensions::*; -pub use metadata_schema::*; -pub use metadata_views_functions::*; -pub use query_execution::*; -pub use roles_schema_objects::*; -pub use statistics_activity::*; +use deadpool_postgres::Pool; +use std::sync::Arc; + +use crate::error::AppError; /// Safely get a pool Arc from the AppState client map. /// Returns a cloned Arc so the caller can drop the MutexGuard immediately. @@ -34,15 +25,15 @@ pub fn get_pool( } /// Cell separator for packed format (Unit Separator, ASCII 0x1F) -pub(crate) const CELL_SEP: char = '\x1F'; +pub const CELL_SEP: char = '\x1F'; /// Row separator for packed format (Record Separator, ASCII 0x1E) -pub(crate) const ROW_SEP: char = '\x1E'; +pub const ROW_SEP: char = '\x1E'; /// A cached query: pre-packed page strings for zero-copy serving. /// Each page is a single large String (~1-2 MB) so the OS reclaims RSS on drop. pub struct CachedQuery { - pub(crate) pages: Vec, - pub(crate) page_size: usize, + pub pages: Vec, + pub page_size: usize, } pub type VirtualCache = std::collections::BTreeMap; diff --git a/src-tauri/src/drivers/pgsql/query_execution/helpers.rs b/crates/rsql-core/src/drivers/pgsql/query_execution/helpers.rs similarity index 95% rename from src-tauri/src/drivers/pgsql/query_execution/helpers.rs rename to crates/rsql-core/src/drivers/pgsql/query_execution/helpers.rs index 35898f6..f779462 100644 --- a/src-tauri/src/drivers/pgsql/query_execution/helpers.rs +++ b/crates/rsql-core/src/drivers/pgsql/query_execution/helpers.rs @@ -5,7 +5,7 @@ use super::super::{CELL_SEP, ROW_SEP}; /// Process simple_query messages, returning the last result set that had rows. /// If no result set had rows but commands ran, returns synthetic "N rows affected". /// If nothing at all, returns empty vecs. -pub(crate) fn process_simple_messages( +pub fn process_simple_messages( messages: Vec, ) -> (Vec, Vec>) { let mut cur_columns: Vec = Vec::new(); @@ -65,7 +65,7 @@ pub(crate) fn process_simple_messages( /// Join string slices with a char separator — avoids .to_string() on the separator. #[inline] -pub(crate) fn join_sep(items: &[String], sep: char) -> String { +pub fn join_sep(items: &[String], sep: char) -> String { let total: usize = items.iter().map(|s| s.len()).sum::() + items.len(); let mut out = String::with_capacity(total); for (i, item) in items.iter().enumerate() { @@ -79,7 +79,7 @@ pub(crate) fn join_sep(items: &[String], sep: char) -> String { /// Pack a slice of rows (each row = Vec) into wire format. /// Pre-allocates capacity and writes directly — zero intermediate allocations. -pub(crate) fn pack_rows_vec(rows: &[Vec]) -> String { +pub fn pack_rows_vec(rows: &[Vec]) -> String { if rows.is_empty() { return String::new(); } diff --git a/src-tauri/src/drivers/pgsql/query_execution/mod.rs b/crates/rsql-core/src/drivers/pgsql/query_execution/mod.rs similarity index 70% rename from src-tauri/src/drivers/pgsql/query_execution/mod.rs rename to crates/rsql-core/src/drivers/pgsql/query_execution/mod.rs index 94f3a0c..c57cd65 100644 --- a/src-tauri/src/drivers/pgsql/query_execution/mod.rs +++ b/crates/rsql-core/src/drivers/pgsql/query_execution/mod.rs @@ -1,8 +1,7 @@ mod helpers; mod simple; -mod streaming; mod virtual_cache; +pub use helpers::*; pub use simple::*; -pub use streaming::*; pub use virtual_cache::*; diff --git a/src-tauri/src/drivers/pgsql/query_execution/simple.rs b/crates/rsql-core/src/drivers/pgsql/query_execution/simple.rs similarity index 98% rename from src-tauri/src/drivers/pgsql/query_execution/simple.rs rename to crates/rsql-core/src/drivers/pgsql/query_execution/simple.rs index 28cac88..8459343 100644 --- a/src-tauri/src/drivers/pgsql/query_execution/simple.rs +++ b/crates/rsql-core/src/drivers/pgsql/query_execution/simple.rs @@ -1,7 +1,7 @@ use std::time::Instant; use tokio_postgres::Client; -use crate::common::enums::AppError; +use crate::error::AppError; use super::super::{CELL_SEP, ROW_SEP}; use super::helpers::{join_sep, pack_rows_vec, process_simple_messages}; diff --git a/src-tauri/src/drivers/pgsql/query_execution/virtual_cache.rs b/crates/rsql-core/src/drivers/pgsql/query_execution/virtual_cache.rs similarity index 98% rename from src-tauri/src/drivers/pgsql/query_execution/virtual_cache.rs rename to crates/rsql-core/src/drivers/pgsql/query_execution/virtual_cache.rs index 83caeec..43b5615 100644 --- a/src-tauri/src/drivers/pgsql/query_execution/virtual_cache.rs +++ b/crates/rsql-core/src/drivers/pgsql/query_execution/virtual_cache.rs @@ -2,7 +2,7 @@ use rayon::prelude::*; use std::time::Instant; use tokio_postgres::Client; -use crate::common::enums::AppError; +use crate::error::AppError; use super::super::{CELL_SEP, CachedQuery, ROW_SEP, VirtualCache}; use super::helpers::{join_sep, pack_rows_vec, process_simple_messages}; diff --git a/src-tauri/src/drivers/pgsql/roles_schema_objects/csv_import.rs b/crates/rsql-core/src/drivers/pgsql/roles_schema_objects/csv_import.rs similarity index 98% rename from src-tauri/src/drivers/pgsql/roles_schema_objects/csv_import.rs rename to crates/rsql-core/src/drivers/pgsql/roles_schema_objects/csv_import.rs index deac3d5..6334835 100644 --- a/src-tauri/src/drivers/pgsql/roles_schema_objects/csv_import.rs +++ b/crates/rsql-core/src/drivers/pgsql/roles_schema_objects/csv_import.rs @@ -1,4 +1,4 @@ -use crate::common::enums::AppError; +use crate::error::AppError; pub async fn parse_csv_preview( file_path: &str, diff --git a/src-tauri/src/drivers/pgsql/roles_schema_objects/mod.rs b/crates/rsql-core/src/drivers/pgsql/roles_schema_objects/mod.rs similarity index 100% rename from src-tauri/src/drivers/pgsql/roles_schema_objects/mod.rs rename to crates/rsql-core/src/drivers/pgsql/roles_schema_objects/mod.rs diff --git a/src-tauri/src/drivers/pgsql/roles_schema_objects/roles_grants.rs b/crates/rsql-core/src/drivers/pgsql/roles_schema_objects/roles_grants.rs similarity index 99% rename from src-tauri/src/drivers/pgsql/roles_schema_objects/roles_grants.rs rename to crates/rsql-core/src/drivers/pgsql/roles_schema_objects/roles_grants.rs index b58265d..3fdfb14 100644 --- a/src-tauri/src/drivers/pgsql/roles_schema_objects/roles_grants.rs +++ b/crates/rsql-core/src/drivers/pgsql/roles_schema_objects/roles_grants.rs @@ -1,4 +1,4 @@ -use crate::common::enums::AppError; +use crate::error::AppError; #[derive(Debug, Clone, serde::Serialize)] pub struct PgRole { diff --git a/src-tauri/src/drivers/pgsql/roles_schema_objects/schema_objects.rs b/crates/rsql-core/src/drivers/pgsql/roles_schema_objects/schema_objects.rs similarity index 99% rename from src-tauri/src/drivers/pgsql/roles_schema_objects/schema_objects.rs rename to crates/rsql-core/src/drivers/pgsql/roles_schema_objects/schema_objects.rs index 0a3da18..5f755f1 100644 --- a/src-tauri/src/drivers/pgsql/roles_schema_objects/schema_objects.rs +++ b/crates/rsql-core/src/drivers/pgsql/roles_schema_objects/schema_objects.rs @@ -1,4 +1,4 @@ -use crate::common::enums::AppError; +use crate::error::AppError; #[derive(Debug, Clone, serde::Serialize)] pub struct SchemaObject { diff --git a/src-tauri/src/drivers/pgsql/statistics_activity/database.rs b/crates/rsql-core/src/drivers/pgsql/statistics_activity/database.rs similarity index 99% rename from src-tauri/src/drivers/pgsql/statistics_activity/database.rs rename to crates/rsql-core/src/drivers/pgsql/statistics_activity/database.rs index 577b5f8..06036d3 100644 --- a/src-tauri/src/drivers/pgsql/statistics_activity/database.rs +++ b/crates/rsql-core/src/drivers/pgsql/statistics_activity/database.rs @@ -1,6 +1,6 @@ use tokio_postgres::Client; -use crate::common::enums::AppError; +use crate::error::AppError; use super::super::DbStat; diff --git a/src-tauri/src/drivers/pgsql/statistics_activity/mod.rs b/crates/rsql-core/src/drivers/pgsql/statistics_activity/mod.rs similarity index 100% rename from src-tauri/src/drivers/pgsql/statistics_activity/mod.rs rename to crates/rsql-core/src/drivers/pgsql/statistics_activity/mod.rs diff --git a/src-tauri/src/drivers/pgsql/statistics_activity/objects.rs b/crates/rsql-core/src/drivers/pgsql/statistics_activity/objects.rs similarity index 99% rename from src-tauri/src/drivers/pgsql/statistics_activity/objects.rs rename to crates/rsql-core/src/drivers/pgsql/statistics_activity/objects.rs index 8f2606d..5e87316 100644 --- a/src-tauri/src/drivers/pgsql/statistics_activity/objects.rs +++ b/crates/rsql-core/src/drivers/pgsql/statistics_activity/objects.rs @@ -1,6 +1,6 @@ use tokio_postgres::Client; -use crate::common::enums::AppError; +use crate::error::AppError; use super::super::{FKDetail, ForeignKeyInfo, ObjectStats}; diff --git a/src-tauri/src/common/enums.rs b/crates/rsql-core/src/error.rs similarity index 88% rename from src-tauri/src/common/enums.rs rename to crates/rsql-core/src/error.rs index d6f8f3e..3f58a02 100644 --- a/src-tauri/src/common/enums.rs +++ b/crates/rsql-core/src/error.rs @@ -42,8 +42,8 @@ pub enum AppError { SerializationError(String), } -impl From for tauri::Error { - fn from(e: AppError) -> Self { - tauri::Error::Io(std::io::Error::other(e.to_string())) +impl Serialize for AppError { + fn serialize(&self, serializer: S) -> Result { + serializer.serialize_str(&self.to_string()) } } diff --git a/crates/rsql-core/src/lib.rs b/crates/rsql-core/src/lib.rs new file mode 100644 index 0000000..417882c --- /dev/null +++ b/crates/rsql-core/src/lib.rs @@ -0,0 +1,11 @@ +//! rsql-core: shared business logic for the rsql desktop and proxy builds. +//! Pure Rust — no Tauri, no axum. + +pub mod common; +pub mod drivers; +pub mod error; +pub mod ssh; +pub mod state; +pub mod utils; + +pub use state::AppState; diff --git a/src-tauri/src/ssh.rs b/crates/rsql-core/src/ssh.rs similarity index 100% rename from src-tauri/src/ssh.rs rename to crates/rsql-core/src/ssh.rs diff --git a/crates/rsql-core/src/state/mod.rs b/crates/rsql-core/src/state/mod.rs new file mode 100644 index 0000000..2553f38 --- /dev/null +++ b/crates/rsql-core/src/state/mod.rs @@ -0,0 +1,24 @@ +pub mod project; +pub mod query; +pub mod workspace; + +use deadpool_postgres::Pool; +use std::{collections::BTreeMap, sync::Arc}; +use tokio::sync::Mutex; +use tokio_postgres::CancelToken; + +use crate::drivers::pgsql::VirtualCache; +use crate::ssh::SshTunnel; +use crate::utils::ResourceMonitor; + +pub struct AppState { + pub clients: Arc>>>, + pub meta_clients: Arc>>>, + pub cancel_tokens: Arc>>, + pub client_ssl: Arc>>, + pub local_db: libsql::Database, + pub resource_monitor: Arc>, + pub virtual_cache: Arc>, + pub notify_handles: Arc>>>, + pub ssh_tunnels: Arc>>, +} diff --git a/src-tauri/src/dbs/project.rs b/crates/rsql-core/src/state/project.rs similarity index 83% rename from src-tauri/src/dbs/project.rs rename to crates/rsql-core/src/state/project.rs index bd480f1..b5e1a4d 100644 --- a/src-tauri/src/dbs/project.rs +++ b/crates/rsql-core/src/state/project.rs @@ -1,13 +1,9 @@ -use crate::AppState; use crate::common::BTreeVecStore; -use crate::common::enums::AppError; +use crate::error::AppError; use std::collections::BTreeMap; -use tauri::{Result, State}; -#[tauri::command(rename_all = "snake_case")] -pub async fn project_db_select(app_state: State<'_, AppState>) -> Result { - let conn = app_state - .local_db +pub async fn project_db_select(local_db: &libsql::Database) -> Result { + let conn = local_db .connect() .map_err(|e| AppError::DatabaseError(e.to_string()))?; @@ -77,14 +73,12 @@ pub async fn project_db_select(app_state: State<'_, AppState>) -> Result, - app_state: State<'_, AppState>, -) -> Result<()> { - let conn = app_state - .local_db +) -> Result<(), AppError> { + let conn = local_db .connect() .map_err(|e| AppError::DatabaseError(e.to_string()))?; @@ -116,10 +110,11 @@ pub async fn project_db_insert( Ok(()) } -#[tauri::command(rename_all = "snake_case")] -pub async fn project_db_delete(project_id: &str, app_state: State<'_, AppState>) -> Result<()> { - let conn = app_state - .local_db +pub async fn project_db_delete( + local_db: &libsql::Database, + project_id: &str, +) -> Result<(), AppError> { + let conn = local_db .connect() .map_err(|e| AppError::DatabaseError(e.to_string()))?; @@ -130,7 +125,6 @@ pub async fn project_db_delete(project_id: &str, app_state: State<'_, AppState>) .await .map_err(|e| AppError::DatabaseError(e.to_string()))?; - // Remove persisted virtual snapshots tied to this project. conn.execute( "DELETE FROM virtual_query_pages WHERE query_id IN ( @@ -147,11 +141,5 @@ pub async fn project_db_delete(project_id: &str, app_state: State<'_, AppState>) .await .map_err(|e| AppError::DatabaseError(e.to_string()))?; - // Best-effort cleanup for in-memory connection state. - app_state.clients.lock().await.remove(project_id); - app_state.meta_clients.lock().await.remove(project_id); - app_state.cancel_tokens.lock().await.remove(project_id); - app_state.client_ssl.lock().await.remove(project_id); - Ok(()) } diff --git a/src-tauri/src/dbs/query.rs b/crates/rsql-core/src/state/query.rs similarity index 65% rename from src-tauri/src/dbs/query.rs rename to crates/rsql-core/src/state/query.rs index 6ae7a90..e3ad8c5 100644 --- a/src-tauri/src/dbs/query.rs +++ b/crates/rsql-core/src/state/query.rs @@ -1,12 +1,10 @@ -use crate::AppState; -use crate::common::enums::AppError; +use crate::error::AppError; use std::collections::BTreeMap; -use tauri::{AppHandle, Manager, Result, State}; -#[tauri::command(rename_all = "snake_case")] -pub async fn query_db_select(app_state: State<'_, AppState>) -> Result> { - let conn = app_state - .local_db +pub async fn query_db_select( + local_db: &libsql::Database, +) -> Result, AppError> { + let conn = local_db .connect() .map_err(|e| AppError::DatabaseError(e.to_string()))?; @@ -32,11 +30,12 @@ pub async fn query_db_select(app_state: State<'_, AppState>) -> Result Result<()> { - let app_state = app.state::(); - let conn = app_state - .local_db +pub async fn query_db_insert( + local_db: &libsql::Database, + query_id: &str, + sql: &str, +) -> Result<(), AppError> { + let conn = local_db .connect() .map_err(|e| AppError::DatabaseError(e.to_string()))?; @@ -50,10 +49,11 @@ pub async fn query_db_insert(query_id: &str, sql: &str, app: AppHandle) -> Resul Ok(()) } -#[tauri::command(rename_all = "snake_case")] -pub async fn query_db_delete(query_id: &str, app_state: State<'_, AppState>) -> Result<()> { - let conn = app_state - .local_db +pub async fn query_db_delete( + local_db: &libsql::Database, + query_id: &str, +) -> Result<(), AppError> { + let conn = local_db .connect() .map_err(|e| AppError::DatabaseError(e.to_string()))?; diff --git a/src-tauri/src/dbs/workspace.rs b/crates/rsql-core/src/state/workspace.rs similarity index 67% rename from src-tauri/src/dbs/workspace.rs rename to crates/rsql-core/src/state/workspace.rs index 5a6ea44..4ad55d9 100644 --- a/src-tauri/src/dbs/workspace.rs +++ b/crates/rsql-core/src/state/workspace.rs @@ -1,11 +1,11 @@ -use crate::AppState; -use crate::common::enums::AppError; -use tauri::{Result, State}; +use crate::error::AppError; -#[tauri::command(rename_all = "snake_case")] -pub async fn workspace_save(name: &str, tabs: &str, app_state: State<'_, AppState>) -> Result<()> { - let conn = app_state - .local_db +pub async fn workspace_save( + local_db: &libsql::Database, + name: &str, + tabs: &str, +) -> Result<(), AppError> { + let conn = local_db .connect() .map_err(|e| AppError::DatabaseError(e.to_string()))?; @@ -19,10 +19,10 @@ pub async fn workspace_save(name: &str, tabs: &str, app_state: State<'_, AppStat Ok(()) } -#[tauri::command(rename_all = "snake_case")] -pub async fn workspace_load_all(app_state: State<'_, AppState>) -> Result> { - let conn = app_state - .local_db +pub async fn workspace_load_all( + local_db: &libsql::Database, +) -> Result, AppError> { + let conn = local_db .connect() .map_err(|e| AppError::DatabaseError(e.to_string()))?; @@ -48,10 +48,11 @@ pub async fn workspace_load_all(app_state: State<'_, AppState>) -> Result) -> Result<()> { - let conn = app_state - .local_db +pub async fn workspace_delete( + local_db: &libsql::Database, + name: &str, +) -> Result<(), AppError> { + let conn = local_db .connect() .map_err(|e| AppError::DatabaseError(e.to_string()))?; diff --git a/crates/rsql-core/src/utils/diff.rs b/crates/rsql-core/src/utils/diff.rs new file mode 100644 index 0000000..aeff540 --- /dev/null +++ b/crates/rsql-core/src/utils/diff.rs @@ -0,0 +1,80 @@ +use rayon::prelude::*; +use std::collections::HashSet; + +const ROW_SEP: char = '\x1E'; + +fn parse_packed_rows(packed: &str) -> Vec<&str> { + if packed.is_empty() { + return Vec::new(); + } + let parts: Vec<&str> = packed.split(ROW_SEP).collect(); + if parts.len() > 1 { + parts[1..].to_vec() + } else { + Vec::new() + } +} + +fn pack_rows(header: &str, rows: &[&str]) -> String { + if rows.is_empty() { + return header.to_string(); + } + let mut result = + String::with_capacity(header.len() + rows.iter().map(|r| r.len() + 1).sum::()); + result.push_str(header); + for row in rows { + result.push(ROW_SEP); + result.push_str(row); + } + result +} + +pub fn compute_diff(pinned_packed: &str, current_packed: &str) -> (String, String, usize) { + let pinned_rows = parse_packed_rows(pinned_packed); + let current_rows = parse_packed_rows(current_packed); + + let pinned_set: HashSet<&str> = pinned_rows.iter().copied().collect(); + let current_set: HashSet<&str> = current_rows.iter().copied().collect(); + + let (added, removed, unchanged_count) = + if current_rows.len() > 5000 || pinned_rows.len() > 5000 { + let added: Vec<&str> = current_rows + .par_iter() + .filter(|r| !pinned_set.contains(*r)) + .copied() + .collect(); + let removed: Vec<&str> = pinned_rows + .par_iter() + .filter(|r| !current_set.contains(*r)) + .copied() + .collect(); + let unchanged: usize = current_rows + .par_iter() + .filter(|r| pinned_set.contains(*r)) + .count(); + (added, removed, unchanged) + } else { + let added: Vec<&str> = current_rows + .iter() + .filter(|r| !pinned_set.contains(*r)) + .copied() + .collect(); + let removed: Vec<&str> = pinned_rows + .iter() + .filter(|r| !current_set.contains(*r)) + .copied() + .collect(); + let unchanged: usize = current_rows + .iter() + .filter(|r| pinned_set.contains(*r)) + .count(); + (added, removed, unchanged) + }; + + let header = pinned_packed.split(ROW_SEP).next().unwrap_or(""); + ( + pack_rows(header, &added), + pack_rows(header, &removed), + unchanged_count, + ) +} diff --git a/crates/rsql-core/src/utils/mod.rs b/crates/rsql-core/src/utils/mod.rs new file mode 100644 index 0000000..73db876 --- /dev/null +++ b/crates/rsql-core/src/utils/mod.rs @@ -0,0 +1,132 @@ +use std::collections::HashSet; +use std::time::Instant; + +use sysinfo::{Networks, Pid, ProcessRefreshKind, ProcessesToUpdate, System, get_current_pid}; + +pub mod diff; + +#[derive(serde::Serialize, Clone, Debug)] +pub struct SystemResourceUsage { + pub app_cpu_percent: f32, + pub app_memory_rss_mb: u64, + pub app_process_count: usize, + pub network_rx_mbps: f32, + pub network_tx_mbps: f32, + pub db_connections_in_use: usize, + pub db_connections_open: usize, + pub db_connections_max: usize, + pub db_connections_waiting: usize, +} + +pub struct ResourceMonitor { + system: System, + networks: Networks, + last_sample_at: Instant, + app_pid: Pid, +} + +impl ResourceMonitor { + pub fn new() -> Self { + let app_pid = get_current_pid().unwrap_or_else(|_| Pid::from_u32(std::process::id())); + let mut system = System::new_all(); + system.refresh_processes(ProcessesToUpdate::All, true); + let mut networks = Networks::new_with_refreshed_list(); + networks.refresh(true); + + Self { + system, + networks, + last_sample_at: Instant::now(), + app_pid, + } + } + + pub fn sample(&mut self) -> SystemResourceUsage { + self.system.refresh_processes_specifics( + ProcessesToUpdate::All, + true, + ProcessRefreshKind::nothing().with_cpu().with_memory(), + ); + self.networks.refresh(true); + let dt = self.last_sample_at.elapsed().as_secs_f32().max(0.001); + self.last_sample_at = Instant::now(); + + let processes = self.system.processes(); + let mut included = HashSet::new(); + included.insert(self.app_pid); + + let mut changed = true; + while changed { + changed = false; + for (pid, process) in processes { + if included.contains(pid) { + continue; + } + if let Some(parent) = process.parent() + && included.contains(&parent) + { + included.insert(*pid); + changed = true; + } + } + } + + let mut total_cpu = 0.0f32; + let mut total_rss = 0u64; + for pid in &included { + if let Some(process) = processes.get(pid) { + total_cpu += process.cpu_usage(); + total_rss = total_rss.saturating_add(process.memory()); + } + } + + let mut rx_bytes: u64 = 0; + let mut tx_bytes: u64 = 0; + for (_iface, net) in &self.networks { + rx_bytes = rx_bytes.saturating_add(net.received()); + tx_bytes = tx_bytes.saturating_add(net.transmitted()); + } + let network_rx_mbps = (rx_bytes as f32 * 8.0) / dt / 1_000_000.0; + let network_tx_mbps = (tx_bytes as f32 * 8.0) / dt / 1_000_000.0; + + SystemResourceUsage { + app_cpu_percent: total_cpu, + app_memory_rss_mb: total_rss / (1024 * 1024), + app_process_count: included.len(), + network_rx_mbps, + network_tx_mbps, + db_connections_in_use: 0, + db_connections_open: 0, + db_connections_max: 0, + db_connections_waiting: 0, + } + } +} + +impl Default for ResourceMonitor { + fn default() -> Self { + Self::new() + } +} + +/// Aggregate pool-stats from a deadpool pool map. +/// Returns (open, available, max, waiting). +pub async fn pool_stats( + pools: &tokio::sync::Mutex< + std::collections::BTreeMap>, + >, +) -> (usize, usize, usize, usize) { + let clients = pools.lock().await; + let mut open = 0usize; + let mut available = 0usize; + let mut max = 0usize; + let mut waiting = 0usize; + for pool in clients.values() { + let status = pool.status(); + open = open.saturating_add(status.size); + available = available.saturating_add(status.available); + max = max.saturating_add(status.max_size); + waiting = waiting.saturating_add(status.waiting); + } + (open, available, max, waiting) +} diff --git a/crates/rsql-core/tests/state_smoke.rs b/crates/rsql-core/tests/state_smoke.rs new file mode 100644 index 0000000..efe4c2c --- /dev/null +++ b/crates/rsql-core/tests/state_smoke.rs @@ -0,0 +1,104 @@ +use rsql_core::state::project; + +#[tokio::test] +async fn project_roundtrip() { + // Use a temp file path rather than ":memory:" because libsql's in-memory + // databases are scoped per-connection, and the project_* helpers open + // their own connections internally. + let tmp_dir = std::env::temp_dir(); + let db_path = tmp_dir.join(format!( + "rsql_core_state_smoke_{}.db", + std::process::id() + )); + let _ = std::fs::remove_file(&db_path); + + let db = libsql::Builder::new_local(&db_path) + .build() + .await + .expect("open db"); + + let conn = db.connect().expect("connect"); + conn.execute( + "CREATE TABLE projects ( + id TEXT PRIMARY KEY, + driver TEXT NOT NULL DEFAULT 'PGSQL', + username TEXT NOT NULL DEFAULT '', + password TEXT NOT NULL DEFAULT '', + database TEXT NOT NULL DEFAULT '', + host TEXT NOT NULL DEFAULT '', + port TEXT NOT NULL DEFAULT '', + ssl TEXT NOT NULL DEFAULT 'false', + ssh_enabled TEXT NOT NULL DEFAULT '', + ssh_host TEXT NOT NULL DEFAULT '', + ssh_port TEXT NOT NULL DEFAULT '', + ssh_user TEXT NOT NULL DEFAULT '', + ssh_password TEXT NOT NULL DEFAULT '', + ssh_key_path TEXT NOT NULL DEFAULT '' + )", + (), + ) + .await + .expect("create projects table"); + + conn.execute( + "CREATE TABLE virtual_query_snapshots ( + query_id TEXT PRIMARY KEY, + project_id TEXT NOT NULL, + sql TEXT NOT NULL, + columns_packed TEXT NOT NULL DEFAULT '', + total_rows INTEGER NOT NULL DEFAULT 0, + page_size INTEGER NOT NULL DEFAULT 0, + col_count INTEGER NOT NULL DEFAULT 0, + created_at INTEGER NOT NULL + )", + (), + ) + .await + .expect("create snapshots table"); + conn.execute( + "CREATE TABLE virtual_query_pages ( + query_id TEXT NOT NULL, + page_index INTEGER NOT NULL, + packed_page TEXT NOT NULL DEFAULT '', + PRIMARY KEY (query_id, page_index) + )", + (), + ) + .await + .expect("create pages table"); + + let details = vec![ + "PGSQL".to_string(), + "user".to_string(), + "pass".to_string(), + "db".to_string(), + "localhost".to_string(), + "5432".to_string(), + "false".to_string(), + String::new(), + String::new(), + String::new(), + String::new(), + String::new(), + String::new(), + ]; + + project::project_db_insert(&db, "p1", details.clone()) + .await + .expect("insert"); + + let projects = project::project_db_select(&db).await.expect("select"); + assert_eq!(projects.len(), 1); + assert!(projects.contains_key("p1")); + + project::project_db_delete(&db, "p1").await.expect("delete"); + + let projects = project::project_db_select(&db) + .await + .expect("select after delete"); + assert_eq!(projects.len(), 0); + + drop(conn); + drop(db); + let _ = std::fs::remove_file(&db_path); +} diff --git a/src-tauri/.gitignore b/crates/rsql-tauri/.gitignore similarity index 100% rename from src-tauri/.gitignore rename to crates/rsql-tauri/.gitignore diff --git a/crates/rsql-tauri/Cargo.toml b/crates/rsql-tauri/Cargo.toml new file mode 100644 index 0000000..70193a5 --- /dev/null +++ b/crates/rsql-tauri/Cargo.toml @@ -0,0 +1,42 @@ +[package] +name = "rsql" +version.workspace = true +edition.workspace = true +authors.workspace = true +description.workspace = true + +[lib] +name = "rsql_lib" +crate-type = ["staticlib", "cdylib", "rlib"] + +[build-dependencies] +tauri-build = { version = "2", features = [] } + +[dependencies] +tauri = { version = "2", features = [] } +tauri-plugin-opener = "2" +tauri-plugin-shell = "2.3.1" +tauri-plugin-fs = "2.4.2" +tauri-plugin-dialog = "2.6.0" +tauri-plugin-process = "2.3.1" +tauri-plugin-updater = "2.10.0" + +serde.workspace = true +serde_json.workspace = true +sonic-rs.workspace = true +tokio.workspace = true +tokio-postgres.workspace = true +deadpool-postgres.workspace = true +postgres-native-tls.workspace = true +native-tls.workspace = true +tracing.workspace = true +tracing-subscriber.workspace = true +libsql.workspace = true +thiserror.workspace = true +portable-pty.workspace = true +rayon.workspace = true +sysinfo.workspace = true +csv.workspace = true +futures-util.workspace = true +russh.workspace = true +rsql-core = { path = "../rsql-core" } diff --git a/src-tauri/build.rs b/crates/rsql-tauri/build.rs similarity index 100% rename from src-tauri/build.rs rename to crates/rsql-tauri/build.rs diff --git a/src-tauri/capabilities/default.json b/crates/rsql-tauri/capabilities/default.json similarity index 100% rename from src-tauri/capabilities/default.json rename to crates/rsql-tauri/capabilities/default.json diff --git a/src-tauri/icons/128x128.png b/crates/rsql-tauri/icons/128x128.png similarity index 100% rename from src-tauri/icons/128x128.png rename to crates/rsql-tauri/icons/128x128.png diff --git a/src-tauri/icons/128x128@2x.png b/crates/rsql-tauri/icons/128x128@2x.png similarity index 100% rename from src-tauri/icons/128x128@2x.png rename to crates/rsql-tauri/icons/128x128@2x.png diff --git a/src-tauri/icons/32x32.png b/crates/rsql-tauri/icons/32x32.png similarity index 100% rename from src-tauri/icons/32x32.png rename to crates/rsql-tauri/icons/32x32.png diff --git a/src-tauri/icons/Square107x107Logo.png b/crates/rsql-tauri/icons/Square107x107Logo.png similarity index 100% rename from src-tauri/icons/Square107x107Logo.png rename to crates/rsql-tauri/icons/Square107x107Logo.png diff --git a/src-tauri/icons/Square142x142Logo.png b/crates/rsql-tauri/icons/Square142x142Logo.png similarity index 100% rename from src-tauri/icons/Square142x142Logo.png rename to crates/rsql-tauri/icons/Square142x142Logo.png diff --git a/src-tauri/icons/Square150x150Logo.png b/crates/rsql-tauri/icons/Square150x150Logo.png similarity index 100% rename from src-tauri/icons/Square150x150Logo.png rename to crates/rsql-tauri/icons/Square150x150Logo.png diff --git a/src-tauri/icons/Square284x284Logo.png b/crates/rsql-tauri/icons/Square284x284Logo.png similarity index 100% rename from src-tauri/icons/Square284x284Logo.png rename to crates/rsql-tauri/icons/Square284x284Logo.png diff --git a/src-tauri/icons/Square30x30Logo.png b/crates/rsql-tauri/icons/Square30x30Logo.png similarity index 100% rename from src-tauri/icons/Square30x30Logo.png rename to crates/rsql-tauri/icons/Square30x30Logo.png diff --git a/src-tauri/icons/Square310x310Logo.png b/crates/rsql-tauri/icons/Square310x310Logo.png similarity index 100% rename from src-tauri/icons/Square310x310Logo.png rename to crates/rsql-tauri/icons/Square310x310Logo.png diff --git a/src-tauri/icons/Square44x44Logo.png b/crates/rsql-tauri/icons/Square44x44Logo.png similarity index 100% rename from src-tauri/icons/Square44x44Logo.png rename to crates/rsql-tauri/icons/Square44x44Logo.png diff --git a/src-tauri/icons/Square71x71Logo.png b/crates/rsql-tauri/icons/Square71x71Logo.png similarity index 100% rename from src-tauri/icons/Square71x71Logo.png rename to crates/rsql-tauri/icons/Square71x71Logo.png diff --git a/src-tauri/icons/Square89x89Logo.png b/crates/rsql-tauri/icons/Square89x89Logo.png similarity index 100% rename from src-tauri/icons/Square89x89Logo.png rename to crates/rsql-tauri/icons/Square89x89Logo.png diff --git a/src-tauri/icons/StoreLogo.png b/crates/rsql-tauri/icons/StoreLogo.png similarity index 100% rename from src-tauri/icons/StoreLogo.png rename to crates/rsql-tauri/icons/StoreLogo.png diff --git a/src-tauri/icons/icon.icns b/crates/rsql-tauri/icons/icon.icns similarity index 100% rename from src-tauri/icons/icon.icns rename to crates/rsql-tauri/icons/icon.icns diff --git a/src-tauri/icons/icon.ico b/crates/rsql-tauri/icons/icon.ico similarity index 100% rename from src-tauri/icons/icon.ico rename to crates/rsql-tauri/icons/icon.ico diff --git a/src-tauri/icons/icon.png b/crates/rsql-tauri/icons/icon.png similarity index 100% rename from src-tauri/icons/icon.png rename to crates/rsql-tauri/icons/icon.png diff --git a/src-tauri/src/app_setup.rs b/crates/rsql-tauri/src/app_setup.rs similarity index 98% rename from src-tauri/src/app_setup.rs rename to crates/rsql-tauri/src/app_setup.rs index 3b95dd2..c2eef60 100644 --- a/src-tauri/src/app_setup.rs +++ b/crates/rsql-tauri/src/app_setup.rs @@ -3,7 +3,8 @@ use tauri::Manager; use tauri::menu::{AboutMetadata, MenuBuilder, SubmenuBuilder}; use tokio::sync::Mutex; -use crate::{AppState, LOCAL_DB_NAME, terminal, utils}; +use crate::{LOCAL_DB_NAME, terminal, utils}; +use rsql_core::AppState; pub fn setup_app(app: &mut tauri::App) -> Result<(), Box> { #[cfg(desktop)] diff --git a/crates/rsql-tauri/src/commands.rs b/crates/rsql-tauri/src/commands.rs new file mode 100644 index 0000000..b544607 --- /dev/null +++ b/crates/rsql-tauri/src/commands.rs @@ -0,0 +1,81 @@ +use rsql_core::AppState; +use rsql_core::common::BTreeVecStore; +use rsql_core::error::AppError; +use std::collections::BTreeMap; +use tauri::{AppHandle, Manager, State}; + +#[tauri::command(rename_all = "snake_case")] +pub async fn project_db_select( + app_state: State<'_, AppState>, +) -> Result { + rsql_core::state::project::project_db_select(&app_state.local_db).await +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn project_db_insert( + project_id: &str, + project_details: Vec, + app_state: State<'_, AppState>, +) -> Result<(), AppError> { + rsql_core::state::project::project_db_insert( + &app_state.local_db, + project_id, + project_details, + ) + .await +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn project_db_delete( + project_id: &str, + app_state: State<'_, AppState>, +) -> Result<(), AppError> { + rsql_core::state::project::project_db_delete(&app_state.local_db, project_id).await?; + app_state.clients.lock().await.remove(project_id); + app_state.meta_clients.lock().await.remove(project_id); + app_state.cancel_tokens.lock().await.remove(project_id); + app_state.client_ssl.lock().await.remove(project_id); + Ok(()) +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn query_db_select( + app_state: State<'_, AppState>, +) -> Result, AppError> { + rsql_core::state::query::query_db_select(&app_state.local_db).await +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn query_db_insert(query_id: &str, sql: &str, app: AppHandle) -> Result<(), AppError> { + let app_state = app.state::(); + rsql_core::state::query::query_db_insert(&app_state.local_db, query_id, sql).await +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn query_db_delete( + query_id: &str, + app_state: State<'_, AppState>, +) -> Result<(), AppError> { + rsql_core::state::query::query_db_delete(&app_state.local_db, query_id).await +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn workspace_save( + name: &str, + tabs: &str, + app_state: State<'_, AppState>, +) -> Result<(), AppError> { + rsql_core::state::workspace::workspace_save(&app_state.local_db, name, tabs).await +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn workspace_load_all( + app_state: State<'_, AppState>, +) -> Result, AppError> { + rsql_core::state::workspace::workspace_load_all(&app_state.local_db).await +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn workspace_delete(name: &str, app_state: State<'_, AppState>) -> Result<(), AppError> { + rsql_core::state::workspace::workspace_delete(&app_state.local_db, name).await +} diff --git a/crates/rsql-tauri/src/drivers/mod.rs b/crates/rsql-tauri/src/drivers/mod.rs new file mode 100644 index 0000000..c23eeb7 --- /dev/null +++ b/crates/rsql-tauri/src/drivers/mod.rs @@ -0,0 +1 @@ +pub mod pgsql; diff --git a/crates/rsql-tauri/src/drivers/pgsql/commands/admin_commands.rs b/crates/rsql-tauri/src/drivers/pgsql/commands/admin_commands.rs new file mode 100644 index 0000000..a38e7e4 --- /dev/null +++ b/crates/rsql-tauri/src/drivers/pgsql/commands/admin_commands.rs @@ -0,0 +1,118 @@ +use rsql_core::AppState; +use rsql_core::drivers::pgsql::commands::admin; +use rsql_core::drivers::pgsql::roles_schema_objects::{DbGrant, PgRole, SchemaObject, TableGrant}; +use rsql_core::error::AppError; + +use tauri::State; +use tauri::ipc::Response; + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_csv_preview( + file_path: &str, +) -> Result<(Vec, Vec>), AppError> { + admin::pgsql_csv_preview(file_path).await +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_csv_import( + project_id: &str, + file_path: &str, + schema: &str, + table: &str, + column_mapping: Vec<(usize, String)>, + app_state: State<'_, AppState>, +) -> Result { + admin::pgsql_csv_import( + app_state.inner(), + project_id, + file_path, + schema, + table, + column_mapping, + ) + .await +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_load_roles( + project_id: &str, + app_state: State<'_, AppState>, +) -> Result, AppError> { + admin::pgsql_load_roles(app_state.inner(), project_id).await +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_load_table_grants( + project_id: &str, + role_name: &str, + app_state: State<'_, AppState>, +) -> Result, AppError> { + admin::pgsql_load_table_grants(app_state.inner(), project_id, role_name).await +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_load_database_grants( + project_id: &str, + role_name: &str, + app_state: State<'_, AppState>, +) -> Result, AppError> { + admin::pgsql_load_database_grants(app_state.inner(), project_id, role_name).await +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_extract_schema_objects( + project_id: &str, + schema: &str, + app_state: State<'_, AppState>, +) -> Result, AppError> { + admin::pgsql_extract_schema_objects(app_state.inner(), project_id, schema).await +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_load_extensions( + project_id: &str, + app_state: State<'_, AppState>, +) -> Result { + let json = admin::pgsql_load_extensions(app_state.inner(), project_id).await?; + Ok(Response::new(json)) +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_load_available_extensions( + project_id: &str, + app_state: State<'_, AppState>, +) -> Result { + let json = admin::pgsql_load_available_extensions(app_state.inner(), project_id).await?; + Ok(Response::new(json)) +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_load_enum_types( + project_id: &str, + app_state: State<'_, AppState>, +) -> Result { + let json = admin::pgsql_load_enum_types(app_state.inner(), project_id).await?; + Ok(Response::new(json)) +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_table_action( + project_id: &str, + action: &str, + schema: &str, + table: &str, + object_type: &str, + app_state: State<'_, AppState>, +) -> Result { + admin::pgsql_table_action(app_state.inner(), project_id, action, schema, table, object_type) + .await +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_load_pg_settings( + project_id: &str, + app_state: State<'_, AppState>, +) -> Result { + let json = admin::pgsql_load_pg_settings(app_state.inner(), project_id).await?; + Ok(Response::new(json)) +} diff --git a/crates/rsql-tauri/src/drivers/pgsql/commands/metadata_commands.rs b/crates/rsql-tauri/src/drivers/pgsql/commands/metadata_commands.rs new file mode 100644 index 0000000..bdb59a2 --- /dev/null +++ b/crates/rsql-tauri/src/drivers/pgsql/commands/metadata_commands.rs @@ -0,0 +1,151 @@ +use rsql_core::AppState; +use rsql_core::common::pgsql::{PgsqlLoadColumns, PgsqlLoadSchemas, PgsqlLoadTables}; +use rsql_core::drivers::pgsql::commands::metadata; +use rsql_core::drivers::pgsql::{ + ColumnDetail, ConstraintDetail, FunctionInfo, IndexDetail, PolicyDetail, RuleDetail, + TriggerDetail, +}; +use rsql_core::error::AppError; + +use tauri::{AppHandle, Manager, State}; + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_load_databases( + project_id: &str, + app: AppHandle, +) -> Result, AppError> { + let app_state = app.state::(); + metadata::pgsql_load_databases(app_state.inner(), project_id).await +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_load_tablespaces( + project_id: &str, + app: AppHandle, +) -> Result, AppError> { + let app_state = app.state::(); + metadata::pgsql_load_tablespaces(app_state.inner(), project_id).await +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_load_schemas( + project_id: &str, + app_state: State<'_, AppState>, +) -> Result { + metadata::pgsql_load_schemas(app_state.inner(), project_id).await +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_load_tables( + project_id: &str, + schema: &str, + app_state: State<'_, AppState>, +) -> Result { + metadata::pgsql_load_tables(app_state.inner(), project_id, schema).await +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_load_columns( + project_id: &str, + schema: &str, + table: &str, + app_state: State<'_, AppState>, +) -> Result { + metadata::pgsql_load_columns(app_state.inner(), project_id, schema, table).await +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_load_column_details( + project_id: &str, + schema: &str, + table: &str, + app_state: State<'_, AppState>, +) -> Result, AppError> { + metadata::pgsql_load_column_details(app_state.inner(), project_id, schema, table).await +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_load_indexes( + project_id: &str, + schema: &str, + table: &str, + app_state: State<'_, AppState>, +) -> Result, AppError> { + metadata::pgsql_load_indexes(app_state.inner(), project_id, schema, table).await +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_load_constraints( + project_id: &str, + schema: &str, + table: &str, + app_state: State<'_, AppState>, +) -> Result, AppError> { + metadata::pgsql_load_constraints(app_state.inner(), project_id, schema, table).await +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_load_triggers( + project_id: &str, + schema: &str, + table: &str, + app_state: State<'_, AppState>, +) -> Result, AppError> { + metadata::pgsql_load_triggers(app_state.inner(), project_id, schema, table).await +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_load_rules( + project_id: &str, + schema: &str, + table: &str, + app_state: State<'_, AppState>, +) -> Result, AppError> { + metadata::pgsql_load_rules(app_state.inner(), project_id, schema, table).await +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_load_policies( + project_id: &str, + schema: &str, + table: &str, + app_state: State<'_, AppState>, +) -> Result, AppError> { + metadata::pgsql_load_policies(app_state.inner(), project_id, schema, table).await +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_load_views( + project_id: &str, + schema: &str, + app_state: State<'_, AppState>, +) -> Result, AppError> { + metadata::pgsql_load_views(app_state.inner(), project_id, schema).await +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_load_materialized_views( + project_id: &str, + schema: &str, + app_state: State<'_, AppState>, +) -> Result, AppError> { + metadata::pgsql_load_materialized_views(app_state.inner(), project_id, schema).await +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_load_functions( + project_id: &str, + schema: &str, + app_state: State<'_, AppState>, +) -> Result, AppError> { + metadata::pgsql_load_functions(app_state.inner(), project_id, schema).await +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_load_trigger_functions( + project_id: &str, + schema: &str, + app_state: State<'_, AppState>, +) -> Result, AppError> { + metadata::pgsql_load_trigger_functions(app_state.inner(), project_id, schema).await +} diff --git a/src-tauri/src/drivers/pgsql/commands/mod.rs b/crates/rsql-tauri/src/drivers/pgsql/commands/mod.rs similarity index 75% rename from src-tauri/src/drivers/pgsql/commands/mod.rs rename to crates/rsql-tauri/src/drivers/pgsql/commands/mod.rs index a417f43..86abb13 100644 --- a/src-tauri/src/drivers/pgsql/commands/mod.rs +++ b/crates/rsql-tauri/src/drivers/pgsql/commands/mod.rs @@ -1,13 +1,9 @@ -pub(crate) const CELL_SEP: char = '\x1F'; -pub(crate) const SNAPSHOT_PAGE_WRITE_RETRIES: usize = 3; - pub mod admin_commands; pub mod metadata_commands; pub mod object_info_commands; pub mod pool_connection; pub mod pubsub_commands; pub mod query_commands; -pub mod snapshot_persistence; pub mod statistics_commands; pub use admin_commands::*; diff --git a/crates/rsql-tauri/src/drivers/pgsql/commands/object_info_commands.rs b/crates/rsql-tauri/src/drivers/pgsql/commands/object_info_commands.rs new file mode 100644 index 0000000..3ed4aad --- /dev/null +++ b/crates/rsql-tauri/src/drivers/pgsql/commands/object_info_commands.rs @@ -0,0 +1,47 @@ +use rsql_core::AppState; +use rsql_core::drivers::pgsql::ObjectStats; +use rsql_core::drivers::pgsql::commands::object_info; +use rsql_core::error::AppError; + +use tauri::State; + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_view_info( + project_id: &str, + schema: &str, + view: &str, + app_state: State<'_, AppState>, +) -> Result { + object_info::pgsql_view_info(app_state.inner(), project_id, schema, view).await +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_matview_info( + project_id: &str, + schema: &str, + matview: &str, + app_state: State<'_, AppState>, +) -> Result { + object_info::pgsql_matview_info(app_state.inner(), project_id, schema, matview).await +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_function_info( + project_id: &str, + schema: &str, + func_name: &str, + app_state: State<'_, AppState>, +) -> Result { + object_info::pgsql_function_info(app_state.inner(), project_id, schema, func_name).await +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_generate_ddl( + project_id: &str, + schema: &str, + name: &str, + object_type: &str, + app_state: State<'_, AppState>, +) -> Result { + object_info::pgsql_generate_ddl(app_state.inner(), project_id, schema, name, object_type).await +} diff --git a/src-tauri/src/drivers/pgsql/commands/pool_connection.rs b/crates/rsql-tauri/src/drivers/pgsql/commands/pool_connection.rs similarity index 58% rename from src-tauri/src/drivers/pgsql/commands/pool_connection.rs rename to crates/rsql-tauri/src/drivers/pgsql/commands/pool_connection.rs index 6d7e355..825168e 100644 --- a/src-tauri/src/drivers/pgsql/commands/pool_connection.rs +++ b/crates/rsql-tauri/src/drivers/pgsql/commands/pool_connection.rs @@ -1,128 +1,18 @@ -use std::{collections::BTreeMap, sync::Arc}; +use std::sync::Arc; -use deadpool_postgres::{Manager as PgManager, ManagerConfig, Pool, RecyclingMethod}; +use rsql_core::AppState; +use rsql_core::drivers::pgsql::commands::connection; +use rsql_core::drivers::pgsql::commands::pool_helpers::{create_pg_pool, full_error_chain}; +use rsql_core::error::{AppError, ProjectConnectionStatus}; -use crate::AppState; -use crate::common::enums::{AppError, ProjectConnectionStatus}; -use crate::drivers::pgsql::get_pool; +use tauri::{AppHandle, Manager}; +use tokio_postgres::Config; -use native_tls::TlsConnector; -use postgres_native_tls::MakeTlsConnector; -use tauri::{AppHandle, Manager, Result}; -use tokio_postgres::{CancelToken, Config, NoTls}; - -pub(crate) fn is_sqlite_lock_error(message: &str) -> bool { - let lower = message.to_ascii_lowercase(); - lower.contains("database is locked") || lower.contains("database busy") -} - -pub(crate) fn full_error_chain(e: &dyn std::error::Error) -> String { - let mut msg = e.to_string(); - let mut src = e.source(); - while let Some(cause) = src { - msg.push_str(": "); - msg.push_str(&cause.to_string()); - src = cause.source(); - } - msg -} - -pub(crate) fn create_pg_pool( - cfg: &Config, - use_ssl: bool, - max_size: usize, -) -> std::result::Result { - let manager_config = ManagerConfig { - recycling_method: RecyclingMethod::Custom("ROLLBACK".into()), - }; - - if use_ssl { - let tls_connector = TlsConnector::builder() - .build() - .map_err(|e| AppError::ConnectionFailed(e.to_string()))?; - let tls = MakeTlsConnector::new(tls_connector); - let manager = PgManager::from_config(cfg.clone(), tls, manager_config); - Pool::builder(manager) - .max_size(max_size) - .build() - .map_err(|e| AppError::ConnectionFailed(e.to_string())) - } else { - let manager = PgManager::from_config(cfg.clone(), NoTls, manager_config); - Pool::builder(manager) - .max_size(max_size) - .build() - .map_err(|e| AppError::ConnectionFailed(e.to_string())) - } -} - -pub(crate) async fn acquire_client( - pools_mutex: &tokio::sync::Mutex>>, - project_id: &str, -) -> std::result::Result { - let pool = { - let pools = pools_mutex.lock().await; - get_pool(&pools, project_id)? - }; - - pool.get() - .await - .map_err(|e| AppError::ConnectionFailed(e.to_string())) -} - -pub(crate) async fn apply_statement_timeout(client: &deadpool_postgres::Client, timeout_ms: u32) { - if timeout_ms > 0 { - client - .simple_query(&format!("SET statement_timeout = {}", timeout_ms)) - .await - .ok(); - } -} - -pub(crate) async fn reset_statement_timeout(client: &deadpool_postgres::Client, timeout_ms: u32) { - if timeout_ms > 0 { - client.simple_query("RESET statement_timeout").await.ok(); - } -} - -pub(crate) async fn set_cancel_token( - app_state: &AppState, - project_id: &str, - token: CancelToken, -) -> std::result::Result<(), AppError> { - let mut cancel_tokens = app_state.cancel_tokens.lock().await; - cancel_tokens.insert(project_id.to_string(), token); - Ok(()) -} +pub(crate) use rsql_core::drivers::pgsql::commands::pool_helpers::{acquire_client, set_cancel_token}; #[tauri::command(rename_all = "snake_case")] -pub async fn pgsql_test_connection(key: [&str; 6]) -> Result { - let user = key[0]; - let password = key[1]; - let database = key[2]; - let host = key[3]; - let port: u16 = key[4].parse().unwrap_or(5432); - let use_ssl = key[5] == "true"; - - let mut cfg = Config::new(); - cfg.user(user) - .password(password) - .dbname(database) - .host(host) - .port(port); - - let pool = create_pg_pool(&cfg, use_ssl, 1)?; - let client = pool - .get() - .await - .map_err(|e| AppError::ConnectionFailed(full_error_chain(&e)))?; - - let row = client - .query_one("SELECT version()", &[]) - .await - .map_err(|e| AppError::ConnectionFailed(e.to_string()))?; - - let version: String = row.get(0); - Ok(version) +pub async fn pgsql_test_connection(key: [&str; 6]) -> Result { + connection::pgsql_test_connection(key).await } #[tauri::command(rename_all = "snake_case")] @@ -131,7 +21,7 @@ pub async fn pgsql_connector( key: Option<[&str; 6]>, ssh: Option>, app: AppHandle, -) -> Result { +) -> Result { let app_state = app.state::(); { let clients = app_state.clients.lock().await; @@ -194,7 +84,7 @@ pub async fn pgsql_connector( app_state.ssh_tunnels.lock().await.remove(project_id); - let tunnel = crate::ssh::start_tunnel( + let tunnel = rsql_core::ssh::start_tunnel( ssh_host, ssh_port, ssh_user, @@ -233,14 +123,14 @@ pub async fn pgsql_connector( Ok(p) => Arc::new(p), Err(e) => { tracing::error!("Query pool creation failed: {:?}", e); - return Err(AppError::ConnectionFailed(full_error_chain(&e)).into()); + return Err(AppError::ConnectionFailed(full_error_chain(&e))); } }; let meta_pool = match create_pg_pool(&cfg, use_ssl, 8) { Ok(p) => Arc::new(p), Err(e) => { tracing::error!("Meta pool creation failed: {:?}", e); - return Err(AppError::ConnectionFailed(full_error_chain(&e)).into()); + return Err(AppError::ConnectionFailed(full_error_chain(&e))); } }; @@ -249,7 +139,7 @@ pub async fn pgsql_connector( Ok(c) => c, Err(e) => { tracing::error!("Query pool initial connection failed: {:?}", e); - return Err(AppError::ConnectionFailed(full_error_chain(&e)).into()); + return Err(AppError::ConnectionFailed(full_error_chain(&e))); } }; if let Err(e) = meta_pool.get().await { diff --git a/src-tauri/src/drivers/pgsql/commands/pubsub_commands.rs b/crates/rsql-tauri/src/drivers/pgsql/commands/pubsub_commands.rs similarity index 84% rename from src-tauri/src/drivers/pgsql/commands/pubsub_commands.rs rename to crates/rsql-tauri/src/drivers/pgsql/commands/pubsub_commands.rs index 064b20d..eb2cf08 100644 --- a/src-tauri/src/drivers/pgsql/commands/pubsub_commands.rs +++ b/crates/rsql-tauri/src/drivers/pgsql/commands/pubsub_commands.rs @@ -1,17 +1,19 @@ -use crate::AppState; -use crate::common::enums::AppError; -use crate::drivers::pgsql::discover_notify_channels; +use rsql_core::AppState; +use rsql_core::drivers::pgsql::commands::pubsub; +use rsql_core::error::AppError; use futures_util::StreamExt; use native_tls::TlsConnector; use postgres_native_tls::MakeTlsConnector; -use tauri::{AppHandle, Emitter, Manager, Result, State}; +use tauri::{AppHandle, Emitter, Manager, State}; use tokio_postgres::{AsyncMessage, Config, NoTls}; -use super::pool_connection::acquire_client; - #[tauri::command(rename_all = "snake_case")] -pub async fn pgsql_listen_start(project_id: &str, channel: &str, app: AppHandle) -> Result { +pub async fn pgsql_listen_start( + project_id: &str, + channel: &str, + app: AppHandle, +) -> Result { let app_handle = app.clone(); let app_state = app_handle.state::(); let listen_key = format!("{}:{}", project_id, channel); @@ -134,7 +136,11 @@ pub async fn pgsql_listen_start(project_id: &str, channel: &str, app: AppHandle) } #[tauri::command(rename_all = "snake_case")] -pub async fn pgsql_listen_stop(project_id: &str, channel: &str, app: AppHandle) -> Result { +pub async fn pgsql_listen_stop( + project_id: &str, + channel: &str, + app: AppHandle, +) -> Result { let app_state = app.state::(); let listen_key = format!("{}:{}", project_id, channel); @@ -152,25 +158,14 @@ pub async fn pgsql_notify_send( channel: &str, payload: &str, app_state: State<'_, AppState>, -) -> Result { - let client = acquire_client(&app_state.clients, project_id).await?; - let sql = format!( - "SELECT pg_notify('{}', '{}')", - channel.replace('\'', "''"), - payload.replace('\'', "''"), - ); - client - .batch_execute(&sql) - .await - .map_err(|e| AppError::QueryFailed(e.to_string()))?; - Ok(true) +) -> Result { + pubsub::pgsql_notify_send(app_state.inner(), project_id, channel, payload).await } #[tauri::command(rename_all = "snake_case")] pub async fn pgsql_discover_channels( project_id: &str, app_state: State<'_, AppState>, -) -> Result> { - let client = acquire_client(&app_state.meta_clients, project_id).await?; - discover_notify_channels(&client).await.map_err(Into::into) +) -> Result, AppError> { + pubsub::pgsql_discover_channels(app_state.inner(), project_id).await } diff --git a/crates/rsql-tauri/src/drivers/pgsql/commands/query_commands.rs b/crates/rsql-tauri/src/drivers/pgsql/commands/query_commands.rs new file mode 100644 index 0000000..bab2132 --- /dev/null +++ b/crates/rsql-tauri/src/drivers/pgsql/commands/query_commands.rs @@ -0,0 +1,95 @@ +use rsql_core::AppState; +use rsql_core::drivers::pgsql::commands::query; +use rsql_core::error::AppError; + +use tauri::ipc::Response; +use tauri::{AppHandle, Manager, State}; + +use crate::drivers::pgsql::streaming::execute_query_streamed; + +use super::pool_connection::{acquire_client, set_cancel_token}; + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_run_query( + project_id: &str, + sql: &str, + app_state: State<'_, AppState>, +) -> Result { + let json = query::pgsql_run_query(app_state.inner(), project_id, sql).await?; + Ok(Response::new(json)) +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_cancel_query( + project_id: &str, + app_state: State<'_, AppState>, +) -> Result { + query::pgsql_cancel_query(app_state.inner(), project_id).await +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_run_query_packed( + project_id: &str, + sql: &str, + timeout_ms: Option, + app_state: State<'_, AppState>, +) -> Result { + let json = query::pgsql_run_query_packed(app_state.inner(), project_id, sql, timeout_ms).await?; + Ok(Response::new(json)) +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_run_query_streamed( + project_id: &str, + sql: &str, + stream_id: &str, + app: AppHandle, +) -> Result<(), AppError> { + let app_state = app.state::(); + let client = acquire_client(&app_state.clients, project_id).await?; + set_cancel_token(&app_state, project_id, client.cancel_token()).await?; + + execute_query_streamed(&client, sql, stream_id, &app).await +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_execute_virtual( + project_id: &str, + sql: &str, + query_id: &str, + page_size: usize, + timeout_ms: Option, + app_state: State<'_, AppState>, +) -> Result { + let json = query::pgsql_execute_virtual( + app_state.inner(), + project_id, + sql, + query_id, + page_size, + timeout_ms, + ) + .await?; + Ok(Response::new(json)) +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_fetch_page( + query_id: &str, + col_count: usize, + offset: usize, + limit: usize, + app_state: State<'_, AppState>, +) -> Result { + let json = + query::pgsql_fetch_page(app_state.inner(), query_id, col_count, offset, limit).await?; + Ok(Response::new(json)) +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_close_virtual( + query_id: &str, + app_state: State<'_, AppState>, +) -> Result<(), AppError> { + query::pgsql_close_virtual(app_state.inner(), query_id).await +} diff --git a/crates/rsql-tauri/src/drivers/pgsql/commands/statistics_commands.rs b/crates/rsql-tauri/src/drivers/pgsql/commands/statistics_commands.rs new file mode 100644 index 0000000..1f76f08 --- /dev/null +++ b/crates/rsql-tauri/src/drivers/pgsql/commands/statistics_commands.rs @@ -0,0 +1,90 @@ +use rsql_core::AppState; +use rsql_core::drivers::pgsql::{DbStat, FKDetail, ForeignKeyInfo, ObjectStats}; +use rsql_core::drivers::pgsql::commands::statistics; +use rsql_core::error::AppError; + +use tauri::State; +use tauri::ipc::Response; + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_load_activity( + project_id: &str, + app_state: State<'_, AppState>, +) -> Result { + let json = statistics::pgsql_load_activity(app_state.inner(), project_id).await?; + Ok(Response::new(json)) +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_load_database_stats( + project_id: &str, + app_state: State<'_, AppState>, +) -> Result, AppError> { + statistics::pgsql_load_database_stats(app_state.inner(), project_id).await +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_load_table_stats( + project_id: &str, + app_state: State<'_, AppState>, +) -> Result { + let json = statistics::pgsql_load_table_stats(app_state.inner(), project_id).await?; + Ok(Response::new(json)) +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_load_foreign_keys( + project_id: &str, + schema: &str, + app_state: State<'_, AppState>, +) -> Result, AppError> { + statistics::pgsql_load_foreign_keys(app_state.inner(), project_id, schema).await +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_table_statistics( + project_id: &str, + schema: &str, + table: &str, + app_state: State<'_, AppState>, +) -> Result { + statistics::pgsql_table_statistics(app_state.inner(), project_id, schema, table).await +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_fk_details( + project_id: &str, + schema: &str, + table: &str, + direction: &str, + app_state: State<'_, AppState>, +) -> Result, AppError> { + statistics::pgsql_fk_details(app_state.inner(), project_id, schema, table, direction).await +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_load_locks( + project_id: &str, + app_state: State<'_, AppState>, +) -> Result { + let json = statistics::pgsql_load_locks(app_state.inner(), project_id).await?; + Ok(Response::new(json)) +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_load_index_usage( + project_id: &str, + app_state: State<'_, AppState>, +) -> Result { + let json = statistics::pgsql_load_index_usage(app_state.inner(), project_id).await?; + Ok(Response::new(json)) +} + +#[tauri::command(rename_all = "snake_case")] +pub async fn pgsql_load_table_bloat( + project_id: &str, + app_state: State<'_, AppState>, +) -> Result { + let json = statistics::pgsql_load_table_bloat(app_state.inner(), project_id).await?; + Ok(Response::new(json)) +} diff --git a/crates/rsql-tauri/src/drivers/pgsql/mod.rs b/crates/rsql-tauri/src/drivers/pgsql/mod.rs new file mode 100644 index 0000000..958a71b --- /dev/null +++ b/crates/rsql-tauri/src/drivers/pgsql/mod.rs @@ -0,0 +1,4 @@ +pub mod commands; +pub mod streaming; + +pub use commands::*; diff --git a/src-tauri/src/drivers/pgsql/query_execution/streaming.rs b/crates/rsql-tauri/src/drivers/pgsql/streaming.rs similarity index 97% rename from src-tauri/src/drivers/pgsql/query_execution/streaming.rs rename to crates/rsql-tauri/src/drivers/pgsql/streaming.rs index 9e362fb..4b578ac 100644 --- a/src-tauri/src/drivers/pgsql/query_execution/streaming.rs +++ b/crates/rsql-tauri/src/drivers/pgsql/streaming.rs @@ -1,10 +1,9 @@ use std::time::Instant; use tokio_postgres::{Client, SimpleQueryMessage}; -use crate::common::enums::AppError; - -use super::super::CELL_SEP; -use super::helpers::{join_sep, pack_rows_vec, process_simple_messages}; +use rsql_core::drivers::pgsql::CELL_SEP; +use rsql_core::drivers::pgsql::query_execution::{join_sep, pack_rows_vec, process_simple_messages}; +use rsql_core::error::AppError; /// Events emitted during streamed query execution. #[derive(serde::Serialize, Clone)] diff --git a/src-tauri/src/lib.rs b/crates/rsql-tauri/src/lib.rs similarity index 100% rename from src-tauri/src/lib.rs rename to crates/rsql-tauri/src/lib.rs diff --git a/src-tauri/src/main.rs b/crates/rsql-tauri/src/main.rs similarity index 76% rename from src-tauri/src/main.rs rename to crates/rsql-tauri/src/main.rs index 0e6e1a3..a7e547d 100644 --- a/src-tauri/src/main.rs +++ b/crates/rsql-tauri/src/main.rs @@ -2,33 +2,15 @@ #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] mod app_setup; -mod common; -mod dbs; +mod commands; mod drivers; -mod ssh; mod terminal; mod utils; const LOCAL_DB_NAME: &str = "rsql.db"; -use deadpool_postgres::Pool; -use std::{collections::BTreeMap, sync::Arc}; -use tokio::sync::Mutex; -use tokio_postgres::CancelToken; use tracing::Level; -pub struct AppState { - pub clients: Arc>>>, - pub meta_clients: Arc>>>, - pub cancel_tokens: Arc>>, - pub client_ssl: Arc>>, - pub local_db: libsql::Database, - pub resource_monitor: Arc>, - pub virtual_cache: Arc>, - pub notify_handles: Arc>>>, - pub ssh_tunnels: Arc>>, -} - fn main() { tracing_subscriber::fmt() .with_file(true) @@ -44,15 +26,15 @@ fn main() { .plugin(tauri_plugin_process::init()) .setup(app_setup::setup_app) .invoke_handler(tauri::generate_handler![ - dbs::project::project_db_select, - dbs::project::project_db_insert, - dbs::project::project_db_delete, - dbs::query::query_db_select, - dbs::query::query_db_insert, - dbs::query::query_db_delete, - dbs::workspace::workspace_save, - dbs::workspace::workspace_load_all, - dbs::workspace::workspace_delete, + commands::project_db_select, + commands::project_db_insert, + commands::project_db_delete, + commands::query_db_select, + commands::query_db_insert, + commands::query_db_delete, + commands::workspace_save, + commands::workspace_load_all, + commands::workspace_delete, drivers::pgsql::pgsql_test_connection, drivers::pgsql::pgsql_connector, drivers::pgsql::pgsql_load_databases, diff --git a/src-tauri/src/terminal.rs b/crates/rsql-tauri/src/terminal.rs similarity index 100% rename from src-tauri/src/terminal.rs rename to crates/rsql-tauri/src/terminal.rs diff --git a/crates/rsql-tauri/src/utils.rs b/crates/rsql-tauri/src/utils.rs new file mode 100644 index 0000000..c73caa8 --- /dev/null +++ b/crates/rsql-tauri/src/utils.rs @@ -0,0 +1,33 @@ +use rsql_core::AppState; +use rsql_core::utils::{SystemResourceUsage, pool_stats}; +use tauri::State; + +#[tauri::command(rename_all = "snake_case")] +pub async fn system_resource_usage( + app_state: State<'_, AppState>, +) -> Result { + let mut usage = { + let mut monitor = app_state.resource_monitor.lock().await; + monitor.sample() + }; + + let (q_open, q_available, q_max, q_waiting) = pool_stats(&app_state.clients).await; + let (m_open, m_available, m_max, m_waiting) = pool_stats(&app_state.meta_clients).await; + + let total_open = q_open.saturating_add(m_open); + let total_available = q_available.saturating_add(m_available); + + usage.db_connections_open = total_open; + usage.db_connections_max = q_max.saturating_add(m_max); + usage.db_connections_waiting = q_waiting.saturating_add(m_waiting); + usage.db_connections_in_use = total_open.saturating_sub(total_available); + + Ok(usage) +} + +#[tauri::command(rename_all = "snake_case")] +pub fn compute_diff(pinned_packed: String, current_packed: String) -> (String, String, usize) { + rsql_core::utils::diff::compute_diff(&pinned_packed, ¤t_packed) +} + +pub use rsql_core::utils::ResourceMonitor; diff --git a/src-tauri/tauri.conf.json b/crates/rsql-tauri/tauri.conf.json similarity index 96% rename from src-tauri/tauri.conf.json rename to crates/rsql-tauri/tauri.conf.json index e5350aa..9547de9 100644 --- a/src-tauri/tauri.conf.json +++ b/crates/rsql-tauri/tauri.conf.json @@ -7,7 +7,7 @@ "beforeDevCommand": "yarn dev", "devUrl": "http://localhost:1420", "beforeBuildCommand": "yarn build", - "frontendDist": "../dist" + "frontendDist": "../../dist" }, "app": { "windows": [ diff --git a/package.json b/package.json index d5d9f0a..9f1303e 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "dev": "vite", "build": "tsc && vite build", "preview": "vite preview", - "tauri": "tauri", + "tauri": "cd crates/rsql-tauri && tauri", "format": "biome format --write .", "lint": "biome lint .", "check": "biome check --write .", diff --git a/scripts/check-rsql-core-purity.sh b/scripts/check-rsql-core-purity.sh new file mode 100755 index 0000000..d4a1f1e --- /dev/null +++ b/scripts/check-rsql-core-purity.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +# Fails if rsql-core gains a forbidden dependency (tauri/axum/tokio-tungstenite). +# The rsql-core crate must remain a pure-Rust library so it can be reused by +# both the desktop Tauri bin and the upcoming rsql-proxy WebSocket bin. + +set -euo pipefail + +cd "$(dirname "$0")/.." + +forbidden_patterns='^[│ ]*(tauri[- ]|axum[- ]|tokio-tungstenite[- ])' + +if cargo tree -p rsql-core --depth 99 2>/dev/null | grep -E "$forbidden_patterns" >/dev/null; then + echo "FAIL: rsql-core has a forbidden dependency." + cargo tree -p rsql-core --depth 99 | grep -E "$forbidden_patterns" || true + exit 1 +fi + +echo "OK: rsql-core is pure-Rust (no tauri/axum/tokio-tungstenite deps)." diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock deleted file mode 100644 index 3fc52d9..0000000 --- a/src-tauri/Cargo.lock +++ /dev/null @@ -1,8571 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" - -[[package]] -name = "aead" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" -dependencies = [ - "crypto-common 0.1.6", - "generic-array 0.14.7", -] - -[[package]] -name = "aes" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - -[[package]] -name = "aes-gcm" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" -dependencies = [ - "aead", - "aes", - "cipher", - "ctr", - "ghash", - "subtle", -] - -[[package]] -name = "ahash" -version = "0.8.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" -dependencies = [ - "cfg-if", - "getrandom 0.3.3", - "once_cell", - "version_check", - "zerocopy 0.8.27", -] - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "alloc-no-stdlib" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" - -[[package]] -name = "alloc-stdlib" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" -dependencies = [ - "alloc-no-stdlib", -] - -[[package]] -name = "allocator-api2" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "anyhow" -version = "1.0.99" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" - -[[package]] -name = "arbitrary" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" -dependencies = [ - "derive_arbitrary", -] - -[[package]] -name = "argon2" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" -dependencies = [ - "base64ct", - "blake2", - "cpufeatures", - "password-hash", -] - -[[package]] -name = "async-broadcast" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" -dependencies = [ - "event-listener", - "event-listener-strategy", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-channel" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" -dependencies = [ - "concurrent-queue", - "event-listener-strategy", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-executor" -version = "1.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8" -dependencies = [ - "async-task", - "concurrent-queue", - "fastrand", - "futures-lite", - "pin-project-lite", - "slab", -] - -[[package]] -name = "async-io" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19634d6336019ef220f09fd31168ce5c184b295cbf80345437cc36094ef223ca" -dependencies = [ - "async-lock", - "cfg-if", - "concurrent-queue", - "futures-io", - "futures-lite", - "parking", - "polling", - "rustix 1.1.2", - "slab", - "windows-sys 0.60.2", -] - -[[package]] -name = "async-lock" -version = "3.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" -dependencies = [ - "event-listener", - "event-listener-strategy", - "pin-project-lite", -] - -[[package]] -name = "async-process" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65daa13722ad51e6ab1a1b9c01299142bc75135b337923cfa10e79bbbd669f00" -dependencies = [ - "async-channel", - "async-io", - "async-lock", - "async-signal", - "async-task", - "blocking", - "cfg-if", - "event-listener", - "futures-lite", - "rustix 1.1.2", -] - -[[package]] -name = "async-recursion" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "async-signal" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f567af260ef69e1d52c2b560ce0ea230763e6fbb9214a85d768760a920e3e3c1" -dependencies = [ - "async-io", - "async-lock", - "atomic-waker", - "cfg-if", - "futures-core", - "futures-io", - "rustix 1.1.2", - "signal-hook-registry", - "slab", - "windows-sys 0.60.2", -] - -[[package]] -name = "async-stream" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" -dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "async-task" -version = "4.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" - -[[package]] -name = "async-trait" -version = "0.1.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "atk" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241b621213072e993be4f6f3a9e4b45f65b7e6faad43001be957184b7bb1824b" -dependencies = [ - "atk-sys", - "glib", - "libc", -] - -[[package]] -name = "atk-sys" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e48b684b0ca77d2bbadeef17424c2ea3c897d44d566a1617e7e8f30614d086" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - -[[package]] -name = "autocfg" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" - -[[package]] -name = "aws-lc-rs" -version = "1.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94bffc006df10ac2a68c83692d734a465f8ee6c5b384d8545a636f81d858f4bf" -dependencies = [ - "aws-lc-sys", - "untrusted 0.7.1", - "zeroize", -] - -[[package]] -name = "aws-lc-sys" -version = "0.38.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4321e568ed89bb5a7d291a7f37997c2c0df89809d7b6d12062c81ddb54aa782e" -dependencies = [ - "cc", - "cmake", - "dunce", - "fs_extra", -] - -[[package]] -name = "axum" -version = "0.6.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" -dependencies = [ - "async-trait", - "axum-core", - "bitflags 1.3.2", - "bytes", - "futures-util", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.32", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "sync_wrapper 0.1.2", - "tower 0.4.13", - "tower-layer", - "tower-service", -] - -[[package]] -name = "axum-core" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http 0.2.12", - "http-body 0.4.6", - "mime", - "rustversion", - "tower-layer", - "tower-service", -] - -[[package]] -name = "backtrace" -version = "0.3.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets 0.52.6", -] - -[[package]] -name = "base16ct" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" - -[[package]] -name = "base16ct" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd307490d624467aa6f74b0eabb77633d1f758a7b25f12bceb0b22e08d9726f6" - -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "base64ct" -version = "1.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" - -[[package]] -name = "bcrypt-pbkdf" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aeac2e1fe888769f34f05ac343bbef98b14d1ffb292ab69d4608b3abc86f2a2" -dependencies = [ - "blowfish", - "pbkdf2", - "sha2 0.10.9", -] - -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - -[[package]] -name = "bindgen" -version = "0.66.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b84e06fc203107bfbad243f4aba2af864eb7db3b1cf46ea0a023b0b433d2a7" -dependencies = [ - "bitflags 2.9.4", - "cexpr", - "clang-sys", - "lazy_static", - "lazycell", - "log", - "peeking_take_while", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn 2.0.106", - "which", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" -dependencies = [ - "serde", -] - -[[package]] -name = "blake2" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" -dependencies = [ - "digest 0.10.7", -] - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array 0.14.7", -] - -[[package]] -name = "block-buffer" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" -dependencies = [ - "hybrid-array", -] - -[[package]] -name = "block-padding" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" -dependencies = [ - "generic-array 0.14.7", -] - -[[package]] -name = "block2" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" -dependencies = [ - "objc2 0.5.2", -] - -[[package]] -name = "block2" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "340d2f0bdb2a43c1d3cd40513185b2bd7def0aa1052f956455114bc98f82dcf2" -dependencies = [ - "objc2 0.6.2", -] - -[[package]] -name = "blocking" -version = "1.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" -dependencies = [ - "async-channel", - "async-task", - "futures-io", - "futures-lite", - "piper", -] - -[[package]] -name = "blowfish" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e412e2cd0f2b2d93e02543ceae7917b3c70331573df19ee046bcbc35e45e87d7" -dependencies = [ - "byteorder", - "cipher", -] - -[[package]] -name = "brotli" -version = "8.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", - "brotli-decompressor", -] - -[[package]] -name = "brotli-decompressor" -version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", -] - -[[package]] -name = "bumpalo" -version = "3.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" - -[[package]] -name = "bytemuck" -version = "1.23.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytes" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" -dependencies = [ - "serde", -] - -[[package]] -name = "cairo-rs" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" -dependencies = [ - "bitflags 2.9.4", - "cairo-sys-rs", - "glib", - "libc", - "once_cell", - "thiserror 1.0.69", -] - -[[package]] -name = "cairo-sys-rs" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" -dependencies = [ - "glib-sys", - "libc", - "system-deps", -] - -[[package]] -name = "camino" -version = "1.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0b03af37dad7a14518b7691d81acb0f8222604ad3d1b02f6b4bed5188c0cd5" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo-platform" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo_metadata" -version = "0.19.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" -dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", - "thiserror 2.0.16", -] - -[[package]] -name = "cargo_toml" -version = "0.22.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374b7c592d9c00c1f4972ea58390ac6b18cbb6ab79011f3bdc90a0b82ca06b77" -dependencies = [ - "serde", - "toml 0.9.5", -] - -[[package]] -name = "cbc" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" -dependencies = [ - "cipher", -] - -[[package]] -name = "cc" -version = "1.2.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" -dependencies = [ - "find-msvc-tools", - "jobserver", - "libc", - "shlex", -] - -[[package]] -name = "cesu8" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" - -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - -[[package]] -name = "cfb" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" -dependencies = [ - "byteorder", - "fnv", - "uuid", -] - -[[package]] -name = "cfg-expr" -version = "0.15.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" -dependencies = [ - "smallvec", - "target-lexicon", -] - -[[package]] -name = "cfg-if" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" - -[[package]] -name = "cfg_aliases" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" - -[[package]] -name = "cfg_aliases" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - -[[package]] -name = "chacha20" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - -[[package]] -name = "chrono" -version = "0.4.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" -dependencies = [ - "iana-time-zone", - "js-sys", - "num-traits", - "serde", - "wasm-bindgen", - "windows-link 0.2.0", -] - -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common 0.1.6", - "inout", -] - -[[package]] -name = "clang-sys" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" -dependencies = [ - "glob", - "libc", - "libloading 0.8.9", -] - -[[package]] -name = "cmake" -version = "0.1.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" -dependencies = [ - "cc", -] - -[[package]] -name = "cmov" -version = "0.5.0-pre.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5417da527aa9bf6a1e10a781231effd1edd3ee82f27d5f8529ac9b279babce96" - -[[package]] -name = "combine" -version = "4.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" -dependencies = [ - "bytes", - "memchr", -] - -[[package]] -name = "concurrent-queue" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "const-oid" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" - -[[package]] -name = "const-oid" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" - -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - -[[package]] -name = "cookie" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" -dependencies = [ - "time", - "version_check", -] - -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "core-graphics" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" -dependencies = [ - "bitflags 2.9.4", - "core-foundation 0.10.1", - "core-graphics-types", - "foreign-types 0.5.0", - "libc", -] - -[[package]] -name = "core-graphics" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "064badf302c3194842cf2c5d61f56cc88e54a759313879cdf03abdd27d0c3b97" -dependencies = [ - "bitflags 2.9.4", - "core-foundation 0.10.1", - "core-graphics-types", - "foreign-types 0.5.0", - "libc", -] - -[[package]] -name = "core-graphics-types" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" -dependencies = [ - "bitflags 2.9.4", - "core-foundation 0.10.1", - "libc", -] - -[[package]] -name = "core-models" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0940496e5c83c54f3b753d5317daec82e8edac71c33aaa1f666d76f518de2444" -dependencies = [ - "hax-lib", - "pastey", - "rand 0.9.2", -] - -[[package]] -name = "cpufeatures" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" -dependencies = [ - "libc", -] - -[[package]] -name = "crc32fast" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - -[[package]] -name = "crypto-bigint" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" -dependencies = [ - "generic-array 0.14.7", - "rand_core 0.6.4", - "subtle", - "zeroize", -] - -[[package]] -name = "crypto-bigint" -version = "0.7.0-rc.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37387ceb32048ff590f2cbd24d8b05fffe63c3f69a5cfa089d4f722ca4385a19" -dependencies = [ - "ctutils", - "num-traits", - "rand_core 0.10.0-rc-3", - "serdect", - "zeroize", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array 0.14.7", - "typenum", -] - -[[package]] -name = "crypto-common" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710" -dependencies = [ - "hybrid-array", -] - -[[package]] -name = "crypto-primes" -version = "0.7.0-pre.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79c98a281f9441200b24e3151407a629bfbe720399186e50516da939195e482" -dependencies = [ - "crypto-bigint 0.7.0-rc.18", - "libm", - "rand_core 0.10.0-rc-3", -] - -[[package]] -name = "cssparser" -version = "0.29.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93d03419cb5950ccfd3daf3ff1c7a36ace64609a1a8746d493df1ca0afde0fa" -dependencies = [ - "cssparser-macros", - "dtoa-short", - "itoa", - "matches", - "phf 0.10.1", - "proc-macro2", - "quote", - "smallvec", - "syn 1.0.109", -] - -[[package]] -name = "cssparser-macros" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" -dependencies = [ - "quote", - "syn 2.0.106", -] - -[[package]] -name = "csv" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52cd9d68cf7efc6ddfaaee42e7288d3a99d613d4b50f76ce9827ae0c6e14f938" -dependencies = [ - "csv-core", - "itoa", - "ryu", - "serde_core", -] - -[[package]] -name = "csv-core" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "704a3c26996a80471189265814dbc2c257598b96b8a7feae2d31ace646bb9782" -dependencies = [ - "memchr", -] - -[[package]] -name = "ctor" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" -dependencies = [ - "quote", - "syn 2.0.106", -] - -[[package]] -name = "ctr" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" -dependencies = [ - "cipher", -] - -[[package]] -name = "ctutils" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "758e5ed90be3c8abff7f9a6f37ab7f6d8c59c2210d448b81f3f508134aec84e4" -dependencies = [ - "cmov", -] - -[[package]] -name = "curve25519-dalek" -version = "4.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" -dependencies = [ - "cfg-if", - "cpufeatures", - "curve25519-dalek-derive", - "digest 0.10.7", - "fiat-crypto", - "rustc_version", - "subtle", - "zeroize", -] - -[[package]] -name = "curve25519-dalek-derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "darling" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 2.0.106", -] - -[[package]] -name = "darling_macro" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" -dependencies = [ - "darling_core", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "data-encoding" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" - -[[package]] -name = "deadpool" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0be2b1d1d6ec8d846f05e137292d0b89133caf95ef33695424c09568bdd39b1b" -dependencies = [ - "deadpool-runtime", - "lazy_static", - "num_cpus", - "tokio", -] - -[[package]] -name = "deadpool-postgres" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d697d376cbfa018c23eb4caab1fd1883dd9c906a8c034e8d9a3cb06a7e0bef9" -dependencies = [ - "async-trait", - "deadpool", - "getrandom 0.2.16", - "tokio", - "tokio-postgres", - "tracing", -] - -[[package]] -name = "deadpool-runtime" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "092966b41edc516079bdf31ec78a2e0588d1d0c08f78b91d8307215928642b2b" -dependencies = [ - "tokio", -] - -[[package]] -name = "delegate" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "780eb241654bf097afb00fc5f054a09b687dad862e485fdcf8399bb056565370" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "der" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" -dependencies = [ - "const-oid 0.9.6", - "pem-rfc7468 0.7.0", - "zeroize", -] - -[[package]] -name = "der" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71fd89660b2dc699704064e59e9dba0147b903e85319429e131620d022be411b" -dependencies = [ - "const-oid 0.10.2", - "pem-rfc7468 1.0.0", - "zeroize", -] - -[[package]] -name = "deranged" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d630bccd429a5bb5a64b5e94f693bfc48c9f8566418fda4c494cc94f911f87cc" -dependencies = [ - "powerfmt", - "serde", -] - -[[package]] -name = "derive_arbitrary" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "derive_more" -version = "0.99.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version", - "syn 2.0.106", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer 0.10.4", - "const-oid 0.9.6", - "crypto-common 0.1.6", - "subtle", -] - -[[package]] -name = "digest" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "285743a676ccb6b3e116bc14cc69319b957867930ae9c4822f8e0f54509d7243" -dependencies = [ - "block-buffer 0.12.0", - "const-oid 0.10.2", - "crypto-common 0.2.1", -] - -[[package]] -name = "dirs" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" -dependencies = [ - "libc", - "option-ext", - "redox_users", - "windows-sys 0.61.0", -] - -[[package]] -name = "dispatch2" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" -dependencies = [ - "bitflags 2.9.4", - "block2 0.6.1", - "libc", - "objc2 0.6.2", -] - -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "dlopen2" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b54f373ccf864bf587a89e880fb7610f8d73f3045f13580948ccbcaff26febff" -dependencies = [ - "dlopen2_derive", - "libc", - "once_cell", - "winapi", -] - -[[package]] -name = "dlopen2_derive" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "788160fb30de9cdd857af31c6a2675904b16ece8fc2737b2c7127ba368c9d0f4" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "downcast-rs" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" - -[[package]] -name = "dpi" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" -dependencies = [ - "serde", -] - -[[package]] -name = "dtoa" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04" - -[[package]] -name = "dtoa-short" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" -dependencies = [ - "dtoa", -] - -[[package]] -name = "dunce" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" - -[[package]] -name = "dyn-clone" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" - -[[package]] -name = "ecdsa" -version = "0.16.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" -dependencies = [ - "der 0.7.10", - "digest 0.10.7", - "elliptic-curve", - "rfc6979", - "signature 2.2.0", - "spki 0.7.3", -] - -[[package]] -name = "ed25519" -version = "2.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" -dependencies = [ - "pkcs8 0.10.2", - "signature 2.2.0", -] - -[[package]] -name = "ed25519-dalek" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" -dependencies = [ - "curve25519-dalek", - "ed25519", - "rand_core 0.6.4", - "serde", - "sha2 0.10.9", - "subtle", - "zeroize", -] - -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - -[[package]] -name = "elliptic-curve" -version = "0.13.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" -dependencies = [ - "base16ct 0.2.0", - "crypto-bigint 0.5.5", - "digest 0.10.7", - "ff", - "generic-array 0.14.7", - "group", - "hkdf", - "pem-rfc7468 0.7.0", - "pkcs8 0.10.2", - "rand_core 0.6.4", - "sec1", - "subtle", - "zeroize", -] - -[[package]] -name = "embed-resource" -version = "3.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6d81016d6c977deefb2ef8d8290da019e27cc26167e102185da528e6c0ab38" -dependencies = [ - "cc", - "memchr", - "rustc_version", - "toml 0.9.5", - "vswhom", - "winreg 0.55.0", -] - -[[package]] -name = "embed_plist" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7" - -[[package]] -name = "encoding_rs" -version = "0.8.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "endi" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf" - -[[package]] -name = "enum_dispatch" -version = "0.3.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa18ce2bc66555b3218614519ac839ddb759a7d6720732f979ef8d13be147ecd" -dependencies = [ - "once_cell", - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "enumflags2" -version = "0.7.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" -dependencies = [ - "enumflags2_derive", - "serde", -] - -[[package]] -name = "enumflags2_derive" -version = "0.7.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "erased-serde" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e004d887f51fcb9fef17317a2f3525c887d8aa3f4f50fed920816a688284a5b7" -dependencies = [ - "serde", - "typeid", -] - -[[package]] -name = "errno" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" -dependencies = [ - "libc", - "windows-sys 0.61.0", -] - -[[package]] -name = "event-listener" -version = "5.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] - -[[package]] -name = "event-listener-strategy" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" -dependencies = [ - "event-listener", - "pin-project-lite", -] - -[[package]] -name = "fallible-iterator" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" - -[[package]] -name = "fallible-iterator" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" - -[[package]] -name = "fallible-streaming-iterator" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" - -[[package]] -name = "fastrand" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" - -[[package]] -name = "faststr" -version = "0.2.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ca7d44d22004409a61c393afb3369c8f7bb74abcae49fe249ee01dcc3002113" -dependencies = [ - "bytes", - "rkyv", - "serde", - "simdutf8", -] - -[[package]] -name = "fdeflate" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" -dependencies = [ - "simd-adler32", -] - -[[package]] -name = "ff" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" -dependencies = [ - "rand_core 0.6.4", - "subtle", -] - -[[package]] -name = "fiat-crypto" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" - -[[package]] -name = "field-offset" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" -dependencies = [ - "memoffset", - "rustc_version", -] - -[[package]] -name = "filedescriptor" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e40758ed24c9b2eeb76c35fb0aebc66c626084edd827e07e1552279814c6682d" -dependencies = [ - "libc", - "thiserror 1.0.69", - "winapi", -] - -[[package]] -name = "filetime" -version = "0.2.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db" -dependencies = [ - "cfg-if", - "libc", - "libredox", -] - -[[package]] -name = "find-msvc-tools" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" - -[[package]] -name = "flate2" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared 0.1.1", -] - -[[package]] -name = "foreign-types" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" -dependencies = [ - "foreign-types-macros", - "foreign-types-shared 0.3.1", -] - -[[package]] -name = "foreign-types-macros" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "foreign-types-shared" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" - -[[package]] -name = "form_urlencoded" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "fs_extra" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" - -[[package]] -name = "futf" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" -dependencies = [ - "mac", - "new_debug_unreachable", -] - -[[package]] -name = "futures" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-executor" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" - -[[package]] -name = "futures-lite" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" -dependencies = [ - "fastrand", - "futures-core", - "futures-io", - "parking", - "pin-project-lite", -] - -[[package]] -name = "futures-macro" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "futures-sink" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" - -[[package]] -name = "futures-task" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" - -[[package]] -name = "futures-util" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - -[[package]] -name = "gdk" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9f245958c627ac99d8e529166f9823fb3b838d1d41fd2b297af3075093c2691" -dependencies = [ - "cairo-rs", - "gdk-pixbuf", - "gdk-sys", - "gio", - "glib", - "libc", - "pango", -] - -[[package]] -name = "gdk-pixbuf" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50e1f5f1b0bfb830d6ccc8066d18db35c487b1b2b1e8589b5dfe9f07e8defaec" -dependencies = [ - "gdk-pixbuf-sys", - "gio", - "glib", - "libc", - "once_cell", -] - -[[package]] -name = "gdk-pixbuf-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7" -dependencies = [ - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "gdk-sys" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c2d13f38594ac1e66619e188c6d5a1adb98d11b2fcf7894fc416ad76aa2f3f7" -dependencies = [ - "cairo-sys-rs", - "gdk-pixbuf-sys", - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "pango-sys", - "pkg-config", - "system-deps", -] - -[[package]] -name = "gdkwayland-sys" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "140071d506d223f7572b9f09b5e155afbd77428cd5cc7af8f2694c41d98dfe69" -dependencies = [ - "gdk-sys", - "glib-sys", - "gobject-sys", - "libc", - "pkg-config", - "system-deps", -] - -[[package]] -name = "gdkx11" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3caa00e14351bebbc8183b3c36690327eb77c49abc2268dd4bd36b856db3fbfe" -dependencies = [ - "gdk", - "gdkx11-sys", - "gio", - "glib", - "libc", - "x11", -] - -[[package]] -name = "gdkx11-sys" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e7445fe01ac26f11601db260dd8608fe172514eb63b3b5e261ea6b0f4428d" -dependencies = [ - "gdk-sys", - "glib-sys", - "libc", - "system-deps", - "x11", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", - "zeroize", -] - -[[package]] -name = "generic-array" -version = "1.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf57c49a95fd1fe24b90b3033bee6dc7e8f1288d51494cb44e627c295e38542" -dependencies = [ - "generic-array 0.14.7", - "rustversion", - "typenum", -] - -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - -[[package]] -name = "getrandom" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi 0.11.1+wasi-snapshot-preview1", - "wasm-bindgen", -] - -[[package]] -name = "getrandom" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" -dependencies = [ - "cfg-if", - "libc", - "r-efi", - "wasi 0.14.5+wasi-0.2.4", -] - -[[package]] -name = "ghash" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" -dependencies = [ - "opaque-debug", - "polyval", -] - -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - -[[package]] -name = "gio" -version = "0.18.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fc8f532f87b79cbc51a79748f16a6828fb784be93145a322fa14d06d354c73" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-util", - "gio-sys", - "glib", - "libc", - "once_cell", - "pin-project-lite", - "smallvec", - "thiserror 1.0.69", -] - -[[package]] -name = "gio-sys" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", - "winapi", -] - -[[package]] -name = "glib" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" -dependencies = [ - "bitflags 2.9.4", - "futures-channel", - "futures-core", - "futures-executor", - "futures-task", - "futures-util", - "gio-sys", - "glib-macros", - "glib-sys", - "gobject-sys", - "libc", - "memchr", - "once_cell", - "smallvec", - "thiserror 1.0.69", -] - -[[package]] -name = "glib-macros" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc" -dependencies = [ - "heck 0.4.1", - "proc-macro-crate 2.0.0", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "glib-sys" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" -dependencies = [ - "libc", - "system-deps", -] - -[[package]] -name = "glob" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" - -[[package]] -name = "gobject-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" -dependencies = [ - "glib-sys", - "libc", - "system-deps", -] - -[[package]] -name = "group" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" -dependencies = [ - "ff", - "rand_core 0.6.4", - "subtle", -] - -[[package]] -name = "gtk" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd56fb197bfc42bd5d2751f4f017d44ff59fbb58140c6b49f9b3b2bdab08506a" -dependencies = [ - "atk", - "cairo-rs", - "field-offset", - "futures-channel", - "gdk", - "gdk-pixbuf", - "gio", - "glib", - "gtk-sys", - "gtk3-macros", - "libc", - "pango", - "pkg-config", -] - -[[package]] -name = "gtk-sys" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f29a1c21c59553eb7dd40e918be54dccd60c52b049b75119d5d96ce6b624414" -dependencies = [ - "atk-sys", - "cairo-sys-rs", - "gdk-pixbuf-sys", - "gdk-sys", - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "pango-sys", - "system-deps", -] - -[[package]] -name = "gtk3-macros" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ff3c5b21f14f0736fed6dcfc0bfb4225ebf5725f3c0209edeec181e4d73e9d" -dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "h2" -version = "0.3.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http 0.2.12", - "indexmap 2.11.1", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash", - "allocator-api2", -] - -[[package]] -name = "hashbrown" -version = "0.15.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" - -[[package]] -name = "hashbrown" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" - -[[package]] -name = "hashlink" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" -dependencies = [ - "hashbrown 0.14.5", -] - -[[package]] -name = "hax-lib" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d9ba66d1739c68e0219b2b2238b5c4145f491ebf181b9c6ab561a19352ae86" -dependencies = [ - "hax-lib-macros", - "num-bigint", - "num-traits", -] - -[[package]] -name = "hax-lib-macros" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24ba777a231a58d1bce1d68313fa6b6afcc7966adef23d60f45b8a2b9b688bf1" -dependencies = [ - "hax-lib-macros-types", - "proc-macro-error2", - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "hax-lib-macros-types" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "867e19177d7425140b417cd27c2e05320e727ee682e98368f88b7194e80ad515" -dependencies = [ - "proc-macro2", - "quote", - "serde", - "serde_json", - "uuid", -] - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hermit-abi" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hex-literal" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" - -[[package]] -name = "hkdf" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" -dependencies = [ - "hmac", -] - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest 0.10.7", -] - -[[package]] -name = "home" -version = "0.5.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" -dependencies = [ - "windows-sys 0.61.0", -] - -[[package]] -name = "html5ever" -version = "0.29.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b7410cae13cbc75623c98ac4cbfd1f0bedddf3227afc24f370cf0f50a44a11c" -dependencies = [ - "log", - "mac", - "markup5ever", - "match_token", -] - -[[package]] -name = "http" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http 0.2.12", - "pin-project-lite", -] - -[[package]] -name = "http-body" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" -dependencies = [ - "bytes", - "http 1.3.1", -] - -[[package]] -name = "http-body-util" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" -dependencies = [ - "bytes", - "futures-core", - "http 1.3.1", - "http-body 1.0.1", - "pin-project-lite", -] - -[[package]] -name = "http-range-header" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" - -[[package]] -name = "httparse" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "hybrid-array" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1b229d73f5803b562cc26e4da0396c8610a4ee209f4fac8fa4f8d709166dc45" -dependencies = [ - "typenum", -] - -[[package]] -name = "hyper" -version = "0.14.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http 0.2.12", - "http-body 0.4.6", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2 0.5.10", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" -dependencies = [ - "atomic-waker", - "bytes", - "futures-channel", - "futures-core", - "http 1.3.1", - "http-body 1.0.1", - "httparse", - "itoa", - "pin-project-lite", - "pin-utils", - "smallvec", - "tokio", - "want", -] - -[[package]] -name = "hyper-rustls" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "399c78f9338483cb7e630c8474b07268983c6bd5acee012e4211f9f7bb21b070" -dependencies = [ - "futures-util", - "http 0.2.12", - "hyper 0.14.32", - "log", - "rustls 0.22.4", - "rustls-native-certs 0.7.3", - "rustls-pki-types", - "tokio", - "tokio-rustls 0.25.0", - "webpki-roots 0.26.11", -] - -[[package]] -name = "hyper-rustls" -version = "0.27.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" -dependencies = [ - "http 1.3.1", - "hyper 1.7.0", - "hyper-util", - "rustls 0.23.37", - "rustls-pki-types", - "tokio", - "tokio-rustls 0.26.4", - "tower-service", -] - -[[package]] -name = "hyper-timeout" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" -dependencies = [ - "hyper 0.14.32", - "pin-project-lite", - "tokio", - "tokio-io-timeout", -] - -[[package]] -name = "hyper-util" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e" -dependencies = [ - "base64 0.22.1", - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "http 1.3.1", - "http-body 1.0.1", - "hyper 1.7.0", - "ipnet", - "libc", - "percent-encoding", - "pin-project-lite", - "socket2 0.6.0", - "tokio", - "tower-service", - "tracing", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "log", - "wasm-bindgen", - "windows-core 0.61.2", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "ico" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e795dff5605e0f04bff85ca41b51a96b83e80b281e96231bcaaf1ac35103371" -dependencies = [ - "byteorder", - "png", -] - -[[package]] -name = "icu_collections" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" -dependencies = [ - "displaydoc", - "potential_utf", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locale_core" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_normalizer" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" - -[[package]] -name = "icu_properties" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_locale_core", - "icu_properties_data", - "icu_provider", - "potential_utf", - "zerotrie", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" - -[[package]] -name = "icu_provider" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" -dependencies = [ - "displaydoc", - "icu_locale_core", - "stable_deref_trait", - "tinystr", - "writeable", - "yoke", - "zerofrom", - "zerotrie", - "zerovec", -] - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "idna" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", - "serde", -] - -[[package]] -name = "indexmap" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "206a8042aec68fa4a62e8d3f7aa4ceb508177d9324faf261e1959e495b7a1921" -dependencies = [ - "equivalent", - "hashbrown 0.15.5", - "serde", -] - -[[package]] -name = "infer" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a588916bfdfd92e71cacef98a63d9b1f0d74d6599980d11894290e7ddefffcf7" -dependencies = [ - "cfb", -] - -[[package]] -name = "inout" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" -dependencies = [ - "block-padding", - "generic-array 0.14.7", -] - -[[package]] -name = "internal-russh-forked-ssh-key" -version = "0.6.16+upstream-0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe44f2bbd99fcb302e246e2d6bcf51aeda346d02a365f80296a07a8c711b6da6" -dependencies = [ - "argon2", - "bcrypt-pbkdf", - "digest 0.11.1", - "ecdsa", - "ed25519-dalek", - "hex", - "hmac", - "num-bigint-dig", - "p256", - "p384", - "p521", - "rand_core 0.6.4", - "rsa", - "sec1", - "sha1 0.10.6", - "sha1 0.11.0-rc.5", - "sha2 0.10.9", - "signature 2.2.0", - "signature 3.0.0-rc.6", - "ssh-cipher", - "ssh-encoding", - "subtle", - "zeroize", -] - -[[package]] -name = "io-uring" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" -dependencies = [ - "bitflags 2.9.4", - "cfg-if", - "libc", -] - -[[package]] -name = "ipnet" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" - -[[package]] -name = "iri-string" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" -dependencies = [ - "memchr", - "serde", -] - -[[package]] -name = "is-docker" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3" -dependencies = [ - "once_cell", -] - -[[package]] -name = "is-wsl" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5" -dependencies = [ - "is-docker", - "once_cell", -] - -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" - -[[package]] -name = "javascriptcore-rs" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca5671e9ffce8ffba57afc24070e906da7fc4b1ba66f2cabebf61bf2ea257fcc" -dependencies = [ - "bitflags 1.3.2", - "glib", - "javascriptcore-rs-sys", -] - -[[package]] -name = "javascriptcore-rs-sys" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1be78d14ffa4b75b66df31840478fef72b51f8c2465d4ca7c194da9f7a5124" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "jni" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" -dependencies = [ - "cesu8", - "cfg-if", - "combine", - "jni-sys", - "log", - "thiserror 1.0.69", - "walkdir", - "windows-sys 0.45.0", -] - -[[package]] -name = "jni-sys" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" - -[[package]] -name = "jobserver" -version = "0.1.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" -dependencies = [ - "getrandom 0.3.3", - "libc", -] - -[[package]] -name = "js-sys" -version = "0.3.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" -dependencies = [ - "once_cell", - "wasm-bindgen", -] - -[[package]] -name = "json-patch" -version = "3.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "863726d7afb6bc2590eeff7135d923545e5e964f004c2ccf8716c25e70a86f08" -dependencies = [ - "jsonptr", - "serde", - "serde_json", - "thiserror 1.0.69", -] - -[[package]] -name = "jsonptr" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dea2b27dd239b2556ed7a25ba842fe47fd602e7fc7433c2a8d6106d4d9edd70" -dependencies = [ - "serde", - "serde_json", -] - -[[package]] -name = "keyboard-types" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" -dependencies = [ - "bitflags 2.9.4", - "serde", - "unicode-segmentation", -] - -[[package]] -name = "kuchikiki" -version = "0.8.8-speedreader" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02cb977175687f33fa4afa0c95c112b987ea1443e5a51c8f8ff27dc618270cc2" -dependencies = [ - "cssparser", - "html5ever", - "indexmap 2.11.1", - "selectors", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -dependencies = [ - "spin", -] - -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - -[[package]] -name = "libappindicator" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03589b9607c868cc7ae54c0b2a22c8dc03dd41692d48f2d7df73615c6a95dc0a" -dependencies = [ - "glib", - "gtk", - "gtk-sys", - "libappindicator-sys", - "log", -] - -[[package]] -name = "libappindicator-sys" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf" -dependencies = [ - "gtk-sys", - "libloading 0.7.4", - "once_cell", -] - -[[package]] -name = "libc" -version = "0.2.175" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" - -[[package]] -name = "libcrux-intrinsics" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc9ee7ef66569dd7516454fe26de4e401c0c62073929803486b96744594b9632" -dependencies = [ - "core-models", - "hax-lib", -] - -[[package]] -name = "libcrux-ml-kem" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb6a88086bf11bd2ec90926c749c4a427f2e59841437dbdede8cde8a96334ab" -dependencies = [ - "hax-lib", - "libcrux-intrinsics", - "libcrux-platform", - "libcrux-secrets", - "libcrux-sha3", - "libcrux-traits", - "rand 0.9.2", - "tls_codec", -] - -[[package]] -name = "libcrux-platform" -version = "0.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db82d058aa76ea315a3b2092f69dfbd67ddb0e462038a206e1dcd73f058c0778" -dependencies = [ - "libc", -] - -[[package]] -name = "libcrux-secrets" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4dbbf6bc9f2bc0f20dc3bea3e5c99adff3bdccf6d2a40488963da69e2ec307" -dependencies = [ - "hax-lib", -] - -[[package]] -name = "libcrux-sha3" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2400bec764d1c75b8a496d5747cffe32f1fb864a12577f0aca2f55a92021c962" -dependencies = [ - "hax-lib", - "libcrux-intrinsics", - "libcrux-platform", - "libcrux-traits", -] - -[[package]] -name = "libcrux-traits" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9adfd58e79d860f6b9e40e35127bfae9e5bd3ade33201d1347459011a2add034" -dependencies = [ - "libcrux-secrets", - "rand 0.9.2", -] - -[[package]] -name = "libloading" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" -dependencies = [ - "cfg-if", - "winapi", -] - -[[package]] -name = "libloading" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" -dependencies = [ - "cfg-if", - "windows-link 0.2.0", -] - -[[package]] -name = "libm" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" - -[[package]] -name = "libredox" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3" -dependencies = [ - "bitflags 2.9.4", - "libc", - "redox_syscall", -] - -[[package]] -name = "libsql" -version = "0.9.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2329faffc510cc3c6b4f00169a39177cc7099d3ed7647fc92f7cf26e53a8d976" -dependencies = [ - "anyhow", - "async-stream", - "async-trait", - "base64 0.21.7", - "bincode", - "bitflags 2.9.4", - "bytes", - "chrono", - "crc32fast", - "fallible-iterator 0.3.0", - "futures", - "http 0.2.12", - "hyper 0.14.32", - "hyper-rustls 0.25.0", - "libsql-hrana", - "libsql-sqlite3-parser", - "libsql-sys", - "libsql_replication", - "parking_lot", - "serde", - "serde_json", - "thiserror 1.0.69", - "tokio", - "tokio-stream", - "tokio-util", - "tonic", - "tonic-web", - "tower 0.4.13", - "tower-http 0.4.4", - "tracing", - "uuid", - "zerocopy 0.7.35", -] - -[[package]] -name = "libsql-ffi" -version = "0.9.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cd1c1662822495393327856774f6803be25d85bfdcd5b9d4af35458f5daaf75" -dependencies = [ - "bindgen", - "cc", - "cmake", - "glob", -] - -[[package]] -name = "libsql-hrana" -version = "0.9.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "646d0aa75e412769018422f0da798f72e93bd51964f0b2ddad4317aa779ae444" -dependencies = [ - "base64 0.21.7", - "bytes", - "prost", - "serde", -] - -[[package]] -name = "libsql-rusqlite" -version = "0.9.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a4ce3a78c6e3c2b23b02ab6272df8340e1c53380497979d456882254f348d5f" -dependencies = [ - "bitflags 2.9.4", - "fallible-iterator 0.2.0", - "fallible-streaming-iterator", - "hashlink", - "libsql-ffi", - "smallvec", -] - -[[package]] -name = "libsql-sqlite3-parser" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15a90128c708356af8f7d767c9ac2946692c9112b4f74f07b99a01a60680e413" -dependencies = [ - "bitflags 2.9.4", - "cc", - "fallible-iterator 0.3.0", - "indexmap 2.11.1", - "log", - "memchr", - "phf 0.11.3", - "phf_codegen 0.11.3", - "phf_shared 0.11.3", - "uncased", -] - -[[package]] -name = "libsql-sys" -version = "0.9.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a3c326fcfc36fe7578238d5ee6b58c529f8c76372acd61ec50267529cdaff95" -dependencies = [ - "bytes", - "libsql-ffi", - "libsql-rusqlite", - "once_cell", - "tracing", - "zerocopy 0.7.35", -] - -[[package]] -name = "libsql_replication" -version = "0.9.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d9a2e469ac8400659bd31f81a745908bcc5cb6b40be2f2ff8de90b15bec5501" -dependencies = [ - "aes", - "async-stream", - "async-trait", - "bytes", - "cbc", - "libsql-rusqlite", - "libsql-sys", - "parking_lot", - "prost", - "serde", - "thiserror 1.0.69", - "tokio", - "tokio-stream", - "tokio-util", - "tonic", - "tracing", - "uuid", - "zerocopy 0.7.35", -] - -[[package]] -name = "linux-raw-sys" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" - -[[package]] -name = "linux-raw-sys" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" - -[[package]] -name = "litemap" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" - -[[package]] -name = "lock_api" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" - -[[package]] -name = "mac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" - -[[package]] -name = "markup5ever" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7a7213d12e1864c0f002f52c2923d4556935a43dec5e71355c2760e0f6e7a18" -dependencies = [ - "log", - "phf 0.11.3", - "phf_codegen 0.11.3", - "string_cache", - "string_cache_codegen", - "tendril", -] - -[[package]] -name = "match_token" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "matches" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" - -[[package]] -name = "matchit" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" - -[[package]] -name = "md-5" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" -dependencies = [ - "cfg-if", - "digest 0.10.7", -] - -[[package]] -name = "md5" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" - -[[package]] -name = "memchr" -version = "2.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" - -[[package]] -name = "memoffset" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" -dependencies = [ - "autocfg", -] - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "minisign-verify" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22f9645cb765ea72b8111f36c522475d2daa0d22c957a9826437e97534bc4e9e" - -[[package]] -name = "miniz_oxide" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", - "simd-adler32", -] - -[[package]] -name = "mio" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" -dependencies = [ - "libc", - "wasi 0.11.1+wasi-snapshot-preview1", - "windows-sys 0.59.0", -] - -[[package]] -name = "muda" -version = "0.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01c1738382f66ed56b3b9c8119e794a2e23148ac8ea214eda86622d4cb9d415a" -dependencies = [ - "crossbeam-channel", - "dpi", - "gtk", - "keyboard-types", - "objc2 0.6.2", - "objc2-app-kit", - "objc2-core-foundation", - "objc2-foundation 0.3.1", - "once_cell", - "png", - "serde", - "thiserror 2.0.16", - "windows-sys 0.60.2", -] - -[[package]] -name = "munge" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e17401f259eba956ca16491461b6e8f72913a0a114e39736ce404410f915a0c" -dependencies = [ - "munge_macro", -] - -[[package]] -name = "munge_macro" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4568f25ccbd45ab5d5603dc34318c1ec56b117531781260002151b8530a9f931" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "native-tls" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe 0.1.6", - "openssl-sys", - "schannel", - "security-framework 2.11.1", - "security-framework-sys", - "tempfile", -] - -[[package]] -name = "ndk" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" -dependencies = [ - "bitflags 2.9.4", - "jni-sys", - "log", - "ndk-sys", - "num_enum", - "raw-window-handle", - "thiserror 1.0.69", -] - -[[package]] -name = "ndk-context" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" - -[[package]] -name = "ndk-sys" -version = "0.6.0+11769913" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" -dependencies = [ - "jni-sys", -] - -[[package]] -name = "new_debug_unreachable" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" - -[[package]] -name = "nix" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" -dependencies = [ - "bitflags 2.9.4", - "cfg-if", - "cfg_aliases 0.1.1", - "libc", -] - -[[package]] -name = "nix" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" -dependencies = [ - "bitflags 2.9.4", - "cfg-if", - "cfg_aliases 0.2.1", - "libc", -] - -[[package]] -name = "nix" -version = "0.30.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" -dependencies = [ - "bitflags 2.9.4", - "cfg-if", - "cfg_aliases 0.2.1", - "libc", - "memoffset", -] - -[[package]] -name = "nodrop" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "ntapi" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3b335231dfd352ffb0f8017f3b6027a4917f7df785ea2143d8af2adc66980ae" -dependencies = [ - "winapi", -] - -[[package]] -name = "nu-ansi-term" -version = "0.50.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", - "rand 0.8.5", -] - -[[package]] -name = "num-bigint-dig" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" -dependencies = [ - "lazy_static", - "libm", - "num-integer", - "num-iter", - "num-traits", - "rand 0.8.5", - "serde", - "smallvec", -] - -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "num_enum" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a" -dependencies = [ - "num_enum_derive", - "rustversion", -] - -[[package]] -name = "num_enum_derive" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" -dependencies = [ - "proc-macro-crate 3.3.0", - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "objc-sys" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" - -[[package]] -name = "objc2" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" -dependencies = [ - "objc-sys", - "objc2-encode", -] - -[[package]] -name = "objc2" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561f357ba7f3a2a61563a186a163d0a3a5247e1089524a3981d49adb775078bc" -dependencies = [ - "objc2-encode", - "objc2-exception-helper", -] - -[[package]] -name = "objc2-app-kit" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6f29f568bec459b0ddff777cec4fe3fd8666d82d5a40ebd0ff7e66134f89bcc" -dependencies = [ - "bitflags 2.9.4", - "block2 0.6.1", - "objc2 0.6.2", - "objc2-core-foundation", - "objc2-foundation 0.3.1", -] - -[[package]] -name = "objc2-core-foundation" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" -dependencies = [ - "bitflags 2.9.4", - "dispatch2", - "objc2 0.6.2", -] - -[[package]] -name = "objc2-core-graphics" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989c6c68c13021b5c2d6b71456ebb0f9dc78d752e86a98da7c716f4f9470f5a4" -dependencies = [ - "bitflags 2.9.4", - "objc2-core-foundation", -] - -[[package]] -name = "objc2-encode" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" - -[[package]] -name = "objc2-exception-helper" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7a1c5fbb72d7735b076bb47b578523aedc40f3c439bea6dfd595c089d79d98a" -dependencies = [ - "cc", -] - -[[package]] -name = "objc2-foundation" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" -dependencies = [ - "bitflags 2.9.4", - "block2 0.5.1", - "libc", - "objc2 0.5.2", -] - -[[package]] -name = "objc2-foundation" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c" -dependencies = [ - "bitflags 2.9.4", - "block2 0.6.1", - "libc", - "objc2 0.6.2", - "objc2-core-foundation", -] - -[[package]] -name = "objc2-io-kit" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71c1c64d6120e51cd86033f67176b1cb66780c2efe34dec55176f77befd93c0a" -dependencies = [ - "libc", - "objc2-core-foundation", -] - -[[package]] -name = "objc2-metal" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" -dependencies = [ - "bitflags 2.9.4", - "block2 0.5.1", - "objc2 0.5.2", - "objc2-foundation 0.2.2", -] - -[[package]] -name = "objc2-osa-kit" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26bb88504b5a050dbba515d2414607bf5e57dd56b107bc5f0351197a3e7bdc5d" -dependencies = [ - "bitflags 2.9.4", - "objc2 0.6.2", - "objc2-app-kit", - "objc2-foundation 0.3.1", -] - -[[package]] -name = "objc2-quartz-core" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" -dependencies = [ - "bitflags 2.9.4", - "block2 0.5.1", - "objc2 0.5.2", - "objc2-foundation 0.2.2", - "objc2-metal", -] - -[[package]] -name = "objc2-ui-kit" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25b1312ad7bc8a0e92adae17aa10f90aae1fb618832f9b993b022b591027daed" -dependencies = [ - "bitflags 2.9.4", - "objc2 0.6.2", - "objc2-core-foundation", - "objc2-foundation 0.3.1", -] - -[[package]] -name = "objc2-web-kit" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91672909de8b1ce1c2252e95bbee8c1649c9ad9d14b9248b3d7b4c47903c47ad" -dependencies = [ - "bitflags 2.9.4", - "block2 0.6.1", - "objc2 0.6.2", - "objc2-app-kit", - "objc2-core-foundation", - "objc2-foundation 0.3.1", -] - -[[package]] -name = "object" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" - -[[package]] -name = "opaque-debug" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" - -[[package]] -name = "open" -version = "5.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2483562e62ea94312f3576a7aca397306df7990b8d89033e18766744377ef95" -dependencies = [ - "dunce", - "is-wsl", - "libc", - "pathdiff", -] - -[[package]] -name = "openssl" -version = "0.10.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24ad14dd45412269e1a30f52ad8f0664f0f4f4a89ee8fe28c3b3527021ebb654" -dependencies = [ - "bitflags 2.9.4", - "cfg-if", - "foreign-types 0.3.2", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "openssl-probe" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" - -[[package]] -name = "openssl-probe" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" - -[[package]] -name = "openssl-sys" -version = "0.9.110" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a9f0075ba3c21b09f8e8b2026584b1d18d49388648f2fbbf3c97ea8deced8e2" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "option-ext" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" - -[[package]] -name = "ordered-stream" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" -dependencies = [ - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "os_pipe" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db335f4760b14ead6290116f2427bf33a14d4f0617d49f78a246de10c1831224" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] - -[[package]] -name = "osakit" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "732c71caeaa72c065bb69d7ea08717bd3f4863a4f451402fc9513e29dbd5261b" -dependencies = [ - "objc2 0.6.2", - "objc2-foundation 0.3.1", - "objc2-osa-kit", - "serde", - "serde_json", - "thiserror 2.0.16", -] - -[[package]] -name = "p256" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" -dependencies = [ - "ecdsa", - "elliptic-curve", - "primeorder", - "sha2 0.10.9", -] - -[[package]] -name = "p384" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" -dependencies = [ - "ecdsa", - "elliptic-curve", - "primeorder", - "sha2 0.10.9", -] - -[[package]] -name = "p521" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc9e2161f1f215afdfce23677034ae137bbd45016a880c2eb3ba8eb95f085b2" -dependencies = [ - "base16ct 0.2.0", - "ecdsa", - "elliptic-curve", - "primeorder", - "rand_core 0.6.4", - "sha2 0.10.9", -] - -[[package]] -name = "pageant" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b537f975f6d8dcf48db368d7ec209d583b015713b5df0f5d92d2631e4ff5595" -dependencies = [ - "byteorder", - "bytes", - "delegate", - "futures", - "log", - "rand 0.8.5", - "sha2 0.10.9", - "thiserror 1.0.69", - "tokio", - "windows 0.62.1", - "windows-strings 0.5.0", -] - -[[package]] -name = "pango" -version = "0.18.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ca27ec1eb0457ab26f3036ea52229edbdb74dee1edd29063f5b9b010e7ebee4" -dependencies = [ - "gio", - "glib", - "libc", - "once_cell", - "pango-sys", -] - -[[package]] -name = "pango-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "parking" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" - -[[package]] -name = "parking_lot" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.52.6", -] - -[[package]] -name = "password-hash" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" -dependencies = [ - "base64ct", - "rand_core 0.6.4", - "subtle", -] - -[[package]] -name = "pastey" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec" - -[[package]] -name = "pathdiff" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" - -[[package]] -name = "pbkdf2" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" -dependencies = [ - "digest 0.10.7", - "hmac", -] - -[[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" - -[[package]] -name = "pem-rfc7468" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" -dependencies = [ - "base64ct", -] - -[[package]] -name = "pem-rfc7468" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6305423e0e7738146434843d1694d621cce767262b2a86910beab705e4493d9" -dependencies = [ - "base64ct", -] - -[[package]] -name = "percent-encoding" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" - -[[package]] -name = "phf" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" -dependencies = [ - "phf_shared 0.8.0", -] - -[[package]] -name = "phf" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" -dependencies = [ - "phf_macros 0.10.0", - "phf_shared 0.10.0", - "proc-macro-hack", -] - -[[package]] -name = "phf" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" -dependencies = [ - "phf_macros 0.11.3", - "phf_shared 0.11.3", -] - -[[package]] -name = "phf" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" -dependencies = [ - "phf_shared 0.13.1", - "serde", -] - -[[package]] -name = "phf_codegen" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" -dependencies = [ - "phf_generator 0.8.0", - "phf_shared 0.8.0", -] - -[[package]] -name = "phf_codegen" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" -dependencies = [ - "phf_generator 0.11.3", - "phf_shared 0.11.3", -] - -[[package]] -name = "phf_generator" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" -dependencies = [ - "phf_shared 0.8.0", - "rand 0.7.3", -] - -[[package]] -name = "phf_generator" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" -dependencies = [ - "phf_shared 0.10.0", - "rand 0.8.5", -] - -[[package]] -name = "phf_generator" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" -dependencies = [ - "phf_shared 0.11.3", - "rand 0.8.5", -] - -[[package]] -name = "phf_macros" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0" -dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", - "proc-macro-hack", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "phf_macros" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" -dependencies = [ - "phf_generator 0.11.3", - "phf_shared 0.11.3", - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "phf_shared" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" -dependencies = [ - "siphasher 0.3.11", -] - -[[package]] -name = "phf_shared" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" -dependencies = [ - "siphasher 0.3.11", -] - -[[package]] -name = "phf_shared" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" -dependencies = [ - "siphasher 1.0.1", - "uncased", -] - -[[package]] -name = "phf_shared" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" -dependencies = [ - "siphasher 1.0.1", -] - -[[package]] -name = "pin-project" -version = "1.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "piper" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" -dependencies = [ - "atomic-waker", - "fastrand", - "futures-io", -] - -[[package]] -name = "pkcs1" -version = "0.8.0-rc.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "986d2e952779af96ea048f160fd9194e1751b4faea78bcf3ceb456efe008088e" -dependencies = [ - "der 0.8.0", - "spki 0.8.0-rc.4", -] - -[[package]] -name = "pkcs5" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e847e2c91a18bfa887dd028ec33f2fe6f25db77db3619024764914affe8b69a6" -dependencies = [ - "aes", - "cbc", - "der 0.7.10", - "pbkdf2", - "scrypt", - "sha2 0.10.9", - "spki 0.7.3", -] - -[[package]] -name = "pkcs8" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" -dependencies = [ - "der 0.7.10", - "pkcs5", - "rand_core 0.6.4", - "spki 0.7.3", -] - -[[package]] -name = "pkcs8" -version = "0.11.0-rc.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12922b6296c06eb741b02d7b5161e3aaa22864af38dfa025a1a3ba3f68c84577" -dependencies = [ - "der 0.8.0", - "spki 0.8.0-rc.4", -] - -[[package]] -name = "pkg-config" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" - -[[package]] -name = "plist" -version = "1.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3af6b589e163c5a788fab00ce0c0366f6efbb9959c2f9874b224936af7fce7e1" -dependencies = [ - "base64 0.22.1", - "indexmap 2.11.1", - "quick-xml", - "serde", - "time", -] - -[[package]] -name = "png" -version = "0.17.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" -dependencies = [ - "bitflags 1.3.2", - "crc32fast", - "fdeflate", - "flate2", - "miniz_oxide", -] - -[[package]] -name = "polling" -version = "3.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5bd19146350fe804f7cb2669c851c03d69da628803dab0d98018142aaa5d829" -dependencies = [ - "cfg-if", - "concurrent-queue", - "hermit-abi", - "pin-project-lite", - "rustix 1.1.2", - "windows-sys 0.60.2", -] - -[[package]] -name = "poly1305" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" -dependencies = [ - "cpufeatures", - "opaque-debug", - "universal-hash", -] - -[[package]] -name = "polyval" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" -dependencies = [ - "cfg-if", - "cpufeatures", - "opaque-debug", - "universal-hash", -] - -[[package]] -name = "portable-pty" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4a596a2b3d2752d94f51fac2d4a96737b8705dddd311a32b9af47211f08671e" -dependencies = [ - "anyhow", - "bitflags 1.3.2", - "downcast-rs", - "filedescriptor", - "lazy_static", - "libc", - "log", - "nix 0.28.0", - "serial2", - "shared_library", - "shell-words", - "winapi", - "winreg 0.10.1", -] - -[[package]] -name = "postgres-native-tls" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac73153d92e4bde922bd6f1dfba7f1ab8132266c031153b55e20a1521cd36d49" -dependencies = [ - "native-tls", - "tokio", - "tokio-native-tls", - "tokio-postgres", -] - -[[package]] -name = "postgres-protocol" -version = "0.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbef655056b916eb868048276cfd5d6a7dea4f81560dfd047f97c8c6fe3fcfd4" -dependencies = [ - "base64 0.22.1", - "byteorder", - "bytes", - "fallible-iterator 0.2.0", - "hmac", - "md-5", - "memchr", - "rand 0.9.2", - "sha2 0.10.9", - "stringprep", -] - -[[package]] -name = "postgres-types" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef4605b7c057056dd35baeb6ac0c0338e4975b1f2bef0f65da953285eb007095" -dependencies = [ - "bytes", - "fallible-iterator 0.2.0", - "postgres-protocol", -] - -[[package]] -name = "potential_utf" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" -dependencies = [ - "zerovec", -] - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "ppv-lite86" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" -dependencies = [ - "zerocopy 0.8.27", -] - -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - -[[package]] -name = "prettyplease" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" -dependencies = [ - "proc-macro2", - "syn 2.0.106", -] - -[[package]] -name = "primeorder" -version = "0.13.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" -dependencies = [ - "elliptic-curve", -] - -[[package]] -name = "proc-macro-crate" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" -dependencies = [ - "once_cell", - "toml_edit 0.19.15", -] - -[[package]] -name = "proc-macro-crate" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" -dependencies = [ - "toml_edit 0.20.7", -] - -[[package]] -name = "proc-macro-crate" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" -dependencies = [ - "toml_edit 0.22.27", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" -dependencies = [ - "proc-macro2", - "quote", -] - -[[package]] -name = "proc-macro-error2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" -dependencies = [ - "proc-macro-error-attr2", - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - -[[package]] -name = "proc-macro2" -version = "1.0.101" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "prost" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" -dependencies = [ - "bytes", - "prost-derive", -] - -[[package]] -name = "prost-derive" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" -dependencies = [ - "anyhow", - "itertools", - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "ptr_meta" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9a0cf95a1196af61d4f1cbdab967179516d9a4a4312af1f31948f8f6224a79" -dependencies = [ - "ptr_meta_derive", -] - -[[package]] -name = "ptr_meta_derive" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7347867d0a7e1208d93b46767be83e2b8f978c3dad35f775ac8d8847551d6fe1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "quick-xml" -version = "0.38.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42a232e7487fc2ef313d96dde7948e7a3c05101870d8985e4fd8d26aedd27b89" -dependencies = [ - "memchr", -] - -[[package]] -name = "quote" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "r-efi" -version = "5.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" - -[[package]] -name = "rancor" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a063ea72381527c2a0561da9c80000ef822bdd7c3241b1cc1b12100e3df081ee" -dependencies = [ - "ptr_meta", -] - -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", - "rand_pcg", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" -dependencies = [ - "rand_chacha 0.9.0", - "rand_core 0.9.3", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" -dependencies = [ - "ppv-lite86", - "rand_core 0.9.3", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.16", -] - -[[package]] -name = "rand_core" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" -dependencies = [ - "getrandom 0.3.3", -] - -[[package]] -name = "rand_core" -version = "0.10.0-rc-3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f66ee92bc15280519ef199a274fe0cafff4245d31bc39aaa31c011ad56cb1f05" - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "rand_pcg" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "raw-window-handle" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" - -[[package]] -name = "rayon" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - -[[package]] -name = "redox_syscall" -version = "0.5.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" -dependencies = [ - "bitflags 2.9.4", -] - -[[package]] -name = "redox_users" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" -dependencies = [ - "getrandom 0.2.16", - "libredox", - "thiserror 2.0.16", -] - -[[package]] -name = "ref-cast" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" -dependencies = [ - "ref-cast-impl", -] - -[[package]] -name = "ref-cast-impl" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "regex" -version = "1.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" - -[[package]] -name = "rend" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cadadef317c2f20755a64d7fdc48f9e7178ee6b0e1f7fce33fa60f1d68a276e6" - -[[package]] -name = "reqwest" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801" -dependencies = [ - "base64 0.22.1", - "bytes", - "futures-core", - "futures-util", - "http 1.3.1", - "http-body 1.0.1", - "http-body-util", - "hyper 1.7.0", - "hyper-rustls 0.27.7", - "hyper-util", - "js-sys", - "log", - "percent-encoding", - "pin-project-lite", - "rustls 0.23.37", - "rustls-pki-types", - "rustls-platform-verifier", - "serde", - "serde_json", - "sync_wrapper 1.0.2", - "tokio", - "tokio-rustls 0.26.4", - "tokio-util", - "tower 0.5.2", - "tower-http 0.6.8", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-streams", - "web-sys", -] - -[[package]] -name = "rfc6979" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" -dependencies = [ - "hmac", - "subtle", -] - -[[package]] -name = "rfd" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15ad77d9e70a92437d8f74c35d99b4e4691128df018833e99f90bcd36152672" -dependencies = [ - "block2 0.6.1", - "dispatch2", - "glib-sys", - "gobject-sys", - "gtk-sys", - "js-sys", - "log", - "objc2 0.6.2", - "objc2-app-kit", - "objc2-core-foundation", - "objc2-foundation 0.3.1", - "raw-window-handle", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "windows-sys 0.60.2", -] - -[[package]] -name = "ring" -version = "0.17.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" -dependencies = [ - "cc", - "cfg-if", - "getrandom 0.2.16", - "libc", - "untrusted 0.9.0", - "windows-sys 0.52.0", -] - -[[package]] -name = "rkyv" -version = "0.8.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a30e631b7f4a03dee9056b8ef6982e8ba371dd5bedb74d3ec86df4499132c70" -dependencies = [ - "bytes", - "hashbrown 0.16.1", - "indexmap 2.11.1", - "munge", - "ptr_meta", - "rancor", - "rend", - "rkyv_derive", - "tinyvec", - "uuid", -] - -[[package]] -name = "rkyv_derive" -version = "0.8.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8100bb34c0a1d0f907143db3149e6b4eea3c33b9ee8b189720168e818303986f" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "rsa" -version = "0.10.0-rc.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9a2b1eacbc34fbaf77f6f1db1385518446008d49b9f9f59dc9d1340fce4ca9e" -dependencies = [ - "const-oid 0.10.2", - "crypto-bigint 0.7.0-rc.18", - "crypto-primes", - "digest 0.11.1", - "pkcs1", - "pkcs8 0.11.0-rc.11", - "rand_core 0.10.0-rc-3", - "sha2 0.11.0-rc.5", - "signature 3.0.0-rc.6", - "spki 0.8.0-rc.4", - "zeroize", -] - -[[package]] -name = "rsql" -version = "1.1.5" -dependencies = [ - "csv", - "deadpool-postgres", - "futures-util", - "libsql", - "native-tls", - "portable-pty", - "postgres-native-tls", - "rayon", - "russh", - "serde", - "serde_json", - "sonic-rs", - "sysinfo", - "tauri", - "tauri-build", - "tauri-plugin-dialog", - "tauri-plugin-fs", - "tauri-plugin-opener", - "tauri-plugin-process", - "tauri-plugin-shell", - "tauri-plugin-updater", - "thiserror 2.0.16", - "tokio", - "tokio-postgres", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "russh" -version = "0.57.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afe62631a04a1f4d71a14b99505483b95ff97c503b67d876c042fce659186956" -dependencies = [ - "aes", - "aws-lc-rs", - "bitflags 2.9.4", - "block-padding", - "byteorder", - "bytes", - "cbc", - "ctr", - "curve25519-dalek", - "data-encoding", - "delegate", - "der 0.7.10", - "digest 0.10.7", - "ecdsa", - "ed25519-dalek", - "elliptic-curve", - "enum_dispatch", - "flate2", - "futures", - "generic-array 1.3.5", - "getrandom 0.2.16", - "hex-literal", - "hmac", - "home", - "inout", - "internal-russh-forked-ssh-key", - "libcrux-ml-kem", - "log", - "md5", - "num-bigint", - "p256", - "p384", - "p521", - "pageant", - "pbkdf2", - "pkcs1", - "pkcs5", - "pkcs8 0.10.2", - "rand 0.9.2", - "rand_core 0.10.0-rc-3", - "rsa", - "russh-cryptovec", - "russh-util", - "sec1", - "sha1 0.10.6", - "sha2 0.10.9", - "signature 2.2.0", - "spki 0.7.3", - "ssh-encoding", - "subtle", - "thiserror 1.0.69", - "tokio", - "typenum", - "zeroize", -] - -[[package]] -name = "russh-cryptovec" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb0ed583ff0f6b4aa44c7867dd7108df01b30571ee9423e250b4cc939f8c6cf" -dependencies = [ - "libc", - "log", - "nix 0.29.0", - "ssh-encoding", - "winapi", -] - -[[package]] -name = "russh-util" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "668424a5dde0bcb45b55ba7de8476b93831b4aa2fa6947e145f3b053e22c60b6" -dependencies = [ - "chrono", - "tokio", - "wasm-bindgen", - "wasm-bindgen-futures", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - -[[package]] -name = "rustix" -version = "0.38.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" -dependencies = [ - "bitflags 2.9.4", - "errno", - "libc", - "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", -] - -[[package]] -name = "rustix" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" -dependencies = [ - "bitflags 2.9.4", - "errno", - "libc", - "linux-raw-sys 0.11.0", - "windows-sys 0.61.0", -] - -[[package]] -name = "rustls" -version = "0.22.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" -dependencies = [ - "log", - "ring", - "rustls-pki-types", - "rustls-webpki 0.102.8", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls" -version = "0.23.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" -dependencies = [ - "once_cell", - "ring", - "rustls-pki-types", - "rustls-webpki 0.103.9", - "subtle", - "zeroize", -] - -[[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", - "rustls-pki-types", - "schannel", - "security-framework 2.11.1", -] - -[[package]] -name = "rustls-native-certs" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" -dependencies = [ - "openssl-probe 0.2.1", - "rustls-pki-types", - "schannel", - "security-framework 3.5.1", -] - -[[package]] -name = "rustls-pemfile" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "rustls-pki-types" -version = "1.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" -dependencies = [ - "zeroize", -] - -[[package]] -name = "rustls-platform-verifier" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" -dependencies = [ - "core-foundation 0.10.1", - "core-foundation-sys", - "jni", - "log", - "once_cell", - "rustls 0.23.37", - "rustls-native-certs 0.8.3", - "rustls-platform-verifier-android", - "rustls-webpki 0.103.9", - "security-framework 3.5.1", - "security-framework-sys", - "webpki-root-certs", - "windows-sys 0.61.0", -] - -[[package]] -name = "rustls-platform-verifier-android" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" - -[[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.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" -dependencies = [ - "ring", - "rustls-pki-types", - "untrusted 0.9.0", -] - -[[package]] -name = "rustversion" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" - -[[package]] -name = "ryu" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" - -[[package]] -name = "salsa20" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" -dependencies = [ - "cipher", -] - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "schannel" -version = "0.1.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" -dependencies = [ - "windows-sys 0.61.0", -] - -[[package]] -name = "schemars" -version = "0.8.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" -dependencies = [ - "dyn-clone", - "indexmap 1.9.3", - "schemars_derive", - "serde", - "serde_json", - "url", - "uuid", -] - -[[package]] -name = "schemars" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" -dependencies = [ - "dyn-clone", - "ref-cast", - "serde", - "serde_json", -] - -[[package]] -name = "schemars" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0" -dependencies = [ - "dyn-clone", - "ref-cast", - "serde", - "serde_json", -] - -[[package]] -name = "schemars_derive" -version = "0.8.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" -dependencies = [ - "proc-macro2", - "quote", - "serde_derive_internals", - "syn 2.0.106", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "scrypt" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f" -dependencies = [ - "pbkdf2", - "salsa20", - "sha2 0.10.9", -] - -[[package]] -name = "sec1" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" -dependencies = [ - "base16ct 0.2.0", - "der 0.7.10", - "generic-array 0.14.7", - "pkcs8 0.10.2", - "subtle", - "zeroize", -] - -[[package]] -name = "security-framework" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" -dependencies = [ - "bitflags 2.9.4", - "core-foundation 0.9.4", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework" -version = "3.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" -dependencies = [ - "bitflags 2.9.4", - "core-foundation 0.10.1", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "selectors" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c37578180969d00692904465fb7f6b3d50b9a2b952b87c23d0e2e5cb5013416" -dependencies = [ - "bitflags 1.3.2", - "cssparser", - "derive_more", - "fxhash", - "log", - "phf 0.8.0", - "phf_codegen 0.8.0", - "precomputed-hash", - "servo_arc", - "smallvec", -] - -[[package]] -name = "semver" -version = "1.0.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" -dependencies = [ - "serde", -] - -[[package]] -name = "serde" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" -dependencies = [ - "serde_core", - "serde_derive", -] - -[[package]] -name = "serde-untagged" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34836a629bcbc6f1afdf0907a744870039b1e14c0561cb26094fa683b158eff3" -dependencies = [ - "erased-serde", - "serde", - "typeid", -] - -[[package]] -name = "serde_core" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "serde_derive_internals" -version = "0.29.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "serde_json" -version = "1.0.149" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" -dependencies = [ - "itoa", - "memchr", - "serde", - "serde_core", - "zmij", -] - -[[package]] -name = "serde_repr" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "serde_spanned" -version = "0.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_spanned" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_with" -version = "3.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2c45cd61fefa9db6f254525d46e392b852e0e61d9a1fd36e5bd183450a556d5" -dependencies = [ - "base64 0.22.1", - "chrono", - "hex", - "indexmap 1.9.3", - "indexmap 2.11.1", - "schemars 0.9.0", - "schemars 1.0.4", - "serde", - "serde_derive", - "serde_json", - "serde_with_macros", - "time", -] - -[[package]] -name = "serde_with_macros" -version = "3.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de90945e6565ce0d9a25098082ed4ee4002e047cb59892c318d66821e14bb30f" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "serdect" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9af4a3e75ebd5599b30d4de5768e00b5095d518a79fefc3ecbaf77e665d1ec06" -dependencies = [ - "base16ct 1.0.0", - "serde", -] - -[[package]] -name = "serial2" -version = "0.2.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1401f562d358cdfdbdf8946e51a7871ede1db68bd0fd99bedc79e400241550" -dependencies = [ - "cfg-if", - "libc", - "winapi", -] - -[[package]] -name = "serialize-to-javascript" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04f3666a07a197cdb77cdf306c32be9b7f598d7060d50cfd4d5aa04bfd92f6c5" -dependencies = [ - "serde", - "serde_json", - "serialize-to-javascript-impl", -] - -[[package]] -name = "serialize-to-javascript-impl" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "servo_arc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52aa42f8fdf0fed91e5ce7f23d8138441002fa31dca008acf47e6fd4721f741" -dependencies = [ - "nodrop", - "stable_deref_trait", -] - -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.7", -] - -[[package]] -name = "sha1" -version = "0.11.0-rc.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b167252f3c126be0d8926639c4c4706950f01445900c4b3db0fd7e89fcb750a" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.11.1", -] - -[[package]] -name = "sha2" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.7", -] - -[[package]] -name = "sha2" -version = "0.11.0-rc.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c5f3b1e2dc8aad28310d8410bd4d7e180eca65fca176c52ab00d364475d0024" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.11.1", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "shared_child" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e362d9935bc50f019969e2f9ecd66786612daae13e8f277be7bfb66e8bed3f7" -dependencies = [ - "libc", - "sigchld", - "windows-sys 0.60.2", -] - -[[package]] -name = "shared_library" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9e7e0f2bfae24d8a5b5a66c5b257a83c7412304311512a0c054cd5e619da11" -dependencies = [ - "lazy_static", - "libc", -] - -[[package]] -name = "shell-words" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc6fe69c597f9c37bfeeeeeb33da3530379845f10be461a66d16d03eca2ded77" - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "sigchld" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47106eded3c154e70176fc83df9737335c94ce22f821c32d17ed1db1f83badb1" -dependencies = [ - "libc", - "os_pipe", - "signal-hook", -] - -[[package]] -name = "signal-hook" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" -dependencies = [ - "libc", - "signal-hook-registry", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" -dependencies = [ - "libc", -] - -[[package]] -name = "signature" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" -dependencies = [ - "digest 0.10.7", - "rand_core 0.6.4", -] - -[[package]] -name = "signature" -version = "3.0.0-rc.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a96996ccff7dfa16f052bd995b4cecc72af22c35138738dc029f0ead6608d" -dependencies = [ - "digest 0.11.1", - "rand_core 0.10.0-rc-3", -] - -[[package]] -name = "simd-adler32" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" - -[[package]] -name = "simdutf8" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" - -[[package]] -name = "siphasher" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" - -[[package]] -name = "siphasher" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" - -[[package]] -name = "slab" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" - -[[package]] -name = "smallvec" -version = "1.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" - -[[package]] -name = "socket2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "socket2" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] - -[[package]] -name = "softbuffer" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18051cdd562e792cad055119e0cdb2cfc137e44e3987532e0f9659a77931bb08" -dependencies = [ - "bytemuck", - "cfg_aliases 0.2.1", - "core-graphics 0.24.0", - "foreign-types 0.5.0", - "js-sys", - "log", - "objc2 0.5.2", - "objc2-foundation 0.2.2", - "objc2-quartz-core", - "raw-window-handle", - "redox_syscall", - "wasm-bindgen", - "web-sys", - "windows-sys 0.59.0", -] - -[[package]] -name = "sonic-number" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5661364b38abad49cf1ade6631fcc35d2ccf882a7d68616b4228b7717feb5fba" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "sonic-rs" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16b39f36452a4fa6f14a481b02e9ba5c6842c6a44d0545da967eca122f2eed9" -dependencies = [ - "ahash", - "bumpalo", - "bytes", - "cfg-if", - "faststr", - "itoa", - "ref-cast", - "serde", - "simdutf8", - "sonic-number", - "sonic-simd", - "thiserror 2.0.16", - "zmij", -] - -[[package]] -name = "sonic-simd" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9f944718c33623919878cf74b4c9361eb3024f635733922b26722b14cd3f8cc" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "soup3" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "471f924a40f31251afc77450e781cb26d55c0b650842efafc9c6cbd2f7cc4f9f" -dependencies = [ - "futures-channel", - "gio", - "glib", - "libc", - "soup3-sys", -] - -[[package]] -name = "soup3-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ebe8950a680a12f24f15ebe1bf70db7af98ad242d9db43596ad3108aab86c27" -dependencies = [ - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - -[[package]] -name = "spki" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" -dependencies = [ - "base64ct", - "der 0.7.10", -] - -[[package]] -name = "spki" -version = "0.8.0-rc.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8baeff88f34ed0691978ec34440140e1572b68c7dd4a495fd14a3dc1944daa80" -dependencies = [ - "base64ct", - "der 0.8.0", -] - -[[package]] -name = "ssh-cipher" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caac132742f0d33c3af65bfcde7f6aa8f62f0e991d80db99149eb9d44708784f" -dependencies = [ - "aes", - "aes-gcm", - "cbc", - "chacha20", - "cipher", - "ctr", - "poly1305", - "ssh-encoding", - "subtle", -] - -[[package]] -name = "ssh-encoding" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9242b9ef4108a78e8cd1a2c98e193ef372437f8c22be363075233321dd4a15" -dependencies = [ - "base64ct", - "bytes", - "pem-rfc7468 0.7.0", - "sha2 0.10.9", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "string_cache" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" -dependencies = [ - "new_debug_unreachable", - "parking_lot", - "phf_shared 0.11.3", - "precomputed-hash", - "serde", -] - -[[package]] -name = "string_cache_codegen" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0" -dependencies = [ - "phf_generator 0.11.3", - "phf_shared 0.11.3", - "proc-macro2", - "quote", -] - -[[package]] -name = "stringprep" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" -dependencies = [ - "unicode-bidi", - "unicode-normalization", - "unicode-properties", -] - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - -[[package]] -name = "swift-rs" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4057c98e2e852d51fdcfca832aac7b571f6b351ad159f9eda5db1655f8d0c4d7" -dependencies = [ - "base64 0.21.7", - "serde", - "serde_json", -] - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - -[[package]] -name = "sync_wrapper" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" -dependencies = [ - "futures-core", -] - -[[package]] -name = "synstructure" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "sysinfo" -version = "0.38.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d03c61d2a49c649a15c407338afe7accafde9dac869995dccb73e5f7ef7d9034" -dependencies = [ - "libc", - "memchr", - "ntapi", - "objc2-core-foundation", - "objc2-io-kit", - "windows 0.62.1", -] - -[[package]] -name = "system-deps" -version = "6.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" -dependencies = [ - "cfg-expr", - "heck 0.5.0", - "pkg-config", - "toml 0.8.23", - "version-compare", -] - -[[package]] -name = "tao" -version = "0.34.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d52c379e63da659a483a958110bbde891695a0ecb53e48cc7786d5eda7bb" -dependencies = [ - "bitflags 2.9.4", - "block2 0.6.1", - "core-foundation 0.10.1", - "core-graphics 0.25.0", - "crossbeam-channel", - "dispatch2", - "dlopen2", - "dpi", - "gdkwayland-sys", - "gdkx11-sys", - "gtk", - "jni", - "libc", - "log", - "ndk", - "ndk-context", - "ndk-sys", - "objc2 0.6.2", - "objc2-app-kit", - "objc2-foundation 0.3.1", - "once_cell", - "parking_lot", - "raw-window-handle", - "tao-macros", - "unicode-segmentation", - "url", - "windows 0.61.3", - "windows-core 0.61.2", - "windows-version", - "x11-dl", -] - -[[package]] -name = "tao-macros" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "tar" -version = "0.4.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" -dependencies = [ - "filetime", - "libc", - "xattr", -] - -[[package]] -name = "target-lexicon" -version = "0.12.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" - -[[package]] -name = "tauri" -version = "2.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da77cc00fb9028caf5b5d4650f75e31f1ef3693459dfca7f7e506d1ecef0ba2d" -dependencies = [ - "anyhow", - "bytes", - "cookie", - "dirs", - "dunce", - "embed_plist", - "getrandom 0.3.3", - "glob", - "gtk", - "heck 0.5.0", - "http 1.3.1", - "jni", - "libc", - "log", - "mime", - "muda", - "objc2 0.6.2", - "objc2-app-kit", - "objc2-foundation 0.3.1", - "objc2-ui-kit", - "objc2-web-kit", - "percent-encoding", - "plist", - "raw-window-handle", - "reqwest", - "serde", - "serde_json", - "serde_repr", - "serialize-to-javascript", - "swift-rs", - "tauri-build", - "tauri-macros", - "tauri-runtime", - "tauri-runtime-wry", - "tauri-utils", - "thiserror 2.0.16", - "tokio", - "tray-icon", - "url", - "webkit2gtk", - "webview2-com", - "window-vibrancy", - "windows 0.61.3", -] - -[[package]] -name = "tauri-build" -version = "2.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bbc990d1dbf57a8e1c7fa2327f2a614d8b757805603c1b9ba5c81bade09fd4d" -dependencies = [ - "anyhow", - "cargo_toml", - "dirs", - "glob", - "heck 0.5.0", - "json-patch", - "schemars 0.8.22", - "semver", - "serde", - "serde_json", - "tauri-utils", - "tauri-winres", - "toml 0.9.5", - "walkdir", -] - -[[package]] -name = "tauri-codegen" -version = "2.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a24476afd977c5d5d169f72425868613d82747916dd29e0a357c84c4bd6d29" -dependencies = [ - "base64 0.22.1", - "brotli", - "ico", - "json-patch", - "plist", - "png", - "proc-macro2", - "quote", - "semver", - "serde", - "serde_json", - "sha2 0.10.9", - "syn 2.0.106", - "tauri-utils", - "thiserror 2.0.16", - "time", - "url", - "uuid", - "walkdir", -] - -[[package]] -name = "tauri-macros" -version = "2.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d39b349a98dadaffebb73f0a40dcd1f23c999211e5a2e744403db384d0c33de7" -dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "syn 2.0.106", - "tauri-codegen", - "tauri-utils", -] - -[[package]] -name = "tauri-plugin" -version = "2.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddde7d51c907b940fb573006cdda9a642d6a7c8153657e88f8a5c3c9290cd4aa" -dependencies = [ - "anyhow", - "glob", - "plist", - "schemars 0.8.22", - "serde", - "serde_json", - "tauri-utils", - "toml 0.9.5", - "walkdir", -] - -[[package]] -name = "tauri-plugin-dialog" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9204b425d9be8d12aa60c2a83a289cf7d1caae40f57f336ed1155b3a5c0e359b" -dependencies = [ - "log", - "raw-window-handle", - "rfd", - "serde", - "serde_json", - "tauri", - "tauri-plugin", - "tauri-plugin-fs", - "thiserror 2.0.16", - "url", -] - -[[package]] -name = "tauri-plugin-fs" -version = "2.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed390cc669f937afeb8b28032ce837bac8ea023d975a2e207375ec05afaf1804" -dependencies = [ - "anyhow", - "dunce", - "glob", - "percent-encoding", - "schemars 0.8.22", - "serde", - "serde_json", - "serde_repr", - "tauri", - "tauri-plugin", - "tauri-utils", - "thiserror 2.0.16", - "toml 0.9.5", - "url", -] - -[[package]] -name = "tauri-plugin-opener" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "786156aa8e89e03d271fbd3fe642207da8e65f3c961baa9e2930f332bf80a1f5" -dependencies = [ - "dunce", - "glob", - "objc2-app-kit", - "objc2-foundation 0.3.1", - "open", - "schemars 0.8.22", - "serde", - "serde_json", - "tauri", - "tauri-plugin", - "thiserror 2.0.16", - "url", - "windows 0.61.3", - "zbus", -] - -[[package]] -name = "tauri-plugin-process" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d55511a7bf6cd70c8767b02c97bf8134fa434daf3926cfc1be0a0f94132d165a" -dependencies = [ - "tauri", - "tauri-plugin", -] - -[[package]] -name = "tauri-plugin-shell" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54777d0c0d8add34eea3ced84378619ef5b97996bd967d3038c668feefd21071" -dependencies = [ - "encoding_rs", - "log", - "open", - "os_pipe", - "regex", - "schemars 0.8.22", - "serde", - "serde_json", - "shared_child", - "tauri", - "tauri-plugin", - "thiserror 2.0.16", - "tokio", -] - -[[package]] -name = "tauri-plugin-updater" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fe8e9bebd88fc222938ffdfbdcfa0307081423bd01e3252fc337d8bde81fc61" -dependencies = [ - "base64 0.22.1", - "dirs", - "flate2", - "futures-util", - "http 1.3.1", - "infer", - "log", - "minisign-verify", - "osakit", - "percent-encoding", - "reqwest", - "rustls 0.23.37", - "semver", - "serde", - "serde_json", - "tar", - "tauri", - "tauri-plugin", - "tempfile", - "thiserror 2.0.16", - "time", - "tokio", - "url", - "windows-sys 0.60.2", - "zip", -] - -[[package]] -name = "tauri-runtime" -version = "2.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2826d79a3297ed08cd6ea7f412644ef58e32969504bc4fbd8d7dbeabc4445ea2" -dependencies = [ - "cookie", - "dpi", - "gtk", - "http 1.3.1", - "jni", - "objc2 0.6.2", - "objc2-ui-kit", - "objc2-web-kit", - "raw-window-handle", - "serde", - "serde_json", - "tauri-utils", - "thiserror 2.0.16", - "url", - "webkit2gtk", - "webview2-com", - "windows 0.61.3", -] - -[[package]] -name = "tauri-runtime-wry" -version = "2.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e11ea2e6f801d275fdd890d6c9603736012742a1c33b96d0db788c9cdebf7f9e" -dependencies = [ - "gtk", - "http 1.3.1", - "jni", - "log", - "objc2 0.6.2", - "objc2-app-kit", - "once_cell", - "percent-encoding", - "raw-window-handle", - "softbuffer", - "tao", - "tauri-runtime", - "tauri-utils", - "url", - "webkit2gtk", - "webview2-com", - "windows 0.61.3", - "wry", -] - -[[package]] -name = "tauri-utils" -version = "2.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219a1f983a2af3653f75b5747f76733b0da7ff03069c7a41901a5eb3ace4557d" -dependencies = [ - "anyhow", - "brotli", - "cargo_metadata", - "ctor", - "dunce", - "glob", - "html5ever", - "http 1.3.1", - "infer", - "json-patch", - "kuchikiki", - "log", - "memchr", - "phf 0.11.3", - "proc-macro2", - "quote", - "regex", - "schemars 0.8.22", - "semver", - "serde", - "serde-untagged", - "serde_json", - "serde_with", - "swift-rs", - "thiserror 2.0.16", - "toml 0.9.5", - "url", - "urlpattern", - "uuid", - "walkdir", -] - -[[package]] -name = "tauri-winres" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd21509dd1fa9bd355dc29894a6ff10635880732396aa38c0066c1e6c1ab8074" -dependencies = [ - "embed-resource", - "toml 0.9.5", -] - -[[package]] -name = "tempfile" -version = "3.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84fa4d11fadde498443cca10fd3ac23c951f0dc59e080e9f4b93d4df4e4eea53" -dependencies = [ - "fastrand", - "getrandom 0.3.3", - "once_cell", - "rustix 1.1.2", - "windows-sys 0.61.0", -] - -[[package]] -name = "tendril" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" -dependencies = [ - "futf", - "mac", - "utf-8", -] - -[[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl 1.0.69", -] - -[[package]] -name = "thiserror" -version = "2.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" -dependencies = [ - "thiserror-impl 2.0.16", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "thread_local" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "time" -version = "0.3.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83bde6f1ec10e72d583d91623c939f623002284ef622b87de38cfd546cbf2031" -dependencies = [ - "deranged", - "num-conv", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" - -[[package]] -name = "time-macros" -version = "0.2.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" -dependencies = [ - "num-conv", - "time-core", -] - -[[package]] -name = "tinystr" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" -dependencies = [ - "displaydoc", - "zerovec", -] - -[[package]] -name = "tinyvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "tls_codec" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de2e01245e2bb89d6f05801c564fa27624dbd7b1846859876c7dad82e90bf6b" -dependencies = [ - "tls_codec_derive", - "zeroize", -] - -[[package]] -name = "tls_codec_derive" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d2e76690929402faae40aebdda620a2c0e25dd6d3b9afe48867dfd95991f4bd" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "tokio" -version = "1.47.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" -dependencies = [ - "backtrace", - "bytes", - "io-uring", - "libc", - "mio", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "slab", - "socket2 0.6.0", - "tokio-macros", - "windows-sys 0.59.0", -] - -[[package]] -name = "tokio-io-timeout" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bd86198d9ee903fedd2f9a2e72014287c0d9167e4ae43b5853007205dda1b76" -dependencies = [ - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-macros" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - -[[package]] -name = "tokio-postgres" -version = "0.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b40d66d9b2cfe04b628173409368e58247e8eddbbd3b0e6c6ba1d09f20f6c9e" -dependencies = [ - "async-trait", - "byteorder", - "bytes", - "fallible-iterator 0.2.0", - "futures-channel", - "futures-util", - "log", - "parking_lot", - "percent-encoding", - "phf 0.13.1", - "pin-project-lite", - "postgres-protocol", - "postgres-types", - "rand 0.9.2", - "socket2 0.6.0", - "tokio", - "tokio-util", - "whoami", -] - -[[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.37", - "tokio", -] - -[[package]] -name = "tokio-stream" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "toml" -version = "0.8.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" -dependencies = [ - "serde", - "serde_spanned 0.6.9", - "toml_datetime 0.6.11", - "toml_edit 0.22.27", -] - -[[package]] -name = "toml" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75129e1dc5000bfbaa9fee9d1b21f974f9fbad9daec557a521ee6e080825f6e8" -dependencies = [ - "indexmap 2.11.1", - "serde", - "serde_spanned 1.0.0", - "toml_datetime 0.7.0", - "toml_parser", - "toml_writer", - "winnow 0.7.13", -] - -[[package]] -name = "toml_datetime" -version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_datetime" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.19.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" -dependencies = [ - "indexmap 2.11.1", - "toml_datetime 0.6.11", - "winnow 0.5.40", -] - -[[package]] -name = "toml_edit" -version = "0.20.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" -dependencies = [ - "indexmap 2.11.1", - "toml_datetime 0.6.11", - "winnow 0.5.40", -] - -[[package]] -name = "toml_edit" -version = "0.22.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" -dependencies = [ - "indexmap 2.11.1", - "serde", - "serde_spanned 0.6.9", - "toml_datetime 0.6.11", - "winnow 0.7.13", -] - -[[package]] -name = "toml_parser" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b551886f449aa90d4fe2bdaa9f4a2577ad2dde302c61ecf262d80b116db95c10" -dependencies = [ - "winnow 0.7.13", -] - -[[package]] -name = "toml_writer" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64" - -[[package]] -name = "tonic" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76c4eb7a4e9ef9d4763600161f12f5070b92a578e1b634db88a6887844c91a13" -dependencies = [ - "async-stream", - "async-trait", - "axum", - "base64 0.21.7", - "bytes", - "h2", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.32", - "hyper-timeout", - "percent-encoding", - "pin-project", - "prost", - "tokio", - "tokio-stream", - "tower 0.4.13", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tonic-web" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc3b0e1cedbf19fdfb78ef3d672cb9928e0a91a9cb4629cc0c916e8cff8aaaa1" -dependencies = [ - "base64 0.21.7", - "bytes", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.32", - "pin-project", - "tokio-stream", - "tonic", - "tower-http 0.4.4", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "indexmap 1.9.3", - "pin-project", - "pin-project-lite", - "rand 0.8.5", - "slab", - "tokio", - "tokio-util", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" -dependencies = [ - "futures-core", - "futures-util", - "pin-project-lite", - "sync_wrapper 1.0.2", - "tokio", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-http" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" -dependencies = [ - "bitflags 2.9.4", - "bytes", - "futures-core", - "futures-util", - "http 0.2.12", - "http-body 0.4.6", - "http-range-header", - "pin-project-lite", - "tower 0.4.13", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower-http" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" -dependencies = [ - "bitflags 2.9.4", - "bytes", - "futures-util", - "http 1.3.1", - "http-body 1.0.1", - "iri-string", - "pin-project-lite", - "tower 0.5.2", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-layer" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" - -[[package]] -name = "tower-service" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" - -[[package]] -name = "tracing" -version = "0.1.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" -dependencies = [ - "log", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "tracing-core" -version = "0.1.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" -dependencies = [ - "nu-ansi-term", - "sharded-slab", - "smallvec", - "thread_local", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "tray-icon" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0d92153331e7d02ec09137538996a7786fe679c629c279e82a6be762b7e6fe2" -dependencies = [ - "crossbeam-channel", - "dirs", - "libappindicator", - "muda", - "objc2 0.6.2", - "objc2-app-kit", - "objc2-core-foundation", - "objc2-core-graphics", - "objc2-foundation 0.3.1", - "once_cell", - "png", - "serde", - "thiserror 2.0.16", - "windows-sys 0.59.0", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - -[[package]] -name = "typeid" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" - -[[package]] -name = "typenum" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" - -[[package]] -name = "uds_windows" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9" -dependencies = [ - "memoffset", - "tempfile", - "winapi", -] - -[[package]] -name = "uncased" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1b88fcfe09e89d3866a5c11019378088af2d24c3fbd4f0543f96b479ec90697" -dependencies = [ - "version_check", -] - -[[package]] -name = "unic-char-property" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" -dependencies = [ - "unic-char-range", -] - -[[package]] -name = "unic-char-range" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" - -[[package]] -name = "unic-common" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" - -[[package]] -name = "unic-ucd-ident" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e230a37c0381caa9219d67cf063aa3a375ffed5bf541a452db16e744bdab6987" -dependencies = [ - "unic-char-property", - "unic-char-range", - "unic-ucd-version", -] - -[[package]] -name = "unic-ucd-version" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" -dependencies = [ - "unic-common", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" - -[[package]] -name = "unicode-ident" -version = "1.0.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" - -[[package]] -name = "unicode-normalization" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-properties" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" - -[[package]] -name = "unicode-segmentation" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" - -[[package]] -name = "universal-hash" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" -dependencies = [ - "crypto-common 0.1.6", - "subtle", -] - -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "url" -version = "2.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", - "serde", -] - -[[package]] -name = "urlpattern" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70acd30e3aa1450bc2eece896ce2ad0d178e9c079493819301573dae3c37ba6d" -dependencies = [ - "regex", - "serde", - "unic-ucd-ident", - "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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - -[[package]] -name = "uuid" -version = "1.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" -dependencies = [ - "getrandom 0.3.3", - "js-sys", - "serde", - "wasm-bindgen", -] - -[[package]] -name = "valuable" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version-compare" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "vswhom" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be979b7f07507105799e854203b470ff7c78a1639e330a58f183b5fea574608b" -dependencies = [ - "libc", - "vswhom-sys", -] - -[[package]] -name = "vswhom-sys" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb067e4cbd1ff067d1df46c9194b5de0e98efd2810bbc95c5d5e5f25a3231150" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - -[[package]] -name = "wasi" -version = "0.11.1+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" - -[[package]] -name = "wasi" -version = "0.14.5+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4494f6290a82f5fe584817a676a34b9d6763e8d9d18204009fb31dceca98fd4" -dependencies = [ - "wasip2", -] - -[[package]] -name = "wasip2" -version = "1.0.0+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03fa2761397e5bd52002cd7e73110c71af2109aca4e521a9f40473fe685b0a24" -dependencies = [ - "wit-bindgen", -] - -[[package]] -name = "wasite" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" - -[[package]] -name = "wasm-bindgen" -version = "0.2.114" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8" -dependencies = [ - "cfg-if", - "futures-util", - "js-sys", - "once_cell", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.114" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.114" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" -dependencies = [ - "bumpalo", - "proc-macro2", - "quote", - "syn 2.0.106", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.114" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "wasm-streams" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb" -dependencies = [ - "futures-util", - "js-sys", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "web-sys" -version = "0.3.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "webkit2gtk" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1027150013530fb2eaf806408df88461ae4815a45c541c8975e61d6f2fc4793" -dependencies = [ - "bitflags 1.3.2", - "cairo-rs", - "gdk", - "gdk-sys", - "gio", - "gio-sys", - "glib", - "glib-sys", - "gobject-sys", - "gtk", - "gtk-sys", - "javascriptcore-rs", - "libc", - "once_cell", - "soup3", - "webkit2gtk-sys", -] - -[[package]] -name = "webkit2gtk-sys" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "916a5f65c2ef0dfe12fff695960a2ec3d4565359fdbb2e9943c974e06c734ea5" -dependencies = [ - "bitflags 1.3.2", - "cairo-sys-rs", - "gdk-sys", - "gio-sys", - "glib-sys", - "gobject-sys", - "gtk-sys", - "javascriptcore-rs-sys", - "libc", - "pkg-config", - "soup3-sys", - "system-deps", -] - -[[package]] -name = "webpki-root-certs" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "804f18a4ac2676ffb4e8b5b5fa9ae38af06df08162314f96a68d2a363e21a8ca" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "webpki-roots" -version = "0.26.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" -dependencies = [ - "webpki-roots 1.0.6", -] - -[[package]] -name = "webpki-roots" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "webview2-com" -version = "0.38.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4ba622a989277ef3886dd5afb3e280e3dd6d974b766118950a08f8f678ad6a4" -dependencies = [ - "webview2-com-macros", - "webview2-com-sys", - "windows 0.61.3", - "windows-core 0.61.2", - "windows-implement", - "windows-interface", -] - -[[package]] -name = "webview2-com-macros" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d228f15bba3b9d56dde8bddbee66fa24545bd17b48d5128ccf4a8742b18e431" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "webview2-com-sys" -version = "0.38.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36695906a1b53a3bf5c4289621efedac12b73eeb0b89e7e1a89b517302d5d75c" -dependencies = [ - "thiserror 2.0.16", - "windows 0.61.3", - "windows-core 0.61.2", -] - -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix 0.38.44", -] - -[[package]] -name = "whoami" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d" -dependencies = [ - "libredox", - "wasite", - "web-sys", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" -dependencies = [ - "windows-sys 0.61.0", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "window-vibrancy" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9bec5a31f3f9362f2258fd0e9c9dd61a9ca432e7306cc78c444258f0dce9a9c" -dependencies = [ - "objc2 0.6.2", - "objc2-app-kit", - "objc2-core-foundation", - "objc2-foundation 0.3.1", - "raw-window-handle", - "windows-sys 0.59.0", - "windows-version", -] - -[[package]] -name = "windows" -version = "0.61.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" -dependencies = [ - "windows-collections 0.2.0", - "windows-core 0.61.2", - "windows-future 0.2.1", - "windows-link 0.1.3", - "windows-numerics 0.2.0", -] - -[[package]] -name = "windows" -version = "0.62.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49e6c4a1f363c8210c6f77ba24f645c61c6fb941eccf013da691f7e09515b8ac" -dependencies = [ - "windows-collections 0.3.1", - "windows-core 0.62.1", - "windows-future 0.3.1", - "windows-numerics 0.3.0", -] - -[[package]] -name = "windows-collections" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" -dependencies = [ - "windows-core 0.61.2", -] - -[[package]] -name = "windows-collections" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "123e712f464a8a60ce1a13f4c446d2d43ab06464cb5842ff68f5c71b6fb7852e" -dependencies = [ - "windows-core 0.62.1", -] - -[[package]] -name = "windows-core" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link 0.1.3", - "windows-result 0.3.4", - "windows-strings 0.4.2", -] - -[[package]] -name = "windows-core" -version = "0.62.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6844ee5416b285084d3d3fffd743b925a6c9385455f64f6d4fa3031c4c2749a9" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link 0.2.0", - "windows-result 0.4.0", - "windows-strings 0.5.0", -] - -[[package]] -name = "windows-future" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" -dependencies = [ - "windows-core 0.61.2", - "windows-link 0.1.3", - "windows-threading 0.1.0", -] - -[[package]] -name = "windows-future" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f3db6b24b120200d649cd4811b4947188ed3a8d2626f7075146c5d178a9a4a" -dependencies = [ - "windows-core 0.62.1", - "windows-link 0.2.0", - "windows-threading 0.2.0", -] - -[[package]] -name = "windows-implement" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "windows-interface" -version = "0.59.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "windows-link" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" - -[[package]] -name = "windows-link" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" - -[[package]] -name = "windows-numerics" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" -dependencies = [ - "windows-core 0.61.2", - "windows-link 0.1.3", -] - -[[package]] -name = "windows-numerics" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ce3498fe0aba81e62e477408383196b4b0363db5e0c27646f932676283b43d8" -dependencies = [ - "windows-core 0.62.1", - "windows-link 0.2.0", -] - -[[package]] -name = "windows-result" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" -dependencies = [ - "windows-link 0.1.3", -] - -[[package]] -name = "windows-result" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f" -dependencies = [ - "windows-link 0.2.0", -] - -[[package]] -name = "windows-strings" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" -dependencies = [ - "windows-link 0.1.3", -] - -[[package]] -name = "windows-strings" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda" -dependencies = [ - "windows-link 0.2.0", -] - -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" -dependencies = [ - "windows-targets 0.53.3", -] - -[[package]] -name = "windows-sys" -version = "0.61.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" -dependencies = [ - "windows-link 0.2.0", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.53.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" -dependencies = [ - "windows-link 0.1.3", - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", -] - -[[package]] -name = "windows-threading" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" -dependencies = [ - "windows-link 0.1.3", -] - -[[package]] -name = "windows-threading" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab47f085ad6932defa48855254c758cdd0e2f2d48e62a34118a268d8f345e118" -dependencies = [ - "windows-link 0.2.0", -] - -[[package]] -name = "windows-version" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69e061eb0a22b4a1d778ad70f7575ec7845490abb35b08fa320df7895882cacb" -dependencies = [ - "windows-link 0.2.0", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_i686_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" - -[[package]] -name = "winnow" -version = "0.5.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" -dependencies = [ - "memchr", -] - -[[package]] -name = "winnow" -version = "0.7.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" -dependencies = [ - "memchr", -] - -[[package]] -name = "winreg" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" -dependencies = [ - "winapi", -] - -[[package]] -name = "winreg" -version = "0.55.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb5a765337c50e9ec252c2069be9bf91c7df47afb103b642ba3a53bf8101be97" -dependencies = [ - "cfg-if", - "windows-sys 0.59.0", -] - -[[package]] -name = "wit-bindgen" -version = "0.45.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c573471f125075647d03df72e026074b7203790d41351cd6edc96f46bcccd36" - -[[package]] -name = "writeable" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" - -[[package]] -name = "wry" -version = "0.54.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb26159b420aa77684589a744ae9a9461a95395b848764ad12290a14d960a11a" -dependencies = [ - "base64 0.22.1", - "block2 0.6.1", - "cookie", - "crossbeam-channel", - "dirs", - "dpi", - "dunce", - "gdkx11", - "gtk", - "html5ever", - "http 1.3.1", - "javascriptcore-rs", - "jni", - "kuchikiki", - "libc", - "ndk", - "objc2 0.6.2", - "objc2-app-kit", - "objc2-core-foundation", - "objc2-foundation 0.3.1", - "objc2-ui-kit", - "objc2-web-kit", - "once_cell", - "percent-encoding", - "raw-window-handle", - "sha2 0.10.9", - "soup3", - "tao-macros", - "thiserror 2.0.16", - "url", - "webkit2gtk", - "webkit2gtk-sys", - "webview2-com", - "windows 0.61.3", - "windows-core 0.61.2", - "windows-version", - "x11-dl", -] - -[[package]] -name = "x11" -version = "2.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e" -dependencies = [ - "libc", - "pkg-config", -] - -[[package]] -name = "x11-dl" -version = "2.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" -dependencies = [ - "libc", - "once_cell", - "pkg-config", -] - -[[package]] -name = "xattr" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" -dependencies = [ - "libc", - "rustix 1.1.2", -] - -[[package]] -name = "yoke" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" -dependencies = [ - "serde", - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", - "synstructure", -] - -[[package]] -name = "zbus" -version = "5.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d07e46d035fb8e375b2ce63ba4e4ff90a7f73cf2ffb0138b29e1158d2eaadf7" -dependencies = [ - "async-broadcast", - "async-executor", - "async-io", - "async-lock", - "async-process", - "async-recursion", - "async-task", - "async-trait", - "blocking", - "enumflags2", - "event-listener", - "futures-core", - "futures-lite", - "hex", - "nix 0.30.1", - "ordered-stream", - "serde", - "serde_repr", - "tracing", - "uds_windows", - "windows-sys 0.60.2", - "winnow 0.7.13", - "zbus_macros", - "zbus_names", - "zvariant", -] - -[[package]] -name = "zbus_macros" -version = "5.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57e797a9c847ed3ccc5b6254e8bcce056494b375b511b3d6edcec0aeb4defaca" -dependencies = [ - "proc-macro-crate 3.3.0", - "proc-macro2", - "quote", - "syn 2.0.106", - "zbus_names", - "zvariant", - "zvariant_utils", -] - -[[package]] -name = "zbus_names" -version = "4.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7be68e64bf6ce8db94f63e72f0c7eb9a60d733f7e0499e628dfab0f84d6bcb97" -dependencies = [ - "serde", - "static_assertions", - "winnow 0.7.13", - "zvariant", -] - -[[package]] -name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "byteorder", - "zerocopy-derive 0.7.35", -] - -[[package]] -name = "zerocopy" -version = "0.8.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" -dependencies = [ - "zerocopy-derive 0.8.27", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "zerofrom" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", - "synstructure", -] - -[[package]] -name = "zeroize" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "zerotrie" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", -] - -[[package]] -name = "zerovec" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "zip" -version = "4.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caa8cd6af31c3b31c6631b8f483848b91589021b28fffe50adada48d4f4d2ed1" -dependencies = [ - "arbitrary", - "crc32fast", - "indexmap 2.11.1", - "memchr", -] - -[[package]] -name = "zmij" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" - -[[package]] -name = "zvariant" -version = "5.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "999dd3be73c52b1fccd109a4a81e4fcd20fab1d3599c8121b38d04e1419498db" -dependencies = [ - "endi", - "enumflags2", - "serde", - "winnow 0.7.13", - "zvariant_derive", - "zvariant_utils", -] - -[[package]] -name = "zvariant_derive" -version = "5.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6643fd0b26a46d226bd90d3f07c1b5321fe9bb7f04673cb37ac6d6883885b68e" -dependencies = [ - "proc-macro-crate 3.3.0", - "proc-macro2", - "quote", - "syn 2.0.106", - "zvariant_utils", -] - -[[package]] -name = "zvariant_utils" -version = "3.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6949d142f89f6916deca2232cf26a8afacf2b9fdc35ce766105e104478be599" -dependencies = [ - "proc-macro2", - "quote", - "serde", - "syn 2.0.106", - "winnow 0.7.13", -] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml deleted file mode 100644 index 1ff94c4..0000000 --- a/src-tauri/Cargo.toml +++ /dev/null @@ -1,45 +0,0 @@ -[package] -name = "rsql" -version = "1.1.5" -description = "Modern SQL Client" -authors = ["rust-dd"] -edition = "2024" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[lib] -# The `_lib` suffix may seem redundant but it is necessary -# to make the lib name unique and wouldn't conflict with the bin name. -# This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519 -name = "rsql_lib" -crate-type = ["staticlib", "cdylib", "rlib"] - -[build-dependencies] -tauri-build = { version = "2", features = [] } - -[dependencies] -tauri = { version = "2", features = [] } -tauri-plugin-opener = "2" -serde = { version = "1", features = ["derive"] } -serde_json = "1" -sonic-rs = "0.5" -tokio = "1.47.1" -tokio-postgres = "0.7.13" -deadpool-postgres = "0.14.1" -postgres-native-tls = "0.5" -native-tls = "0.2" -tracing = "0.1.41" -tracing-subscriber = {version = "0.3.20", features = ["fmt"] } -libsql = "0.9.29" -tauri-plugin-shell = "2.3.1" -tauri-plugin-fs = "2.4.2" -thiserror = "2" -tauri-plugin-dialog = "2.6.0" -tauri-plugin-process = "2.3.1" -tauri-plugin-updater = "2.10.0" -portable-pty = "0.9.0" -rayon = "1.11.0" -sysinfo = "0.38.3" -csv = "1.3" -futures-util = "0.3" -russh = "0.57" diff --git a/src-tauri/src/dbs/mod.rs b/src-tauri/src/dbs/mod.rs deleted file mode 100644 index 8f815bb..0000000 --- a/src-tauri/src/dbs/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod project; -pub mod query; -pub mod workspace; diff --git a/src-tauri/src/drivers/pgsql/commands/metadata_commands.rs b/src-tauri/src/drivers/pgsql/commands/metadata_commands.rs deleted file mode 100644 index 343861e..0000000 --- a/src-tauri/src/drivers/pgsql/commands/metadata_commands.rs +++ /dev/null @@ -1,219 +0,0 @@ -use crate::AppState; -use crate::common::pgsql::{PgsqlLoadColumns, PgsqlLoadSchemas, PgsqlLoadTables}; -use crate::drivers::pgsql::{ - ColumnDetail, ConstraintDetail, FunctionInfo, IndexDetail, PolicyDetail, RuleDetail, - TriggerDetail, get_pool, load_column_details, load_columns, load_constraints, load_databases, - load_functions, load_indexes, load_materialized_views, load_policies, load_rules, load_schemas, - load_tables, load_tablespaces, load_trigger_functions, load_triggers, load_views, -}; - -use tauri::{AppHandle, Manager, Result, State}; - -use super::pool_connection::acquire_client; - -#[tauri::command(rename_all = "snake_case")] -pub async fn pgsql_load_databases(project_id: &str, app: AppHandle) -> Result> { - let app_state = app.state::(); - let pool = { - let pools = app_state.meta_clients.lock().await; - get_pool(&pools, project_id)? - }; - - load_databases(&pool).await.map_err(Into::into) -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn pgsql_load_tablespaces( - project_id: &str, - app: AppHandle, -) -> Result> { - let app_state = app.state::(); - let pool = { - let pools = app_state.meta_clients.lock().await; - get_pool(&pools, project_id)? - }; - - load_tablespaces(&pool).await.map_err(Into::into) -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn pgsql_load_schemas( - project_id: &str, - app_state: State<'_, AppState>, -) -> Result { - let client = acquire_client(&app_state.meta_clients, project_id).await?; - - load_schemas( - &client, - r#"SELECT schema_name FROM information_schema.schemata - WHERE schema_name NOT IN ('pg_catalog', 'information_schema') - ORDER BY schema_name"#, - ) - .await - .map_err(Into::into) -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn pgsql_load_tables( - project_id: &str, - schema: &str, - app_state: State<'_, AppState>, -) -> Result { - let client = acquire_client(&app_state.meta_clients, project_id).await?; - - load_tables( - &client, - r#"SELECT table_name, - pg_size_pretty(pg_total_relation_size('"' || table_schema || '"."' || table_name || '"')) AS size - FROM information_schema.tables - WHERE table_schema = $1 - ORDER BY table_name"#, - schema, - ) - .await - .map_err(Into::into) -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn pgsql_load_columns( - project_id: &str, - schema: &str, - table: &str, - app_state: State<'_, AppState>, -) -> Result { - let client = acquire_client(&app_state.meta_clients, project_id).await?; - - load_columns(&client, schema, table) - .await - .map_err(Into::into) -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn pgsql_load_column_details( - project_id: &str, - schema: &str, - table: &str, - app_state: State<'_, AppState>, -) -> Result> { - let client = acquire_client(&app_state.meta_clients, project_id).await?; - - load_column_details(&client, schema, table) - .await - .map_err(Into::into) -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn pgsql_load_indexes( - project_id: &str, - schema: &str, - table: &str, - app_state: State<'_, AppState>, -) -> Result> { - let client = acquire_client(&app_state.meta_clients, project_id).await?; - - load_indexes(&client, schema, table) - .await - .map_err(Into::into) -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn pgsql_load_constraints( - project_id: &str, - schema: &str, - table: &str, - app_state: State<'_, AppState>, -) -> Result> { - let client = acquire_client(&app_state.meta_clients, project_id).await?; - - load_constraints(&client, schema, table) - .await - .map_err(Into::into) -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn pgsql_load_triggers( - project_id: &str, - schema: &str, - table: &str, - app_state: State<'_, AppState>, -) -> Result> { - let client = acquire_client(&app_state.meta_clients, project_id).await?; - - load_triggers(&client, schema, table) - .await - .map_err(Into::into) -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn pgsql_load_rules( - project_id: &str, - schema: &str, - table: &str, - app_state: State<'_, AppState>, -) -> Result> { - let client = acquire_client(&app_state.meta_clients, project_id).await?; - - load_rules(&client, schema, table).await.map_err(Into::into) -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn pgsql_load_policies( - project_id: &str, - schema: &str, - table: &str, - app_state: State<'_, AppState>, -) -> Result> { - let client = acquire_client(&app_state.meta_clients, project_id).await?; - - load_policies(&client, schema, table) - .await - .map_err(Into::into) -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn pgsql_load_views( - project_id: &str, - schema: &str, - app_state: State<'_, AppState>, -) -> Result> { - let client = acquire_client(&app_state.meta_clients, project_id).await?; - - load_views(&client, schema).await.map_err(Into::into) -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn pgsql_load_materialized_views( - project_id: &str, - schema: &str, - app_state: State<'_, AppState>, -) -> Result> { - let client = acquire_client(&app_state.meta_clients, project_id).await?; - - load_materialized_views(&client, schema) - .await - .map_err(Into::into) -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn pgsql_load_functions( - project_id: &str, - schema: &str, - app_state: State<'_, AppState>, -) -> Result> { - let client = acquire_client(&app_state.meta_clients, project_id).await?; - - load_functions(&client, schema).await.map_err(Into::into) -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn pgsql_load_trigger_functions( - project_id: &str, - schema: &str, - app_state: State<'_, AppState>, -) -> Result> { - let client = acquire_client(&app_state.meta_clients, project_id).await?; - - load_trigger_functions(&client, schema) - .await - .map_err(Into::into) -} diff --git a/src-tauri/src/drivers/pgsql/commands/object_info_commands.rs b/src-tauri/src/drivers/pgsql/commands/object_info_commands.rs deleted file mode 100644 index 97b2a08..0000000 --- a/src-tauri/src/drivers/pgsql/commands/object_info_commands.rs +++ /dev/null @@ -1,61 +0,0 @@ -use crate::AppState; -use crate::drivers::pgsql::{ - ObjectStats, generate_full_ddl, load_function_info, load_matview_info, load_view_info, -}; - -use tauri::{Result, State}; - -use super::pool_connection::acquire_client; - -#[tauri::command(rename_all = "snake_case")] -pub async fn pgsql_view_info( - project_id: &str, - schema: &str, - view: &str, - app_state: State<'_, AppState>, -) -> Result { - let client = acquire_client(&app_state.meta_clients, project_id).await?; - load_view_info(&client, schema, view) - .await - .map_err(Into::into) -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn pgsql_matview_info( - project_id: &str, - schema: &str, - matview: &str, - app_state: State<'_, AppState>, -) -> Result { - let client = acquire_client(&app_state.meta_clients, project_id).await?; - load_matview_info(&client, schema, matview) - .await - .map_err(Into::into) -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn pgsql_function_info( - project_id: &str, - schema: &str, - func_name: &str, - app_state: State<'_, AppState>, -) -> Result { - let client = acquire_client(&app_state.meta_clients, project_id).await?; - load_function_info(&client, schema, func_name) - .await - .map_err(Into::into) -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn pgsql_generate_ddl( - project_id: &str, - schema: &str, - name: &str, - object_type: &str, - app_state: State<'_, AppState>, -) -> Result { - let client = acquire_client(&app_state.meta_clients, project_id).await?; - generate_full_ddl(&client, schema, name, object_type) - .await - .map_err(Into::into) -} diff --git a/src-tauri/src/drivers/pgsql/commands/statistics_commands.rs b/src-tauri/src/drivers/pgsql/commands/statistics_commands.rs deleted file mode 100644 index 3c9485f..0000000 --- a/src-tauri/src/drivers/pgsql/commands/statistics_commands.rs +++ /dev/null @@ -1,117 +0,0 @@ -use crate::AppState; -use crate::common::enums::AppError; -use crate::drivers::pgsql::{ - DbStat, FKDetail, ForeignKeyInfo, ObjectStats, load_active_locks, load_activity, - load_database_stats, load_fk_details, load_foreign_keys, load_index_usage, load_table_bloat, - load_table_statistics, load_table_stats, -}; - -use tauri::ipc::Response; -use tauri::{Result, State}; - -use super::pool_connection::acquire_client; - -#[tauri::command(rename_all = "snake_case")] -pub async fn pgsql_load_activity( - project_id: &str, - app_state: State<'_, AppState>, -) -> Result { - let client = acquire_client(&app_state.meta_clients, project_id).await?; - - let result = load_activity(&client).await?; - let json = sonic_rs::to_string(&result).map_err(|e| AppError::QueryFailed(e.to_string()))?; - Ok(Response::new(json)) -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn pgsql_load_database_stats( - project_id: &str, - app_state: State<'_, AppState>, -) -> Result> { - let client = acquire_client(&app_state.meta_clients, project_id).await?; - - load_database_stats(&client).await.map_err(Into::into) -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn pgsql_load_table_stats( - project_id: &str, - app_state: State<'_, AppState>, -) -> Result { - let client = acquire_client(&app_state.meta_clients, project_id).await?; - - let result = load_table_stats(&client).await?; - let json = sonic_rs::to_string(&result).map_err(|e| AppError::QueryFailed(e.to_string()))?; - Ok(Response::new(json)) -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn pgsql_load_foreign_keys( - project_id: &str, - schema: &str, - app_state: State<'_, AppState>, -) -> Result> { - let client = acquire_client(&app_state.meta_clients, project_id).await?; - - load_foreign_keys(&client, schema).await.map_err(Into::into) -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn pgsql_table_statistics( - project_id: &str, - schema: &str, - table: &str, - app_state: State<'_, AppState>, -) -> Result { - let client = acquire_client(&app_state.meta_clients, project_id).await?; - load_table_statistics(&client, schema, table) - .await - .map_err(Into::into) -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn pgsql_fk_details( - project_id: &str, - schema: &str, - table: &str, - direction: &str, - app_state: State<'_, AppState>, -) -> Result> { - let client = acquire_client(&app_state.meta_clients, project_id).await?; - load_fk_details(&client, schema, table, direction) - .await - .map_err(Into::into) -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn pgsql_load_locks( - project_id: &str, - app_state: State<'_, AppState>, -) -> Result { - let client = acquire_client(&app_state.meta_clients, project_id).await?; - let result = load_active_locks(&client).await?; - let json = sonic_rs::to_string(&result).map_err(|e| AppError::QueryFailed(e.to_string()))?; - Ok(Response::new(json)) -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn pgsql_load_index_usage( - project_id: &str, - app_state: State<'_, AppState>, -) -> Result { - let client = acquire_client(&app_state.meta_clients, project_id).await?; - let result = load_index_usage(&client).await?; - let json = sonic_rs::to_string(&result).map_err(|e| AppError::QueryFailed(e.to_string()))?; - Ok(Response::new(json)) -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn pgsql_load_table_bloat( - project_id: &str, - app_state: State<'_, AppState>, -) -> Result { - let client = acquire_client(&app_state.meta_clients, project_id).await?; - let result = load_table_bloat(&client).await?; - let json = sonic_rs::to_string(&result).map_err(|e| AppError::QueryFailed(e.to_string()))?; - Ok(Response::new(json)) -} diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs deleted file mode 100644 index c07dc36..0000000 --- a/src-tauri/src/utils.rs +++ /dev/null @@ -1,243 +0,0 @@ -use std::collections::HashSet; -use std::time::Instant; - -use rayon::prelude::*; -use sysinfo::{Networks, Pid, ProcessRefreshKind, ProcessesToUpdate, System, get_current_pid}; -use tauri::State; - -use crate::AppState; - -#[derive(serde::Serialize, Clone, Debug)] -pub struct SystemResourceUsage { - pub app_cpu_percent: f32, - pub app_memory_rss_mb: u64, - pub app_process_count: usize, - pub network_rx_mbps: f32, - pub network_tx_mbps: f32, - pub db_connections_in_use: usize, - pub db_connections_open: usize, - pub db_connections_max: usize, - pub db_connections_waiting: usize, -} - -pub struct ResourceMonitor { - system: System, - networks: Networks, - last_sample_at: Instant, - app_pid: Pid, -} - -impl ResourceMonitor { - pub fn new() -> Self { - let app_pid = get_current_pid().unwrap_or_else(|_| Pid::from_u32(std::process::id())); - let mut system = System::new_all(); - system.refresh_processes(ProcessesToUpdate::All, true); - let mut networks = Networks::new_with_refreshed_list(); - networks.refresh(true); - - Self { - system, - networks, - last_sample_at: Instant::now(), - app_pid, - } - } - - pub fn sample(&mut self) -> SystemResourceUsage { - self.system.refresh_processes_specifics( - ProcessesToUpdate::All, - true, - ProcessRefreshKind::nothing().with_cpu().with_memory(), - ); - self.networks.refresh(true); - let dt = self.last_sample_at.elapsed().as_secs_f32().max(0.001); - self.last_sample_at = Instant::now(); - - let processes = self.system.processes(); - let mut included = HashSet::new(); - included.insert(self.app_pid); - - let mut changed = true; - while changed { - changed = false; - for (pid, process) in processes { - if included.contains(pid) { - continue; - } - if let Some(parent) = process.parent() - && included.contains(&parent) - { - included.insert(*pid); - changed = true; - } - } - } - - let mut total_cpu = 0.0f32; - let mut total_rss = 0u64; - for pid in &included { - if let Some(process) = processes.get(pid) { - total_cpu += process.cpu_usage(); - total_rss = total_rss.saturating_add(process.memory()); - } - } - - let mut rx_bytes: u64 = 0; - let mut tx_bytes: u64 = 0; - for (_iface, net) in &self.networks { - rx_bytes = rx_bytes.saturating_add(net.received()); - tx_bytes = tx_bytes.saturating_add(net.transmitted()); - } - let network_rx_mbps = (rx_bytes as f32 * 8.0) / dt / 1_000_000.0; - let network_tx_mbps = (tx_bytes as f32 * 8.0) / dt / 1_000_000.0; - - SystemResourceUsage { - app_cpu_percent: total_cpu, - app_memory_rss_mb: total_rss / (1024 * 1024), - app_process_count: included.len(), - network_rx_mbps, - network_tx_mbps, - db_connections_in_use: 0, - db_connections_open: 0, - db_connections_max: 0, - db_connections_waiting: 0, - } - } -} - -#[tauri::command(rename_all = "snake_case")] -pub async fn system_resource_usage( - app_state: State<'_, AppState>, -) -> Result { - let mut usage = { - let mut monitor = app_state.resource_monitor.lock().await; - monitor.sample() - }; - - let (query_open, query_available, query_max, query_waiting) = { - let clients = app_state.clients.lock().await; - let mut open = 0usize; - let mut available = 0usize; - let mut max = 0usize; - let mut waiting = 0usize; - for pool in clients.values() { - let status = pool.status(); - open = open.saturating_add(status.size); - available = available.saturating_add(status.available); - max = max.saturating_add(status.max_size); - waiting = waiting.saturating_add(status.waiting); - } - (open, available, max, waiting) - }; - - let (meta_open, meta_available, meta_max, meta_waiting) = { - let clients = app_state.meta_clients.lock().await; - let mut open = 0usize; - let mut available = 0usize; - let mut max = 0usize; - let mut waiting = 0usize; - for pool in clients.values() { - let status = pool.status(); - open = open.saturating_add(status.size); - available = available.saturating_add(status.available); - max = max.saturating_add(status.max_size); - waiting = waiting.saturating_add(status.waiting); - } - (open, available, max, waiting) - }; - - let total_open = query_open.saturating_add(meta_open); - let total_available = query_available.saturating_add(meta_available); - - usage.db_connections_open = total_open; - usage.db_connections_max = query_max.saturating_add(meta_max); - usage.db_connections_waiting = query_waiting.saturating_add(meta_waiting); - usage.db_connections_in_use = total_open.saturating_sub(total_available); - - Ok(usage) -} - -const ROW_SEP: char = '\x1E'; - -fn parse_packed_rows(packed: &str) -> Vec<&str> { - if packed.is_empty() { - return Vec::new(); - } - let parts: Vec<&str> = packed.split(ROW_SEP).collect(); - if parts.len() > 1 { - parts[1..].to_vec() - } else { - Vec::new() - } -} - -fn pack_rows(header: &str, rows: &[&str]) -> String { - if rows.is_empty() { - return header.to_string(); - } - let mut result = - String::with_capacity(header.len() + rows.iter().map(|r| r.len() + 1).sum::()); - result.push_str(header); - for row in rows { - result.push(ROW_SEP); - result.push_str(row); - } - result -} - -/// Compute diff between two packed result sets. -/// Input: two packed strings (rows separated by \x1E, cells by \x1F). -/// First row of each is the header (columns). -/// Returns: (added_packed, removed_packed, unchanged_count) -#[tauri::command(rename_all = "snake_case")] -pub fn compute_diff(pinned_packed: String, current_packed: String) -> (String, String, usize) { - let pinned_rows = parse_packed_rows(&pinned_packed); - let current_rows = parse_packed_rows(¤t_packed); - - // Build hash sets for O(1) lookup - let pinned_set: HashSet<&str> = pinned_rows.iter().copied().collect(); - let current_set: HashSet<&str> = current_rows.iter().copied().collect(); - - // Compute diff using parallel iteration for large datasets - let (added, removed, unchanged_count) = if current_rows.len() > 5000 || pinned_rows.len() > 5000 - { - let added: Vec<&str> = current_rows - .par_iter() - .filter(|r| !pinned_set.contains(*r)) - .copied() - .collect(); - let removed: Vec<&str> = pinned_rows - .par_iter() - .filter(|r| !current_set.contains(*r)) - .copied() - .collect(); - let unchanged: usize = current_rows - .par_iter() - .filter(|r| pinned_set.contains(*r)) - .count(); - (added, removed, unchanged) - } else { - let added: Vec<&str> = current_rows - .iter() - .filter(|r| !pinned_set.contains(*r)) - .copied() - .collect(); - let removed: Vec<&str> = pinned_rows - .iter() - .filter(|r| !current_set.contains(*r)) - .copied() - .collect(); - let unchanged: usize = current_rows - .iter() - .filter(|r| pinned_set.contains(*r)) - .count(); - (added, removed, unchanged) - }; - - let header = pinned_packed.split(ROW_SEP).next().unwrap_or(""); - ( - pack_rows(header, &added), - pack_rows(header, &removed), - unchanged_count, - ) -} diff --git a/vite.config.ts b/vite.config.ts index ae4d118..4be0090 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -32,8 +32,7 @@ export default defineConfig(async () => ({ } : undefined, watch: { - // 3. tell Vite to ignore watching `src-tauri` - ignored: ["**/src-tauri/**"], + ignored: ["**/crates/rsql-tauri/**", "**/crates/rsql-core/**", "**/target/**"], }, }, })); From fbf7cd8282deb0f8e520efb4cdcd8d11ce8278bb Mon Sep 17 00:00:00 2001 From: Daniel Boros Date: Sun, 17 May 2026 14:59:24 +0200 Subject: [PATCH 02/11] fix: error --- crates/rsql-tauri/src/drivers/pgsql/commands/pool_connection.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/rsql-tauri/src/drivers/pgsql/commands/pool_connection.rs b/crates/rsql-tauri/src/drivers/pgsql/commands/pool_connection.rs index 825168e..9924d43 100644 --- a/crates/rsql-tauri/src/drivers/pgsql/commands/pool_connection.rs +++ b/crates/rsql-tauri/src/drivers/pgsql/commands/pool_connection.rs @@ -144,7 +144,7 @@ pub async fn pgsql_connector( }; if let Err(e) = meta_pool.get().await { tracing::error!("Meta pool initial connection failed: {:?}", e); - return Err(AppError::ConnectionFailed(full_error_chain(&e)).into()); + return Err(AppError::ConnectionFailed(full_error_chain(&e))); } { From d486623668dc83a036930c9df474a85060a8c935 Mon Sep 17 00:00:00 2001 From: Daniel Boros Date: Mon, 18 May 2026 10:21:01 +0200 Subject: [PATCH 03/11] feat: add rsql-proxy --- Cargo.lock | 466 +++++++++++++++++++++++++- Cargo.toml | 8 +- crates/rsql-proxy/Cargo.toml | 31 ++ crates/rsql-proxy/src/health.rs | 13 + crates/rsql-proxy/src/lib.rs | 21 ++ crates/rsql-proxy/src/main.rs | 48 +++ crates/rsql-proxy/src/static_serve.rs | 9 + crates/rsql-proxy/src/ws.rs | 35 ++ crates/rsql-proxy/tests/health.rs | 24 ++ crates/rsql-proxy/tests/ws_echo.rs | 38 +++ package.json | 3 + 11 files changed, 687 insertions(+), 9 deletions(-) create mode 100644 crates/rsql-proxy/Cargo.toml create mode 100644 crates/rsql-proxy/src/health.rs create mode 100644 crates/rsql-proxy/src/lib.rs create mode 100644 crates/rsql-proxy/src/main.rs create mode 100644 crates/rsql-proxy/src/static_serve.rs create mode 100644 crates/rsql-proxy/src/ws.rs create mode 100644 crates/rsql-proxy/tests/health.rs create mode 100644 crates/rsql-proxy/tests/ws_echo.rs diff --git a/Cargo.lock b/Cargo.lock index f7c9dc7..97099cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -104,6 +104,56 @@ dependencies = [ "libc", ] +[[package]] +name = "anstream" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys 0.61.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.61.0", +] + [[package]] name = "anyhow" version = "1.0.99" @@ -349,7 +399,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" dependencies = [ "async-trait", - "axum-core", + "axum-core 0.3.4", "bitflags 1.3.2", "bytes", "futures-util", @@ -357,7 +407,7 @@ dependencies = [ "http-body 0.4.6", "hyper 0.14.32", "itoa", - "matchit", + "matchit 0.7.3", "memchr", "mime", "percent-encoding", @@ -370,6 +420,43 @@ dependencies = [ "tower-service", ] +[[package]] +name = "axum" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31b698c5f9a010f6573133b09e0de5408834d0c82f8d7475a89fc1867a71cd90" +dependencies = [ + "axum-core 0.5.6", + "axum-macros", + "base64 0.22.1", + "bytes", + "form_urlencoded", + "futures-util", + "http 1.3.1", + "http-body 1.0.1", + "http-body-util", + "hyper 1.7.0", + "hyper-util", + "itoa", + "matchit 0.8.4", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "serde_core", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sha1 0.10.6", + "sync_wrapper 1.0.2", + "tokio", + "tokio-tungstenite 0.29.0", + "tower 0.5.2", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "axum-core" version = "0.3.4" @@ -387,6 +474,36 @@ dependencies = [ "tower-service", ] +[[package]] +name = "axum-core" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" +dependencies = [ + "bytes", + "futures-core", + "http 1.3.1", + "http-body 1.0.1", + "http-body-util", + "mime", + "pin-project-lite", + "sync_wrapper 1.0.2", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-macros" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aa268c23bfbbd2c4363b9cd302a4f504fb2a9dfe7e3451d66f35dd392e20aca" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + [[package]] name = "backtrace" version = "0.3.75" @@ -469,7 +586,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "rustc-hash", + "rustc-hash 1.1.0", "shlex", "syn 2.0.106", "which", @@ -803,6 +920,46 @@ dependencies = [ "libloading 0.8.9", ] +[[package]] +name = "clap" +version = "4.5.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "clap_lex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" + [[package]] name = "cmake" version = "0.1.57" @@ -818,6 +975,12 @@ version = "0.5.0-pre.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5417da527aa9bf6a1e10a781231effd1edd3ee82f27d5f8529ac9b279babce96" +[[package]] +name = "colorchoice" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" + [[package]] name = "combine" version = "4.6.7" @@ -2050,9 +2213,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", + "js-sys", "libc", "r-efi", "wasi 0.14.5+wasi-0.2.4", + "wasm-bindgen", ] [[package]] @@ -2454,6 +2619,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" +[[package]] +name = "http-range-header" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9171a2ea8a68358193d15dd5d70c1c10a2afc3e7e4c5bc92bc9f025cebd7359c" + [[package]] name = "httparse" version = "1.10.1" @@ -2512,6 +2683,7 @@ dependencies = [ "http 1.3.1", "http-body 1.0.1", "httparse", + "httpdate", "itoa", "pin-project-lite", "pin-utils", @@ -2552,6 +2724,7 @@ dependencies = [ "tokio", "tokio-rustls 0.26.4", "tower-service", + "webpki-roots 1.0.6", ] [[package]] @@ -2855,6 +3028,12 @@ dependencies = [ "once_cell", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + [[package]] name = "itertools" version = "0.12.1" @@ -3298,6 +3477,12 @@ version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + [[package]] name = "mac" version = "0.1.1" @@ -3329,6 +3514,15 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + [[package]] name = "matches" version = "0.1.10" @@ -3341,6 +3535,12 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" +[[package]] +name = "matchit" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" + [[package]] name = "md-5" version = "0.10.6" @@ -3378,6 +3578,16 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -3858,6 +4068,12 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + [[package]] name = "opaque-debug" version = "0.3.1" @@ -4705,6 +4921,61 @@ dependencies = [ "memchr", ] +[[package]] +name = "quinn" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" +dependencies = [ + "bytes", + "cfg_aliases 0.2.1", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash 2.1.2", + "rustls 0.23.37", + "socket2 0.6.0", + "thiserror 2.0.16", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" +dependencies = [ + "bytes", + "getrandom 0.3.3", + "lru-slab", + "rand 0.9.2", + "ring", + "rustc-hash 2.1.2", + "rustls 0.23.37", + "rustls-pki-types", + "slab", + "thiserror 2.0.16", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +dependencies = [ + "cfg_aliases 0.2.1", + "libc", + "once_cell", + "socket2 0.6.0", + "tracing", + "windows-sys 0.60.2", +] + [[package]] name = "quote" version = "1.0.40" @@ -4946,6 +5217,44 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cadadef317c2f20755a64d7fdc48f9e7178ee6b0e1f7fce33fa60f1d68a276e6" +[[package]] +name = "reqwest" +version = "0.12.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-core", + "http 1.3.1", + "http-body 1.0.1", + "http-body-util", + "hyper 1.7.0", + "hyper-rustls 0.27.7", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls 0.23.37", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 1.0.2", + "tokio", + "tokio-rustls 0.26.4", + "tower 0.5.2", + "tower-http 0.6.8", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots 1.0.6", +] + [[package]] name = "reqwest" version = "0.13.2" @@ -5137,6 +5446,24 @@ dependencies = [ "tracing", ] +[[package]] +name = "rsql-proxy" +version = "1.1.5" +dependencies = [ + "axum 0.8.9", + "clap", + "futures-util", + "reqwest 0.12.28", + "serde", + "serde_json", + "tokio", + "tokio-tungstenite 0.24.0", + "tower 0.5.2", + "tower-http 0.6.8", + "tracing", + "tracing-subscriber", +] + [[package]] name = "russh" version = "0.57.1" @@ -5236,6 +5563,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" + [[package]] name = "rustc_version" version = "0.4.1" @@ -5339,6 +5672,7 @@ version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" dependencies = [ + "web-time", "zeroize", ] @@ -5640,6 +5974,17 @@ dependencies = [ "zmij", ] +[[package]] +name = "serde_path_to_error" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" +dependencies = [ + "itoa", + "serde", + "serde_core", +] + [[package]] name = "serde_repr" version = "0.1.20" @@ -5669,6 +6014,18 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + [[package]] name = "serde_with" version = "3.14.0" @@ -6330,7 +6687,7 @@ dependencies = [ "percent-encoding", "plist", "raw-window-handle", - "reqwest", + "reqwest 0.13.2", "serde", "serde_json", "serde_repr", @@ -6540,7 +6897,7 @@ dependencies = [ "minisign-verify", "osakit", "percent-encoding", - "reqwest", + "reqwest 0.13.2", "rustls 0.23.37", "semver", "serde", @@ -6914,6 +7271,30 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-tungstenite" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite 0.24.0", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f72a05e828585856dacd553fba484c242c46e391fb0e58917c942ee9202915c" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite 0.29.0", +] + [[package]] name = "tokio-util" version = "0.7.16" @@ -7030,7 +7411,7 @@ checksum = "76c4eb7a4e9ef9d4763600161f12f5070b92a578e1b634db88a6887844c91a13" dependencies = [ "async-stream", "async-trait", - "axum", + "axum 0.6.20", "base64 0.21.7", "bytes", "h2", @@ -7102,6 +7483,7 @@ dependencies = [ "tokio", "tower-layer", "tower-service", + "tracing", ] [[package]] @@ -7116,7 +7498,7 @@ dependencies = [ "futures-util", "http 0.2.12", "http-body 0.4.6", - "http-range-header", + "http-range-header 0.3.1", "pin-project-lite", "tower 0.4.13", "tower-layer", @@ -7132,14 +7514,24 @@ checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ "bitflags 2.9.4", "bytes", + "futures-core", "futures-util", "http 1.3.1", "http-body 1.0.1", + "http-body-util", + "http-range-header 0.4.2", + "httpdate", "iri-string", + "mime", + "mime_guess", + "percent-encoding", "pin-project-lite", + "tokio", + "tokio-util", "tower 0.5.2", "tower-layer", "tower-service", + "tracing", ] [[package]] @@ -7204,10 +7596,14 @@ version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" dependencies = [ + "matchers", "nu-ansi-term", + "once_cell", + "regex-automata", "sharded-slab", "smallvec", "thread_local", + "tracing", "tracing-core", "tracing-log", ] @@ -7240,6 +7636,40 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "tungstenite" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http 1.3.1", + "httparse", + "log", + "rand 0.8.5", + "sha1 0.10.6", + "thiserror 1.0.69", + "utf-8", +] + +[[package]] +name = "tungstenite" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c01152af293afb9c7c2a57e4b559c5620b421f6d133261c60dd2d0cdb38e6b8" +dependencies = [ + "bytes", + "data-encoding", + "http 1.3.1", + "httparse", + "log", + "rand 0.9.2", + "sha1 0.10.6", + "thiserror 2.0.16", +] + [[package]] name = "typeid" version = "1.0.3" @@ -7313,6 +7743,12 @@ dependencies = [ "unic-common", ] +[[package]] +name = "unicase" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" + [[package]] name = "unicode-bidi" version = "0.3.18" @@ -7404,6 +7840,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "uuid" version = "1.18.1" @@ -7597,6 +8039,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "webkit2gtk" version = "2.0.2" diff --git a/Cargo.toml b/Cargo.toml index 7b9635b..2d7ee14 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["crates/rsql-tauri", "crates/rsql-core"] +members = ["crates/rsql-tauri", "crates/rsql-core", "crates/rsql-proxy"] resolver = "3" [workspace.package] @@ -18,7 +18,7 @@ deadpool-postgres = "0.14.1" postgres-native-tls = "0.5" native-tls = "0.2" tracing = "0.1.41" -tracing-subscriber = { version = "0.3.20", features = ["fmt"] } +tracing-subscriber = { version = "0.3.20", features = ["fmt", "env-filter"] } libsql = "0.9.29" thiserror = "2" portable-pty = "0.9.0" @@ -27,6 +27,10 @@ sysinfo = "0.38.3" csv = "1.3" futures-util = "0.3" russh = "0.57" +axum = { version = "0.8", features = ["ws", "macros"] } +tower-http = { version = "0.6", features = ["fs", "trace"] } +tower = "0.5" +clap = { version = "4.5", features = ["derive"] } [profile.release] codegen-units = 1 diff --git a/crates/rsql-proxy/Cargo.toml b/crates/rsql-proxy/Cargo.toml new file mode 100644 index 0000000..8162338 --- /dev/null +++ b/crates/rsql-proxy/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "rsql-proxy" +version.workspace = true +edition.workspace = true +authors.workspace = true +description = "rsql-proxy: WebSocket bridge for the browser/hosted RSQL build" + +[lib] +name = "rsql_proxy" +path = "src/lib.rs" + +[[bin]] +name = "rsql-proxy" +path = "src/main.rs" + +[dependencies] +axum = { workspace = true } +tower = { workspace = true } +tower-http = { workspace = true } +tokio = { workspace = true, features = ["rt-multi-thread", "macros", "signal", "net"] } +tracing = { workspace = true } +tracing-subscriber = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +clap = { workspace = true } +futures-util = { workspace = true } + +[dev-dependencies] +reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] } +tokio-tungstenite = "0.24" +tokio = { workspace = true, features = ["macros", "rt-multi-thread", "time"] } diff --git a/crates/rsql-proxy/src/health.rs b/crates/rsql-proxy/src/health.rs new file mode 100644 index 0000000..f6ec535 --- /dev/null +++ b/crates/rsql-proxy/src/health.rs @@ -0,0 +1,13 @@ +use axum::{Json, Router, routing::get}; +use serde_json::{Value, json}; + +pub fn routes() -> Router { + Router::new().route("/health", get(handler)) +} + +async fn handler() -> Json { + Json(json!({ + "status": "ok", + "version": env!("CARGO_PKG_VERSION"), + })) +} diff --git a/crates/rsql-proxy/src/lib.rs b/crates/rsql-proxy/src/lib.rs new file mode 100644 index 0000000..5509629 --- /dev/null +++ b/crates/rsql-proxy/src/lib.rs @@ -0,0 +1,21 @@ +//! rsql-proxy: WebSocket bridge for browser/hosted RSQL. + +pub mod health; +pub mod static_serve; +pub mod ws; + +use axum::Router; +use std::path::PathBuf; +use tower_http::trace::TraceLayer; + +pub fn router(dist_dir: Option<&str>) -> Router { + let mut app = Router::new() + .merge(health::routes()) + .merge(ws::routes()); + + if let Some(dir) = dist_dir { + app = app.merge(static_serve::routes(PathBuf::from(dir))); + } + + app.layer(TraceLayer::new_for_http()) +} diff --git a/crates/rsql-proxy/src/main.rs b/crates/rsql-proxy/src/main.rs new file mode 100644 index 0000000..76b0be2 --- /dev/null +++ b/crates/rsql-proxy/src/main.rs @@ -0,0 +1,48 @@ +use clap::Parser; +use std::net::SocketAddr; +use tokio::net::TcpListener; +use tracing_subscriber::EnvFilter; + +#[derive(Parser, Debug)] +#[command(name = "rsql-proxy", version, about = "rsql-proxy: WebSocket bridge for browser/hosted RSQL")] +struct Args { + #[arg(long, default_value = "127.0.0.1:8080")] + addr: SocketAddr, + + #[arg(long, default_value = "dist")] + dist_dir: String, +} + +#[tokio::main] +async fn main() { + let args = Args::parse(); + + tracing_subscriber::fmt() + .with_env_filter( + EnvFilter::try_from_default_env() + .unwrap_or_else(|_| EnvFilter::new("info,rsql_proxy=debug")), + ) + .with_target(false) + .init(); + + let listener = TcpListener::bind(args.addr) + .await + .expect("failed to bind listener"); + tracing::info!( + version = env!("CARGO_PKG_VERSION"), + addr = %listener.local_addr().unwrap(), + dist = %args.dist_dir, + "rsql-proxy listening" + ); + + let app = rsql_proxy::router(Some(&args.dist_dir)); + axum::serve(listener, app) + .with_graceful_shutdown(shutdown_signal()) + .await + .expect("axum::serve failed"); +} + +async fn shutdown_signal() { + tokio::signal::ctrl_c().await.expect("ctrl-c handler"); + tracing::info!("shutdown signal received"); +} diff --git a/crates/rsql-proxy/src/static_serve.rs b/crates/rsql-proxy/src/static_serve.rs new file mode 100644 index 0000000..e2d2d53 --- /dev/null +++ b/crates/rsql-proxy/src/static_serve.rs @@ -0,0 +1,9 @@ +use axum::Router; +use std::path::PathBuf; +use tower_http::services::{ServeDir, ServeFile}; + +pub fn routes(dist_dir: PathBuf) -> Router { + let index = dist_dir.join("index.html"); + let serve_dir = ServeDir::new(&dist_dir).fallback(ServeFile::new(&index)); + Router::new().fallback_service(serve_dir) +} diff --git a/crates/rsql-proxy/src/ws.rs b/crates/rsql-proxy/src/ws.rs new file mode 100644 index 0000000..7bf7745 --- /dev/null +++ b/crates/rsql-proxy/src/ws.rs @@ -0,0 +1,35 @@ +use axum::{ + Router, + extract::ws::{Message, WebSocket, WebSocketUpgrade}, + response::IntoResponse, + routing::get, +}; +use futures_util::StreamExt; + +pub fn routes() -> Router { + Router::new().route("/ws", get(upgrade)) +} + +async fn upgrade(ws: WebSocketUpgrade) -> impl IntoResponse { + ws.on_upgrade(echo_loop) +} + +async fn echo_loop(mut socket: WebSocket) { + while let Some(Ok(msg)) = socket.next().await { + match msg { + Message::Text(t) => { + if socket.send(Message::Text(t)).await.is_err() { + break; + } + } + Message::Binary(b) => { + if socket.send(Message::Binary(b)).await.is_err() { + break; + } + } + Message::Close(_) => break, + // Ping/Pong: axum handles automatically. + _ => {} + } + } +} diff --git a/crates/rsql-proxy/tests/health.rs b/crates/rsql-proxy/tests/health.rs new file mode 100644 index 0000000..b41f64f --- /dev/null +++ b/crates/rsql-proxy/tests/health.rs @@ -0,0 +1,24 @@ +use std::net::SocketAddr; +use tokio::net::TcpListener; + +async fn spawn_test_server() -> SocketAddr { + let listener = TcpListener::bind("127.0.0.1:0").await.expect("bind"); + let addr = listener.local_addr().expect("local_addr"); + let app = rsql_proxy::router(None); + tokio::spawn(async move { + axum::serve(listener, app).await.expect("serve"); + }); + // Small wait for the server to be ready + tokio::time::sleep(std::time::Duration::from_millis(50)).await; + addr +} + +#[tokio::test] +async fn health_returns_ok_with_version() { + let addr = spawn_test_server().await; + let url = format!("http://{addr}/health"); + let resp: serde_json::Value = reqwest::get(&url).await.unwrap().json().await.unwrap(); + assert_eq!(resp["status"], "ok"); + assert!(resp["version"].is_string()); + assert!(!resp["version"].as_str().unwrap().is_empty()); +} diff --git a/crates/rsql-proxy/tests/ws_echo.rs b/crates/rsql-proxy/tests/ws_echo.rs new file mode 100644 index 0000000..c67082c --- /dev/null +++ b/crates/rsql-proxy/tests/ws_echo.rs @@ -0,0 +1,38 @@ +use futures_util::{SinkExt, StreamExt}; +use std::net::SocketAddr; +use tokio::net::TcpListener; +use tokio_tungstenite::tungstenite::Message; + +async fn spawn_test_server() -> SocketAddr { + let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); + let addr = listener.local_addr().unwrap(); + let app = rsql_proxy::router(None); + tokio::spawn(async move { + axum::serve(listener, app).await.unwrap(); + }); + tokio::time::sleep(std::time::Duration::from_millis(50)).await; + addr +} + +#[tokio::test] +async fn ws_echoes_text_frame() { + let addr = spawn_test_server().await; + let url = format!("ws://{addr}/ws"); + let (mut stream, _) = tokio_tungstenite::connect_async(&url).await.expect("connect"); + + stream.send(Message::Text("hello".into())).await.unwrap(); + let received = stream.next().await.expect("frame").expect("ok"); + assert_eq!(received, Message::Text("hello".into())); +} + +#[tokio::test] +async fn ws_echoes_binary_frame() { + let addr = spawn_test_server().await; + let url = format!("ws://{addr}/ws"); + let (mut stream, _) = tokio_tungstenite::connect_async(&url).await.expect("connect"); + + let payload = vec![0u8, 1, 2, 3, 0x1F, 0x1E, 0xFF]; + stream.send(Message::Binary(payload.clone().into())).await.unwrap(); + let received = stream.next().await.expect("frame").expect("ok"); + assert_eq!(received, Message::Binary(payload.into())); +} diff --git a/package.json b/package.json index 9f1303e..7a4b733 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,9 @@ "build": "tsc && vite build", "preview": "vite preview", "tauri": "cd crates/rsql-tauri && tauri", + "proxy": "cargo run -p rsql-proxy", + "proxy:build": "yarn build && cargo build -p rsql-proxy --release", + "proxy:release": "yarn build && cargo run -p rsql-proxy --release", "format": "biome format --write .", "lint": "biome lint .", "check": "biome check --write .", From 7930dbc7ce14b8b173eb307dbdd38a30ff1cecc6 Mon Sep 17 00:00:00 2001 From: Daniel Boros Date: Mon, 18 May 2026 14:33:02 +0200 Subject: [PATCH 04/11] feat: phase 3 --- Cargo.lock | 9 + Cargo.toml | 2 + crates/rsql-core/Cargo.toml | 3 + .../src/drivers/pgsql/commands/connection.rs | 153 ++++++++++++- .../src/drivers/pgsql/commands/pubsub.rs | 118 ++++++++++ crates/rsql-core/src/drivers/pgsql/mod.rs | 1 + .../src/drivers/pgsql/streaming.rs | 89 ++++---- crates/rsql-core/src/events.rs | 47 ++++ crates/rsql-core/src/lib.rs | 3 + crates/rsql-core/src/state/bootstrap.rs | 117 ++++++++++ crates/rsql-core/src/state/mod.rs | 3 + crates/rsql-core/src/terminal/mod.rs | 72 +++++++ crates/rsql-core/src/terminal/session.rs | 67 ++++++ crates/rsql-core/tests/state_smoke.rs | 30 +++ crates/rsql-proxy/Cargo.toml | 6 + crates/rsql-proxy/src/dispatch/mod.rs | 57 +++++ crates/rsql-proxy/src/dispatch/pgsql_meta.rs | 70 ++++++ .../src/dispatch/pgsql_meta_admin.rs | 140 ++++++++++++ .../src/dispatch/pgsql_meta_connection.rs | 87 ++++++++ .../src/dispatch/pgsql_meta_metadata.rs | 204 ++++++++++++++++++ .../src/dispatch/pgsql_meta_objects.rs | 89 ++++++++ .../src/dispatch/pgsql_meta_statistics.rs | 92 ++++++++ .../rsql-proxy/src/dispatch/pgsql_pubsub.rs | 54 +++++ crates/rsql-proxy/src/dispatch/pgsql_query.rs | 141 ++++++++++++ crates/rsql-proxy/src/dispatch/state_cmds.rs | 124 +++++++++++ .../rsql-proxy/src/dispatch/terminal_cmds.rs | 49 +++++ crates/rsql-proxy/src/dispatch/utils_cmds.rs | 50 +++++ crates/rsql-proxy/src/event_sink.rs | 23 ++ crates/rsql-proxy/src/lib.rs | 20 +- crates/rsql-proxy/src/main.rs | 24 ++- crates/rsql-proxy/src/protocol.rs | 151 +++++++++++++ crates/rsql-proxy/src/session.rs | 58 +++++ crates/rsql-proxy/src/ws.rs | 114 ++++++++-- crates/rsql-proxy/tests/common/mod.rs | 27 +++ crates/rsql-proxy/tests/dispatch_smoke.rs | 53 +++++ crates/rsql-proxy/tests/health.rs | 18 +- crates/rsql-proxy/tests/integration_pg.rs | 56 +++++ crates/rsql-proxy/tests/protocol.rs | 24 +++ crates/rsql-proxy/tests/session_lifecycle.rs | 31 +++ crates/rsql-proxy/tests/ws_echo.rs | 39 +--- crates/rsql-tauri/Cargo.toml | 1 + crates/rsql-tauri/src/app_setup.rs | 119 +--------- .../drivers/pgsql/commands/pool_connection.rs | 147 +------------ .../drivers/pgsql/commands/pubsub_commands.rs | 141 +----------- .../drivers/pgsql/commands/query_commands.rs | 5 +- crates/rsql-tauri/src/drivers/pgsql/mod.rs | 1 - crates/rsql-tauri/src/event_sink.rs | 22 ++ crates/rsql-tauri/src/main.rs | 1 + crates/rsql-tauri/src/terminal.rs | 111 ++-------- 49 files changed, 2444 insertions(+), 619 deletions(-) rename crates/{rsql-tauri => rsql-core}/src/drivers/pgsql/streaming.rs (61%) create mode 100644 crates/rsql-core/src/events.rs create mode 100644 crates/rsql-core/src/state/bootstrap.rs create mode 100644 crates/rsql-core/src/terminal/mod.rs create mode 100644 crates/rsql-core/src/terminal/session.rs create mode 100644 crates/rsql-proxy/src/dispatch/mod.rs create mode 100644 crates/rsql-proxy/src/dispatch/pgsql_meta.rs create mode 100644 crates/rsql-proxy/src/dispatch/pgsql_meta_admin.rs create mode 100644 crates/rsql-proxy/src/dispatch/pgsql_meta_connection.rs create mode 100644 crates/rsql-proxy/src/dispatch/pgsql_meta_metadata.rs create mode 100644 crates/rsql-proxy/src/dispatch/pgsql_meta_objects.rs create mode 100644 crates/rsql-proxy/src/dispatch/pgsql_meta_statistics.rs create mode 100644 crates/rsql-proxy/src/dispatch/pgsql_pubsub.rs create mode 100644 crates/rsql-proxy/src/dispatch/pgsql_query.rs create mode 100644 crates/rsql-proxy/src/dispatch/state_cmds.rs create mode 100644 crates/rsql-proxy/src/dispatch/terminal_cmds.rs create mode 100644 crates/rsql-proxy/src/dispatch/utils_cmds.rs create mode 100644 crates/rsql-proxy/src/event_sink.rs create mode 100644 crates/rsql-proxy/src/protocol.rs create mode 100644 crates/rsql-proxy/src/session.rs create mode 100644 crates/rsql-proxy/tests/common/mod.rs create mode 100644 crates/rsql-proxy/tests/dispatch_smoke.rs create mode 100644 crates/rsql-proxy/tests/integration_pg.rs create mode 100644 crates/rsql-proxy/tests/protocol.rs create mode 100644 crates/rsql-proxy/tests/session_lifecycle.rs create mode 100644 crates/rsql-tauri/src/event_sink.rs diff --git a/Cargo.lock b/Cargo.lock index 97099cb..9e5f5c6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5394,6 +5394,7 @@ dependencies = [ name = "rsql" version = "1.1.5" dependencies = [ + "async-trait", "csv", "deadpool-postgres", "futures-util", @@ -5427,6 +5428,7 @@ dependencies = [ name = "rsql-core" version = "1.1.5" dependencies = [ + "async-trait", "csv", "deadpool-postgres", "futures-util", @@ -5440,28 +5442,35 @@ dependencies = [ "serde_json", "sonic-rs", "sysinfo", + "tempfile", "thiserror 2.0.16", "tokio", "tokio-postgres", "tracing", + "uuid", ] [[package]] name = "rsql-proxy" version = "1.1.5" dependencies = [ + "async-trait", "axum 0.8.9", "clap", "futures-util", "reqwest 0.12.28", + "rsql-core", "serde", "serde_json", + "tempfile", "tokio", + "tokio-postgres", "tokio-tungstenite 0.24.0", "tower 0.5.2", "tower-http 0.6.8", "tracing", "tracing-subscriber", + "uuid", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 2d7ee14..6078f53 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,8 @@ axum = { version = "0.8", features = ["ws", "macros"] } tower-http = { version = "0.6", features = ["fs", "trace"] } tower = "0.5" clap = { version = "4.5", features = ["derive"] } +async-trait = "0.1" +uuid = { version = "1", features = ["v7", "serde"] } [profile.release] codegen-units = 1 diff --git a/crates/rsql-core/Cargo.toml b/crates/rsql-core/Cargo.toml index 9bbfefd..cf34622 100644 --- a/crates/rsql-core/Cargo.toml +++ b/crates/rsql-core/Cargo.toml @@ -26,6 +26,9 @@ sysinfo.workspace = true csv.workspace = true futures-util.workspace = true russh.workspace = true +async-trait = { workspace = true } +uuid = { workspace = true } [dev-dependencies] tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } +tempfile = "3" diff --git a/crates/rsql-core/src/drivers/pgsql/commands/connection.rs b/crates/rsql-core/src/drivers/pgsql/commands/connection.rs index 90861be..24e204e 100644 --- a/crates/rsql-core/src/drivers/pgsql/commands/connection.rs +++ b/crates/rsql-core/src/drivers/pgsql/commands/connection.rs @@ -1,9 +1,160 @@ +use std::sync::Arc; + use tokio_postgres::Config; -use crate::error::AppError; +use crate::AppState; +use crate::error::{AppError, ProjectConnectionStatus}; use super::pool_helpers::{create_pg_pool, full_error_chain}; +pub async fn pgsql_connector( + state: &AppState, + project_id: &str, + key: Option<[&str; 6]>, + ssh: Option>, +) -> Result { + { + let clients = state.clients.lock().await; + if clients.contains_key(project_id) { + return Ok(ProjectConnectionStatus::Connected); + } + } + + let (user, password, database, host, port_str, use_ssl) = match key { + Some(k) => ( + k[0].to_string(), + k[1].to_string(), + k[2].to_string(), + k[3].to_string(), + k[4].to_string(), + k[5] == "true", + ), + None => { + let conn = state + .local_db + .connect() + .map_err(|e| AppError::DatabaseError(e.to_string()))?; + let mut rows = conn + .query( + "SELECT username, password, database, host, port, ssl FROM projects WHERE id = ?1", + libsql::params![project_id], + ) + .await + .map_err(|e| AppError::DatabaseError(e.to_string()))?; + let row = rows + .next() + .await + .map_err(|e| AppError::DatabaseError(e.to_string()))? + .ok_or_else(|| AppError::ProjectNotFound(project_id.to_string()))?; + ( + row.get::(0).unwrap_or_default(), + row.get::(1).unwrap_or_default(), + row.get::(2).unwrap_or_default(), + row.get::(3).unwrap_or_default(), + row.get::(4).unwrap_or_default(), + row.get::(5).map(|s| s == "true").unwrap_or(false), + ) + } + }; + + let (effective_host, effective_port_str) = if let Some(ref ssh_params) = ssh { + if ssh_params.len() >= 3 && !ssh_params[0].is_empty() { + let ssh_host = &ssh_params[0]; + let ssh_port: u16 = ssh_params[1].parse().unwrap_or(22); + let ssh_user = &ssh_params[2]; + let ssh_password = ssh_params + .get(3) + .filter(|s| !s.is_empty()) + .map(|s| s.as_str()); + let ssh_key_path = ssh_params + .get(4) + .filter(|s| !s.is_empty()) + .map(|s| s.as_str()); + + state.ssh_tunnels.lock().await.remove(project_id); + + let tunnel = crate::ssh::start_tunnel( + ssh_host, + ssh_port, + ssh_user, + ssh_password, + ssh_key_path, + &host, + port_str.parse().unwrap_or(5432), + ) + .await + .map_err(|e| AppError::ConnectionFailed(e))?; + + let local_port = tunnel.local_port; + state + .ssh_tunnels + .lock() + .await + .insert(project_id.to_string(), tunnel); + + ("127.0.0.1".to_string(), local_port.to_string()) + } else { + (host.clone(), port_str.clone()) + } + } else { + (host.clone(), port_str.clone()) + }; + + let port: u16 = effective_port_str.parse().unwrap_or(5432); + let mut cfg = Config::new(); + cfg.user(&user) + .password(&password) + .dbname(&database) + .host(&effective_host) + .port(port); + + let query_pool = match create_pg_pool(&cfg, use_ssl, 16) { + Ok(p) => Arc::new(p), + Err(e) => { + tracing::error!("Query pool creation failed: {:?}", e); + return Err(AppError::ConnectionFailed(full_error_chain(&e))); + } + }; + let meta_pool = match create_pg_pool(&cfg, use_ssl, 8) { + Ok(p) => Arc::new(p), + Err(e) => { + tracing::error!("Meta pool creation failed: {:?}", e); + return Err(AppError::ConnectionFailed(full_error_chain(&e))); + } + }; + + let query_client = match query_pool.get().await { + Ok(c) => c, + Err(e) => { + tracing::error!("Query pool initial connection failed: {:?}", e); + return Err(AppError::ConnectionFailed(full_error_chain(&e))); + } + }; + if let Err(e) = meta_pool.get().await { + tracing::error!("Meta pool initial connection failed: {:?}", e); + return Err(AppError::ConnectionFailed(full_error_chain(&e))); + } + + { + let mut clients = state.clients.lock().await; + clients.insert(project_id.to_string(), Arc::clone(&query_pool)); + } + { + let mut meta_clients = state.meta_clients.lock().await; + meta_clients.insert(project_id.to_string(), Arc::clone(&meta_pool)); + } + { + let mut cancel_tokens = state.cancel_tokens.lock().await; + cancel_tokens.insert(project_id.to_string(), query_client.cancel_token()); + } + { + let mut client_ssl = state.client_ssl.lock().await; + client_ssl.insert(project_id.to_string(), use_ssl); + } + + Ok(ProjectConnectionStatus::Connected) +} + pub async fn pgsql_test_connection(key: [&str; 6]) -> Result { let user = key[0]; let password = key[1]; diff --git a/crates/rsql-core/src/drivers/pgsql/commands/pubsub.rs b/crates/rsql-core/src/drivers/pgsql/commands/pubsub.rs index 3a9c814..176e2d0 100644 --- a/crates/rsql-core/src/drivers/pgsql/commands/pubsub.rs +++ b/crates/rsql-core/src/drivers/pgsql/commands/pubsub.rs @@ -1,6 +1,12 @@ use crate::AppState; use crate::drivers::pgsql::roles_schema_objects::discover_notify_channels; use crate::error::AppError; +use crate::events::SharedEventSink; + +use futures_util::StreamExt; +use native_tls::TlsConnector; +use postgres_native_tls::MakeTlsConnector; +use tokio_postgres::{AsyncMessage, Config, NoTls}; use super::pool_helpers::acquire_client; @@ -30,3 +36,115 @@ pub async fn pgsql_discover_channels( let client = acquire_client(&app_state.meta_clients, project_id).await?; discover_notify_channels(&client).await } + +pub async fn listen_start( + app_state: &AppState, + project_id: &str, + channel: &str, + sink: SharedEventSink, +) -> Result { + let listen_key = format!("{project_id}:{channel}"); + { + let handles = app_state.notify_handles.lock().await; + if handles.contains_key(&listen_key) { + return Ok(true); + } + } + + let (cfg, use_ssl) = { + let conn = app_state + .local_db + .connect() + .map_err(|e| AppError::DatabaseError(e.to_string()))?; + let mut rows = conn + .query( + "SELECT username, password, database, host, port, ssl FROM projects WHERE id = ?1", + libsql::params![project_id], + ) + .await + .map_err(|e| AppError::DatabaseError(e.to_string()))?; + let row = rows + .next() + .await + .map_err(|e| AppError::DatabaseError(e.to_string()))? + .ok_or_else(|| AppError::ProjectNotFound(project_id.to_string()))?; + let mut cfg = Config::new(); + cfg.user(row.get::(0).unwrap_or_default()) + .password(row.get::(1).unwrap_or_default()) + .dbname(row.get::(2).unwrap_or_default()) + .host(row.get::(3).unwrap_or_default()) + .port(row.get::(4).unwrap_or_default().parse().unwrap_or(5432)); + let ssl = row.get::(5).map(|s| s == "true").unwrap_or(false); + (cfg, ssl) + }; + + let channel_owned = channel.to_string(); + let event_name = format!("pg-notify-{project_id}"); + let handle = tokio::spawn(async move { + async fn listen_loop( + client: tokio_postgres::Client, + mut connection: tokio_postgres::Connection, + channel: &str, + event_name: &str, + sink: &SharedEventSink, + ) where + S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin, + T: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin, + { + let listen_sql = format!("LISTEN \"{}\"", channel.replace('"', "\"\"")); + if let Err(e) = client.batch_execute(&listen_sql).await { + tracing::error!("LISTEN command failed: {e:?}"); + return; + } + let mut stream = futures_util::stream::poll_fn(move |cx| connection.poll_message(cx)); + while let Some(msg) = stream.next().await { + match msg { + Ok(AsyncMessage::Notification(n)) => { + let payload = serde_json::json!({ + "channel": n.channel(), + "payload": n.payload(), + }); + sink.emit_json(event_name, payload).await; + } + Ok(_) => {} + Err(e) => { + tracing::error!("LISTEN stream error: {e:?}"); + break; + } + } + } + drop(client); + } + + if use_ssl { + let tls_connector = match TlsConnector::builder().build() { + Ok(c) => c, + Err(e) => { + tracing::error!("LISTEN TLS error: {e:?}"); + return; + } + }; + let tls = MakeTlsConnector::new(tls_connector); + if let Ok((client, connection)) = cfg.connect(tls).await { + listen_loop(client, connection, &channel_owned, &event_name, &sink).await; + } + } else if let Ok((client, connection)) = cfg.connect(NoTls).await { + listen_loop(client, connection, &channel_owned, &event_name, &sink).await; + } + }); + + app_state.notify_handles.lock().await.insert(listen_key, handle); + Ok(true) +} + +pub async fn listen_stop( + app_state: &AppState, + project_id: &str, + channel: &str, +) -> Result { + let listen_key = format!("{project_id}:{channel}"); + if let Some(handle) = app_state.notify_handles.lock().await.remove(&listen_key) { + handle.abort(); + } + Ok(true) +} diff --git a/crates/rsql-core/src/drivers/pgsql/mod.rs b/crates/rsql-core/src/drivers/pgsql/mod.rs index ae7ed91..bbed2fa 100644 --- a/crates/rsql-core/src/drivers/pgsql/mod.rs +++ b/crates/rsql-core/src/drivers/pgsql/mod.rs @@ -4,6 +4,7 @@ pub mod extensions; pub mod metadata_schema; pub mod metadata_views_functions; pub mod query_execution; +pub mod streaming; pub mod roles_schema_objects; pub mod statistics_activity; diff --git a/crates/rsql-tauri/src/drivers/pgsql/streaming.rs b/crates/rsql-core/src/drivers/pgsql/streaming.rs similarity index 61% rename from crates/rsql-tauri/src/drivers/pgsql/streaming.rs rename to crates/rsql-core/src/drivers/pgsql/streaming.rs index 4b578ac..92f596d 100644 --- a/crates/rsql-tauri/src/drivers/pgsql/streaming.rs +++ b/crates/rsql-core/src/drivers/pgsql/streaming.rs @@ -1,11 +1,11 @@ use std::time::Instant; use tokio_postgres::{Client, SimpleQueryMessage}; -use rsql_core::drivers::pgsql::CELL_SEP; -use rsql_core::drivers::pgsql::query_execution::{join_sep, pack_rows_vec, process_simple_messages}; -use rsql_core::error::AppError; +use crate::drivers::pgsql::CELL_SEP; +use crate::drivers::pgsql::query_execution::{join_sep, pack_rows_vec, process_simple_messages}; +use crate::error::AppError; +use crate::events::{SharedEventSink, emit_typed}; -/// Events emitted during streamed query execution. #[derive(serde::Serialize, Clone)] #[serde(tag = "type")] pub enum QueryStreamEvent { @@ -17,35 +17,27 @@ pub enum QueryStreamEvent { Done { elapsed: f32, capped: bool }, } -/// Maximum rows to send to the frontend to prevent OOM in the webview. const MAX_STREAM_ROWS: usize = 500_000; const CURSOR_FETCH_SIZE: usize = 10_000; -/// Stream query results using a PostgreSQL cursor. -/// Fetches rows in batches from the server — never loads the full result into Rust memory. -/// Caps at MAX_STREAM_ROWS to protect the webview from OOM. pub async fn execute_query_streamed( client: &Client, sql: &str, stream_id: &str, - app: &tauri::AppHandle, + sink: &SharedEventSink, ) -> Result<(), AppError> { - use tauri::Emitter; - let start = Instant::now(); - let event_name = format!("query-stream-{}", stream_id); + let event_name = format!("query-stream-{stream_id}"); - // Begin transaction + declare cursor for memory-efficient streaming client .batch_execute("BEGIN") .await .map_err(|e| AppError::QueryFailed(e.to_string()))?; - let cursor_sql = format!("DECLARE _rsql_cur NO SCROLL CURSOR FOR {}", sql); + let cursor_sql = format!("DECLARE _rsql_cur NO SCROLL CURSOR FOR {sql}"); match client.batch_execute(&cursor_sql).await { Ok(_) => { - // Cursor-based fetch loop using simple_query for zero type conversion - let fetch_sql = format!("FETCH {} FROM _rsql_cur", CURSOR_FETCH_SIZE); + let fetch_sql = format!("FETCH {CURSOR_FETCH_SIZE} FROM _rsql_cur"); let mut total_sent: usize = 0; let mut columns_sent = false; let mut capped = false; @@ -86,18 +78,17 @@ pub async fn execute_query_streamed( if !columns_sent && let Some(cols) = batch_columns { let header = join_sep(&cols, CELL_SEP); - let _ = app.emit( + emit_typed( + sink, &event_name, - QueryStreamEvent::Columns { - columns: header, - total_rows: 0, - }, - ); + &QueryStreamEvent::Columns { columns: header, total_rows: 0 }, + ) + .await; columns_sent = true; } let packed = pack_rows_vec(&batch_rows); - let _ = app.emit(&event_name, QueryStreamEvent::Chunk { data: packed }); + emit_typed(sink, &event_name, &QueryStreamEvent::Chunk { data: packed }).await; total_sent += batch_rows.len(); if total_sent >= MAX_STREAM_ROWS { @@ -107,26 +98,23 @@ pub async fn execute_query_streamed( } if !columns_sent { - let _ = app.emit( + emit_typed( + sink, &event_name, - QueryStreamEvent::Columns { - columns: String::new(), - total_rows: 0, - }, - ); + &QueryStreamEvent::Columns { columns: String::new(), total_rows: 0 }, + ) + .await; } client.batch_execute("CLOSE _rsql_cur").await.ok(); client.batch_execute("COMMIT").await.ok(); let elapsed = start.elapsed().as_millis() as f32; - let _ = app.emit(&event_name, QueryStreamEvent::Done { elapsed, capped }); + emit_typed(sink, &event_name, &QueryStreamEvent::Done { elapsed, capped }).await; } - Err(_cursor_err) => { - // DECLARE CURSOR failed (non-SELECT query like INSERT/UPDATE/DDL) + Err(_) => { client.batch_execute("ROLLBACK").await.ok(); - // Re-execute with simple_query for multi-statement support let messages = client .simple_query(sql) .await @@ -135,35 +123,32 @@ pub async fn execute_query_streamed( let (columns, rows) = process_simple_messages(messages); if columns.is_empty() { - let _ = app.emit( + emit_typed( + sink, &event_name, - QueryStreamEvent::Columns { - columns: String::new(), - total_rows: 0, - }, - ); + &QueryStreamEvent::Columns { columns: String::new(), total_rows: 0 }, + ) + .await; } else { let header = join_sep(&columns, CELL_SEP); - let _ = app.emit( + emit_typed( + sink, &event_name, - QueryStreamEvent::Columns { - columns: header, - total_rows: rows.len(), - }, - ); + &QueryStreamEvent::Columns { columns: header, total_rows: rows.len() }, + ) + .await; let packed = pack_rows_vec(&rows); - let _ = app.emit(&event_name, QueryStreamEvent::Chunk { data: packed }); + emit_typed(sink, &event_name, &QueryStreamEvent::Chunk { data: packed }).await; } let elapsed = start.elapsed().as_millis() as f32; - let _ = app.emit( + emit_typed( + sink, &event_name, - QueryStreamEvent::Done { - elapsed, - capped: false, - }, - ); + &QueryStreamEvent::Done { elapsed, capped: false }, + ) + .await; } } diff --git a/crates/rsql-core/src/events.rs b/crates/rsql-core/src/events.rs new file mode 100644 index 0000000..d51ed8f --- /dev/null +++ b/crates/rsql-core/src/events.rs @@ -0,0 +1,47 @@ +use serde::Serialize; +use std::sync::Arc; + +#[async_trait::async_trait] +pub trait EventSink: Send + Sync + 'static { + async fn emit_json(&self, event: &str, payload: serde_json::Value); +} + +pub type SharedEventSink = Arc; + +pub async fn emit_typed(sink: &SharedEventSink, event: &str, payload: &T) { + match serde_json::to_value(payload) { + Ok(v) => sink.emit_json(event, v).await, + Err(e) => tracing::error!(error = %e, event, "emit_typed: serialize failed"), + } +} + +#[cfg(test)] +mod tests { + use super::*; + use tokio::sync::Mutex; + + struct RecordingSink(Arc>>); + + #[async_trait::async_trait] + impl EventSink for RecordingSink { + async fn emit_json(&self, event: &str, payload: serde_json::Value) { + self.0.lock().await.push((event.to_string(), payload)); + } + } + + #[tokio::test] + async fn emit_typed_serializes_and_forwards() { + #[derive(serde::Serialize)] + struct Probe { n: u32, label: &'static str } + + let log = Arc::new(Mutex::new(Vec::new())); + let sink: SharedEventSink = Arc::new(RecordingSink(log.clone())); + + emit_typed(&sink, "probe", &Probe { n: 7, label: "hi" }).await; + + let recorded = log.lock().await; + assert_eq!(recorded.len(), 1); + assert_eq!(recorded[0].0, "probe"); + assert_eq!(recorded[0].1, serde_json::json!({"n": 7, "label": "hi"})); + } +} diff --git a/crates/rsql-core/src/lib.rs b/crates/rsql-core/src/lib.rs index 417882c..b445695 100644 --- a/crates/rsql-core/src/lib.rs +++ b/crates/rsql-core/src/lib.rs @@ -4,8 +4,11 @@ pub mod common; pub mod drivers; pub mod error; +pub mod events; pub mod ssh; pub mod state; +pub mod terminal; pub mod utils; +pub use events::{EventSink, SharedEventSink, emit_typed}; pub use state::AppState; diff --git a/crates/rsql-core/src/state/bootstrap.rs b/crates/rsql-core/src/state/bootstrap.rs new file mode 100644 index 0000000..12341d7 --- /dev/null +++ b/crates/rsql-core/src/state/bootstrap.rs @@ -0,0 +1,117 @@ +use std::{collections::BTreeMap, sync::Arc}; +use tokio::sync::Mutex; + +use crate::error::AppError; +use crate::utils::ResourceMonitor; +use super::AppState; + +pub async fn bootstrap(db_path: &str) -> Result { + let db = libsql::Builder::new_local(db_path) + .build() + .await + .map_err(|e| AppError::DatabaseError(e.to_string()))?; + + let conn = db + .connect() + .map_err(|e| AppError::DatabaseError(e.to_string()))?; + + conn.execute( + "CREATE TABLE IF NOT EXISTS projects ( + id TEXT PRIMARY KEY, + driver TEXT NOT NULL DEFAULT 'PGSQL', + username TEXT NOT NULL DEFAULT '', + password TEXT NOT NULL DEFAULT '', + database TEXT NOT NULL DEFAULT '', + host TEXT NOT NULL DEFAULT '', + port TEXT NOT NULL DEFAULT '', + ssl TEXT NOT NULL DEFAULT 'false' + )", + (), + ) + .await + .map_err(|e| AppError::DatabaseError(e.to_string()))?; + + conn.execute( + "CREATE TABLE IF NOT EXISTS queries ( + id TEXT PRIMARY KEY, + sql TEXT NOT NULL DEFAULT '' + )", + (), + ) + .await + .map_err(|e| AppError::DatabaseError(e.to_string()))?; + + conn.execute( + "CREATE TABLE IF NOT EXISTS workspaces ( + name TEXT PRIMARY KEY, + tabs TEXT NOT NULL DEFAULT '[]' + )", + (), + ) + .await + .map_err(|e| AppError::DatabaseError(e.to_string()))?; + + conn.execute( + "CREATE TABLE IF NOT EXISTS virtual_query_snapshots ( + query_id TEXT PRIMARY KEY, + project_id TEXT NOT NULL, + sql TEXT NOT NULL, + columns_packed TEXT NOT NULL DEFAULT '', + total_rows INTEGER NOT NULL DEFAULT 0, + page_size INTEGER NOT NULL DEFAULT 0, + col_count INTEGER NOT NULL DEFAULT 0, + created_at INTEGER NOT NULL + )", + (), + ) + .await + .map_err(|e| AppError::DatabaseError(e.to_string()))?; + + conn.execute( + "CREATE TABLE IF NOT EXISTS virtual_query_pages ( + query_id TEXT NOT NULL, + page_index INTEGER NOT NULL, + packed_page TEXT NOT NULL DEFAULT '', + PRIMARY KEY (query_id, page_index) + )", + (), + ) + .await + .map_err(|e| AppError::DatabaseError(e.to_string()))?; + + conn.execute( + "DELETE FROM virtual_query_pages + WHERE query_id NOT IN (SELECT query_id FROM virtual_query_snapshots)", + (), + ) + .await + .ok(); + + for col in [ + "ssh_enabled", + "ssh_host", + "ssh_port", + "ssh_user", + "ssh_password", + "ssh_key_path", + ] { + conn.execute( + &format!("ALTER TABLE projects ADD COLUMN {col} TEXT NOT NULL DEFAULT ''"), + (), + ) + .await + .ok(); + } + + Ok(AppState { + clients: Arc::new(Mutex::new(BTreeMap::new())), + meta_clients: Arc::new(Mutex::new(BTreeMap::new())), + cancel_tokens: Arc::new(Mutex::new(BTreeMap::new())), + client_ssl: Arc::new(Mutex::new(BTreeMap::new())), + local_db: db, + resource_monitor: Arc::new(Mutex::new(ResourceMonitor::new())), + virtual_cache: Arc::new(Mutex::new(BTreeMap::new())), + notify_handles: Arc::new(Mutex::new(BTreeMap::new())), + ssh_tunnels: Arc::new(Mutex::new(BTreeMap::new())), + }) +} diff --git a/crates/rsql-core/src/state/mod.rs b/crates/rsql-core/src/state/mod.rs index 2553f38..507d8d6 100644 --- a/crates/rsql-core/src/state/mod.rs +++ b/crates/rsql-core/src/state/mod.rs @@ -1,7 +1,10 @@ +pub mod bootstrap; pub mod project; pub mod query; pub mod workspace; +pub use bootstrap::bootstrap; + use deadpool_postgres::Pool; use std::{collections::BTreeMap, sync::Arc}; use tokio::sync::Mutex; diff --git a/crates/rsql-core/src/terminal/mod.rs b/crates/rsql-core/src/terminal/mod.rs new file mode 100644 index 0000000..cfd005e --- /dev/null +++ b/crates/rsql-core/src/terminal/mod.rs @@ -0,0 +1,72 @@ +pub mod session; + +pub use session::TerminalRegistry; + +use portable_pty::{CommandBuilder, PtySize, native_pty_system}; +use std::io::Read; + +use crate::error::AppError; +use crate::events::SharedEventSink; + +pub async fn spawn( + registry: &TerminalRegistry, + sink: SharedEventSink, + id: String, + cols: u16, + rows: u16, +) -> Result<(), AppError> { + let pty_system = native_pty_system(); + let pair = pty_system + .openpty(PtySize { rows, cols, pixel_width: 0, pixel_height: 0 }) + .map_err(|e| AppError::QueryFailed(e.to_string()))?; + + let mut cmd = CommandBuilder::new_default_prog(); + cmd.env("TERM", "xterm-256color"); + + pair.slave + .spawn_command(cmd) + .map_err(|e| AppError::QueryFailed(e.to_string()))?; + drop(pair.slave); + + let writer = pair + .master + .take_writer() + .map_err(|e| AppError::QueryFailed(e.to_string()))?; + let mut reader = pair + .master + .try_clone_reader() + .map_err(|e| AppError::QueryFailed(e.to_string()))?; + + let session = session::TerminalSession { writer, master: pair.master }; + registry.insert(id.clone(), session).await; + + let terminal_id = id; + let reader_sink = sink.clone(); + let handle = tokio::runtime::Handle::current(); + std::thread::spawn(move || { + let mut buf = [0u8; 4096]; + loop { + match reader.read(&mut buf) { + Ok(0) => { + let event = format!("terminal-exit-{terminal_id}"); + let sink = reader_sink.clone(); + handle.spawn(async move { + sink.emit_json(&event, serde_json::Value::Null).await + }); + break; + } + Ok(n) => { + let data = String::from_utf8_lossy(&buf[..n]).to_string(); + let event = format!("terminal-data-{terminal_id}"); + let sink = reader_sink.clone(); + handle.spawn(async move { + sink.emit_json(&event, serde_json::Value::String(data)).await + }); + } + Err(_) => break, + } + } + }); + + Ok(()) +} diff --git a/crates/rsql-core/src/terminal/session.rs b/crates/rsql-core/src/terminal/session.rs new file mode 100644 index 0000000..eaddbad --- /dev/null +++ b/crates/rsql-core/src/terminal/session.rs @@ -0,0 +1,67 @@ +use portable_pty::{MasterPty, PtySize}; +use std::{collections::HashMap, io::Write, sync::Arc}; +use tokio::sync::Mutex; + +use crate::error::AppError; + +pub(crate) struct TerminalSession { + pub(crate) writer: Box, + pub(crate) master: Box, +} + +#[derive(Clone)] +pub struct TerminalRegistry { + inner: Arc>>, +} + +impl Default for TerminalRegistry { + fn default() -> Self { + Self { inner: Arc::new(Mutex::new(HashMap::new())) } + } +} + +impl TerminalRegistry { + pub fn new() -> Self { Self::default() } + + pub(crate) async fn insert(&self, id: String, session: TerminalSession) { + self.inner.lock().await.insert(id, session); + } + + pub async fn write(&self, id: &str, bytes: &[u8]) -> Result<(), AppError> { + let mut sessions = self.inner.lock().await; + let session = sessions + .get_mut(id) + .ok_or_else(|| AppError::QueryFailed(format!("terminal not found: {id}")))?; + session + .writer + .write_all(bytes) + .map_err(|e| AppError::QueryFailed(e.to_string()))?; + session + .writer + .flush() + .map_err(|e| AppError::QueryFailed(e.to_string()))?; + Ok(()) + } + + pub async fn resize(&self, id: &str, cols: u16, rows: u16) -> Result<(), AppError> { + let sessions = self.inner.lock().await; + let session = sessions + .get(id) + .ok_or_else(|| AppError::QueryFailed(format!("terminal not found: {id}")))?; + session + .master + .resize(PtySize { rows, cols, pixel_width: 0, pixel_height: 0 }) + .map_err(|e| AppError::QueryFailed(e.to_string()))?; + Ok(()) + } + + pub async fn kill(&self, id: &str) -> Result<(), AppError> { + self.inner.lock().await.remove(id); + Ok(()) + } + + /// Drop all sessions; their reader threads exit on next read after the master PTY is dropped. + pub async fn drain_all(&self) { + self.inner.lock().await.clear(); + } +} diff --git a/crates/rsql-core/tests/state_smoke.rs b/crates/rsql-core/tests/state_smoke.rs index efe4c2c..be3c7c9 100644 --- a/crates/rsql-core/tests/state_smoke.rs +++ b/crates/rsql-core/tests/state_smoke.rs @@ -102,3 +102,33 @@ async fn project_roundtrip() { drop(db); let _ = std::fs::remove_file(&db_path); } + +#[tokio::test] +async fn bootstrap_creates_tables() { + let tmp = tempfile::NamedTempFile::new().unwrap(); + let path = tmp.path().to_string_lossy().to_string(); + let state = rsql_core::state::bootstrap(&path) + .await + .expect("bootstrap should succeed"); + + let conn = state.local_db.connect().unwrap(); + let mut rows = conn + .query("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name", ()) + .await + .unwrap(); + + let mut names = Vec::new(); + while let Some(row) = rows.next().await.unwrap() { + names.push(row.get::(0).unwrap()); + } + + for required in [ + "projects", + "queries", + "workspaces", + "virtual_query_snapshots", + "virtual_query_pages", + ] { + assert!(names.contains(&required.to_string()), "missing table: {required}"); + } +} diff --git a/crates/rsql-proxy/Cargo.toml b/crates/rsql-proxy/Cargo.toml index 8162338..e87f00e 100644 --- a/crates/rsql-proxy/Cargo.toml +++ b/crates/rsql-proxy/Cargo.toml @@ -24,8 +24,14 @@ serde = { workspace = true } serde_json = { workspace = true } clap = { workspace = true } futures-util = { workspace = true } +rsql-core = { path = "../rsql-core" } +uuid = { workspace = true } +async-trait = { workspace = true } +tokio-postgres = { workspace = true } [dev-dependencies] reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] } tokio-tungstenite = "0.24" tokio = { workspace = true, features = ["macros", "rt-multi-thread", "time"] } +tempfile = "3" +serde_json = { workspace = true } diff --git a/crates/rsql-proxy/src/dispatch/mod.rs b/crates/rsql-proxy/src/dispatch/mod.rs new file mode 100644 index 0000000..5f3a0bc --- /dev/null +++ b/crates/rsql-proxy/src/dispatch/mod.rs @@ -0,0 +1,57 @@ +pub mod state_cmds; +pub mod utils_cmds; +pub mod pgsql_meta; +mod pgsql_meta_admin; +mod pgsql_meta_connection; +mod pgsql_meta_metadata; +mod pgsql_meta_objects; +mod pgsql_meta_statistics; +pub mod pgsql_query; +pub mod pgsql_pubsub; +pub mod terminal_cmds; + +use uuid::Uuid; + +use crate::protocol::{Outbound, Request}; +use crate::session::ProxySession; + +pub async fn dispatch(session: &ProxySession, req: Request) -> Outbound { + let Request { id, cmd, payload } = req; + let result = route(session, &cmd, payload, id).await; + match result { + Ok(out) => out, + Err(message) => Outbound::error(id, message), + } +} + +async fn route( + session: &ProxySession, + cmd: &str, + payload: serde_json::Value, + id: Uuid, +) -> Result { + match cmd { + "project_db_select" | "project_db_insert" | "project_db_delete" + | "query_db_select" | "query_db_insert" | "query_db_delete" + | "workspace_save" | "workspace_load_all" | "workspace_delete" => { + state_cmds::handle(session, cmd, payload, id).await + } + "system_resource_usage" | "compute_diff" => { + utils_cmds::handle(session, cmd, payload, id).await + } + "pgsql_run_query" | "pgsql_run_query_packed" | "pgsql_execute_virtual" + | "pgsql_fetch_page" | "pgsql_close_virtual" | "pgsql_cancel_query" + | "pgsql_run_query_streamed" => { + pgsql_query::handle(session, cmd, payload, id).await + } + "pgsql_listen_start" | "pgsql_listen_stop" + | "pgsql_notify_send" | "pgsql_discover_channels" => { + pgsql_pubsub::handle(session, cmd, payload, id).await + } + "terminal_spawn" | "terminal_write" | "terminal_resize" | "terminal_kill" => { + terminal_cmds::handle(session, cmd, payload, id).await + } + c if c.starts_with("pgsql_") => pgsql_meta::handle(session, c, payload, id).await, + _ => Err(format!("unknown command: {cmd}")), + } +} diff --git a/crates/rsql-proxy/src/dispatch/pgsql_meta.rs b/crates/rsql-proxy/src/dispatch/pgsql_meta.rs new file mode 100644 index 0000000..4282526 --- /dev/null +++ b/crates/rsql-proxy/src/dispatch/pgsql_meta.rs @@ -0,0 +1,70 @@ +use uuid::Uuid; + +use crate::protocol::Outbound; +use crate::session::ProxySession; + +pub async fn handle( + session: &ProxySession, + cmd: &str, + payload: serde_json::Value, + id: Uuid, +) -> Result { + match cmd { + "pgsql_test_connection" | "pgsql_connector" => { + super::pgsql_meta_connection::handle(session, cmd, payload, id).await + } + + "pgsql_load_databases" + | "pgsql_load_tablespaces" + | "pgsql_load_schemas" + | "pgsql_load_tables" + | "pgsql_load_columns" + | "pgsql_load_column_details" + | "pgsql_load_indexes" + | "pgsql_load_constraints" + | "pgsql_load_triggers" + | "pgsql_load_rules" + | "pgsql_load_policies" + | "pgsql_load_views" + | "pgsql_load_materialized_views" + | "pgsql_load_functions" + | "pgsql_load_trigger_functions" => { + super::pgsql_meta_metadata::handle(session, cmd, payload, id).await + } + + "pgsql_load_activity" + | "pgsql_load_database_stats" + | "pgsql_load_table_stats" + | "pgsql_load_foreign_keys" + | "pgsql_table_statistics" + | "pgsql_fk_details" + | "pgsql_load_locks" + | "pgsql_load_index_usage" + | "pgsql_load_table_bloat" => { + super::pgsql_meta_statistics::handle(session, cmd, payload, id).await + } + + "pgsql_view_info" + | "pgsql_matview_info" + | "pgsql_function_info" + | "pgsql_generate_ddl" => { + super::pgsql_meta_objects::handle(session, cmd, payload, id).await + } + + "pgsql_csv_preview" + | "pgsql_csv_import" + | "pgsql_load_roles" + | "pgsql_load_table_grants" + | "pgsql_load_database_grants" + | "pgsql_extract_schema_objects" + | "pgsql_load_extensions" + | "pgsql_load_available_extensions" + | "pgsql_load_enum_types" + | "pgsql_table_action" + | "pgsql_load_pg_settings" => { + super::pgsql_meta_admin::handle(session, cmd, payload, id).await + } + + _ => Err(format!("pgsql_meta: unknown command: {cmd}")), + } +} diff --git a/crates/rsql-proxy/src/dispatch/pgsql_meta_admin.rs b/crates/rsql-proxy/src/dispatch/pgsql_meta_admin.rs new file mode 100644 index 0000000..f93d628 --- /dev/null +++ b/crates/rsql-proxy/src/dispatch/pgsql_meta_admin.rs @@ -0,0 +1,140 @@ +use rsql_core::drivers::pgsql::commands::admin; +use rsql_core::error::AppError; +use serde::Deserialize; +use uuid::Uuid; + +use crate::protocol::Outbound; +use crate::session::ProxySession; + +pub async fn handle( + session: &ProxySession, + cmd: &str, + payload: serde_json::Value, + id: Uuid, +) -> Result { + let state = session.app_state.as_ref(); + let json_resp = |value: serde_json::Value| Ok(Outbound::response(id, value)); + + macro_rules! call_pid_only { + ($fn:ident) => {{ + #[derive(Deserialize)] + struct Args { + project_id: String, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let v = admin::$fn(state, &a.project_id).await.map_err(stringify)?; + json_resp(serde_json::to_value(v).map_err(|e| e.to_string())?) + }}; + } + + match cmd { + "pgsql_csv_preview" => { + #[derive(Deserialize)] + struct Args { + file_path: String, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let v = admin::pgsql_csv_preview(&a.file_path).await.map_err(stringify)?; + json_resp(serde_json::to_value(v).map_err(|e| e.to_string())?) + } + + "pgsql_csv_import" => { + #[derive(Deserialize)] + struct Args { + project_id: String, + file_path: String, + schema: String, + table: String, + column_mapping: Vec<(usize, String)>, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let v = admin::pgsql_csv_import( + state, + &a.project_id, + &a.file_path, + &a.schema, + &a.table, + a.column_mapping, + ) + .await + .map_err(stringify)?; + json_resp(serde_json::to_value(v).map_err(|e| e.to_string())?) + } + + "pgsql_load_roles" => call_pid_only!(pgsql_load_roles), + + "pgsql_load_table_grants" => { + #[derive(Deserialize)] + struct Args { + project_id: String, + role_name: String, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let v = admin::pgsql_load_table_grants(state, &a.project_id, &a.role_name) + .await + .map_err(stringify)?; + json_resp(serde_json::to_value(v).map_err(|e| e.to_string())?) + } + + "pgsql_load_database_grants" => { + #[derive(Deserialize)] + struct Args { + project_id: String, + role_name: String, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let v = admin::pgsql_load_database_grants(state, &a.project_id, &a.role_name) + .await + .map_err(stringify)?; + json_resp(serde_json::to_value(v).map_err(|e| e.to_string())?) + } + + "pgsql_extract_schema_objects" => { + #[derive(Deserialize)] + struct Args { + project_id: String, + schema: String, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let v = admin::pgsql_extract_schema_objects(state, &a.project_id, &a.schema) + .await + .map_err(stringify)?; + json_resp(serde_json::to_value(v).map_err(|e| e.to_string())?) + } + + "pgsql_load_extensions" => call_pid_only!(pgsql_load_extensions), + "pgsql_load_available_extensions" => call_pid_only!(pgsql_load_available_extensions), + "pgsql_load_enum_types" => call_pid_only!(pgsql_load_enum_types), + + "pgsql_table_action" => { + #[derive(Deserialize)] + struct Args { + project_id: String, + action: String, + schema: String, + table: String, + object_type: String, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let v = admin::pgsql_table_action( + state, + &a.project_id, + &a.action, + &a.schema, + &a.table, + &a.object_type, + ) + .await + .map_err(stringify)?; + json_resp(serde_json::Value::String(v)) + } + + "pgsql_load_pg_settings" => call_pid_only!(pgsql_load_pg_settings), + + _ => unreachable!("pgsql_meta_admin: unexpected command {cmd}"), + } +} + +fn stringify(e: AppError) -> String { + e.to_string() +} diff --git a/crates/rsql-proxy/src/dispatch/pgsql_meta_connection.rs b/crates/rsql-proxy/src/dispatch/pgsql_meta_connection.rs new file mode 100644 index 0000000..ddd8d4e --- /dev/null +++ b/crates/rsql-proxy/src/dispatch/pgsql_meta_connection.rs @@ -0,0 +1,87 @@ +use rsql_core::drivers::pgsql::commands::connection; +use rsql_core::error::AppError; +use serde::Deserialize; +use uuid::Uuid; + +use crate::protocol::Outbound; +use crate::session::ProxySession; + +pub async fn handle( + session: &ProxySession, + cmd: &str, + payload: serde_json::Value, + id: Uuid, +) -> Result { + let state = session.app_state.as_ref(); + let json_resp = |value: serde_json::Value| Ok(Outbound::response(id, value)); + + match cmd { + "pgsql_test_connection" => { + #[derive(Deserialize)] + struct Args { + key: Vec, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + if a.key.len() != 6 { + return Err(format!( + "pgsql_test_connection: key must have 6 elements, got {}", + a.key.len() + )); + } + let key: [&str; 6] = [ + &a.key[0], &a.key[1], &a.key[2], &a.key[3], &a.key[4], &a.key[5], + ]; + let v = connection::pgsql_test_connection(key).await.map_err(stringify)?; + json_resp(serde_json::Value::String(v)) + } + + "pgsql_connector" => { + #[derive(Deserialize)] + struct Args { + project_id: String, + key: Option>, + ssh: Option>, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let key: Option<[String; 6]> = match a.key { + None => None, + Some(v) => { + if v.len() != 6 { + return Err(format!( + "pgsql_connector: key must have 6 elements, got {}", + v.len() + )); + } + Some([ + v[0].clone(), + v[1].clone(), + v[2].clone(), + v[3].clone(), + v[4].clone(), + v[5].clone(), + ]) + } + }; + let key_ref: Option<[&str; 6]> = key.as_ref().map(|k| { + [ + k[0].as_str(), + k[1].as_str(), + k[2].as_str(), + k[3].as_str(), + k[4].as_str(), + k[5].as_str(), + ] + }); + let v = connection::pgsql_connector(state, &a.project_id, key_ref, a.ssh) + .await + .map_err(stringify)?; + json_resp(serde_json::to_value(v).map_err(|e| e.to_string())?) + } + + _ => unreachable!("pgsql_meta_connection: unexpected command {cmd}"), + } +} + +fn stringify(e: AppError) -> String { + e.to_string() +} diff --git a/crates/rsql-proxy/src/dispatch/pgsql_meta_metadata.rs b/crates/rsql-proxy/src/dispatch/pgsql_meta_metadata.rs new file mode 100644 index 0000000..fe30055 --- /dev/null +++ b/crates/rsql-proxy/src/dispatch/pgsql_meta_metadata.rs @@ -0,0 +1,204 @@ +use rsql_core::drivers::pgsql::commands::metadata; +use rsql_core::error::AppError; +use serde::Deserialize; +use uuid::Uuid; + +use crate::protocol::Outbound; +use crate::session::ProxySession; + +pub async fn handle( + session: &ProxySession, + cmd: &str, + payload: serde_json::Value, + id: Uuid, +) -> Result { + let state = session.app_state.as_ref(); + let json_resp = |value: serde_json::Value| Ok(Outbound::response(id, value)); + + macro_rules! call_pid_only { + ($fn:ident) => {{ + #[derive(Deserialize)] + struct Args { + project_id: String, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let v = metadata::$fn(state, &a.project_id).await.map_err(stringify)?; + json_resp(serde_json::to_value(v).map_err(|e| e.to_string())?) + }}; + } + + match cmd { + "pgsql_load_databases" => call_pid_only!(pgsql_load_databases), + "pgsql_load_tablespaces" => call_pid_only!(pgsql_load_tablespaces), + "pgsql_load_schemas" => call_pid_only!(pgsql_load_schemas), + + "pgsql_load_tables" => { + #[derive(Deserialize)] + struct Args { + project_id: String, + schema: String, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let v = metadata::pgsql_load_tables(state, &a.project_id, &a.schema) + .await + .map_err(stringify)?; + json_resp(serde_json::to_value(v).map_err(|e| e.to_string())?) + } + + "pgsql_load_columns" => { + #[derive(Deserialize)] + struct Args { + project_id: String, + schema: String, + table: String, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let v = metadata::pgsql_load_columns(state, &a.project_id, &a.schema, &a.table) + .await + .map_err(stringify)?; + json_resp(serde_json::to_value(v).map_err(|e| e.to_string())?) + } + + "pgsql_load_column_details" => { + #[derive(Deserialize)] + struct Args { + project_id: String, + schema: String, + table: String, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let v = metadata::pgsql_load_column_details(state, &a.project_id, &a.schema, &a.table) + .await + .map_err(stringify)?; + json_resp(serde_json::to_value(v).map_err(|e| e.to_string())?) + } + + "pgsql_load_indexes" => { + #[derive(Deserialize)] + struct Args { + project_id: String, + schema: String, + table: String, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let v = metadata::pgsql_load_indexes(state, &a.project_id, &a.schema, &a.table) + .await + .map_err(stringify)?; + json_resp(serde_json::to_value(v).map_err(|e| e.to_string())?) + } + + "pgsql_load_constraints" => { + #[derive(Deserialize)] + struct Args { + project_id: String, + schema: String, + table: String, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let v = metadata::pgsql_load_constraints(state, &a.project_id, &a.schema, &a.table) + .await + .map_err(stringify)?; + json_resp(serde_json::to_value(v).map_err(|e| e.to_string())?) + } + + "pgsql_load_triggers" => { + #[derive(Deserialize)] + struct Args { + project_id: String, + schema: String, + table: String, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let v = metadata::pgsql_load_triggers(state, &a.project_id, &a.schema, &a.table) + .await + .map_err(stringify)?; + json_resp(serde_json::to_value(v).map_err(|e| e.to_string())?) + } + + "pgsql_load_rules" => { + #[derive(Deserialize)] + struct Args { + project_id: String, + schema: String, + table: String, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let v = metadata::pgsql_load_rules(state, &a.project_id, &a.schema, &a.table) + .await + .map_err(stringify)?; + json_resp(serde_json::to_value(v).map_err(|e| e.to_string())?) + } + + "pgsql_load_policies" => { + #[derive(Deserialize)] + struct Args { + project_id: String, + schema: String, + table: String, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let v = metadata::pgsql_load_policies(state, &a.project_id, &a.schema, &a.table) + .await + .map_err(stringify)?; + json_resp(serde_json::to_value(v).map_err(|e| e.to_string())?) + } + + "pgsql_load_views" => { + #[derive(Deserialize)] + struct Args { + project_id: String, + schema: String, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let v = metadata::pgsql_load_views(state, &a.project_id, &a.schema) + .await + .map_err(stringify)?; + json_resp(serde_json::to_value(v).map_err(|e| e.to_string())?) + } + + "pgsql_load_materialized_views" => { + #[derive(Deserialize)] + struct Args { + project_id: String, + schema: String, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let v = metadata::pgsql_load_materialized_views(state, &a.project_id, &a.schema) + .await + .map_err(stringify)?; + json_resp(serde_json::to_value(v).map_err(|e| e.to_string())?) + } + + "pgsql_load_functions" => { + #[derive(Deserialize)] + struct Args { + project_id: String, + schema: String, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let v = metadata::pgsql_load_functions(state, &a.project_id, &a.schema) + .await + .map_err(stringify)?; + json_resp(serde_json::to_value(v).map_err(|e| e.to_string())?) + } + + "pgsql_load_trigger_functions" => { + #[derive(Deserialize)] + struct Args { + project_id: String, + schema: String, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let v = metadata::pgsql_load_trigger_functions(state, &a.project_id, &a.schema) + .await + .map_err(stringify)?; + json_resp(serde_json::to_value(v).map_err(|e| e.to_string())?) + } + + _ => unreachable!("pgsql_meta_metadata: unexpected command {cmd}"), + } +} + +fn stringify(e: AppError) -> String { + e.to_string() +} diff --git a/crates/rsql-proxy/src/dispatch/pgsql_meta_objects.rs b/crates/rsql-proxy/src/dispatch/pgsql_meta_objects.rs new file mode 100644 index 0000000..eefa8b4 --- /dev/null +++ b/crates/rsql-proxy/src/dispatch/pgsql_meta_objects.rs @@ -0,0 +1,89 @@ +use rsql_core::drivers::pgsql::commands::object_info; +use rsql_core::error::AppError; +use serde::Deserialize; +use uuid::Uuid; + +use crate::protocol::Outbound; +use crate::session::ProxySession; + +pub async fn handle( + session: &ProxySession, + cmd: &str, + payload: serde_json::Value, + id: Uuid, +) -> Result { + let state = session.app_state.as_ref(); + let json_resp = |value: serde_json::Value| Ok(Outbound::response(id, value)); + + match cmd { + "pgsql_view_info" => { + #[derive(Deserialize)] + struct Args { + project_id: String, + schema: String, + view: String, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let v = object_info::pgsql_view_info(state, &a.project_id, &a.schema, &a.view) + .await + .map_err(stringify)?; + json_resp(serde_json::to_value(v).map_err(|e| e.to_string())?) + } + + "pgsql_matview_info" => { + #[derive(Deserialize)] + struct Args { + project_id: String, + schema: String, + matview: String, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let v = object_info::pgsql_matview_info(state, &a.project_id, &a.schema, &a.matview) + .await + .map_err(stringify)?; + json_resp(serde_json::to_value(v).map_err(|e| e.to_string())?) + } + + "pgsql_function_info" => { + #[derive(Deserialize)] + struct Args { + project_id: String, + schema: String, + func_name: String, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let v = + object_info::pgsql_function_info(state, &a.project_id, &a.schema, &a.func_name) + .await + .map_err(stringify)?; + json_resp(serde_json::to_value(v).map_err(|e| e.to_string())?) + } + + "pgsql_generate_ddl" => { + #[derive(Deserialize)] + struct Args { + project_id: String, + schema: String, + name: String, + object_type: String, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let v = object_info::pgsql_generate_ddl( + state, + &a.project_id, + &a.schema, + &a.name, + &a.object_type, + ) + .await + .map_err(stringify)?; + json_resp(serde_json::Value::String(v)) + } + + _ => unreachable!("pgsql_meta_objects: unexpected command {cmd}"), + } +} + +fn stringify(e: AppError) -> String { + e.to_string() +} diff --git a/crates/rsql-proxy/src/dispatch/pgsql_meta_statistics.rs b/crates/rsql-proxy/src/dispatch/pgsql_meta_statistics.rs new file mode 100644 index 0000000..c6f74b9 --- /dev/null +++ b/crates/rsql-proxy/src/dispatch/pgsql_meta_statistics.rs @@ -0,0 +1,92 @@ +use rsql_core::drivers::pgsql::commands::statistics; +use rsql_core::error::AppError; +use serde::Deserialize; +use uuid::Uuid; + +use crate::protocol::Outbound; +use crate::session::ProxySession; + +pub async fn handle( + session: &ProxySession, + cmd: &str, + payload: serde_json::Value, + id: Uuid, +) -> Result { + let state = session.app_state.as_ref(); + let json_resp = |value: serde_json::Value| Ok(Outbound::response(id, value)); + + macro_rules! call_pid_only { + ($fn:ident) => {{ + #[derive(Deserialize)] + struct Args { + project_id: String, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let v = statistics::$fn(state, &a.project_id).await.map_err(stringify)?; + json_resp(serde_json::to_value(v).map_err(|e| e.to_string())?) + }}; + } + + match cmd { + "pgsql_load_activity" => call_pid_only!(pgsql_load_activity), + "pgsql_load_database_stats" => call_pid_only!(pgsql_load_database_stats), + "pgsql_load_table_stats" => call_pid_only!(pgsql_load_table_stats), + "pgsql_load_locks" => call_pid_only!(pgsql_load_locks), + "pgsql_load_index_usage" => call_pid_only!(pgsql_load_index_usage), + "pgsql_load_table_bloat" => call_pid_only!(pgsql_load_table_bloat), + + "pgsql_load_foreign_keys" => { + #[derive(Deserialize)] + struct Args { + project_id: String, + schema: String, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let v = statistics::pgsql_load_foreign_keys(state, &a.project_id, &a.schema) + .await + .map_err(stringify)?; + json_resp(serde_json::to_value(v).map_err(|e| e.to_string())?) + } + + "pgsql_table_statistics" => { + #[derive(Deserialize)] + struct Args { + project_id: String, + schema: String, + table: String, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let v = statistics::pgsql_table_statistics(state, &a.project_id, &a.schema, &a.table) + .await + .map_err(stringify)?; + json_resp(serde_json::to_value(v).map_err(|e| e.to_string())?) + } + + "pgsql_fk_details" => { + #[derive(Deserialize)] + struct Args { + project_id: String, + schema: String, + table: String, + direction: String, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let v = statistics::pgsql_fk_details( + state, + &a.project_id, + &a.schema, + &a.table, + &a.direction, + ) + .await + .map_err(stringify)?; + json_resp(serde_json::to_value(v).map_err(|e| e.to_string())?) + } + + _ => unreachable!("pgsql_meta_statistics: unexpected command {cmd}"), + } +} + +fn stringify(e: AppError) -> String { + e.to_string() +} diff --git a/crates/rsql-proxy/src/dispatch/pgsql_pubsub.rs b/crates/rsql-proxy/src/dispatch/pgsql_pubsub.rs new file mode 100644 index 0000000..b26526c --- /dev/null +++ b/crates/rsql-proxy/src/dispatch/pgsql_pubsub.rs @@ -0,0 +1,54 @@ +use rsql_core::drivers::pgsql::commands::pubsub; +use rsql_core::error::AppError; +use serde::Deserialize; +use uuid::Uuid; + +use crate::protocol::Outbound; +use crate::session::ProxySession; + +pub async fn handle( + session: &ProxySession, + cmd: &str, + payload: serde_json::Value, + id: Uuid, +) -> Result { + let state = session.app_state.as_ref(); + + match cmd { + "pgsql_listen_start" => { + #[derive(Deserialize)] + struct Args { project_id: String, channel: String } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let v = pubsub::listen_start(state, &a.project_id, &a.channel, session.sink.clone()) + .await.map_err(stringify)?; + Ok(Outbound::response(id, serde_json::Value::Bool(v))) + } + "pgsql_listen_stop" => { + #[derive(Deserialize)] + struct Args { project_id: String, channel: String } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let v = pubsub::listen_stop(state, &a.project_id, &a.channel) + .await.map_err(stringify)?; + Ok(Outbound::response(id, serde_json::Value::Bool(v))) + } + "pgsql_notify_send" => { + #[derive(Deserialize)] + struct Args { project_id: String, channel: String, payload: String } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let v = pubsub::pgsql_notify_send(state, &a.project_id, &a.channel, &a.payload) + .await.map_err(stringify)?; + Ok(Outbound::response(id, serde_json::Value::Bool(v))) + } + "pgsql_discover_channels" => { + #[derive(Deserialize)] + struct Args { project_id: String } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let v = pubsub::pgsql_discover_channels(state, &a.project_id) + .await.map_err(stringify)?; + Ok(Outbound::response(id, serde_json::to_value(v).map_err(|e| e.to_string())?)) + } + _ => Err(format!("pgsql_pubsub: unknown command: {cmd}")), + } +} + +fn stringify(e: AppError) -> String { e.to_string() } diff --git a/crates/rsql-proxy/src/dispatch/pgsql_query.rs b/crates/rsql-proxy/src/dispatch/pgsql_query.rs new file mode 100644 index 0000000..80cd135 --- /dev/null +++ b/crates/rsql-proxy/src/dispatch/pgsql_query.rs @@ -0,0 +1,141 @@ +use rsql_core::drivers::pgsql::commands::{pool_helpers, query}; +use rsql_core::drivers::pgsql::streaming::execute_query_streamed; +use rsql_core::error::AppError; +use serde::Deserialize; +use uuid::Uuid; + +use crate::protocol::Outbound; +use crate::session::ProxySession; + +pub async fn handle( + session: &ProxySession, + cmd: &str, + payload: serde_json::Value, + id: Uuid, +) -> Result { + let state = session.app_state.as_ref(); + + match cmd { + "pgsql_run_query" => { + #[derive(Deserialize)] + struct Args { + project_id: String, + sql: String, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let s = query::pgsql_run_query(state, &a.project_id, &a.sql) + .await + .map_err(stringify)?; + Ok(Outbound::binary(id, s.into_bytes())) + } + "pgsql_run_query_packed" => { + #[derive(Deserialize)] + struct Args { + project_id: String, + sql: String, + timeout_ms: Option, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let s = query::pgsql_run_query_packed(state, &a.project_id, &a.sql, a.timeout_ms) + .await + .map_err(stringify)?; + Ok(Outbound::binary(id, s.into_bytes())) + } + "pgsql_execute_virtual" => { + #[derive(Deserialize)] + struct Args { + project_id: String, + sql: String, + query_id: String, + page_size: usize, + timeout_ms: Option, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let s = query::pgsql_execute_virtual( + state, + &a.project_id, + &a.sql, + &a.query_id, + a.page_size, + a.timeout_ms, + ) + .await + .map_err(stringify)?; + Ok(Outbound::binary(id, s.into_bytes())) + } + "pgsql_fetch_page" => { + #[derive(Deserialize)] + struct Args { + query_id: String, + col_count: usize, + offset: usize, + limit: usize, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let s = + query::pgsql_fetch_page(state, &a.query_id, a.col_count, a.offset, a.limit) + .await + .map_err(stringify)?; + Ok(Outbound::binary(id, s.into_bytes())) + } + "pgsql_close_virtual" => { + #[derive(Deserialize)] + struct Args { + query_id: String, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + query::pgsql_close_virtual(state, &a.query_id) + .await + .map_err(stringify)?; + Ok(Outbound::response(id, serde_json::Value::Null)) + } + "pgsql_cancel_query" => { + #[derive(Deserialize)] + struct Args { + project_id: String, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let v = query::pgsql_cancel_query(state, &a.project_id) + .await + .map_err(stringify)?; + Ok(Outbound::response(id, serde_json::Value::Bool(v))) + } + "pgsql_run_query_streamed" => { + #[derive(Deserialize)] + struct Args { + project_id: String, + sql: String, + stream_id: String, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let client = + pool_helpers::acquire_client(&state.clients, &a.project_id) + .await + .map_err(stringify)?; + let token = client.cancel_token(); + pool_helpers::set_cancel_token(state, &a.project_id, token.clone()) + .await + .map_err(stringify)?; + session.record_cancel_token(id, token).await; + + let sink = session.sink.clone(); + let sql = a.sql.clone(); + let stream_id = a.stream_id.clone(); + tokio::spawn(async move { + if let Err(e) = execute_query_streamed(&client, &sql, &stream_id, &sink).await { + sink.emit_json( + &format!("query-stream-{stream_id}"), + serde_json::json!({"type": "error", "message": e.to_string()}), + ) + .await; + } + }); + Ok(Outbound::response(id, serde_json::Value::Null)) + } + _ => Err(format!("pgsql_query: unknown command: {cmd}")), + } +} + +fn stringify(e: AppError) -> String { + e.to_string() +} diff --git a/crates/rsql-proxy/src/dispatch/state_cmds.rs b/crates/rsql-proxy/src/dispatch/state_cmds.rs new file mode 100644 index 0000000..0bb21b1 --- /dev/null +++ b/crates/rsql-proxy/src/dispatch/state_cmds.rs @@ -0,0 +1,124 @@ +use rsql_core::state::{project, query, workspace}; +use serde::Deserialize; +use uuid::Uuid; + +use crate::protocol::Outbound; +use crate::session::ProxySession; + +pub async fn handle( + session: &ProxySession, + cmd: &str, + payload: serde_json::Value, + id: Uuid, +) -> Result { + let db = &session.app_state.local_db; + let json_resp = |value: serde_json::Value| Ok(Outbound::response(id, value)); + + match cmd { + "project_db_select" => { + let v = project::project_db_select(db).await.map_err(stringify)?; + json_resp(serde_json::to_value(v).map_err(|e| e.to_string())?) + } + "project_db_insert" => { + #[derive(Deserialize)] + struct Args { + project_id: String, + project_details: Vec, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + project::project_db_insert(db, &a.project_id, a.project_details) + .await + .map_err(stringify)?; + json_resp(serde_json::Value::Null) + } + "project_db_delete" => { + #[derive(Deserialize)] + struct Args { + project_id: String, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + project::project_db_delete(db, &a.project_id) + .await + .map_err(stringify)?; + session.app_state.clients.lock().await.remove(&a.project_id); + session + .app_state + .meta_clients + .lock() + .await + .remove(&a.project_id); + session + .app_state + .cancel_tokens + .lock() + .await + .remove(&a.project_id); + session + .app_state + .client_ssl + .lock() + .await + .remove(&a.project_id); + json_resp(serde_json::Value::Null) + } + "query_db_select" => { + let v = query::query_db_select(db).await.map_err(stringify)?; + json_resp(serde_json::to_value(v).map_err(|e| e.to_string())?) + } + "query_db_insert" => { + #[derive(Deserialize)] + struct Args { + query_id: String, + sql: String, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + query::query_db_insert(db, &a.query_id, &a.sql) + .await + .map_err(stringify)?; + json_resp(serde_json::Value::Null) + } + "query_db_delete" => { + #[derive(Deserialize)] + struct Args { + query_id: String, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + query::query_db_delete(db, &a.query_id) + .await + .map_err(stringify)?; + json_resp(serde_json::Value::Null) + } + "workspace_save" => { + #[derive(Deserialize)] + struct Args { + name: String, + tabs: String, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + workspace::workspace_save(db, &a.name, &a.tabs) + .await + .map_err(stringify)?; + json_resp(serde_json::Value::Null) + } + "workspace_load_all" => { + let v = workspace::workspace_load_all(db).await.map_err(stringify)?; + json_resp(serde_json::to_value(v).map_err(|e| e.to_string())?) + } + "workspace_delete" => { + #[derive(Deserialize)] + struct Args { + name: String, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + workspace::workspace_delete(db, &a.name) + .await + .map_err(stringify)?; + json_resp(serde_json::Value::Null) + } + _ => Err(format!("state_cmds: unknown command: {cmd}")), + } +} + +fn stringify(e: rsql_core::error::AppError) -> String { + e.to_string() +} diff --git a/crates/rsql-proxy/src/dispatch/terminal_cmds.rs b/crates/rsql-proxy/src/dispatch/terminal_cmds.rs new file mode 100644 index 0000000..781faf7 --- /dev/null +++ b/crates/rsql-proxy/src/dispatch/terminal_cmds.rs @@ -0,0 +1,49 @@ +use rsql_core::error::AppError; +use rsql_core::terminal; +use serde::Deserialize; +use uuid::Uuid; + +use crate::protocol::Outbound; +use crate::session::ProxySession; + +pub async fn handle( + session: &ProxySession, + cmd: &str, + payload: serde_json::Value, + id: Uuid, +) -> Result { + match cmd { + "terminal_spawn" => { + #[derive(Deserialize)] + struct Args { id: String, cols: u16, rows: u16 } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + terminal::spawn(&session.terminals, session.sink.clone(), a.id, a.cols, a.rows) + .await.map_err(stringify)?; + Ok(Outbound::response(id, serde_json::Value::Null)) + } + "terminal_write" => { + #[derive(Deserialize)] + struct Args { id: String, data: String } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + session.terminals.write(&a.id, a.data.as_bytes()).await.map_err(stringify)?; + Ok(Outbound::response(id, serde_json::Value::Null)) + } + "terminal_resize" => { + #[derive(Deserialize)] + struct Args { id: String, cols: u16, rows: u16 } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + session.terminals.resize(&a.id, a.cols, a.rows).await.map_err(stringify)?; + Ok(Outbound::response(id, serde_json::Value::Null)) + } + "terminal_kill" => { + #[derive(Deserialize)] + struct Args { id: String } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + session.terminals.kill(&a.id).await.map_err(stringify)?; + Ok(Outbound::response(id, serde_json::Value::Null)) + } + _ => Err(format!("terminal_cmds: unknown command: {cmd}")), + } +} + +fn stringify(e: AppError) -> String { e.to_string() } diff --git a/crates/rsql-proxy/src/dispatch/utils_cmds.rs b/crates/rsql-proxy/src/dispatch/utils_cmds.rs new file mode 100644 index 0000000..bc9a37d --- /dev/null +++ b/crates/rsql-proxy/src/dispatch/utils_cmds.rs @@ -0,0 +1,50 @@ +use rsql_core::utils::{diff, pool_stats}; +use serde::Deserialize; +use uuid::Uuid; + +use crate::protocol::Outbound; +use crate::session::ProxySession; + +pub async fn handle( + session: &ProxySession, + cmd: &str, + payload: serde_json::Value, + id: Uuid, +) -> Result { + match cmd { + "system_resource_usage" => { + let mut usage = { + let mut monitor = session.app_state.resource_monitor.lock().await; + monitor.sample() + }; + let (q_open, q_avail, q_max, q_wait) = + pool_stats(&session.app_state.clients).await; + let (m_open, m_avail, m_max, m_wait) = + pool_stats(&session.app_state.meta_clients).await; + let total_open = q_open.saturating_add(m_open); + let total_avail = q_avail.saturating_add(m_avail); + usage.db_connections_open = total_open; + usage.db_connections_max = q_max.saturating_add(m_max); + usage.db_connections_waiting = q_wait.saturating_add(m_wait); + usage.db_connections_in_use = total_open.saturating_sub(total_avail); + Ok(Outbound::response( + id, + serde_json::to_value(usage).map_err(|e| e.to_string())?, + )) + } + "compute_diff" => { + #[derive(Deserialize)] + struct Args { + pinned_packed: String, + current_packed: String, + } + let a: Args = serde_json::from_value(payload).map_err(|e| e.to_string())?; + let (a_out, b_out, count) = diff::compute_diff(&a.pinned_packed, &a.current_packed); + Ok(Outbound::response( + id, + serde_json::json!([a_out, b_out, count]), + )) + } + _ => Err(format!("utils_cmds: unknown command: {cmd}")), + } +} diff --git a/crates/rsql-proxy/src/event_sink.rs b/crates/rsql-proxy/src/event_sink.rs new file mode 100644 index 0000000..47c5df1 --- /dev/null +++ b/crates/rsql-proxy/src/event_sink.rs @@ -0,0 +1,23 @@ +use rsql_core::events::EventSink; +use tokio::sync::mpsc::UnboundedSender; + +use crate::protocol::Outbound; + +pub struct ProxyEventSink { + tx: UnboundedSender, +} + +impl ProxyEventSink { + pub fn new(tx: UnboundedSender) -> Self { + Self { tx } + } +} + +#[async_trait::async_trait] +impl EventSink for ProxyEventSink { + async fn emit_json(&self, event: &str, payload: serde_json::Value) { + if let Err(e) = self.tx.send(Outbound::event(event, payload)) { + tracing::debug!(error = %e, "ProxyEventSink: receiver closed"); + } + } +} diff --git a/crates/rsql-proxy/src/lib.rs b/crates/rsql-proxy/src/lib.rs index 5509629..191fbac 100644 --- a/crates/rsql-proxy/src/lib.rs +++ b/crates/rsql-proxy/src/lib.rs @@ -1,20 +1,32 @@ //! rsql-proxy: WebSocket bridge for browser/hosted RSQL. +pub mod dispatch; +pub mod event_sink; pub mod health; +pub mod protocol; +pub mod session; pub mod static_serve; pub mod ws; use axum::Router; +use rsql_core::AppState; use std::path::PathBuf; +use std::sync::Arc; use tower_http::trace::TraceLayer; -pub fn router(dist_dir: Option<&str>) -> Router { +pub struct ProxyConfig { + pub app_state: Arc, + pub dist_dir: Option, +} + +pub fn router(config: ProxyConfig) -> Router { + let ws_state = ws::WsState { app_state: config.app_state }; let mut app = Router::new() .merge(health::routes()) - .merge(ws::routes()); + .merge(ws::routes(ws_state)); - if let Some(dir) = dist_dir { - app = app.merge(static_serve::routes(PathBuf::from(dir))); + if let Some(dir) = config.dist_dir { + app = app.merge(static_serve::routes(dir)); } app.layer(TraceLayer::new_for_http()) diff --git a/crates/rsql-proxy/src/main.rs b/crates/rsql-proxy/src/main.rs index 76b0be2..f1da742 100644 --- a/crates/rsql-proxy/src/main.rs +++ b/crates/rsql-proxy/src/main.rs @@ -1,5 +1,6 @@ use clap::Parser; -use std::net::SocketAddr; +use rsql_proxy::ProxyConfig; +use std::{net::SocketAddr, path::PathBuf, sync::Arc}; use tokio::net::TcpListener; use tracing_subscriber::EnvFilter; @@ -8,15 +9,15 @@ use tracing_subscriber::EnvFilter; struct Args { #[arg(long, default_value = "127.0.0.1:8080")] addr: SocketAddr, - #[arg(long, default_value = "dist")] dist_dir: String, + #[arg(long, default_value = "proxy.db")] + state_path: String, } #[tokio::main] async fn main() { let args = Args::parse(); - tracing_subscriber::fmt() .with_env_filter( EnvFilter::try_from_default_env() @@ -25,18 +26,27 @@ async fn main() { .with_target(false) .init(); - let listener = TcpListener::bind(args.addr) + let listener = TcpListener::bind(args.addr).await.expect("failed to bind listener"); + + let app_state = rsql_core::state::bootstrap(&args.state_path) .await - .expect("failed to bind listener"); + .expect("AppState bootstrap failed"); + let app_state = Arc::new(app_state); + tracing::info!( version = env!("CARGO_PKG_VERSION"), addr = %listener.local_addr().unwrap(), dist = %args.dist_dir, + state = %args.state_path, "rsql-proxy listening" ); - let app = rsql_proxy::router(Some(&args.dist_dir)); - axum::serve(listener, app) + let config = ProxyConfig { + app_state, + dist_dir: Some(PathBuf::from(args.dist_dir)), + }; + + axum::serve(listener, rsql_proxy::router(config)) .with_graceful_shutdown(shutdown_signal()) .await .expect("axum::serve failed"); diff --git a/crates/rsql-proxy/src/protocol.rs b/crates/rsql-proxy/src/protocol.rs new file mode 100644 index 0000000..61d7669 --- /dev/null +++ b/crates/rsql-proxy/src/protocol.rs @@ -0,0 +1,151 @@ +use axum::extract::ws::Message; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +pub const BINARY_ID_LEN: usize = 16; + +#[derive(Debug, Deserialize)] +#[serde(tag = "type", rename_all = "lowercase")] +pub enum Inbound { + Request(Request), + Cancel(Cancel), + #[serde(skip)] + BinaryChunk { id: Uuid, payload: Vec }, +} + +#[derive(Debug, Deserialize)] +pub struct Request { + pub id: Uuid, + pub cmd: String, + #[serde(default)] + pub payload: serde_json::Value, +} + +#[derive(Debug, Deserialize)] +pub struct Cancel { + pub id: Uuid, +} + +#[derive(Debug, Serialize, Clone)] +#[serde(tag = "type", rename_all = "lowercase")] +pub enum OutboundFrame { + Response { + id: Uuid, + payload: serde_json::Value, + #[serde(skip_serializing_if = "Option::is_none")] + end: Option, + }, + Error { + id: Uuid, + message: String, + #[serde(skip_serializing_if = "Option::is_none")] + code: Option, + }, + Event { + event: String, + payload: serde_json::Value, + }, +} + +#[derive(Debug, Clone)] +pub enum Outbound { + Text(OutboundFrame), + Binary { id: Uuid, payload: Vec }, +} + +impl Outbound { + pub fn response(id: Uuid, payload: serde_json::Value) -> Self { + Outbound::Text(OutboundFrame::Response { id, payload, end: Some(true) }) + } + + pub fn error(id: Uuid, message: impl Into) -> Self { + Outbound::Text(OutboundFrame::Error { id, message: message.into(), code: None }) + } + + pub fn event(event: impl Into, payload: serde_json::Value) -> Self { + Outbound::Text(OutboundFrame::Event { event: event.into(), payload }) + } + + pub fn binary(id: Uuid, payload: Vec) -> Self { + Outbound::Binary { id, payload } + } + + pub fn into_ws_message(self) -> Result { + match self { + Outbound::Text(frame) => Ok(Message::Text(serde_json::to_string(&frame)?.into())), + Outbound::Binary { id, payload } => { + let mut buf = Vec::with_capacity(BINARY_ID_LEN + payload.len()); + buf.extend_from_slice(id.as_bytes()); + buf.extend_from_slice(&payload); + Ok(Message::Binary(buf.into())) + } + } + } +} + +pub fn parse_text(text: &str) -> Result { + serde_json::from_str(text) +} + +pub fn parse_binary(bytes: &[u8]) -> Option<(Uuid, &[u8])> { + if bytes.len() < BINARY_ID_LEN { + return None; + } + let id_bytes: [u8; 16] = bytes[..BINARY_ID_LEN].try_into().ok()?; + let id = Uuid::from_bytes(id_bytes); + Some((id, &bytes[BINARY_ID_LEN..])) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn parse_request_text() { + let raw = r#"{"type":"request","id":"01933e44-de63-7c80-8000-000000000000","cmd":"workspace_save","payload":{"name":"a","tabs":"[]"}}"#; + let parsed = parse_text(raw).expect("parse"); + match parsed { + Inbound::Request(req) => { + assert_eq!(req.cmd, "workspace_save"); + assert_eq!(req.payload["name"], "a"); + } + _ => panic!("expected request"), + } + } + + #[test] + fn parse_cancel_text() { + let raw = r#"{"type":"cancel","id":"01933e44-de63-7c80-8000-000000000000"}"#; + let parsed = parse_text(raw).expect("parse"); + assert!(matches!(parsed, Inbound::Cancel(_))); + } + + #[test] + fn binary_frame_roundtrip() { + let id = Uuid::now_v7(); + let payload = b"row1\x1Frow2".to_vec(); + let frame = Outbound::binary(id, payload.clone()); + let msg = frame.into_ws_message().unwrap(); + let bytes: Vec = match msg { + Message::Binary(b) => b.to_vec(), + _ => panic!("expected binary"), + }; + let (parsed_id, parsed_payload) = parse_binary(&bytes).unwrap(); + assert_eq!(parsed_id, id); + assert_eq!(parsed_payload, payload.as_slice()); + } + + #[test] + fn response_serializes_with_end_flag() { + let id = Uuid::now_v7(); + let frame = Outbound::response(id, serde_json::json!({"ok": true})); + let msg = frame.into_ws_message().unwrap(); + let s = match msg { + Message::Text(t) => t.to_string(), + _ => panic!("text"), + }; + assert!(s.contains("\"type\":\"response\"")); + assert!(s.contains("\"end\":true")); + assert!(s.contains(&id.to_string())); + } +} diff --git a/crates/rsql-proxy/src/session.rs b/crates/rsql-proxy/src/session.rs new file mode 100644 index 0000000..532d572 --- /dev/null +++ b/crates/rsql-proxy/src/session.rs @@ -0,0 +1,58 @@ +use rsql_core::AppState; +use rsql_core::events::SharedEventSink; +use rsql_core::terminal::TerminalRegistry; +use std::collections::HashMap; +use std::sync::Arc; +use tokio::sync::Mutex; +use tokio::sync::mpsc::UnboundedSender; +use tokio_postgres::CancelToken; +use uuid::Uuid; + +use crate::event_sink::ProxyEventSink; +use crate::protocol::Outbound; + +#[derive(Clone)] +pub struct ProxySession { + pub app_state: Arc, + pub terminals: TerminalRegistry, + pub sink: SharedEventSink, + pub outbound: UnboundedSender, + pub cancel_tokens: Arc>>, +} + +impl ProxySession { + pub fn new(app_state: Arc, outbound: UnboundedSender) -> Self { + let sink: SharedEventSink = Arc::new(ProxyEventSink::new(outbound.clone())); + Self { + app_state, + terminals: TerminalRegistry::new(), + sink, + outbound, + cancel_tokens: Arc::new(Mutex::new(HashMap::new())), + } + } + + pub async fn record_cancel_token(&self, id: Uuid, token: CancelToken) { + self.cancel_tokens.lock().await.insert(id, token); + } + + pub async fn trip_cancel(&self, id: Uuid) { + if let Some(token) = self.cancel_tokens.lock().await.remove(&id) { + let _ = token.cancel_query(tokio_postgres::NoTls).await; + } + } + + pub async fn cleanup(&self) { + self.terminals.drain_all().await; + { + let mut handles = self.app_state.notify_handles.lock().await; + let drained: Vec<_> = handles.iter().map(|(k, _)| k.clone()).collect(); + for key in drained { + if let Some(h) = handles.remove(&key) { + h.abort(); + } + } + } + self.cancel_tokens.lock().await.clear(); + } +} diff --git a/crates/rsql-proxy/src/ws.rs b/crates/rsql-proxy/src/ws.rs index 7bf7745..c5b21bb 100644 --- a/crates/rsql-proxy/src/ws.rs +++ b/crates/rsql-proxy/src/ws.rs @@ -1,35 +1,117 @@ use axum::{ Router, - extract::ws::{Message, WebSocket, WebSocketUpgrade}, + extract::{State, WebSocketUpgrade, ws::{Message, WebSocket}}, response::IntoResponse, routing::get, }; use futures_util::StreamExt; +use rsql_core::AppState; +use std::sync::Arc; +use std::time::Duration; +use tokio::sync::mpsc; +use tokio::time::{Instant, interval, sleep_until}; -pub fn routes() -> Router { - Router::new().route("/ws", get(upgrade)) +use crate::dispatch::dispatch; +use crate::protocol::{self, Inbound, Outbound}; +use crate::session::ProxySession; + +#[derive(Clone)] +pub struct WsState { + pub app_state: Arc, } -async fn upgrade(ws: WebSocketUpgrade) -> impl IntoResponse { - ws.on_upgrade(echo_loop) +pub fn routes(state: WsState) -> Router { + Router::new().route("/ws", get(upgrade)).with_state(state) } -async fn echo_loop(mut socket: WebSocket) { - while let Some(Ok(msg)) = socket.next().await { - match msg { - Message::Text(t) => { - if socket.send(Message::Text(t)).await.is_err() { - break; +async fn upgrade(ws: WebSocketUpgrade, State(state): State) -> impl IntoResponse { + ws.on_upgrade(move |socket| run(socket, state.app_state)) +} + +async fn run(socket: WebSocket, app_state: Arc) { + let (outbound_tx, mut outbound_rx) = mpsc::unbounded_channel::(); + let session = ProxySession::new(app_state, outbound_tx.clone()); + + let (mut sender, mut receiver) = socket.split(); + + let (ping_tx, mut ping_rx) = mpsc::unbounded_channel::>(); + let writer = tokio::spawn(async move { + loop { + tokio::select! { + Some(msg) = outbound_rx.recv() => { + match msg.into_ws_message() { + Ok(ws_msg) => { + if futures_util::SinkExt::send(&mut sender, ws_msg).await.is_err() { + break; + } + } + Err(e) => tracing::warn!(error = %e, "encode outbound failed"), + } } + Some(payload) = ping_rx.recv() => { + if futures_util::SinkExt::send(&mut sender, Message::Ping(payload.into())).await.is_err() { + break; + } + } + else => break, } - Message::Binary(b) => { - if socket.send(Message::Binary(b)).await.is_err() { + } + }); + + let mut ping_timer = interval(Duration::from_secs(30)); + ping_timer.tick().await; + let mut pong_deadline: Option = None; + + loop { + tokio::select! { + biased; + _ = ping_timer.tick() => { + let payload = b"rsql".to_vec(); + if ping_tx.send(payload).is_err() { break; } + pong_deadline = Some(Instant::now() + Duration::from_secs(10)); + } + _ = async { + if let Some(d) = pong_deadline { + sleep_until(d).await; + } else { + futures_util::future::pending::<()>().await; + } + }, if pong_deadline.is_some() => { + tracing::info!("WS pong deadline missed, closing"); + break; + } + maybe_msg = receiver.next() => { + let Some(Ok(msg)) = maybe_msg else { break }; + match msg { + Message::Text(t) => match protocol::parse_text(&t) { + Ok(Inbound::Request(req)) => { + let session_clone = session.clone(); + let tx_clone = outbound_tx.clone(); + tokio::spawn(async move { + let out = dispatch(&session_clone, req).await; + let _ = tx_clone.send(out); + }); + } + Ok(Inbound::Cancel(c)) => { + let session_clone = session.clone(); + tokio::spawn(async move { session_clone.trip_cancel(c.id).await; }); + } + Ok(Inbound::BinaryChunk { .. }) => {} + Err(e) => tracing::warn!(error = %e, "ignored malformed JSON frame"), + }, + Message::Binary(_b) => {} + Message::Pong(_) => { pong_deadline = None; } + Message::Ping(_) => {} + Message::Close(_) => break, + } } - Message::Close(_) => break, - // Ping/Pong: axum handles automatically. - _ => {} } } + + session.cleanup().await; + drop(outbound_tx); + drop(ping_tx); + let _ = writer.await; } diff --git a/crates/rsql-proxy/tests/common/mod.rs b/crates/rsql-proxy/tests/common/mod.rs new file mode 100644 index 0000000..2101c70 --- /dev/null +++ b/crates/rsql-proxy/tests/common/mod.rs @@ -0,0 +1,27 @@ +use rsql_proxy::ProxyConfig; +use std::{net::SocketAddr, sync::Arc}; +use tempfile::NamedTempFile; +use tokio::net::TcpListener; + +pub async fn spawn_test_server() -> (SocketAddr, NamedTempFile) { + let listener = TcpListener::bind("127.0.0.1:0").await.expect("bind"); + let addr = listener.local_addr().expect("local_addr"); + + let tmp_db = NamedTempFile::new().expect("tempfile"); + let app_state = rsql_core::state::bootstrap(&tmp_db.path().to_string_lossy()) + .await + .expect("bootstrap"); + let config = ProxyConfig { + app_state: Arc::new(app_state), + dist_dir: None, + }; + + tokio::spawn(async move { + axum::serve(listener, rsql_proxy::router(config)) + .await + .expect("serve"); + }); + + tokio::time::sleep(std::time::Duration::from_millis(50)).await; + (addr, tmp_db) +} diff --git a/crates/rsql-proxy/tests/dispatch_smoke.rs b/crates/rsql-proxy/tests/dispatch_smoke.rs new file mode 100644 index 0000000..ed7f160 --- /dev/null +++ b/crates/rsql-proxy/tests/dispatch_smoke.rs @@ -0,0 +1,53 @@ +mod common; + +use futures_util::{SinkExt, StreamExt}; +use serde_json::json; +use tokio_tungstenite::{connect_async, tungstenite::Message}; +use uuid::Uuid; + +#[tokio::test] +async fn workspace_roundtrip_over_ws() { + let (addr, _tmp) = common::spawn_test_server().await; + let url = format!("ws://{addr}/ws"); + let (mut ws, _) = connect_async(url).await.unwrap(); + + let save_id = Uuid::now_v7(); + let save_req = json!({ + "type": "request", + "id": save_id.to_string(), + "cmd": "workspace_save", + "payload": { "name": "ws-test", "tabs": "[]" } + }); + ws.send(Message::Text(save_req.to_string().into())).await.unwrap(); + + let resp = next_text(&mut ws).await; + assert_eq!(resp["type"], "response"); + assert_eq!(resp["id"], save_id.to_string()); + + let load_id = Uuid::now_v7(); + let load_req = json!({ + "type": "request", + "id": load_id.to_string(), + "cmd": "workspace_load_all", + "payload": {} + }); + ws.send(Message::Text(load_req.to_string().into())).await.unwrap(); + + let resp = next_text(&mut ws).await; + assert_eq!(resp["type"], "response"); + let arr = resp["payload"].as_array().unwrap(); + assert!(arr.iter().any(|t| t[0] == "ws-test" && t[1] == "[]")); +} + +async fn next_text(ws: &mut S) -> serde_json::Value +where + S: StreamExt> + Unpin, +{ + loop { + match ws.next().await.unwrap().unwrap() { + Message::Text(t) => return serde_json::from_str(&t).unwrap(), + Message::Ping(_) | Message::Pong(_) => continue, + other => panic!("unexpected: {other:?}"), + } + } +} diff --git a/crates/rsql-proxy/tests/health.rs b/crates/rsql-proxy/tests/health.rs index b41f64f..e075655 100644 --- a/crates/rsql-proxy/tests/health.rs +++ b/crates/rsql-proxy/tests/health.rs @@ -1,24 +1,10 @@ -use std::net::SocketAddr; -use tokio::net::TcpListener; - -async fn spawn_test_server() -> SocketAddr { - let listener = TcpListener::bind("127.0.0.1:0").await.expect("bind"); - let addr = listener.local_addr().expect("local_addr"); - let app = rsql_proxy::router(None); - tokio::spawn(async move { - axum::serve(listener, app).await.expect("serve"); - }); - // Small wait for the server to be ready - tokio::time::sleep(std::time::Duration::from_millis(50)).await; - addr -} +mod common; #[tokio::test] async fn health_returns_ok_with_version() { - let addr = spawn_test_server().await; + let (addr, _tmp) = common::spawn_test_server().await; let url = format!("http://{addr}/health"); let resp: serde_json::Value = reqwest::get(&url).await.unwrap().json().await.unwrap(); assert_eq!(resp["status"], "ok"); assert!(resp["version"].is_string()); - assert!(!resp["version"].as_str().unwrap().is_empty()); } diff --git a/crates/rsql-proxy/tests/integration_pg.rs b/crates/rsql-proxy/tests/integration_pg.rs new file mode 100644 index 0000000..be70fe7 --- /dev/null +++ b/crates/rsql-proxy/tests/integration_pg.rs @@ -0,0 +1,56 @@ +//! Run manually with: +//! RSQL_TEST_PG_KEY="user,pw,db,host,5432,false" cargo test -p rsql-proxy --test integration_pg -- --ignored + +mod common; + +use futures_util::{SinkExt, StreamExt}; +use serde_json::json; +use tokio_tungstenite::{connect_async, tungstenite::Message}; +use uuid::Uuid; + +fn pg_key() -> Option> { + std::env::var("RSQL_TEST_PG_KEY") + .ok() + .map(|s| s.split(',').map(|p| p.to_string()).collect()) +} + +#[tokio::test] +#[ignore] +async fn pgsql_run_query_binary_frame() { + let Some(key) = pg_key() else { + eprintln!("skipping: RSQL_TEST_PG_KEY not set"); + return; + }; + let (addr, _tmp) = common::spawn_test_server().await; + let (mut ws, _) = connect_async(format!("ws://{addr}/ws")).await.unwrap(); + + let id = Uuid::now_v7(); + ws.send(Message::Text(json!({ + "type": "request", + "id": id.to_string(), + "cmd": "pgsql_connector", + "payload": { "project_id": "p", "key": key, "ssh": null } + }).to_string().into())).await.unwrap(); + let _ = ws.next().await; + + let id = Uuid::now_v7(); + ws.send(Message::Text(json!({ + "type": "request", + "id": id.to_string(), + "cmd": "pgsql_run_query_packed", + "payload": { "project_id": "p", "sql": "SELECT 1 AS x", "timeout_ms": null } + }).to_string().into())).await.unwrap(); + + loop { + match ws.next().await.unwrap().unwrap() { + Message::Binary(b) => { + assert!(b.len() > 16); + let id_bytes: [u8; 16] = b[..16].try_into().unwrap(); + assert_eq!(Uuid::from_bytes(id_bytes), id); + return; + } + Message::Text(_) | Message::Ping(_) | Message::Pong(_) => continue, + other => panic!("unexpected: {other:?}"), + } + } +} diff --git a/crates/rsql-proxy/tests/protocol.rs b/crates/rsql-proxy/tests/protocol.rs new file mode 100644 index 0000000..b6bcd49 --- /dev/null +++ b/crates/rsql-proxy/tests/protocol.rs @@ -0,0 +1,24 @@ +use rsql_proxy::protocol::{parse_binary, parse_text, Inbound, Outbound}; +use uuid::Uuid; + +#[test] +fn binary_frame_includes_id_prefix() { + let id = Uuid::now_v7(); + let frame = Outbound::binary(id, b"hello".to_vec()); + let msg = frame.into_ws_message().unwrap(); + let bytes = match msg { + axum::extract::ws::Message::Binary(b) => b.to_vec(), + _ => panic!("expected binary"), + }; + let (parsed_id, payload) = parse_binary(&bytes).unwrap(); + assert_eq!(parsed_id, id); + assert_eq!(payload, b"hello"); +} + +#[test] +fn cancel_frame_parses() { + let id = Uuid::now_v7(); + let raw = format!(r#"{{"type":"cancel","id":"{id}"}}"#); + let parsed = parse_text(&raw).unwrap(); + assert!(matches!(parsed, Inbound::Cancel(c) if c.id == id)); +} diff --git a/crates/rsql-proxy/tests/session_lifecycle.rs b/crates/rsql-proxy/tests/session_lifecycle.rs new file mode 100644 index 0000000..b8c1596 --- /dev/null +++ b/crates/rsql-proxy/tests/session_lifecycle.rs @@ -0,0 +1,31 @@ +mod common; + +use futures_util::{SinkExt, StreamExt}; +use serde_json::json; +use tokio_tungstenite::{connect_async, tungstenite::Message}; +use uuid::Uuid; + +#[tokio::test] +async fn closing_ws_does_not_panic() { + let (addr, _tmp) = common::spawn_test_server().await; + let url = format!("ws://{addr}/ws"); + let (mut ws, _) = connect_async(url).await.unwrap(); + + let id = Uuid::now_v7(); + let req = json!({ + "type": "request", + "id": id.to_string(), + "cmd": "workspace_save", + "payload": { "name": "ephemeral", "tabs": "[]" } + }); + ws.send(Message::Text(req.to_string().into())).await.unwrap(); + let _ = ws.next().await; + + ws.send(Message::Close(None)).await.ok(); + drop(ws); + + tokio::time::sleep(std::time::Duration::from_millis(100)).await; + let url = format!("ws://{addr}/ws"); + let (_ws2, response) = connect_async(url).await.unwrap(); + assert_eq!(response.status().as_u16(), 101); +} diff --git a/crates/rsql-proxy/tests/ws_echo.rs b/crates/rsql-proxy/tests/ws_echo.rs index c67082c..0909106 100644 --- a/crates/rsql-proxy/tests/ws_echo.rs +++ b/crates/rsql-proxy/tests/ws_echo.rs @@ -1,38 +1,11 @@ -use futures_util::{SinkExt, StreamExt}; -use std::net::SocketAddr; -use tokio::net::TcpListener; -use tokio_tungstenite::tungstenite::Message; +mod common; -async fn spawn_test_server() -> SocketAddr { - let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); - let addr = listener.local_addr().unwrap(); - let app = rsql_proxy::router(None); - tokio::spawn(async move { - axum::serve(listener, app).await.unwrap(); - }); - tokio::time::sleep(std::time::Duration::from_millis(50)).await; - addr -} +use tokio_tungstenite::connect_async; #[tokio::test] -async fn ws_echoes_text_frame() { - let addr = spawn_test_server().await; +async fn ws_upgrade_succeeds() { + let (addr, _tmp) = common::spawn_test_server().await; let url = format!("ws://{addr}/ws"); - let (mut stream, _) = tokio_tungstenite::connect_async(&url).await.expect("connect"); - - stream.send(Message::Text("hello".into())).await.unwrap(); - let received = stream.next().await.expect("frame").expect("ok"); - assert_eq!(received, Message::Text("hello".into())); -} - -#[tokio::test] -async fn ws_echoes_binary_frame() { - let addr = spawn_test_server().await; - let url = format!("ws://{addr}/ws"); - let (mut stream, _) = tokio_tungstenite::connect_async(&url).await.expect("connect"); - - let payload = vec![0u8, 1, 2, 3, 0x1F, 0x1E, 0xFF]; - stream.send(Message::Binary(payload.clone().into())).await.unwrap(); - let received = stream.next().await.expect("frame").expect("ok"); - assert_eq!(received, Message::Binary(payload.into())); + let (_ws, response) = connect_async(url).await.expect("connect"); + assert_eq!(response.status().as_u16(), 101); } diff --git a/crates/rsql-tauri/Cargo.toml b/crates/rsql-tauri/Cargo.toml index 70193a5..45d8df8 100644 --- a/crates/rsql-tauri/Cargo.toml +++ b/crates/rsql-tauri/Cargo.toml @@ -39,4 +39,5 @@ sysinfo.workspace = true csv.workspace = true futures-util.workspace = true russh.workspace = true +async-trait = { workspace = true } rsql-core = { path = "../rsql-core" } diff --git a/crates/rsql-tauri/src/app_setup.rs b/crates/rsql-tauri/src/app_setup.rs index c2eef60..38482a3 100644 --- a/crates/rsql-tauri/src/app_setup.rs +++ b/crates/rsql-tauri/src/app_setup.rs @@ -1,10 +1,7 @@ -use std::{collections::BTreeMap, sync::Arc}; use tauri::Manager; use tauri::menu::{AboutMetadata, MenuBuilder, SubmenuBuilder}; -use tokio::sync::Mutex; -use crate::{LOCAL_DB_NAME, terminal, utils}; -use rsql_core::AppState; +use crate::LOCAL_DB_NAME; pub fn setup_app(app: &mut tauri::App) -> Result<(), Box> { #[cfg(desktop)] @@ -31,120 +28,12 @@ pub fn setup_app(app: &mut tauri::App) -> Result<(), Box> app_dir.join(LOCAL_DB_NAME).to_string_lossy().to_string() }; - let db = libsql::Builder::new_local(&db_path) - .build() + let state = rsql_core::state::bootstrap(&db_path) .await - .expect("Failed to open local database"); - - let conn = db.connect().expect("Failed to create connection"); - conn.execute( - "CREATE TABLE IF NOT EXISTS projects ( - id TEXT PRIMARY KEY, - driver TEXT NOT NULL DEFAULT 'PGSQL', - username TEXT NOT NULL DEFAULT '', - password TEXT NOT NULL DEFAULT '', - database TEXT NOT NULL DEFAULT '', - host TEXT NOT NULL DEFAULT '', - port TEXT NOT NULL DEFAULT '', - ssl TEXT NOT NULL DEFAULT 'false' - )", - (), - ) - .await - .expect("Failed to create projects table"); - - conn.execute( - "CREATE TABLE IF NOT EXISTS queries ( - id TEXT PRIMARY KEY, - sql TEXT NOT NULL DEFAULT '' - )", - (), - ) - .await - .expect("Failed to create queries table"); - - conn.execute( - "CREATE TABLE IF NOT EXISTS workspaces ( - name TEXT PRIMARY KEY, - tabs TEXT NOT NULL DEFAULT '[]' - )", - (), - ) - .await - .expect("Failed to create workspaces table"); - - conn.execute( - "CREATE TABLE IF NOT EXISTS virtual_query_snapshots ( - query_id TEXT PRIMARY KEY, - project_id TEXT NOT NULL, - sql TEXT NOT NULL, - columns_packed TEXT NOT NULL DEFAULT '', - total_rows INTEGER NOT NULL DEFAULT 0, - page_size INTEGER NOT NULL DEFAULT 0, - col_count INTEGER NOT NULL DEFAULT 0, - created_at INTEGER NOT NULL - )", - (), - ) - .await - .expect("Failed to create virtual_query_snapshots table"); - - conn.execute( - "CREATE TABLE IF NOT EXISTS virtual_query_pages ( - query_id TEXT NOT NULL, - page_index INTEGER NOT NULL, - packed_page TEXT NOT NULL DEFAULT '', - PRIMARY KEY (query_id, page_index) - )", - (), - ) - .await - .expect("Failed to create virtual_query_pages table"); - - // Best-effort orphan cleanup in case app exited before tab-close cleanup. - conn.execute( - "DELETE FROM virtual_query_pages - WHERE query_id NOT IN (SELECT query_id FROM virtual_query_snapshots)", - (), - ) - .await - .ok(); - - for col in [ - "ssh_enabled", - "ssh_host", - "ssh_port", - "ssh_user", - "ssh_password", - "ssh_key_path", - ] { - conn.execute( - &format!( - "ALTER TABLE projects ADD COLUMN {} TEXT NOT NULL DEFAULT ''", - col - ), - (), - ) - .await - .ok(); // Ignore "column already exists" errors - } - - let state = AppState { - clients: Arc::new(Mutex::new(BTreeMap::new())), - meta_clients: Arc::new(Mutex::new(BTreeMap::new())), - cancel_tokens: Arc::new(Mutex::new(BTreeMap::new())), - client_ssl: Arc::new(Mutex::new(BTreeMap::new())), - local_db: db, - resource_monitor: Arc::new(Mutex::new(utils::ResourceMonitor::new())), - virtual_cache: Arc::new(Mutex::new(BTreeMap::new())), - notify_handles: Arc::new(Mutex::new(BTreeMap::new())), - ssh_tunnels: Arc::new(Mutex::new(BTreeMap::new())), - }; + .expect("AppState bootstrap failed"); app_handle.manage(state); - let terminal_state = terminal::TerminalState { - sessions: Arc::new(Mutex::new(std::collections::HashMap::new())), - }; + let terminal_state = rsql_core::terminal::TerminalRegistry::new(); app_handle.manage(terminal_state); }); diff --git a/crates/rsql-tauri/src/drivers/pgsql/commands/pool_connection.rs b/crates/rsql-tauri/src/drivers/pgsql/commands/pool_connection.rs index 9924d43..8d6f56f 100644 --- a/crates/rsql-tauri/src/drivers/pgsql/commands/pool_connection.rs +++ b/crates/rsql-tauri/src/drivers/pgsql/commands/pool_connection.rs @@ -1,12 +1,8 @@ -use std::sync::Arc; - use rsql_core::AppState; use rsql_core::drivers::pgsql::commands::connection; -use rsql_core::drivers::pgsql::commands::pool_helpers::{create_pg_pool, full_error_chain}; use rsql_core::error::{AppError, ProjectConnectionStatus}; use tauri::{AppHandle, Manager}; -use tokio_postgres::Config; pub(crate) use rsql_core::drivers::pgsql::commands::pool_helpers::{acquire_client, set_cancel_token}; @@ -23,146 +19,5 @@ pub async fn pgsql_connector( app: AppHandle, ) -> Result { let app_state = app.state::(); - { - let clients = app_state.clients.lock().await; - if clients.contains_key(project_id) { - return Ok(ProjectConnectionStatus::Connected); - } - } - - let (user, password, database, host, port_str, use_ssl) = match key { - Some(key) => ( - key[0].to_string(), - key[1].to_string(), - key[2].to_string(), - key[3].to_string(), - key[4].to_string(), - key[5] == "true", - ), - None => { - let conn = app_state - .local_db - .connect() - .map_err(|e| AppError::DatabaseError(e.to_string()))?; - let mut rows = conn - .query( - "SELECT username, password, database, host, port, ssl FROM projects WHERE id = ?1", - libsql::params![project_id], - ) - .await - .map_err(|e| AppError::DatabaseError(e.to_string()))?; - let row = rows - .next() - .await - .map_err(|e| AppError::DatabaseError(e.to_string()))? - .ok_or_else(|| AppError::ProjectNotFound(project_id.to_string()))?; - ( - row.get::(0).unwrap_or_default(), - row.get::(1).unwrap_or_default(), - row.get::(2).unwrap_or_default(), - row.get::(3).unwrap_or_default(), - row.get::(4).unwrap_or_default(), - row.get::(5).map(|s| s == "true").unwrap_or(false), - ) - } - }; - - let (effective_host, effective_port_str) = if let Some(ref ssh_params) = ssh { - // ssh_params: [ssh_host, ssh_port, ssh_user, ssh_password, ssh_key_path] - if ssh_params.len() >= 3 && !ssh_params[0].is_empty() { - let ssh_host = &ssh_params[0]; - let ssh_port: u16 = ssh_params[1].parse().unwrap_or(22); - let ssh_user = &ssh_params[2]; - let ssh_password = ssh_params - .get(3) - .filter(|s| !s.is_empty()) - .map(|s| s.as_str()); - let ssh_key_path = ssh_params - .get(4) - .filter(|s| !s.is_empty()) - .map(|s| s.as_str()); - - app_state.ssh_tunnels.lock().await.remove(project_id); - - let tunnel = rsql_core::ssh::start_tunnel( - ssh_host, - ssh_port, - ssh_user, - ssh_password, - ssh_key_path, - &host, - port_str.parse().unwrap_or(5432), - ) - .await - .map_err(|e| AppError::ConnectionFailed(e))?; - - let local_port = tunnel.local_port; - app_state - .ssh_tunnels - .lock() - .await - .insert(project_id.to_string(), tunnel); - - ("127.0.0.1".to_string(), local_port.to_string()) - } else { - (host.clone(), port_str.clone()) - } - } else { - (host.clone(), port_str.clone()) - }; - - let port: u16 = effective_port_str.parse().unwrap_or(5432); - let mut cfg = Config::new(); - cfg.user(&user) - .password(&password) - .dbname(&database) - .host(&effective_host) - .port(port); - - let query_pool = match create_pg_pool(&cfg, use_ssl, 16) { - Ok(p) => Arc::new(p), - Err(e) => { - tracing::error!("Query pool creation failed: {:?}", e); - return Err(AppError::ConnectionFailed(full_error_chain(&e))); - } - }; - let meta_pool = match create_pg_pool(&cfg, use_ssl, 8) { - Ok(p) => Arc::new(p), - Err(e) => { - tracing::error!("Meta pool creation failed: {:?}", e); - return Err(AppError::ConnectionFailed(full_error_chain(&e))); - } - }; - - // Validate connectivity eagerly so connector keeps previous fail/connected behavior. - let query_client = match query_pool.get().await { - Ok(c) => c, - Err(e) => { - tracing::error!("Query pool initial connection failed: {:?}", e); - return Err(AppError::ConnectionFailed(full_error_chain(&e))); - } - }; - if let Err(e) = meta_pool.get().await { - tracing::error!("Meta pool initial connection failed: {:?}", e); - return Err(AppError::ConnectionFailed(full_error_chain(&e))); - } - - { - let mut clients = app_state.clients.lock().await; - clients.insert(project_id.to_string(), Arc::clone(&query_pool)); - } - { - let mut meta_clients = app_state.meta_clients.lock().await; - meta_clients.insert(project_id.to_string(), Arc::clone(&meta_pool)); - } - { - let mut cancel_tokens = app_state.cancel_tokens.lock().await; - cancel_tokens.insert(project_id.to_string(), query_client.cancel_token()); - } - { - let mut client_ssl = app_state.client_ssl.lock().await; - client_ssl.insert(project_id.to_string(), use_ssl); - } - - Ok(ProjectConnectionStatus::Connected) + connection::pgsql_connector(app_state.inner(), project_id, key, ssh).await } diff --git a/crates/rsql-tauri/src/drivers/pgsql/commands/pubsub_commands.rs b/crates/rsql-tauri/src/drivers/pgsql/commands/pubsub_commands.rs index eb2cf08..2c33bac 100644 --- a/crates/rsql-tauri/src/drivers/pgsql/commands/pubsub_commands.rs +++ b/crates/rsql-tauri/src/drivers/pgsql/commands/pubsub_commands.rs @@ -1,12 +1,9 @@ use rsql_core::AppState; use rsql_core::drivers::pgsql::commands::pubsub; use rsql_core::error::AppError; +use tauri::{AppHandle, Manager, State}; -use futures_util::StreamExt; -use native_tls::TlsConnector; -use postgres_native_tls::MakeTlsConnector; -use tauri::{AppHandle, Emitter, Manager, State}; -use tokio_postgres::{AsyncMessage, Config, NoTls}; +use crate::event_sink::TauriEventSink; #[tauri::command(rename_all = "snake_case")] pub async fn pgsql_listen_start( @@ -14,142 +11,18 @@ pub async fn pgsql_listen_start( channel: &str, app: AppHandle, ) -> Result { - let app_handle = app.clone(); - let app_state = app_handle.state::(); - let listen_key = format!("{}:{}", project_id, channel); - - { - let handles = app_state.notify_handles.lock().await; - if handles.contains_key(&listen_key) { - return Ok(true); // Already listening - } - } - - let (cfg, use_ssl) = { - let conn = app_state - .local_db - .connect() - .map_err(|e| AppError::DatabaseError(e.to_string()))?; - let mut rows = conn - .query( - "SELECT username, password, database, host, port, ssl FROM projects WHERE id = ?1", - libsql::params![project_id], - ) - .await - .map_err(|e| AppError::DatabaseError(e.to_string()))?; - - let row = rows - .next() - .await - .map_err(|e| AppError::DatabaseError(e.to_string()))? - .ok_or_else(|| AppError::ProjectNotFound(project_id.to_string()))?; - - let mut cfg = Config::new(); - cfg.user(&row.get::(0).unwrap_or_default()) - .password(&row.get::(1).unwrap_or_default()) - .dbname(&row.get::(2).unwrap_or_default()) - .host(&row.get::(3).unwrap_or_default()) - .port( - row.get::(4) - .unwrap_or_default() - .parse() - .unwrap_or(5432), - ); - let ssl = row.get::(5).map(|s| s == "true").unwrap_or(false); - (cfg, ssl) - }; - - let channel_owned = channel.to_string(); - let event_name = format!("pg-notify-{}", project_id); - - let handle = tokio::spawn(async move { - async fn listen_loop( - client: tokio_postgres::Client, - mut connection: tokio_postgres::Connection, - channel: &str, - event_name: &str, - app: &AppHandle, - ) where - S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin, - T: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin, - { - let listen_sql = format!("LISTEN \"{}\"", channel.replace('"', "\"\"")); - if let Err(e) = client.batch_execute(&listen_sql).await { - tracing::error!("LISTEN command failed: {:?}", e); - return; - } - tracing::info!("LISTEN started on channel: {}", channel); - - let mut stream = futures_util::stream::poll_fn(move |cx| connection.poll_message(cx)); - - while let Some(msg) = stream.next().await { - match msg { - Ok(AsyncMessage::Notification(n)) => { - let payload = serde_json::json!({ - "channel": n.channel(), - "payload": n.payload(), - }); - let _ = app.emit(event_name, payload); - } - Ok(_) => {} - Err(e) => { - tracing::error!("LISTEN stream error: {:?}", e); - break; - } - } - } - tracing::info!("LISTEN ended on channel: {}", channel); - drop(client); - } - - if use_ssl { - let tls_connector = match TlsConnector::builder().build() { - Ok(c) => c, - Err(e) => { - tracing::error!("LISTEN TLS error: {:?}", e); - return; - } - }; - let tls = MakeTlsConnector::new(tls_connector); - match cfg.connect(tls).await { - Ok((client, connection)) => { - listen_loop(client, connection, &channel_owned, &event_name, &app).await; - } - Err(e) => tracing::error!("LISTEN connect error: {:?}", e), - } - } else { - match cfg.connect(NoTls).await { - Ok((client, connection)) => { - listen_loop(client, connection, &channel_owned, &event_name, &app).await; - } - Err(e) => tracing::error!("LISTEN connect error: {:?}", e), - } - } - }); - - { - let mut handles = app_state.notify_handles.lock().await; - handles.insert(listen_key, handle); - } - - Ok(true) + let app_state = app.state::(); + let sink: rsql_core::events::SharedEventSink = TauriEventSink::new(app.clone()); + pubsub::listen_start(app_state.inner(), project_id, channel, sink).await } #[tauri::command(rename_all = "snake_case")] pub async fn pgsql_listen_stop( project_id: &str, channel: &str, - app: AppHandle, + app_state: State<'_, AppState>, ) -> Result { - let app_state = app.state::(); - let listen_key = format!("{}:{}", project_id, channel); - - let mut handles = app_state.notify_handles.lock().await; - if let Some(handle) = handles.remove(&listen_key) { - handle.abort(); - } - - Ok(true) + pubsub::listen_stop(app_state.inner(), project_id, channel).await } #[tauri::command(rename_all = "snake_case")] diff --git a/crates/rsql-tauri/src/drivers/pgsql/commands/query_commands.rs b/crates/rsql-tauri/src/drivers/pgsql/commands/query_commands.rs index bab2132..b939350 100644 --- a/crates/rsql-tauri/src/drivers/pgsql/commands/query_commands.rs +++ b/crates/rsql-tauri/src/drivers/pgsql/commands/query_commands.rs @@ -5,7 +5,7 @@ use rsql_core::error::AppError; use tauri::ipc::Response; use tauri::{AppHandle, Manager, State}; -use crate::drivers::pgsql::streaming::execute_query_streamed; +use rsql_core::drivers::pgsql::streaming::execute_query_streamed; use super::pool_connection::{acquire_client, set_cancel_token}; @@ -49,7 +49,8 @@ pub async fn pgsql_run_query_streamed( let client = acquire_client(&app_state.clients, project_id).await?; set_cancel_token(&app_state, project_id, client.cancel_token()).await?; - execute_query_streamed(&client, sql, stream_id, &app).await + let sink: rsql_core::events::SharedEventSink = crate::event_sink::TauriEventSink::new(app.clone()); + execute_query_streamed(&client, sql, stream_id, &sink).await } #[tauri::command(rename_all = "snake_case")] diff --git a/crates/rsql-tauri/src/drivers/pgsql/mod.rs b/crates/rsql-tauri/src/drivers/pgsql/mod.rs index 958a71b..6cd26d6 100644 --- a/crates/rsql-tauri/src/drivers/pgsql/mod.rs +++ b/crates/rsql-tauri/src/drivers/pgsql/mod.rs @@ -1,4 +1,3 @@ pub mod commands; -pub mod streaming; pub use commands::*; diff --git a/crates/rsql-tauri/src/event_sink.rs b/crates/rsql-tauri/src/event_sink.rs new file mode 100644 index 0000000..49d0d12 --- /dev/null +++ b/crates/rsql-tauri/src/event_sink.rs @@ -0,0 +1,22 @@ +use rsql_core::events::EventSink; +use std::sync::Arc; +use tauri::{AppHandle, Emitter}; + +pub struct TauriEventSink { + app: AppHandle, +} + +impl TauriEventSink { + pub fn new(app: AppHandle) -> Arc { + Arc::new(Self { app }) + } +} + +#[async_trait::async_trait] +impl EventSink for TauriEventSink { + async fn emit_json(&self, event: &str, payload: serde_json::Value) { + if let Err(e) = self.app.emit(event, payload) { + tracing::warn!(event, error = %e, "TauriEventSink emit failed"); + } + } +} diff --git a/crates/rsql-tauri/src/main.rs b/crates/rsql-tauri/src/main.rs index a7e547d..1f5b1e5 100644 --- a/crates/rsql-tauri/src/main.rs +++ b/crates/rsql-tauri/src/main.rs @@ -4,6 +4,7 @@ mod app_setup; mod commands; mod drivers; +mod event_sink; mod terminal; mod utils; diff --git a/crates/rsql-tauri/src/terminal.rs b/crates/rsql-tauri/src/terminal.rs index e5e1d4f..3bfaba8 100644 --- a/crates/rsql-tauri/src/terminal.rs +++ b/crates/rsql-tauri/src/terminal.rs @@ -1,124 +1,51 @@ -use portable_pty::{CommandBuilder, MasterPty, PtySize, native_pty_system}; -use std::collections::HashMap; -use std::io::{Read, Write}; -use std::sync::Arc; -use tauri::{AppHandle, Emitter}; -use tokio::sync::Mutex; +use rsql_core::terminal::TerminalRegistry; +use tauri::{AppHandle, State}; -pub struct TerminalState { - pub sessions: Arc>>, -} - -pub(crate) struct TerminalSession { - writer: Box, - master: Box, -} +use crate::event_sink::TauriEventSink; #[tauri::command] pub async fn terminal_spawn( app: AppHandle, - terminal_state: tauri::State<'_, TerminalState>, + terminal_state: State<'_, TerminalRegistry>, id: String, cols: u16, rows: u16, ) -> Result<(), String> { - let pty_system = native_pty_system(); - let pair = pty_system - .openpty(PtySize { - rows, - cols, - pixel_width: 0, - pixel_height: 0, - }) - .map_err(|e| e.to_string())?; - - let mut cmd = CommandBuilder::new_default_prog(); - cmd.env("TERM", "xterm-256color"); - - pair.slave.spawn_command(cmd).map_err(|e| e.to_string())?; - - // Drop the slave so we can detect when the child exits - drop(pair.slave); - - let writer = pair.master.take_writer().map_err(|e| e.to_string())?; - let mut reader = pair.master.try_clone_reader().map_err(|e| e.to_string())?; - - let session = TerminalSession { - writer, - master: pair.master, - }; - - terminal_state - .sessions - .lock() + let sink = TauriEventSink::new(app); + rsql_core::terminal::spawn(terminal_state.inner(), sink, id, cols, rows) .await - .insert(id.clone(), session); - - let terminal_id = id.clone(); - std::thread::spawn(move || { - let mut buf = [0u8; 4096]; - loop { - match reader.read(&mut buf) { - Ok(0) => { - // EOF - process exited - let _ = app.emit(&format!("terminal-exit-{}", terminal_id), ()); - break; - } - Ok(n) => { - let data = String::from_utf8_lossy(&buf[..n]).to_string(); - let _ = app.emit(&format!("terminal-data-{}", terminal_id), data); - } - Err(_) => break, - } - } - }); - - Ok(()) + .map_err(|e| e.to_string()) } #[tauri::command] pub async fn terminal_write( - terminal_state: tauri::State<'_, TerminalState>, + terminal_state: State<'_, TerminalRegistry>, id: String, data: String, ) -> Result<(), String> { - let mut sessions = terminal_state.sessions.lock().await; - let session = sessions.get_mut(&id).ok_or("Terminal not found")?; - session - .writer - .write_all(data.as_bytes()) - .map_err(|e| e.to_string())?; - session.writer.flush().map_err(|e| e.to_string())?; - Ok(()) + terminal_state + .write(&id, data.as_bytes()) + .await + .map_err(|e| e.to_string()) } #[tauri::command] pub async fn terminal_resize( - terminal_state: tauri::State<'_, TerminalState>, + terminal_state: State<'_, TerminalRegistry>, id: String, cols: u16, rows: u16, ) -> Result<(), String> { - let sessions = terminal_state.sessions.lock().await; - let session = sessions.get(&id).ok_or("Terminal not found")?; - session - .master - .resize(PtySize { - rows, - cols, - pixel_width: 0, - pixel_height: 0, - }) - .map_err(|e| e.to_string())?; - Ok(()) + terminal_state + .resize(&id, cols, rows) + .await + .map_err(|e| e.to_string()) } #[tauri::command] pub async fn terminal_kill( - terminal_state: tauri::State<'_, TerminalState>, + terminal_state: State<'_, TerminalRegistry>, id: String, ) -> Result<(), String> { - let mut sessions = terminal_state.sessions.lock().await; - sessions.remove(&id); - Ok(()) + terminal_state.kill(&id).await.map_err(|e| e.to_string()) } From 4501bd221fcfec707de1645a5dc18fd0716cc473 Mon Sep 17 00:00:00 2001 From: Daniel Boros Date: Mon, 18 May 2026 15:03:22 +0200 Subject: [PATCH 05/11] chore: close phase 3 --- Cargo.lock | 4 +- Cargo.toml | 1 - crates/rsql-core/Cargo.toml | 1 - .../src/drivers/pgsql/commands/pubsub.rs | 34 +++++++++----- .../rsql-core/src/drivers/pgsql/streaming.rs | 44 +++++++----------- crates/rsql-core/src/events.rs | 45 ++++++++----------- crates/rsql-core/src/lib.rs | 2 +- crates/rsql-core/src/terminal/mod.rs | 20 +++------ crates/rsql-proxy/Cargo.toml | 2 +- crates/rsql-proxy/src/dispatch/pgsql_query.rs | 8 ++-- crates/rsql-proxy/src/event_sink.rs | 12 +++-- crates/rsql-proxy/src/protocol.rs | 9 ++-- crates/rsql-proxy/src/session.rs | 5 +-- crates/rsql-tauri/Cargo.toml | 1 - .../drivers/pgsql/commands/pubsub_commands.rs | 2 +- .../drivers/pgsql/commands/query_commands.rs | 2 +- crates/rsql-tauri/src/event_sink.rs | 3 +- 17 files changed, 89 insertions(+), 106 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9e5f5c6..da359b7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5394,7 +5394,6 @@ dependencies = [ name = "rsql" version = "1.1.5" dependencies = [ - "async-trait", "csv", "deadpool-postgres", "futures-util", @@ -5428,7 +5427,6 @@ dependencies = [ name = "rsql-core" version = "1.1.5" dependencies = [ - "async-trait", "csv", "deadpool-postgres", "futures-util", @@ -5454,7 +5452,6 @@ dependencies = [ name = "rsql-proxy" version = "1.1.5" dependencies = [ - "async-trait", "axum 0.8.9", "clap", "futures-util", @@ -5462,6 +5459,7 @@ dependencies = [ "rsql-core", "serde", "serde_json", + "sonic-rs", "tempfile", "tokio", "tokio-postgres", diff --git a/Cargo.toml b/Cargo.toml index 6078f53..1a4c4c1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,6 @@ axum = { version = "0.8", features = ["ws", "macros"] } tower-http = { version = "0.6", features = ["fs", "trace"] } tower = "0.5" clap = { version = "4.5", features = ["derive"] } -async-trait = "0.1" uuid = { version = "1", features = ["v7", "serde"] } [profile.release] diff --git a/crates/rsql-core/Cargo.toml b/crates/rsql-core/Cargo.toml index cf34622..218309d 100644 --- a/crates/rsql-core/Cargo.toml +++ b/crates/rsql-core/Cargo.toml @@ -26,7 +26,6 @@ sysinfo.workspace = true csv.workspace = true futures-util.workspace = true russh.workspace = true -async-trait = { workspace = true } uuid = { workspace = true } [dev-dependencies] diff --git a/crates/rsql-core/src/drivers/pgsql/commands/pubsub.rs b/crates/rsql-core/src/drivers/pgsql/commands/pubsub.rs index 176e2d0..96aac4a 100644 --- a/crates/rsql-core/src/drivers/pgsql/commands/pubsub.rs +++ b/crates/rsql-core/src/drivers/pgsql/commands/pubsub.rs @@ -1,7 +1,9 @@ +use std::sync::Arc; + use crate::AppState; use crate::drivers::pgsql::roles_schema_objects::discover_notify_channels; use crate::error::AppError; -use crate::events::SharedEventSink; +use crate::events::EventSink; use futures_util::StreamExt; use native_tls::TlsConnector; @@ -37,11 +39,11 @@ pub async fn pgsql_discover_channels( discover_notify_channels(&client).await } -pub async fn listen_start( +pub async fn listen_start( app_state: &AppState, project_id: &str, channel: &str, - sink: SharedEventSink, + sink: Arc, ) -> Result { let listen_key = format!("{project_id}:{channel}"); { @@ -73,7 +75,12 @@ pub async fn listen_start( .password(row.get::(1).unwrap_or_default()) .dbname(row.get::(2).unwrap_or_default()) .host(row.get::(3).unwrap_or_default()) - .port(row.get::(4).unwrap_or_default().parse().unwrap_or(5432)); + .port( + row.get::(4) + .unwrap_or_default() + .parse() + .unwrap_or(5432), + ); let ssl = row.get::(5).map(|s| s == "true").unwrap_or(false); (cfg, ssl) }; @@ -81,15 +88,16 @@ pub async fn listen_start( let channel_owned = channel.to_string(); let event_name = format!("pg-notify-{project_id}"); let handle = tokio::spawn(async move { - async fn listen_loop( + async fn listen_loop( client: tokio_postgres::Client, - mut connection: tokio_postgres::Connection, + mut connection: tokio_postgres::Connection, channel: &str, event_name: &str, - sink: &SharedEventSink, + sink: &Arc, ) where - S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin, - T: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin, + Stream: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin, + TlsStream: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin, + EVT: EventSink, { let listen_sql = format!("LISTEN \"{}\"", channel.replace('"', "\"\"")); if let Err(e) = client.batch_execute(&listen_sql).await { @@ -104,7 +112,7 @@ pub async fn listen_start( "channel": n.channel(), "payload": n.payload(), }); - sink.emit_json(event_name, payload).await; + sink.emit(event_name, &payload); } Ok(_) => {} Err(e) => { @@ -133,7 +141,11 @@ pub async fn listen_start( } }); - app_state.notify_handles.lock().await.insert(listen_key, handle); + app_state + .notify_handles + .lock() + .await + .insert(listen_key, handle); Ok(true) } diff --git a/crates/rsql-core/src/drivers/pgsql/streaming.rs b/crates/rsql-core/src/drivers/pgsql/streaming.rs index 92f596d..346eed8 100644 --- a/crates/rsql-core/src/drivers/pgsql/streaming.rs +++ b/crates/rsql-core/src/drivers/pgsql/streaming.rs @@ -1,10 +1,11 @@ +use std::sync::Arc; use std::time::Instant; use tokio_postgres::{Client, SimpleQueryMessage}; use crate::drivers::pgsql::CELL_SEP; use crate::drivers::pgsql::query_execution::{join_sep, pack_rows_vec, process_simple_messages}; use crate::error::AppError; -use crate::events::{SharedEventSink, emit_typed}; +use crate::events::EventSink; #[derive(serde::Serialize, Clone)] #[serde(tag = "type")] @@ -20,11 +21,11 @@ pub enum QueryStreamEvent { const MAX_STREAM_ROWS: usize = 500_000; const CURSOR_FETCH_SIZE: usize = 10_000; -pub async fn execute_query_streamed( +pub async fn execute_query_streamed( client: &Client, sql: &str, stream_id: &str, - sink: &SharedEventSink, + sink: &Arc, ) -> Result<(), AppError> { let start = Instant::now(); let event_name = format!("query-stream-{stream_id}"); @@ -78,17 +79,12 @@ pub async fn execute_query_streamed( if !columns_sent && let Some(cols) = batch_columns { let header = join_sep(&cols, CELL_SEP); - emit_typed( - sink, - &event_name, - &QueryStreamEvent::Columns { columns: header, total_rows: 0 }, - ) - .await; + sink.emit(&event_name, &QueryStreamEvent::Columns { columns: header, total_rows: 0 }); columns_sent = true; } let packed = pack_rows_vec(&batch_rows); - emit_typed(sink, &event_name, &QueryStreamEvent::Chunk { data: packed }).await; + sink.emit(&event_name, &QueryStreamEvent::Chunk { data: packed }); total_sent += batch_rows.len(); if total_sent >= MAX_STREAM_ROWS { @@ -98,19 +94,17 @@ pub async fn execute_query_streamed( } if !columns_sent { - emit_typed( - sink, + sink.emit( &event_name, &QueryStreamEvent::Columns { columns: String::new(), total_rows: 0 }, - ) - .await; + ); } client.batch_execute("CLOSE _rsql_cur").await.ok(); client.batch_execute("COMMIT").await.ok(); let elapsed = start.elapsed().as_millis() as f32; - emit_typed(sink, &event_name, &QueryStreamEvent::Done { elapsed, capped }).await; + sink.emit(&event_name, &QueryStreamEvent::Done { elapsed, capped }); } Err(_) => { client.batch_execute("ROLLBACK").await.ok(); @@ -123,32 +117,26 @@ pub async fn execute_query_streamed( let (columns, rows) = process_simple_messages(messages); if columns.is_empty() { - emit_typed( - sink, + sink.emit( &event_name, &QueryStreamEvent::Columns { columns: String::new(), total_rows: 0 }, - ) - .await; + ); } else { let header = join_sep(&columns, CELL_SEP); - emit_typed( - sink, + sink.emit( &event_name, &QueryStreamEvent::Columns { columns: header, total_rows: rows.len() }, - ) - .await; + ); let packed = pack_rows_vec(&rows); - emit_typed(sink, &event_name, &QueryStreamEvent::Chunk { data: packed }).await; + sink.emit(&event_name, &QueryStreamEvent::Chunk { data: packed }); } let elapsed = start.elapsed().as_millis() as f32; - emit_typed( - sink, + sink.emit( &event_name, &QueryStreamEvent::Done { elapsed, capped: false }, - ) - .await; + ); } } diff --git a/crates/rsql-core/src/events.rs b/crates/rsql-core/src/events.rs index d51ed8f..e52088a 100644 --- a/crates/rsql-core/src/events.rs +++ b/crates/rsql-core/src/events.rs @@ -1,47 +1,38 @@ -use serde::Serialize; -use std::sync::Arc; - -#[async_trait::async_trait] pub trait EventSink: Send + Sync + 'static { - async fn emit_json(&self, event: &str, payload: serde_json::Value); + fn emit(&self, event: &str, payload: &T); } -pub type SharedEventSink = Arc; - -pub async fn emit_typed(sink: &SharedEventSink, event: &str, payload: &T) { - match serde_json::to_value(payload) { - Ok(v) => sink.emit_json(event, v).await, - Err(e) => tracing::error!(error = %e, event, "emit_typed: serialize failed"), - } +pub fn emit_typed(sink: &S, event: &str, payload: &T) { + sink.emit(event, payload); } #[cfg(test)] mod tests { use super::*; - use tokio::sync::Mutex; + use std::sync::{Arc, Mutex}; - struct RecordingSink(Arc>>); + struct RecordingSink { + log: Mutex>, + } - #[async_trait::async_trait] impl EventSink for RecordingSink { - async fn emit_json(&self, event: &str, payload: serde_json::Value) { - self.0.lock().await.push((event.to_string(), payload)); + fn emit(&self, event: &str, payload: &T) { + let value = serde_json::to_value(payload).expect("serialize"); + self.log.lock().unwrap().push((event.to_string(), value)); } } - #[tokio::test] - async fn emit_typed_serializes_and_forwards() { + #[test] + fn emit_forwards_to_sink() { #[derive(serde::Serialize)] struct Probe { n: u32, label: &'static str } - let log = Arc::new(Mutex::new(Vec::new())); - let sink: SharedEventSink = Arc::new(RecordingSink(log.clone())); - - emit_typed(&sink, "probe", &Probe { n: 7, label: "hi" }).await; + let sink = Arc::new(RecordingSink { log: Mutex::new(Vec::new()) }); + emit_typed(&*sink, "probe", &Probe { n: 7, label: "hi" }); - let recorded = log.lock().await; - assert_eq!(recorded.len(), 1); - assert_eq!(recorded[0].0, "probe"); - assert_eq!(recorded[0].1, serde_json::json!({"n": 7, "label": "hi"})); + let log = sink.log.lock().unwrap(); + assert_eq!(log.len(), 1); + assert_eq!(log[0].0, "probe"); + assert_eq!(log[0].1, serde_json::json!({"n": 7, "label": "hi"})); } } diff --git a/crates/rsql-core/src/lib.rs b/crates/rsql-core/src/lib.rs index b445695..9f36c2b 100644 --- a/crates/rsql-core/src/lib.rs +++ b/crates/rsql-core/src/lib.rs @@ -10,5 +10,5 @@ pub mod state; pub mod terminal; pub mod utils; -pub use events::{EventSink, SharedEventSink, emit_typed}; +pub use events::{EventSink, emit_typed}; pub use state::AppState; diff --git a/crates/rsql-core/src/terminal/mod.rs b/crates/rsql-core/src/terminal/mod.rs index cfd005e..44b7c11 100644 --- a/crates/rsql-core/src/terminal/mod.rs +++ b/crates/rsql-core/src/terminal/mod.rs @@ -4,13 +4,14 @@ pub use session::TerminalRegistry; use portable_pty::{CommandBuilder, PtySize, native_pty_system}; use std::io::Read; +use std::sync::Arc; use crate::error::AppError; -use crate::events::SharedEventSink; +use crate::events::EventSink; -pub async fn spawn( +pub async fn spawn( registry: &TerminalRegistry, - sink: SharedEventSink, + sink: Arc, id: String, cols: u16, rows: u16, @@ -41,27 +42,20 @@ pub async fn spawn( registry.insert(id.clone(), session).await; let terminal_id = id; - let reader_sink = sink.clone(); - let handle = tokio::runtime::Handle::current(); + let reader_sink = sink; std::thread::spawn(move || { let mut buf = [0u8; 4096]; loop { match reader.read(&mut buf) { Ok(0) => { let event = format!("terminal-exit-{terminal_id}"); - let sink = reader_sink.clone(); - handle.spawn(async move { - sink.emit_json(&event, serde_json::Value::Null).await - }); + reader_sink.emit(&event, &serde_json::Value::Null); break; } Ok(n) => { let data = String::from_utf8_lossy(&buf[..n]).to_string(); let event = format!("terminal-data-{terminal_id}"); - let sink = reader_sink.clone(); - handle.spawn(async move { - sink.emit_json(&event, serde_json::Value::String(data)).await - }); + reader_sink.emit(&event, &data); } Err(_) => break, } diff --git a/crates/rsql-proxy/Cargo.toml b/crates/rsql-proxy/Cargo.toml index e87f00e..0d61418 100644 --- a/crates/rsql-proxy/Cargo.toml +++ b/crates/rsql-proxy/Cargo.toml @@ -22,11 +22,11 @@ tracing = { workspace = true } tracing-subscriber = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } +sonic-rs = { workspace = true } clap = { workspace = true } futures-util = { workspace = true } rsql-core = { path = "../rsql-core" } uuid = { workspace = true } -async-trait = { workspace = true } tokio-postgres = { workspace = true } [dev-dependencies] diff --git a/crates/rsql-proxy/src/dispatch/pgsql_query.rs b/crates/rsql-proxy/src/dispatch/pgsql_query.rs index 80cd135..46ddbce 100644 --- a/crates/rsql-proxy/src/dispatch/pgsql_query.rs +++ b/crates/rsql-proxy/src/dispatch/pgsql_query.rs @@ -1,6 +1,7 @@ use rsql_core::drivers::pgsql::commands::{pool_helpers, query}; use rsql_core::drivers::pgsql::streaming::execute_query_streamed; use rsql_core::error::AppError; +use rsql_core::events::EventSink; use serde::Deserialize; use uuid::Uuid; @@ -123,11 +124,8 @@ pub async fn handle( let stream_id = a.stream_id.clone(); tokio::spawn(async move { if let Err(e) = execute_query_streamed(&client, &sql, &stream_id, &sink).await { - sink.emit_json( - &format!("query-stream-{stream_id}"), - serde_json::json!({"type": "error", "message": e.to_string()}), - ) - .await; + let err_payload = serde_json::json!({"type": "error", "message": e.to_string()}); + sink.emit(&format!("query-stream-{stream_id}"), &err_payload); } }); Ok(Outbound::response(id, serde_json::Value::Null)) diff --git a/crates/rsql-proxy/src/event_sink.rs b/crates/rsql-proxy/src/event_sink.rs index 47c5df1..d8cc251 100644 --- a/crates/rsql-proxy/src/event_sink.rs +++ b/crates/rsql-proxy/src/event_sink.rs @@ -13,10 +13,16 @@ impl ProxyEventSink { } } -#[async_trait::async_trait] impl EventSink for ProxyEventSink { - async fn emit_json(&self, event: &str, payload: serde_json::Value) { - if let Err(e) = self.tx.send(Outbound::event(event, payload)) { + fn emit(&self, event: &str, payload: &T) { + let value = match serde_json::to_value(payload) { + Ok(v) => v, + Err(e) => { + tracing::error!(error = %e, event, "ProxyEventSink serialize failed"); + return; + } + }; + if let Err(e) = self.tx.send(Outbound::event(event, value)) { tracing::debug!(error = %e, "ProxyEventSink: receiver closed"); } } diff --git a/crates/rsql-proxy/src/protocol.rs b/crates/rsql-proxy/src/protocol.rs index 61d7669..dc93f9a 100644 --- a/crates/rsql-proxy/src/protocol.rs +++ b/crates/rsql-proxy/src/protocol.rs @@ -1,6 +1,7 @@ use axum::extract::ws::Message; use serde::{Deserialize, Serialize}; use uuid::Uuid; +use sonic_rs; pub const BINARY_ID_LEN: usize = 16; @@ -70,9 +71,9 @@ impl Outbound { Outbound::Binary { id, payload } } - pub fn into_ws_message(self) -> Result { + pub fn into_ws_message(self) -> Result { match self { - Outbound::Text(frame) => Ok(Message::Text(serde_json::to_string(&frame)?.into())), + Outbound::Text(frame) => Ok(Message::Text(sonic_rs::to_string(&frame)?.into())), Outbound::Binary { id, payload } => { let mut buf = Vec::with_capacity(BINARY_ID_LEN + payload.len()); buf.extend_from_slice(id.as_bytes()); @@ -83,8 +84,8 @@ impl Outbound { } } -pub fn parse_text(text: &str) -> Result { - serde_json::from_str(text) +pub fn parse_text(text: &str) -> Result { + sonic_rs::from_str(text) } pub fn parse_binary(bytes: &[u8]) -> Option<(Uuid, &[u8])> { diff --git a/crates/rsql-proxy/src/session.rs b/crates/rsql-proxy/src/session.rs index 532d572..5494910 100644 --- a/crates/rsql-proxy/src/session.rs +++ b/crates/rsql-proxy/src/session.rs @@ -1,5 +1,4 @@ use rsql_core::AppState; -use rsql_core::events::SharedEventSink; use rsql_core::terminal::TerminalRegistry; use std::collections::HashMap; use std::sync::Arc; @@ -15,14 +14,14 @@ use crate::protocol::Outbound; pub struct ProxySession { pub app_state: Arc, pub terminals: TerminalRegistry, - pub sink: SharedEventSink, + pub sink: Arc, pub outbound: UnboundedSender, pub cancel_tokens: Arc>>, } impl ProxySession { pub fn new(app_state: Arc, outbound: UnboundedSender) -> Self { - let sink: SharedEventSink = Arc::new(ProxyEventSink::new(outbound.clone())); + let sink = Arc::new(ProxyEventSink::new(outbound.clone())); Self { app_state, terminals: TerminalRegistry::new(), diff --git a/crates/rsql-tauri/Cargo.toml b/crates/rsql-tauri/Cargo.toml index 45d8df8..70193a5 100644 --- a/crates/rsql-tauri/Cargo.toml +++ b/crates/rsql-tauri/Cargo.toml @@ -39,5 +39,4 @@ sysinfo.workspace = true csv.workspace = true futures-util.workspace = true russh.workspace = true -async-trait = { workspace = true } rsql-core = { path = "../rsql-core" } diff --git a/crates/rsql-tauri/src/drivers/pgsql/commands/pubsub_commands.rs b/crates/rsql-tauri/src/drivers/pgsql/commands/pubsub_commands.rs index 2c33bac..79ec11a 100644 --- a/crates/rsql-tauri/src/drivers/pgsql/commands/pubsub_commands.rs +++ b/crates/rsql-tauri/src/drivers/pgsql/commands/pubsub_commands.rs @@ -12,7 +12,7 @@ pub async fn pgsql_listen_start( app: AppHandle, ) -> Result { let app_state = app.state::(); - let sink: rsql_core::events::SharedEventSink = TauriEventSink::new(app.clone()); + let sink = TauriEventSink::new(app.clone()); pubsub::listen_start(app_state.inner(), project_id, channel, sink).await } diff --git a/crates/rsql-tauri/src/drivers/pgsql/commands/query_commands.rs b/crates/rsql-tauri/src/drivers/pgsql/commands/query_commands.rs index b939350..82e66a2 100644 --- a/crates/rsql-tauri/src/drivers/pgsql/commands/query_commands.rs +++ b/crates/rsql-tauri/src/drivers/pgsql/commands/query_commands.rs @@ -49,7 +49,7 @@ pub async fn pgsql_run_query_streamed( let client = acquire_client(&app_state.clients, project_id).await?; set_cancel_token(&app_state, project_id, client.cancel_token()).await?; - let sink: rsql_core::events::SharedEventSink = crate::event_sink::TauriEventSink::new(app.clone()); + let sink = crate::event_sink::TauriEventSink::new(app.clone()); execute_query_streamed(&client, sql, stream_id, &sink).await } diff --git a/crates/rsql-tauri/src/event_sink.rs b/crates/rsql-tauri/src/event_sink.rs index 49d0d12..a5b2b55 100644 --- a/crates/rsql-tauri/src/event_sink.rs +++ b/crates/rsql-tauri/src/event_sink.rs @@ -12,9 +12,8 @@ impl TauriEventSink { } } -#[async_trait::async_trait] impl EventSink for TauriEventSink { - async fn emit_json(&self, event: &str, payload: serde_json::Value) { + fn emit(&self, event: &str, payload: &T) { if let Err(e) = self.app.emit(event, payload) { tracing::warn!(event, error = %e, "TauriEventSink emit failed"); } From 93d0733586ec3361182c049948110617a58eb93e Mon Sep 17 00:00:00 2001 From: Daniel Boros Date: Mon, 18 May 2026 17:24:52 +0200 Subject: [PATCH 06/11] feat: close p4 --- package.json | 2 + src/components/connection-modal/index.tsx | 2 +- src/components/notify-panel.tsx | 8 +- src/components/results-panel/diff-view.tsx | 4 +- src/components/status-bar.tsx | 2 +- src/components/terminal-panel.tsx | 15 +- src/{tauri.ts => lib/api.ts} | 25 +-- src/lib/database-driver/pgsql.ts | 106 +++++---- src/lib/transport/index.ts | 14 ++ src/lib/transport/protocol.ts | 73 +++++++ src/lib/transport/reconnect.ts | 36 +++ src/lib/transport/runtime.ts | 24 ++ src/lib/transport/tauri-transport.ts | 56 +++++ src/lib/transport/types.ts | 30 +++ src/lib/transport/websocket-transport.ts | 242 +++++++++++++++++++++ src/stores/project-store/core.ts | 2 +- src/stores/query-store.ts | 2 +- src/stores/workspace-store.ts | 2 +- vite.config.ts | 75 ++++--- 19 files changed, 605 insertions(+), 115 deletions(-) rename src/{tauri.ts => lib/api.ts} (61%) create mode 100644 src/lib/transport/index.ts create mode 100644 src/lib/transport/protocol.ts create mode 100644 src/lib/transport/reconnect.ts create mode 100644 src/lib/transport/runtime.ts create mode 100644 src/lib/transport/tauri-transport.ts create mode 100644 src/lib/transport/types.ts create mode 100644 src/lib/transport/websocket-transport.ts diff --git a/package.json b/package.json index 7a4b733..7376fe1 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,8 @@ "type": "module", "scripts": { "dev": "vite", + "dev:web": "VITE_BUILD_TARGET=web vite", + "dev:proxy": "cargo run -p rsql-proxy -- --addr 127.0.0.1:8080 --dist-dir dist --state-path /tmp/rsql-dev.db", "build": "tsc && vite build", "preview": "vite preview", "tauri": "cd crates/rsql-tauri && tauri", diff --git a/src/components/connection-modal/index.tsx b/src/components/connection-modal/index.tsx index 6d203bf..f9c059d 100644 --- a/src/components/connection-modal/index.tsx +++ b/src/components/connection-modal/index.tsx @@ -1,7 +1,7 @@ import { CheckCircle2, Loader2, XCircle } from "lucide-react"; import type React from "react"; import { useEffect, useState } from "react"; -import { pgsqlTestConnection } from "@/tauri"; +import { pgsqlTestConnection } from "@/lib/api"; import type { DriverType, ProjectDetails } from "@/types"; import { Button } from "../ui/button"; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "../ui/dialog"; diff --git a/src/components/notify-panel.tsx b/src/components/notify-panel.tsx index 5994214..bd83dd4 100644 --- a/src/components/notify-panel.tsx +++ b/src/components/notify-panel.tsx @@ -1,4 +1,4 @@ -import { listen } from "@tauri-apps/api/event"; +import { transport } from "@/lib/transport"; import { Bell, BellOff, Radio, Send, Trash2 } from "lucide-react"; import { useCallback, useEffect, useRef, useState } from "react"; import { DriverFactory } from "@/lib/database-driver"; @@ -44,12 +44,12 @@ export function NotifyPanel({ projectId }: NotifyPanelProps) { const eventName = `pg-notify-${projectId}`; let unlisten: (() => void) | null = null; - listen<{ channel: string; payload: string }>(eventName, (event) => { + transport.listen<{ channel: string; payload: string }>(eventName, (payload) => { setNotifications((prev) => [ ...prev, { - channel: event.payload.channel, - payload: event.payload.payload, + channel: payload.channel, + payload: payload.payload, timestamp: new Date().toISOString(), }, ]); diff --git a/src/components/results-panel/diff-view.tsx b/src/components/results-panel/diff-view.tsx index ed8decc..a6a7336 100644 --- a/src/components/results-panel/diff-view.tsx +++ b/src/components/results-panel/diff-view.tsx @@ -1,4 +1,4 @@ -import { invoke } from "@tauri-apps/api/core"; +import { transport } from "@/lib/transport"; import { Diff, Loader2 } from "lucide-react"; import { useRef, useState } from "react"; @@ -44,7 +44,7 @@ export function DiffView({ const pinnedPacked = packRows(pinnedColumns, pinnedRows); const currentPacked = packRows(currentColumns, currentRows); - invoke<[string, string, number]>("compute_diff", { + transport.invoke<[string, string, number]>("compute_diff", { pinned_packed: pinnedPacked, current_packed: currentPacked, }) diff --git a/src/components/status-bar.tsx b/src/components/status-bar.tsx index b5fd198..637e3f2 100644 --- a/src/components/status-bar.tsx +++ b/src/components/status-bar.tsx @@ -3,7 +3,7 @@ import { cn } from "@/lib/utils"; import { useHistoryStore } from "@/stores/history-store"; import { useProjectStore } from "@/stores/project-store"; import { useActiveTab } from "@/stores/tab-store"; -import { getSystemResourceUsage, type SystemResourceUsage } from "@/tauri"; +import { getSystemResourceUsage, type SystemResourceUsage } from "@/lib/api"; import { ProjectConnectionStatus } from "@/types"; export function StatusBar() { diff --git a/src/components/terminal-panel.tsx b/src/components/terminal-panel.tsx index 630d77d..464f156 100644 --- a/src/components/terminal-panel.tsx +++ b/src/components/terminal-panel.tsx @@ -1,5 +1,4 @@ -import { invoke } from "@tauri-apps/api/core"; -import { listen } from "@tauri-apps/api/event"; +import { transport } from "@/lib/transport"; import { FitAddon } from "@xterm/addon-fit"; import { Terminal } from "@xterm/xterm"; import { useCallback, useEffect, useRef } from "react"; @@ -95,28 +94,28 @@ export function TerminalPanel({ terminalId }: TerminalPanelProps) { const cols = term.cols; const rows = term.rows; - invoke("terminal_spawn", { id: terminalId, cols, rows }).catch((err) => { + transport.invoke("terminal_spawn", { id: terminalId, cols, rows }).catch((err) => { term.writeln(`\r\nFailed to spawn terminal: ${err}\r\n`); }); } - const dataUnlisten = listen(`terminal-data-${terminalId}`, (event) => { - term.write(event.payload); + const dataUnlisten = transport.listen(`terminal-data-${terminalId}`, (payload) => { + term.write(payload); }); - const exitUnlisten = listen(`terminal-exit-${terminalId}`, () => { + const exitUnlisten = transport.listen(`terminal-exit-${terminalId}`, () => { term.writeln("\r\n[Process exited]"); }); const dataDisposable = term.onData((data) => { - invoke("terminal_write", { id: terminalId, data }).catch(() => {}); + transport.invoke("terminal_write", { id: terminalId, data }).catch(() => {}); }); const resizeObs = new ResizeObserver(() => { fitAddon.fit(); const cols = term.cols; const rows = term.rows; - invoke("terminal_resize", { id: terminalId, cols, rows }).catch(() => {}); + transport.invoke("terminal_resize", { id: terminalId, cols, rows }).catch(() => {}); }); resizeObs.observe(containerRef.current); diff --git a/src/tauri.ts b/src/lib/api.ts similarity index 61% rename from src/tauri.ts rename to src/lib/api.ts index 4fe2b9b..d3ba613 100644 --- a/src/tauri.ts +++ b/src/lib/api.ts @@ -1,6 +1,5 @@ -import { invoke } from "@tauri-apps/api/core"; +import { transport } from "./transport"; -// Raw wire types from Rust backend (string arrays) export type RawProjectMap = Record; export interface SystemResourceUsage { @@ -16,47 +15,47 @@ export interface SystemResourceUsage { } export async function getProjects(): Promise { - return await invoke("project_db_select"); + return await transport.invoke("project_db_select"); } export async function insertProject(project_id: string, project_details: string[]): Promise { - await invoke("project_db_insert", { project_id, project_details }); + await transport.invoke("project_db_insert", { project_id, project_details }); } export async function deleteProject(project_id: string): Promise { - await invoke("project_db_delete", { project_id }); + await transport.invoke("project_db_delete", { project_id }); } export async function getQueries(): Promise> { - return await invoke>("query_db_select"); + return await transport.invoke>("query_db_select"); } export async function insertQuery(query_id: string, sql: string): Promise { - await invoke("query_db_insert", { query_id, sql }); + await transport.invoke("query_db_insert", { query_id, sql }); } export async function deleteQuery(query_id: string): Promise { - await invoke("query_db_delete", { query_id }); + await transport.invoke("query_db_delete", { query_id }); } export async function getSystemResourceUsage(): Promise { - return await invoke("system_resource_usage"); + return await transport.invoke("system_resource_usage"); } export async function workspaceSave(name: string, tabs: string): Promise { - await invoke("workspace_save", { name, tabs }); + await transport.invoke("workspace_save", { name, tabs }); } export async function workspaceLoadAll(): Promise<[string, string][]> { - return await invoke<[string, string][]>("workspace_load_all"); + return await transport.invoke<[string, string][]>("workspace_load_all"); } export async function workspaceDelete(name: string): Promise { - await invoke("workspace_delete", { name }); + await transport.invoke("workspace_delete", { name }); } export async function pgsqlTestConnection( key: [string, string, string, string, string, string], ): Promise { - return await invoke("pgsql_test_connection", { key }); + return await transport.invoke("pgsql_test_connection", { key }); } diff --git a/src/lib/database-driver/pgsql.ts b/src/lib/database-driver/pgsql.ts index 20bf797..1dc41c8 100644 --- a/src/lib/database-driver/pgsql.ts +++ b/src/lib/database-driver/pgsql.ts @@ -1,5 +1,4 @@ -import { invoke } from "@tauri-apps/api/core"; -import { listen } from "@tauri-apps/api/event"; +import { transport } from "@/lib/transport"; import type { DbGrant, PgRole, ProjectConnectionStatus, SchemaObject, TableGrant } from "@/types"; import type { DatabaseDriver, @@ -37,26 +36,26 @@ export class PostgreSQLDriver implements DatabaseDriver { key: [string, string, string, string, string, string], ssh?: string[], ) { - return invoke("pgsql_connector", { + return transport.invoke("pgsql_connector", { project_id: projectId, key, ssh: ssh ?? null, }); } async cancelQuery(projectId: string) { - return invoke("pgsql_cancel_query", { project_id: projectId }); + return transport.invoke("pgsql_cancel_query", { project_id: projectId }); } async loadSchemas(projectId: string) { - return invoke("pgsql_load_schemas", { project_id: projectId }); + return transport.invoke("pgsql_load_schemas", { project_id: projectId }); } async loadTables(projectId: string, schema: string) { - return invoke("pgsql_load_tables", { project_id: projectId, schema }); + return transport.invoke("pgsql_load_tables", { project_id: projectId, schema }); } async loadColumns(projectId: string, schema: string, table: string) { - return invoke("pgsql_load_columns", { project_id: projectId, schema, table }); + return transport.invoke("pgsql_load_columns", { project_id: projectId, schema, table }); } async loadColumnDetails(projectId: string, schema: string, table: string) { - const wire = await invoke("pgsql_load_column_details", { + const wire = await transport.invoke("pgsql_load_column_details", { project_id: projectId, schema, table, @@ -64,7 +63,7 @@ export class PostgreSQLDriver implements DatabaseDriver { return parseColumnDetails(wire); } async loadIndexes(projectId: string, schema: string, table: string) { - const wire = await invoke("pgsql_load_indexes", { + const wire = await transport.invoke("pgsql_load_indexes", { project_id: projectId, schema, table, @@ -72,7 +71,7 @@ export class PostgreSQLDriver implements DatabaseDriver { return parseIndexDetails(wire); } async loadConstraints(projectId: string, schema: string, table: string) { - const wire = await invoke("pgsql_load_constraints", { + const wire = await transport.invoke("pgsql_load_constraints", { project_id: projectId, schema, table, @@ -80,7 +79,7 @@ export class PostgreSQLDriver implements DatabaseDriver { return parseConstraintDetails(wire); } async loadTriggers(projectId: string, schema: string, table: string) { - const wire = await invoke("pgsql_load_triggers", { + const wire = await transport.invoke("pgsql_load_triggers", { project_id: projectId, schema, table, @@ -88,7 +87,7 @@ export class PostgreSQLDriver implements DatabaseDriver { return parseTriggerDetails(wire); } async loadRules(projectId: string, schema: string, table: string) { - const wire = await invoke("pgsql_load_rules", { + const wire = await transport.invoke("pgsql_load_rules", { project_id: projectId, schema, table, @@ -96,7 +95,7 @@ export class PostgreSQLDriver implements DatabaseDriver { return parseRuleDetails(wire); } async loadPolicies(projectId: string, schema: string, table: string) { - const wire = await invoke("pgsql_load_policies", { + const wire = await transport.invoke("pgsql_load_policies", { project_id: projectId, schema, table, @@ -104,20 +103,20 @@ export class PostgreSQLDriver implements DatabaseDriver { return parsePolicyDetails(wire); } async loadViews(projectId: string, schema: string) { - return invoke("pgsql_load_views", { project_id: projectId, schema }); + return transport.invoke("pgsql_load_views", { project_id: projectId, schema }); } async loadMaterializedViews(projectId: string, schema: string) { - return invoke("pgsql_load_materialized_views", { project_id: projectId, schema }); + return transport.invoke("pgsql_load_materialized_views", { project_id: projectId, schema }); } async loadFunctions(projectId: string, schema: string) { - const wire = await invoke("pgsql_load_functions", { + const wire = await transport.invoke("pgsql_load_functions", { project_id: projectId, schema, }); return parseFunctionInfo(wire); } async loadTriggerFunctions(projectId: string, schema: string) { - const wire = await invoke("pgsql_load_trigger_functions", { + const wire = await transport.invoke("pgsql_load_trigger_functions", { project_id: projectId, schema, }); @@ -125,7 +124,7 @@ export class PostgreSQLDriver implements DatabaseDriver { } async runQuery(projectId: string, sql: string, timeoutMs?: number) { // Use packed format for faster IPC (avoids JSON overhead of nested arrays) - const [packed, time] = await invoke("pgsql_run_query_packed", { + const [packed, time] = await transport.invoke("pgsql_run_query_packed", { project_id: projectId, sql, timeout_ms: timeoutMs ?? null, @@ -145,8 +144,7 @@ export class PostgreSQLDriver implements DatabaseDriver { rejectStream = reject; }); - const unlisten = await listen(`query-stream-${streamId}`, (event) => { - const p = event.payload; + const unlisten = await transport.listen(`query-stream-${streamId}`, (p) => { switch (p.type) { case "columns": { const cols = p.columns ? p.columns.split(CELL_SEP) : []; @@ -169,7 +167,7 @@ export class PostgreSQLDriver implements DatabaseDriver { } }); - invoke("pgsql_run_query_streamed", { + transport.invoke("pgsql_run_query_streamed", { project_id: projectId, sql, stream_id: streamId, @@ -187,7 +185,7 @@ export class PostgreSQLDriver implements DatabaseDriver { pageSize: number, timeoutMs?: number, ) { - return invoke<[string, number, string, number]>("pgsql_execute_virtual", { + return transport.invoke<[string, number, string, number]>("pgsql_execute_virtual", { project_id: projectId, sql, query_id: queryId, @@ -202,7 +200,7 @@ export class PostgreSQLDriver implements DatabaseDriver { offset: number, limit: number, ) { - return invoke("pgsql_fetch_page", { + return transport.invoke("pgsql_fetch_page", { query_id: queryId, col_count: colCount, offset, @@ -210,21 +208,21 @@ export class PostgreSQLDriver implements DatabaseDriver { }); } async closeVirtual(_projectId: string, queryId: string) { - return invoke("pgsql_close_virtual", { + return transport.invoke("pgsql_close_virtual", { query_id: queryId, }); } async loadActivity(projectId: string) { - return invoke("pgsql_load_activity", { project_id: projectId }); + return transport.invoke("pgsql_load_activity", { project_id: projectId }); } async loadDatabaseStats(projectId: string) { - return invoke<[string, string][]>("pgsql_load_database_stats", { project_id: projectId }); + return transport.invoke<[string, string][]>("pgsql_load_database_stats", { project_id: projectId }); } async loadTableStats(projectId: string) { - return invoke("pgsql_load_table_stats", { project_id: projectId }); + return transport.invoke("pgsql_load_table_stats", { project_id: projectId }); } async loadForeignKeys(projectId: string, schema: string) { - const wire = await invoke("pgsql_load_foreign_keys", { + const wire = await transport.invoke("pgsql_load_foreign_keys", { project_id: projectId, schema, }); @@ -236,37 +234,37 @@ export class PostgreSQLDriver implements DatabaseDriver { })); } async loadTableStatistics(projectId: string, schema: string, table: string) { - return invoke<[string, string][]>("pgsql_table_statistics", { + return transport.invoke<[string, string][]>("pgsql_table_statistics", { project_id: projectId, schema, table, }); } async loadFKDetails(projectId: string, schema: string, table: string, direction: string) { - return invoke<[string, string, string, string, string, string, string, string, string][]>( + return transport.invoke<[string, string, string, string, string, string, string, string, string][]>( "pgsql_fk_details", { project_id: projectId, schema, table, direction }, ); } async loadViewInfo(projectId: string, schema: string, view: string) { - return invoke<[string, string][]>("pgsql_view_info", { project_id: projectId, schema, view }); + return transport.invoke<[string, string][]>("pgsql_view_info", { project_id: projectId, schema, view }); } async loadMatviewInfo(projectId: string, schema: string, matview: string) { - return invoke<[string, string][]>("pgsql_matview_info", { + return transport.invoke<[string, string][]>("pgsql_matview_info", { project_id: projectId, schema, matview, }); } async loadFunctionInfo(projectId: string, schema: string, funcName: string) { - return invoke<[string, string][]>("pgsql_function_info", { + return transport.invoke<[string, string][]>("pgsql_function_info", { project_id: projectId, schema, func_name: funcName, }); } async generateDDL(projectId: string, schema: string, name: string, objectType: string) { - return invoke("pgsql_generate_ddl", { + return transport.invoke("pgsql_generate_ddl", { project_id: projectId, schema, name, @@ -274,7 +272,7 @@ export class PostgreSQLDriver implements DatabaseDriver { }); } async csvPreview(filePath: string) { - return invoke<[string[], string[][]]>("pgsql_csv_preview", { file_path: filePath }); + return transport.invoke<[string[], string[][]]>("pgsql_csv_preview", { file_path: filePath }); } async csvImport( projectId: string, @@ -283,7 +281,7 @@ export class PostgreSQLDriver implements DatabaseDriver { table: string, columnMapping: [number, string][], ) { - return invoke("pgsql_csv_import", { + return transport.invoke("pgsql_csv_import", { project_id: projectId, file_path: filePath, schema, @@ -292,64 +290,64 @@ export class PostgreSQLDriver implements DatabaseDriver { }); } async listenStart(projectId: string, channel: string) { - return invoke("pgsql_listen_start", { project_id: projectId, channel }); + return transport.invoke("pgsql_listen_start", { project_id: projectId, channel }); } async listenStop(projectId: string, channel: string) { - return invoke("pgsql_listen_stop", { project_id: projectId, channel }); + return transport.invoke("pgsql_listen_stop", { project_id: projectId, channel }); } async notifySend(projectId: string, channel: string, payload: string) { - return invoke("pgsql_notify_send", { project_id: projectId, channel, payload }); + return transport.invoke("pgsql_notify_send", { project_id: projectId, channel, payload }); } async discoverChannels(projectId: string) { - return invoke("pgsql_discover_channels", { project_id: projectId }); + return transport.invoke("pgsql_discover_channels", { project_id: projectId }); } async loadRoles(projectId: string) { - return invoke("pgsql_load_roles", { project_id: projectId }); + return transport.invoke("pgsql_load_roles", { project_id: projectId }); } async loadTableGrants(projectId: string, roleName: string) { - return invoke("pgsql_load_table_grants", { + return transport.invoke("pgsql_load_table_grants", { project_id: projectId, role_name: roleName, }); } async loadDatabaseGrants(projectId: string, roleName: string) { - return invoke("pgsql_load_database_grants", { + return transport.invoke("pgsql_load_database_grants", { project_id: projectId, role_name: roleName, }); } async extractSchemaObjects(projectId: string, schema: string) { - return invoke("pgsql_extract_schema_objects", { + return transport.invoke("pgsql_extract_schema_objects", { project_id: projectId, schema, }); } async loadLocks(projectId: string) { - return invoke("pgsql_load_locks", { project_id: projectId }); + return transport.invoke("pgsql_load_locks", { project_id: projectId }); } async loadIndexUsage(projectId: string) { - return invoke("pgsql_load_index_usage", { project_id: projectId }); + return transport.invoke("pgsql_load_index_usage", { project_id: projectId }); } async loadTableBloat(projectId: string) { - return invoke("pgsql_load_table_bloat", { project_id: projectId }); + return transport.invoke("pgsql_load_table_bloat", { project_id: projectId }); } async loadDatabases(projectId: string) { - return invoke("pgsql_load_databases", { project_id: projectId }); + return transport.invoke("pgsql_load_databases", { project_id: projectId }); } async loadTablespaces(projectId: string) { - return invoke<[string, string, string][]>("pgsql_load_tablespaces", { project_id: projectId }); + return transport.invoke<[string, string, string][]>("pgsql_load_tablespaces", { project_id: projectId }); } async loadExtensions(projectId: string) { - return invoke("pgsql_load_extensions", { project_id: projectId }); + return transport.invoke("pgsql_load_extensions", { project_id: projectId }); } async loadAvailableExtensions(projectId: string) { - return invoke("pgsql_load_available_extensions", { project_id: projectId }); + return transport.invoke("pgsql_load_available_extensions", { project_id: projectId }); } async loadEnumTypes(projectId: string) { - return invoke("pgsql_load_enum_types", { project_id: projectId }); + return transport.invoke("pgsql_load_enum_types", { project_id: projectId }); } async loadPgSettings(projectId: string) { - return invoke("pgsql_load_pg_settings", { project_id: projectId }); + return transport.invoke("pgsql_load_pg_settings", { project_id: projectId }); } async tableAction( projectId: string, @@ -358,7 +356,7 @@ export class PostgreSQLDriver implements DatabaseDriver { table: string, objectType: string, ) { - return invoke("pgsql_table_action", { + return transport.invoke("pgsql_table_action", { project_id: projectId, action, schema, diff --git a/src/lib/transport/index.ts b/src/lib/transport/index.ts new file mode 100644 index 0000000..a4c169b --- /dev/null +++ b/src/lib/transport/index.ts @@ -0,0 +1,14 @@ +import { deriveProxyUrl, isTauriRuntime } from "./runtime"; +import { TauriTransport } from "./tauri-transport"; +import type { Transport } from "./types"; +import { WebSocketTransport } from "./websocket-transport"; + +function createTransport(): Transport { + if (isTauriRuntime()) return new TauriTransport(); + return new WebSocketTransport(deriveProxyUrl()); +} + +export const transport: Transport = createTransport(); + +export type { EventHandler, InvokeOptions, StreamHandle, Transport, UnlistenFn } from "./types"; +export { TransportError } from "./types"; diff --git a/src/lib/transport/protocol.ts b/src/lib/transport/protocol.ts new file mode 100644 index 0000000..e0ddfae --- /dev/null +++ b/src/lib/transport/protocol.ts @@ -0,0 +1,73 @@ +export type InboundFrame = + | { id: string; type: "request"; cmd: string; payload?: Record } + | { id: string; type: "cancel" }; + +export type OutboundFrame = + | { id: string; type: "response"; payload?: unknown; end?: boolean } + | { id: string; type: "error"; code?: string; message: string } + | { id: string; type: "event"; event: string; payload?: unknown }; + +export interface BinaryEnvelope { + id: string; + payload: Uint8Array; +} + +const UUID_LENGTH = 16; + +export function encodeRequest(id: string, cmd: string, payload?: Record): string { + return JSON.stringify({ id, type: "request", cmd, payload }); +} + +export function encodeCancel(id: string): string { + return JSON.stringify({ id, type: "cancel" }); +} + +export function parseTextFrame(data: string): OutboundFrame { + const parsed = JSON.parse(data) as OutboundFrame; + if (!parsed || typeof parsed !== "object" || !("type" in parsed)) { + throw new Error(`malformed outbound frame: missing type`); + } + return parsed; +} + +export function parseBinaryFrame(buf: ArrayBuffer): BinaryEnvelope { + if (buf.byteLength < UUID_LENGTH) { + throw new Error(`binary frame too short: ${buf.byteLength} bytes`); + } + const view = new Uint8Array(buf); + const id = uuidFromBytes(view.subarray(0, UUID_LENGTH)); + const payload = view.subarray(UUID_LENGTH); + return { id, payload }; +} + +export function uuidFromBytes(bytes: Uint8Array): string { + if (bytes.length !== 16) throw new Error(`uuid bytes must be 16, got ${bytes.length}`); + const hex: string[] = []; + for (let i = 0; i < 16; i++) { + hex.push(bytes[i].toString(16).padStart(2, "0")); + } + return ( + hex.slice(0, 4).join("") + + "-" + + hex.slice(4, 6).join("") + + "-" + + hex.slice(6, 8).join("") + + "-" + + hex.slice(8, 10).join("") + + "-" + + hex.slice(10, 16).join("") + ); +} + +export function generateRequestId(): string { + if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") { + return crypto.randomUUID(); + } + const bytes = new Uint8Array(16); + if (typeof crypto !== "undefined" && typeof crypto.getRandomValues === "function") { + crypto.getRandomValues(bytes); + } else { + for (let i = 0; i < 16; i++) bytes[i] = Math.floor(Math.random() * 256); + } + return uuidFromBytes(bytes); +} diff --git a/src/lib/transport/reconnect.ts b/src/lib/transport/reconnect.ts new file mode 100644 index 0000000..87fa6b3 --- /dev/null +++ b/src/lib/transport/reconnect.ts @@ -0,0 +1,36 @@ +export interface BackoffOptions { + initialMs?: number; + maxMs?: number; + factor?: number; + jitterRatio?: number; +} + +export class ExponentialBackoff { + private attempt = 0; + private readonly initial: number; + private readonly max: number; + private readonly factor: number; + private readonly jitter: number; + + constructor(opts: BackoffOptions = {}) { + this.initial = opts.initialMs ?? 1000; + this.max = opts.maxMs ?? 30000; + this.factor = opts.factor ?? 2; + this.jitter = opts.jitterRatio ?? 0.2; + } + + next(): number { + const base = Math.min(this.initial * this.factor ** this.attempt, this.max); + this.attempt++; + const jitter = base * this.jitter * (Math.random() * 2 - 1); + return Math.max(0, Math.round(base + jitter)); + } + + reset(): void { + this.attempt = 0; + } + + get attempts(): number { + return this.attempt; + } +} diff --git a/src/lib/transport/runtime.ts b/src/lib/transport/runtime.ts new file mode 100644 index 0000000..7ad59ed --- /dev/null +++ b/src/lib/transport/runtime.ts @@ -0,0 +1,24 @@ +declare global { + interface Window { + __TAURI_INTERNALS__?: unknown; + __RSQL_PROXY_URL__?: string; + } +} + +export function isTauriRuntime(): boolean { + if (typeof window === "undefined") return false; + if (import.meta.env.VITE_BUILD_TARGET === "web") return false; + return "__TAURI_INTERNALS__" in window && window.__TAURI_INTERNALS__ != null; +} + +export function deriveProxyUrl(): string { + if (typeof window === "undefined") { + throw new Error("deriveProxyUrl() requires a browser window"); + } + if (window.__RSQL_PROXY_URL__) return window.__RSQL_PROXY_URL__; + const envUrl = import.meta.env.VITE_RSQL_PROXY_URL; + if (typeof envUrl === "string" && envUrl.length > 0) return envUrl; + const { protocol, host } = window.location; + const wsProto = protocol === "https:" ? "wss:" : "ws:"; + return `${wsProto}//${host}/ws`; +} diff --git a/src/lib/transport/tauri-transport.ts b/src/lib/transport/tauri-transport.ts new file mode 100644 index 0000000..866c978 --- /dev/null +++ b/src/lib/transport/tauri-transport.ts @@ -0,0 +1,56 @@ +import type { EventHandler, InvokeOptions, StreamHandle, Transport, UnlistenFn } from "./types"; + +type TauriCore = typeof import("@tauri-apps/api/core"); +type TauriEvent = typeof import("@tauri-apps/api/event"); + +export class TauriTransport implements Transport { + private corePromise: Promise | null = null; + private eventPromise: Promise | null = null; + + private core(): Promise { + this.corePromise ??= import("@tauri-apps/api/core"); + return this.corePromise; + } + + private event(): Promise { + this.eventPromise ??= import("@tauri-apps/api/event"); + return this.eventPromise; + } + + async invoke(cmd: string, args?: Record, _opts?: InvokeOptions): Promise { + const { invoke } = await this.core(); + return invoke(cmd, args); + } + + async invokeRaw(cmd: string, args?: Record, _opts?: InvokeOptions): Promise { + const { invoke } = await this.core(); + const result = await invoke(cmd, args); + if (result instanceof Uint8Array) return result; + if (result instanceof ArrayBuffer) return new Uint8Array(result); + return new TextEncoder().encode(result); + } + + async listen(event: string, handler: EventHandler): Promise { + const { listen } = await this.event(); + return await listen(event, (e) => handler(e.payload)); + } + + async stream( + cmd: string, + args: Record, + event: string, + onFrame: EventHandler, + ): Promise { + const unlisten = await this.listen(event, onFrame); + let cancelled = false; + this.invoke(cmd, args).catch((err) => { + if (!cancelled) console.error(`stream(${cmd}) failed`, err); + }); + return { + cancel: () => { + cancelled = true; + unlisten(); + }, + }; + } +} diff --git a/src/lib/transport/types.ts b/src/lib/transport/types.ts new file mode 100644 index 0000000..6058b5e --- /dev/null +++ b/src/lib/transport/types.ts @@ -0,0 +1,30 @@ +export type UnlistenFn = () => void; + +export interface StreamHandle { + cancel: () => void; +} + +export interface InvokeOptions { + signal?: AbortSignal; +} + +export type EventHandler = (payload: T) => void; + +export interface Transport { + invoke(cmd: string, args?: Record, opts?: InvokeOptions): Promise; + invokeRaw(cmd: string, args?: Record, opts?: InvokeOptions): Promise; + listen(event: string, handler: EventHandler): Promise; + stream( + cmd: string, + args: Record, + event: string, + onFrame: EventHandler, + ): Promise; +} + +export class TransportError extends Error { + constructor(public readonly code: string | undefined, message: string) { + super(message); + this.name = "TransportError"; + } +} diff --git a/src/lib/transport/websocket-transport.ts b/src/lib/transport/websocket-transport.ts new file mode 100644 index 0000000..2b66dfc --- /dev/null +++ b/src/lib/transport/websocket-transport.ts @@ -0,0 +1,242 @@ +import { + type BinaryEnvelope, + encodeCancel, + encodeRequest, + generateRequestId, + type OutboundFrame, + parseBinaryFrame, + parseTextFrame, +} from "./protocol"; +import { ExponentialBackoff } from "./reconnect"; +import { + type EventHandler, + type InvokeOptions, + type StreamHandle, + type Transport, + TransportError, + type UnlistenFn, +} from "./types"; + +type Pending = { + resolveJson: (value: unknown) => void; + resolveBinary: (value: Uint8Array) => void; + reject: (err: unknown) => void; + expectBinary: boolean; +}; + +type EventBus = Map>>; + +const BUFFERED_WARN_THRESHOLD = 64 * 1024 * 1024; + +export class WebSocketTransport implements Transport { + private socket: WebSocket | null = null; + private connectingPromise: Promise | null = null; + private readonly pending = new Map(); + private readonly events: EventBus = new Map(); + private readonly backoff = new ExponentialBackoff(); + private closedByUser = false; + private backpressureWarned = false; + + constructor(private readonly url: string) {} + + async invoke(cmd: string, args?: Record, opts?: InvokeOptions): Promise { + return (await this.dispatch(cmd, args, opts, false)) as T; + } + + async invokeRaw(cmd: string, args?: Record, opts?: InvokeOptions): Promise { + return (await this.dispatch(cmd, args, opts, true)) as Uint8Array; + } + + async listen(event: string, handler: EventHandler): Promise { + await this.ensureConnected(); + const bucket = this.events.get(event) ?? new Set(); + bucket.add(handler as EventHandler); + this.events.set(event, bucket); + return () => { + const set = this.events.get(event); + if (!set) return; + set.delete(handler as EventHandler); + if (set.size === 0) this.events.delete(event); + }; + } + + async stream( + cmd: string, + args: Record, + event: string, + onFrame: EventHandler, + ): Promise { + const unlisten = await this.listen(event, onFrame); + let cancelId: string | null = null; + const startedAt = generateRequestId(); + cancelId = startedAt; + this.dispatch(cmd, { ...args, __stream_id: startedAt }, undefined, false).catch((err) => { + console.error(`stream(${cmd}) failed`, err); + }); + return { + cancel: () => { + unlisten(); + if (cancelId) this.send(encodeCancel(cancelId)); + }, + }; + } + + close(): void { + this.closedByUser = true; + this.socket?.close(1000, "client shutdown"); + for (const p of this.pending.values()) p.reject(new TransportError("CLOSED", "transport closed")); + this.pending.clear(); + this.events.clear(); + } + + private async dispatch( + cmd: string, + args: Record | undefined, + opts: InvokeOptions | undefined, + expectBinary: boolean, + ): Promise { + await this.ensureConnected(); + const id = generateRequestId(); + return new Promise((resolve, reject) => { + this.pending.set(id, { + resolveJson: (v) => resolve(v), + resolveBinary: (v) => resolve(v), + reject, + expectBinary, + }); + opts?.signal?.addEventListener("abort", () => { + if (this.pending.delete(id)) { + this.send(encodeCancel(id)); + reject(new TransportError("ABORTED", "request aborted")); + } + }); + this.send(encodeRequest(id, cmd, args)); + }); + } + + private send(text: string): void { + if (!this.socket || this.socket.readyState !== WebSocket.OPEN) { + throw new TransportError("CLOSED", "websocket is not open"); + } + if (this.socket.bufferedAmount > BUFFERED_WARN_THRESHOLD && !this.backpressureWarned) { + console.warn(`WebSocketTransport: bufferedAmount=${this.socket.bufferedAmount} exceeds threshold`); + this.backpressureWarned = true; + } else if (this.socket.bufferedAmount < BUFFERED_WARN_THRESHOLD / 4) { + this.backpressureWarned = false; + } + this.socket.send(text); + } + + private async ensureConnected(): Promise { + if (this.socket?.readyState === WebSocket.OPEN) return; + if (this.connectingPromise) return this.connectingPromise; + this.connectingPromise = this.connect(); + try { + await this.connectingPromise; + } finally { + this.connectingPromise = null; + } + } + + private connect(): Promise { + return new Promise((resolve, reject) => { + const ws = new WebSocket(this.url); + ws.binaryType = "arraybuffer"; + this.socket = ws; + ws.addEventListener("open", () => { + this.backoff.reset(); + resolve(); + }); + ws.addEventListener("message", (e) => this.onMessage(e)); + ws.addEventListener("close", () => this.onClose()); + ws.addEventListener("error", (err) => { + if (ws.readyState === WebSocket.CONNECTING) reject(err); + }); + }); + } + + private onMessage(event: MessageEvent): void { + if (typeof event.data === "string") { + this.handleTextFrame(event.data); + return; + } + if (event.data instanceof ArrayBuffer) { + this.handleBinaryFrame(event.data); + return; + } + console.error("WebSocketTransport: unexpected message type", event.data); + } + + private handleTextFrame(data: string): void { + let frame: OutboundFrame; + try { + frame = parseTextFrame(data); + } catch (err) { + console.error("WebSocketTransport: malformed text frame", err); + return; + } + if (frame.type === "response") { + const p = this.pending.get(frame.id); + if (!p) return; + this.pending.delete(frame.id); + if (p.expectBinary) { + p.reject(new TransportError("PROTOCOL", "expected binary response, got JSON")); + } else { + p.resolveJson(frame.payload); + } + return; + } + if (frame.type === "error") { + const p = this.pending.get(frame.id); + if (!p) return; + this.pending.delete(frame.id); + p.reject(new TransportError(frame.code, frame.message)); + return; + } + if (frame.type === "event") { + this.dispatchEvent(frame.event, frame.payload); + } + } + + private handleBinaryFrame(buf: ArrayBuffer): void { + let env: BinaryEnvelope; + try { + env = parseBinaryFrame(buf); + } catch (err) { + console.error("WebSocketTransport: malformed binary frame", err); + return; + } + const p = this.pending.get(env.id); + if (!p) return; + this.pending.delete(env.id); + if (p.expectBinary) { + p.resolveBinary(env.payload); + } else { + p.resolveJson(new TextDecoder().decode(env.payload)); + } + } + + private dispatchEvent(event: string, payload: unknown): void { + const bucket = this.events.get(event); + if (!bucket) return; + for (const h of bucket) { + try { + h(payload); + } catch (err) { + console.error(`WebSocketTransport: event handler for "${event}" threw`, err); + } + } + } + + private onClose(): void { + if (this.closedByUser) return; + for (const p of this.pending.values()) p.reject(new TransportError("DISCONNECTED", "websocket closed")); + this.pending.clear(); + const delay = this.backoff.next(); + console.warn(`WebSocketTransport: reconnecting in ${delay}ms`); + setTimeout(() => { + if (this.closedByUser) return; + this.connect().catch((err) => console.error("WebSocketTransport: reconnect failed", err)); + }, delay); + } +} diff --git a/src/stores/project-store/core.ts b/src/stores/project-store/core.ts index 799e96b..15f19d1 100644 --- a/src/stores/project-store/core.ts +++ b/src/stores/project-store/core.ts @@ -1,5 +1,5 @@ import type { StateCreator } from "zustand"; -import { deleteProject as deleteProjectApi, getProjects, insertProject } from "@/tauri"; +import { deleteProject as deleteProjectApi, getProjects, insertProject } from "@/lib/api"; import type { DriverType, ProjectConnectionStatus, ProjectDetails, ProjectMap } from "@/types"; import { ProjectConnectionStatus as PCS } from "@/types"; import type { ProjectState } from "./index"; diff --git a/src/stores/query-store.ts b/src/stores/query-store.ts index 25c6237..a38d753 100644 --- a/src/stores/query-store.ts +++ b/src/stores/query-store.ts @@ -1,6 +1,6 @@ import { create } from "zustand"; import { immer } from "zustand/middleware/immer"; -import { deleteQuery, getQueries, insertQuery } from "@/tauri"; +import { deleteQuery, getQueries, insertQuery } from "@/lib/api"; export interface SavedQuery { id: string; diff --git a/src/stores/workspace-store.ts b/src/stores/workspace-store.ts index 0081750..c2c4efa 100644 --- a/src/stores/workspace-store.ts +++ b/src/stores/workspace-store.ts @@ -1,6 +1,6 @@ import { create } from "zustand"; import { immer } from "zustand/middleware/immer"; -import { workspaceDelete, workspaceLoadAll, workspaceSave } from "@/tauri"; +import { workspaceDelete, workspaceLoadAll, workspaceSave } from "@/lib/api"; interface WorkspaceEntry { name: string; diff --git a/vite.config.ts b/vite.config.ts index 4be0090..96607f0 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,38 +1,55 @@ import path from "node:path"; import tailwindcss from "@tailwindcss/vite"; import react from "@vitejs/plugin-react"; -import { defineConfig } from "vite"; +import { defineConfig, loadEnv } from "vite"; // @ts-expect-error process is a nodejs global const host = process.env.TAURI_DEV_HOST; -// https://vite.dev/config/ -export default defineConfig(async () => ({ - plugins: [react(), tailwindcss()], - resolve: { - alias: { - "@": path.resolve(__dirname, "./src"), - }, - }, +export default defineConfig(async ({ mode }) => { + const env = loadEnv(mode, process.cwd(), "VITE_"); + const target = env.VITE_BUILD_TARGET ?? "tauri"; + const proxyTarget = env.VITE_RSQL_PROXY_DEV ?? "ws://127.0.0.1:8080"; - // Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build` - // - // 1. prevent Vite from obscuring rust errors - clearScreen: false, - // 2. tauri expects a fixed port, fail if that port is not available - server: { - port: 1420, - strictPort: true, - host: host || false, - hmr: host - ? { - protocol: "ws", - host, - port: 1421, - } - : undefined, - watch: { - ignored: ["**/crates/rsql-tauri/**", "**/crates/rsql-core/**", "**/target/**"], + return { + plugins: [react(), tailwindcss()], + define: { + __RSQL_BUILD_TARGET__: JSON.stringify(target), + }, + resolve: { + alias: { + "@": path.resolve(__dirname, "./src"), + }, + }, + clearScreen: false, + server: { + port: 1420, + strictPort: true, + host: host || false, + hmr: host + ? { + protocol: "ws", + host, + port: 1421, + } + : undefined, + watch: { + ignored: ["**/crates/rsql-tauri/**", "**/crates/rsql-core/**", "**/target/**"], + }, + proxy: + target === "web" + ? { + "/ws": { + target: proxyTarget, + ws: true, + changeOrigin: true, + }, + "/health": { + target: proxyTarget.replace(/^ws/, "http"), + changeOrigin: true, + }, + } + : undefined, }, - }, -})); + }; +}); From be607279633fcf283e7ce7f0e254e37e0cf10c35 Mon Sep 17 00:00:00 2001 From: Daniel Boros Date: Tue, 19 May 2026 08:45:18 +0200 Subject: [PATCH 07/11] feat: finish p5 --- src/App.tsx | 6 +- src/components/command-palette/tools.tsx | 24 ++-- src/components/csv-import-modal.tsx | 15 ++- src/components/top-bar.tsx | 10 +- src/hooks/use-app-startup.ts | 4 +- src/lib/export.ts | 12 +- src/lib/platform/dialog.ts | 99 +++++++++++++++ src/lib/platform/index.ts | 10 ++ src/lib/platform/stubs/empty.ts | 1 + src/lib/platform/types.ts | 29 +++++ src/lib/platform/updater.ts | 145 ++++++++++++++++++++++ src/lib/runtime.ts | 17 +++ src/lib/transport/runtime.ts | 9 +- src/lib/updater.ts | 150 ----------------------- src/vite-env.d.ts | 4 + vite.config.ts | 39 +++++- 16 files changed, 385 insertions(+), 189 deletions(-) create mode 100644 src/lib/platform/dialog.ts create mode 100644 src/lib/platform/index.ts create mode 100644 src/lib/platform/stubs/empty.ts create mode 100644 src/lib/platform/types.ts create mode 100644 src/lib/platform/updater.ts create mode 100644 src/lib/runtime.ts delete mode 100644 src/lib/updater.ts diff --git a/src/App.tsx b/src/App.tsx index e371e15..afd1972 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -22,7 +22,7 @@ import { TerminalPanel } from "@/components/terminal-panel"; import { TopBar } from "@/components/top-bar"; import { useAppStartup } from "@/hooks/use-app-startup"; import { useQueryLifecycle } from "@/hooks/use-query-lifecycle"; -import { checkForUpdates } from "@/lib/updater"; +import { updater } from "@/lib/platform"; import { useProjectStore } from "@/stores/project-store"; import { useActiveTab, useTabStore } from "@/stores/tab-store"; import { useUIStore } from "@/stores/ui-store"; @@ -123,7 +123,7 @@ export default function App() { onContextMenu={(e) => e.preventDefault()} > void checkForUpdates()} + onCheckUpdates={() => void updater.checkForUpdates()} onOpenCommandPalette={() => setCommandPaletteOpen(true)} /> @@ -298,7 +298,7 @@ export default function App() { onClose={() => setCommandPaletteOpen(false)} onExecute={() => void runQuery()} onExplain={() => void runExplain()} - onCheckUpdates={() => void checkForUpdates()} + onCheckUpdates={() => void updater.checkForUpdates()} /> diff --git a/src/components/command-palette/tools.tsx b/src/components/command-palette/tools.tsx index 4d2f0ad..6b6ebf0 100644 --- a/src/components/command-palette/tools.tsx +++ b/src/components/command-palette/tools.tsx @@ -152,17 +152,19 @@ export function ActionsGroup({ )} {theme === "light" ? "Dark Mode" : "Light Mode"} - { - onClose(); - onCheckUpdates(); - }} - > - - Check for Updates - App - + {__RSQL_BUILD_TARGET__ !== "web" && ( + { + onClose(); + onCheckUpdates(); + }} + > + + Check for Updates + App + + )} {pinnedResult ? ( s.projects); const pickFile = useCallback(async () => { - const selected = await open({ - multiple: false, + const selected = await dialog.openFile({ filters: [{ name: "CSV", extensions: ["csv", "tsv", "txt"] }], }); if (!selected) return; - const path = typeof selected === "string" ? selected : selected; + if (selected.kind === "file") { + setResult({ + success: false, + message: "CSV import in the web build is coming soon. Use the desktop app to import files.", + }); + return; + } + + const path = selected.path; setFilePath(path); setResult(null); diff --git a/src/components/top-bar.tsx b/src/components/top-bar.tsx index cee9e18..7bede25 100644 --- a/src/components/top-bar.tsx +++ b/src/components/top-bar.tsx @@ -84,10 +84,12 @@ export function TopBar({
- + {__RSQL_BUILD_TARGET__ !== "web" && ( + + )}