mirror of
https://github.com/haexhub/haex-hub.git
synced 2025-12-16 14:10:52 +01:00
zwischenstand
This commit is contained in:
@ -56,6 +56,7 @@
|
||||
"@vue/compiler-sfc": "^3.5.17",
|
||||
"drizzle-kit": "^0.31.2",
|
||||
"globals": "^16.2.0",
|
||||
"prettier": "3.6.2",
|
||||
"typescript": "^5.8.3"
|
||||
},
|
||||
"packageManager": "pnpm@10.12.2",
|
||||
|
||||
10
pnpm-lock.yaml
generated
10
pnpm-lock.yaml
generated
@ -123,6 +123,9 @@ importers:
|
||||
globals:
|
||||
specifier: ^16.2.0
|
||||
version: 16.2.0
|
||||
prettier:
|
||||
specifier: 3.6.2
|
||||
version: 3.6.2
|
||||
typescript:
|
||||
specifier: ^5.8.3
|
||||
version: 5.8.3
|
||||
@ -4374,6 +4377,11 @@ packages:
|
||||
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
|
||||
prettier@3.6.2:
|
||||
resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==}
|
||||
engines: {node: '>=14'}
|
||||
hasBin: true
|
||||
|
||||
pretty-bytes@6.1.1:
|
||||
resolution: {integrity: sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==}
|
||||
engines: {node: ^14.13.1 || >=16.0.0}
|
||||
@ -10003,6 +10011,8 @@ snapshots:
|
||||
|
||||
prelude-ls@1.2.1: {}
|
||||
|
||||
prettier@3.6.2: {}
|
||||
|
||||
pretty-bytes@6.1.1: {}
|
||||
|
||||
process-nextick-args@2.0.1: {}
|
||||
|
||||
262
src-tauri/Cargo.lock
generated
262
src-tauri/Cargo.lock
generated
@ -285,6 +285,15 @@ version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
@ -342,9 +351,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brotli"
|
||||
version = "7.0.0"
|
||||
version = "8.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd"
|
||||
checksum = "9991eea70ea4f293524138648e41ee89b0b2b12ddef3b255effa43c8056e0e0d"
|
||||
dependencies = [
|
||||
"alloc-no-stdlib",
|
||||
"alloc-stdlib",
|
||||
@ -353,9 +362,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brotli-decompressor"
|
||||
version = "4.0.2"
|
||||
version = "5.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74fa05ad7d803d413eb8380983b092cbbaf9a85f151b871360e7b00cd7060b37"
|
||||
checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03"
|
||||
dependencies = [
|
||||
"alloc-no-stdlib",
|
||||
"alloc-stdlib",
|
||||
@ -665,15 +674,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cssparser"
|
||||
version = "0.27.2"
|
||||
version = "0.29.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a"
|
||||
checksum = "f93d03419cb5950ccfd3daf3ff1c7a36ace64609a1a8746d493df1ca0afde0fa"
|
||||
dependencies = [
|
||||
"cssparser-macros",
|
||||
"dtoa-short",
|
||||
"itoa 0.4.8",
|
||||
"itoa",
|
||||
"matches",
|
||||
"phf 0.8.0",
|
||||
"phf 0.10.1",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"smallvec",
|
||||
@ -1545,12 +1554,14 @@ dependencies = [
|
||||
"sqlparser",
|
||||
"tauri",
|
||||
"tauri-build",
|
||||
"tauri-plugin-android-fs",
|
||||
"tauri-plugin-dialog",
|
||||
"tauri-plugin-fs",
|
||||
"tauri-plugin-http",
|
||||
"tauri-plugin-notification",
|
||||
"tauri-plugin-opener",
|
||||
"tauri-plugin-os",
|
||||
"tauri-plugin-persisted-scope",
|
||||
"tauri-plugin-store",
|
||||
"tokio",
|
||||
"uhlc",
|
||||
@ -1606,16 +1617,14 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||
|
||||
[[package]]
|
||||
name = "html5ever"
|
||||
version = "0.26.0"
|
||||
version = "0.29.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7"
|
||||
checksum = "3b7410cae13cbc75623c98ac4cbfd1f0bedddf3227afc24f370cf0f50a44a11c"
|
||||
dependencies = [
|
||||
"log",
|
||||
"mac",
|
||||
"markup5ever",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
"match_token",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1626,7 +1635,7 @@ checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"itoa 1.0.15",
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1683,7 +1692,7 @@ dependencies = [
|
||||
"http",
|
||||
"http-body",
|
||||
"httparse",
|
||||
"itoa 1.0.15",
|
||||
"itoa",
|
||||
"pin-project-lite",
|
||||
"smallvec",
|
||||
"tokio",
|
||||
@ -1936,6 +1945,17 @@ dependencies = [
|
||||
"cfb",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "io-uring"
|
||||
version = "0.7.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b86e202f00093dcba4275d4636b93ef9dd75d025ae560d2521b45ea28ab49013"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ipnet"
|
||||
version = "2.11.0"
|
||||
@ -1961,12 +1981,6 @@ dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.15"
|
||||
@ -2063,14 +2077,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kuchikiki"
|
||||
version = "0.8.2"
|
||||
version = "0.8.8-speedreader"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f29e4755b7b995046f510a7520c42b2fed58b77bd94d5a87a8eb43d2fd126da8"
|
||||
checksum = "02cb977175687f33fa4afa0c95c112b987ea1443e5a51c8f8ff27dc618270cc2"
|
||||
dependencies = [
|
||||
"cssparser",
|
||||
"html5ever",
|
||||
"indexmap 1.9.3",
|
||||
"matches",
|
||||
"indexmap 2.8.0",
|
||||
"selectors",
|
||||
]
|
||||
|
||||
@ -2132,9 +2145,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libsqlite3-sys"
|
||||
version = "0.34.0"
|
||||
version = "0.35.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91632f3b4fb6bd1d72aa3d78f41ffecfcf2b1a6648d8c241dbe7dbfaf4875e15"
|
||||
checksum = "133c182a6a2c87864fe97778797e46c7e999672690dc9fa3ee8e241aa4a9c13f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"openssl-sys",
|
||||
@ -2202,18 +2215,29 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "markup5ever"
|
||||
version = "0.11.0"
|
||||
version = "0.14.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016"
|
||||
checksum = "c7a7213d12e1864c0f002f52c2923d4556935a43dec5e71355c2760e0f6e7a18"
|
||||
dependencies = [
|
||||
"log",
|
||||
"phf 0.10.1",
|
||||
"phf_codegen 0.10.0",
|
||||
"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.100",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matches"
|
||||
version = "0.1.10"
|
||||
@ -2274,9 +2298,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "muda"
|
||||
version = "0.16.1"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4de14a9b5d569ca68d7c891d613b390cf5ab4f851c77aaa2f9e435555d3d9492"
|
||||
checksum = "58b89bf91c19bf036347f1ab85a81c560f08c0667c8601bece664d860a600988"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"dpi",
|
||||
@ -2758,9 +2782,7 @@ version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12"
|
||||
dependencies = [
|
||||
"phf_macros 0.8.0",
|
||||
"phf_shared 0.8.0",
|
||||
"proc-macro-hack",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2769,7 +2791,9 @@ 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]]
|
||||
@ -2794,12 +2818,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "phf_codegen"
|
||||
version = "0.10.0"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd"
|
||||
checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a"
|
||||
dependencies = [
|
||||
"phf_generator 0.10.0",
|
||||
"phf_shared 0.10.0",
|
||||
"phf_generator 0.11.3",
|
||||
"phf_shared 0.11.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2834,12 +2858,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "phf_macros"
|
||||
version = "0.8.0"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c"
|
||||
checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0"
|
||||
dependencies = [
|
||||
"phf_generator 0.8.0",
|
||||
"phf_shared 0.8.0",
|
||||
"phf_generator 0.10.0",
|
||||
"phf_shared 0.10.0",
|
||||
"proc-macro-hack",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -3433,9 +3457,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rusqlite"
|
||||
version = "0.36.0"
|
||||
version = "0.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3de23c3319433716cf134eed225fe9986bc24f63bed9be9f20c329029e672dc7"
|
||||
checksum = "165ca6e57b20e1351573e3729b958bc62f0e48025386970b6e4d29e7a7e71f3f"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"fallible-iterator",
|
||||
@ -3591,22 +3615,20 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "selectors"
|
||||
version = "0.22.0"
|
||||
version = "0.24.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df320f1889ac4ba6bc0cdc9c9af7af4bd64bb927bccdf32d81140dc1f9be12fe"
|
||||
checksum = "0c37578180969d00692904465fb7f6b3d50b9a2b952b87c23d0e2e5cb5013416"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"cssparser",
|
||||
"derive_more",
|
||||
"fxhash",
|
||||
"log",
|
||||
"matches",
|
||||
"phf 0.8.0",
|
||||
"phf_codegen 0.8.0",
|
||||
"precomputed-hash",
|
||||
"servo_arc",
|
||||
"smallvec",
|
||||
"thin-slice",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3666,7 +3688,7 @@ version = "1.0.140"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
|
||||
dependencies = [
|
||||
"itoa 1.0.15",
|
||||
"itoa",
|
||||
"memchr",
|
||||
"ryu",
|
||||
"serde",
|
||||
@ -3699,7 +3721,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"itoa 1.0.15",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
@ -3758,9 +3780,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "servo_arc"
|
||||
version = "0.1.1"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d98238b800e0d1576d8b6e3de32827c2d74bee68bb97748dcf5071fb53965432"
|
||||
checksum = "d52aa42f8fdf0fed91e5ce7f23d8138441002fa31dca008acf47e6fd4721f741"
|
||||
dependencies = [
|
||||
"nodrop",
|
||||
"stable_deref_trait",
|
||||
@ -4071,9 +4093,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tao"
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e59c1f38e657351a2e822eadf40d6a2ad4627b9c25557bc1180ec1b3295ef82"
|
||||
checksum = "49c380ca75a231b87b6c9dd86948f035012e7171d1a7c40a9c2890489a7ffd8a"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"core-foundation 0.10.0",
|
||||
@ -4127,17 +4149,16 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
|
||||
|
||||
[[package]]
|
||||
name = "tauri"
|
||||
version = "2.5.1"
|
||||
version = "2.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7b0bc1aec81bda6bc455ea98fcaed26b3c98c1648c627ad6ff1c704e8bf8cbc"
|
||||
checksum = "124e129c9c0faa6bec792c5948c89e86c90094133b0b9044df0ce5f0a8efaa0d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
"dirs",
|
||||
"dunce",
|
||||
"embed_plist",
|
||||
"futures-util",
|
||||
"getrandom 0.2.15",
|
||||
"getrandom 0.3.2",
|
||||
"glob",
|
||||
"gtk",
|
||||
"heck 0.5.0",
|
||||
@ -4179,9 +4200,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-build"
|
||||
version = "2.2.0"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7a0350f0df1db385ca5c02888a83e0e66655c245b7443db8b78a70da7d7f8fc"
|
||||
checksum = "12f025c389d3adb83114bec704da973142e82fc6ec799c7c750c5e21cefaec83"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cargo_toml",
|
||||
@ -4201,9 +4222,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-codegen"
|
||||
version = "2.2.0"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f93f035551bf7b11b3f51ad9bc231ebbe5e085565527991c16cf326aa38cdf47"
|
||||
checksum = "f5df493a1075a241065bc865ed5ef8d0fbc1e76c7afdc0bf0eccfaa7d4f0e406"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"brotli",
|
||||
@ -4228,9 +4249,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-macros"
|
||||
version = "2.2.0"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8db4df25e2d9d45de0c4c910da61cd5500190da14ae4830749fee3466dddd112"
|
||||
checksum = "f237fbea5866fa5f2a60a21bea807a2d6e0379db070d89c3a10ac0f2d4649bbc"
|
||||
dependencies = [
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
@ -4242,9 +4263,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin"
|
||||
version = "2.1.0"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9972871fcbddf16618f70412d965d4d845cd4b76d03fff168709961ef71e5cdf"
|
||||
checksum = "1d9a0bd00bf1930ad1a604d08b0eb6b2a9c1822686d65d7f4731a7723b8901d3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"glob",
|
||||
@ -4258,10 +4279,25 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-dialog"
|
||||
version = "2.2.0"
|
||||
name = "tauri-plugin-android-fs"
|
||||
version = "9.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b59fd750551b1066744ab956a1cd6b1ea3e1b3763b0b9153ac27a044d596426"
|
||||
checksum = "70913be3272e29ada966e8158ffb4f1b3985041635bf4563baade6178309231a"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tauri",
|
||||
"tauri-plugin",
|
||||
"tauri-plugin-fs",
|
||||
"thiserror 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-dialog"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1aefb14219b492afb30b12647b5b1247cadd2c0603467310c36e0f7ae1698c28"
|
||||
dependencies = [
|
||||
"log",
|
||||
"raw-window-handle",
|
||||
@ -4277,9 +4313,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-fs"
|
||||
version = "2.3.0"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33ead0daec5d305adcefe05af9d970fc437bcc7996052d564e7393eb291252da"
|
||||
checksum = "c341290d31991dbca38b31d412c73dfbdb070bb11536784f19dd2211d13b778f"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"dunce",
|
||||
@ -4299,10 +4335,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-http"
|
||||
version = "2.4.2"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "696ef548befeee6c6c17b80ef73e7c41205b6c2204e87ef78ccc231212389a5c"
|
||||
checksum = "b0c1a38da944b357ffa23bafd563b1579f18e6fbd118fcd84769406d35dcc5c7"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"cookie_store",
|
||||
"data-url",
|
||||
"http",
|
||||
"regex",
|
||||
@ -4321,9 +4359,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-notification"
|
||||
version = "2.2.2"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c474c7cc524385e682ccc1e149e13913a66fd8586ac4c2319cf01b78f070d309"
|
||||
checksum = "cfe06ed89cff6d0ec06ff4f544fb961e4718348a33309f56ccb2086e77bc9116"
|
||||
dependencies = [
|
||||
"log",
|
||||
"notify-rust",
|
||||
@ -4340,9 +4378,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-opener"
|
||||
version = "2.3.0"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c8983f50326d34437142a6d560b5c3426e91324297519b6eeb32ed0a1d1e0f2"
|
||||
checksum = "ecee219f11cdac713ab32959db5d0cceec4810ba4f4458da992292ecf9660321"
|
||||
dependencies = [
|
||||
"dunce",
|
||||
"glob",
|
||||
@ -4362,9 +4400,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-os"
|
||||
version = "2.2.1"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "424f19432397850c2ddd42aa58078630c15287bbce3866eb1d90e7dbee680637"
|
||||
checksum = "05bccb4c6de4299beec5a9b070878a01bce9e2c945aa7a75bcea38bcba4c675d"
|
||||
dependencies = [
|
||||
"gethostname",
|
||||
"log",
|
||||
@ -4379,10 +4417,26 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-store"
|
||||
version = "2.2.0"
|
||||
name = "tauri-plugin-persisted-scope"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c0c08fae6995909f5e9a0da6038273b750221319f2c0f3b526d6de1cde21505"
|
||||
checksum = "7380eff2525adcf7f6b1cf3de191ccd3fdbe2a42281e4659604a26749c77bfbd"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"bincode",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tauri",
|
||||
"tauri-plugin-fs",
|
||||
"thiserror 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-store"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5916c609664a56c82aeaefffca9851fd072d4d41f73d63f22ee3ee451508194f"
|
||||
dependencies = [
|
||||
"dunce",
|
||||
"serde",
|
||||
@ -4396,9 +4450,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-runtime"
|
||||
version = "2.6.0"
|
||||
version = "2.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00f004905d549854069e6774533d742b03cacfd6f03deb08940a8677586cbe39"
|
||||
checksum = "9e7bb73d1bceac06c20b3f755b2c8a2cb13b20b50083084a8cf3700daf397ba4"
|
||||
dependencies = [
|
||||
"cookie",
|
||||
"dpi",
|
||||
@ -4418,9 +4472,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-runtime-wry"
|
||||
version = "2.6.0"
|
||||
version = "2.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f85d056f4d4b014fe874814034f3416d57114b617a493a4fe552580851a3f3a2"
|
||||
checksum = "902b5aa9035e16f342eb64f8bf06ccdc2808e411a2525ed1d07672fa4e780bad"
|
||||
dependencies = [
|
||||
"gtk",
|
||||
"http",
|
||||
@ -4445,9 +4499,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-utils"
|
||||
version = "2.4.0"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2900399c239a471bcff7f15c4399eb1a8c4fe511ba2853e07c996d771a5e0a4"
|
||||
checksum = "41743bbbeb96c3a100d234e5a0b60a46d5aa068f266160862c7afdbf828ca02e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"brotli",
|
||||
@ -4527,12 +4581,6 @@ dependencies = [
|
||||
"utf-8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thin-slice"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c"
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.69"
|
||||
@ -4580,7 +4628,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d9c75b47bdff86fa3334a3db91356b8d7d86a9b839dab7d0bdc5c3d3a077618"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"itoa 1.0.15",
|
||||
"itoa",
|
||||
"num-conv",
|
||||
"powerfmt",
|
||||
"serde",
|
||||
@ -4631,16 +4679,18 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.45.0"
|
||||
version = "1.46.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165"
|
||||
checksum = "0cc3a2344dafbe23a245241fe8b09735b521110d30fcefbbd5feb1797ca35d17"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
"io-uring",
|
||||
"libc",
|
||||
"mio",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"slab",
|
||||
"socket2",
|
||||
"tokio-macros",
|
||||
"tracing",
|
||||
@ -4797,9 +4847,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tray-icon"
|
||||
version = "0.20.0"
|
||||
version = "0.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d433764348e7084bad2c5ea22c96c71b61b17afe3a11645710f533bd72b6a2b5"
|
||||
checksum = "2da75ec677957aa21f6e0b361df0daab972f13a5bee3606de0638fd4ee1c666a"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"dirs",
|
||||
@ -5214,9 +5264,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "webview2-com"
|
||||
version = "0.37.0"
|
||||
version = "0.38.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b542b5cfbd9618c46c2784e4d41ba218c336ac70d44c55e47b251033e7d85601"
|
||||
checksum = "d4ba622a989277ef3886dd5afb3e280e3dd6d974b766118950a08f8f678ad6a4"
|
||||
dependencies = [
|
||||
"webview2-com-macros",
|
||||
"webview2-com-sys",
|
||||
@ -5239,9 +5289,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "webview2-com-sys"
|
||||
version = "0.37.0"
|
||||
version = "0.38.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ae2d11c4a686e4409659d7891791254cf9286d3cfe0eef54df1523533d22295"
|
||||
checksum = "36695906a1b53a3bf5c4289621efedac12b73eeb0b89e7e1a89b517302d5d75c"
|
||||
dependencies = [
|
||||
"thiserror 2.0.12",
|
||||
"windows",
|
||||
@ -5762,9 +5812,9 @@ checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
|
||||
|
||||
[[package]]
|
||||
name = "wry"
|
||||
version = "0.51.2"
|
||||
version = "0.52.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c886a0a9d2a94fd90cfa1d929629b79cfefb1546e2c7430c63a47f0664c0e4e2"
|
||||
checksum = "12a714d9ba7075aae04a6e50229d6109e3d584774b99a6a8c60de1698ca111b9"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"block2 0.6.0",
|
||||
|
||||
@ -18,14 +18,14 @@ crate-type = ["staticlib", "cdylib", "rlib"]
|
||||
tauri-build = { version = "2.2", features = [] }
|
||||
|
||||
[dependencies]
|
||||
rusqlite = { version = "0.36.0", features = [
|
||||
rusqlite = { version = "0.37.0", features = [
|
||||
"load_extension",
|
||||
"bundled-sqlcipher-vendored-openssl",
|
||||
"functions",
|
||||
] }
|
||||
#libsqlite3-sys = { version = "0.31", features = ["bundled-sqlcipher"] }
|
||||
#sqlx = { version = "0.8", features = ["runtime-tokio-rustls", "sqlite"] }
|
||||
tokio = { version = "1.45", features = ["macros", "rt-multi-thread"] }
|
||||
tokio = { version = "1.46", features = ["macros", "rt-multi-thread"] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
hex = "0.4"
|
||||
serde_json = "1"
|
||||
@ -35,12 +35,16 @@ mime = "0.3"
|
||||
fs_extra = "1.3.0"
|
||||
sqlparser = { version = "0.57.0", features = ["visitor"] }
|
||||
uhlc = "0.8"
|
||||
tauri = { version = "2.5", features = ["protocol-asset", "devtools"] }
|
||||
tauri-plugin-dialog = "2.2"
|
||||
tauri-plugin-fs = "2.3.0"
|
||||
tauri-plugin-opener = "2.3.0"
|
||||
tauri-plugin-os = "2"
|
||||
tauri-plugin-store = "2"
|
||||
tauri-plugin-http = "2.4"
|
||||
tauri-plugin-notification = "2"
|
||||
tauri = { version = "2.6.2", features = ["protocol-asset", "devtools"] }
|
||||
tauri-plugin-dialog = "2.3"
|
||||
tauri-plugin-fs = "2.4.0"
|
||||
tauri-plugin-opener = "2.4.0"
|
||||
tauri-plugin-os = "2.3"
|
||||
tauri-plugin-store = "2.3"
|
||||
tauri-plugin-http = "2.5"
|
||||
tauri-plugin-notification = "2.3"
|
||||
tauri-plugin-persisted-scope = "2.0.0"
|
||||
tauri-plugin-android-fs = "9.5.0"
|
||||
#tauri-plugin-sql = { version = "2", features = ["sqlite"] }
|
||||
|
||||
|
||||
|
||||
@ -19,8 +19,17 @@
|
||||
"fs:allow-appdata-read-recursive",
|
||||
"fs:allow-appdata-write-recursive",
|
||||
"fs:allow-read-file",
|
||||
"fs:allow-read-dir",
|
||||
"fs:allow-resource-read-recursive",
|
||||
"fs:allow-resource-write-recursive",
|
||||
"fs:allow-download-read-recursive",
|
||||
"fs:allow-download-write-recursive",
|
||||
"fs:default",
|
||||
"android-fs:default",
|
||||
{
|
||||
"identifier": "fs:scope",
|
||||
"allow": [{ "path": "**" }]
|
||||
},
|
||||
"http:allow-fetch-send",
|
||||
"http:allow-fetch",
|
||||
"http:default",
|
||||
|
||||
@ -19,7 +19,7 @@ android {
|
||||
defaultConfig {
|
||||
manifestPlaceholders["usesCleartextTraffic"] = "false"
|
||||
applicationId = "space.haex.hub"
|
||||
minSdk = 24
|
||||
minSdk = 30
|
||||
targetSdk = 34
|
||||
versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt()
|
||||
versionName = tauriProperties.getProperty("tauri.android.versionName", "1.0")
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
|
||||
<!-- AndroidTV support -->
|
||||
<uses-feature android:name="android.software.leanback" android:required="false" />
|
||||
|
||||
@ -9,7 +11,8 @@
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.haex_hub"
|
||||
android:usesCleartextTraffic="${usesCleartextTraffic}">
|
||||
android:usesCleartextTraffic="${usesCleartextTraffic}"
|
||||
android:requestLegacyExternalStorage="true">
|
||||
<activity
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode"
|
||||
android:launchMode="singleTask"
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@ -1,3 +1,20 @@
|
||||
package space.haex.hub
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.provider.Settings
|
||||
|
||||
class MainActivity : TauriActivity()
|
||||
class MainActivity : TauriActivity(){
|
||||
|
||||
/* override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
startActivity(
|
||||
Intent(
|
||||
Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION,
|
||||
Uri.parse("package:${BuildConfig.APPLICATION_ID}")
|
||||
)
|
||||
)
|
||||
} */
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
package space.haex.hub
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.provider.Settings
|
||||
|
||||
class SettingsOpener {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun openManageAllFilesAccessSettings(context: Context) {
|
||||
val intent = Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION)
|
||||
intent.data = Uri.parse("package:" + context.packageName)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
94
src-tauri/src/android_storage/mod.rs
Normal file
94
src-tauri/src/android_storage/mod.rs
Normal file
@ -0,0 +1,94 @@
|
||||
#[cfg(target_os = "android")]
|
||||
#[tauri::command]
|
||||
pub async fn request_storage_permission(app_handle: tauri::AppHandle) -> Result<String, String> {
|
||||
Ok("Settings opened - Enable 'Allow management of all files'".to_string())
|
||||
/* use tauri_plugin_opener::OpenerExt;
|
||||
|
||||
// Korrekte Android Settings Intent
|
||||
let intent_uri = "android.settings.MANAGE_ALL_FILES_ACCESS_PERMISSION";
|
||||
|
||||
match app.opener().open_url(intent_uri, None::<&str>) {
|
||||
Ok(_) => Ok("Settings opened - Enable 'Allow management of all files'".to_string()),
|
||||
Err(_) => {
|
||||
// Fallback: App-spezifische Settings
|
||||
let app_settings = format!(
|
||||
"android.settings.APPLICATION_DETAILS_SETTINGS?package={}",
|
||||
app.config().identifier
|
||||
);
|
||||
match app.opener().open_url(&app_settings, None::<&str>) {
|
||||
Ok(_) => Ok("App settings opened - Go to Permissions > Files and media".to_string()),
|
||||
Err(_) => Ok("Manually go to: Settings > Apps > Special app access > All files access > HaexHub > Allow".to_string())
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
#[tauri::command]
|
||||
pub async fn has_storage_permission() -> Result<bool, String> {
|
||||
use std::path::Path;
|
||||
|
||||
// Teste Schreibzugriff auf externen Speicher
|
||||
let test_paths = [
|
||||
"/storage/emulated/0/Android",
|
||||
"/sdcard/Android",
|
||||
"/storage/emulated/0",
|
||||
];
|
||||
|
||||
for path in &test_paths {
|
||||
if Path::new(path).exists() {
|
||||
// Versuche Testdatei zu erstellen
|
||||
let test_file = format!("{}/haex_test.tmp", path);
|
||||
match std::fs::write(&test_file, "test") {
|
||||
Ok(_) => {
|
||||
let _ = std::fs::remove_file(&test_file);
|
||||
return Ok(true);
|
||||
}
|
||||
Err(_) => continue,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
#[tauri::command]
|
||||
pub async fn get_external_storage_paths() -> Result<Vec<String>, String> {
|
||||
let mut paths = Vec::new();
|
||||
|
||||
let common_paths = [
|
||||
"/storage/emulated/0",
|
||||
"/sdcard",
|
||||
"/storage/emulated/0/Download",
|
||||
"/storage/emulated/0/Documents",
|
||||
"/storage/emulated/0/Pictures",
|
||||
"/storage/emulated/0/DCIM",
|
||||
];
|
||||
|
||||
for path in &common_paths {
|
||||
if std::path::Path::new(path).exists() {
|
||||
paths.push(path.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(paths)
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "android"))]
|
||||
#[tauri::command]
|
||||
pub async fn request_storage_permission(_app: tauri::AppHandle) -> Result<String, String> {
|
||||
Ok("aaaaaaaa".to_string())
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "android"))]
|
||||
#[tauri::command]
|
||||
pub async fn has_storage_permission() -> Result<bool, String> {
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "android"))]
|
||||
#[tauri::command]
|
||||
pub async fn get_external_storage_paths() -> Result<Vec<String>, String> {
|
||||
Ok(vec![])
|
||||
}
|
||||
22
src-tauri/src/crdt/log.rs
Normal file
22
src-tauri/src/crdt/log.rs
Normal file
@ -0,0 +1,22 @@
|
||||
// src/entities/crdt_log.rs
|
||||
use sea_orm::entity::prelude::*;
|
||||
|
||||
#[sea_orm(table_name = "crdt_log")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, auto_increment = true)]
|
||||
pub id: i64,
|
||||
pub hlc_timestamp: String,
|
||||
pub op_type: String,
|
||||
pub table_name: String,
|
||||
pub row_pk: String, // Wird als JSON-String gespeichert
|
||||
#[sea_orm(nullable)]
|
||||
pub column_name: Option<String>,
|
||||
#[sea_orm(nullable)]
|
||||
pub value: Option<String>,
|
||||
#[sea_orm(nullable)]
|
||||
pub old_value: Option<String>,
|
||||
}
|
||||
|
||||
pub enum Relation {}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
165
src-tauri/src/crdt/proxy.rs
Normal file
165
src-tauri/src/crdt/proxy.rs
Normal file
@ -0,0 +1,165 @@
|
||||
// In src-tauri/src/sql_proxy.rs
|
||||
|
||||
use rusqlite::Connection;
|
||||
use sqlparser::ast::Statement;
|
||||
use sqlparser::ast::{ColumnDef, DataType, Expr, Ident, Query, Statement, TableWithJoins, Value};
|
||||
use sqlparser::dialect::SQLiteDialect;
|
||||
use sqlparser::parser::Parser;
|
||||
use sqlparser::visit_mut::{self, VisitorMut};
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
// Der Name der Tombstone-Spalte als Konstante, um "Magic Strings" zu vermeiden.
|
||||
pub const TOMBSTONE_COLUMN_NAME: &str = "tombstone";
|
||||
const EXCLUDED_TABLES: &[&str] = &["crdt_log"];
|
||||
|
||||
// Die Hauptstruktur unseres Proxys.
|
||||
// Sie ist zustandslos, da wir uns gegen einen Schema-Cache entschieden haben.
|
||||
pub struct SqlProxy;
|
||||
|
||||
impl SqlProxy {
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
|
||||
// Die zentrale Ausführungsfunktion
|
||||
pub fn execute(&self, sql: &str, conn: &Connection) -> Result<(), String> {
|
||||
// 1. Parsen des SQL-Strings in einen oder mehrere ASTs.
|
||||
// Ein String kann mehrere, durch Semikolon getrennte Anweisungen enthalten.
|
||||
let dialect = SQLiteDialect {};
|
||||
let mut ast_vec =
|
||||
Parser::parse_sql(&dialect, sql).map_err(|e| format!("SQL-Parse-Fehler: {}", e))?;
|
||||
|
||||
// 2. Wir durchlaufen und transformieren jedes einzelne Statement im AST-Vektor.
|
||||
for statement in &mut ast_vec {
|
||||
self.transform_statement(statement)?;
|
||||
}
|
||||
|
||||
// 3. Ausführen der (möglicherweise modifizierten) Anweisungen in einer einzigen Transaktion.
|
||||
// Dies stellt sicher, dass alle Operationen atomar sind.
|
||||
let tx = conn.transaction().map_err(|e| e.to_string())?;
|
||||
for statement in ast_vec {
|
||||
let final_sql = statement.to_string();
|
||||
tx.execute(&final_sql)
|
||||
.map_err(|e| format!("DB-Ausführungsfehler bei '{}': {}", final_sql, e))?;
|
||||
|
||||
// Wenn es ein CREATE/ALTER TABLE war, müssen die Trigger neu erstellt werden.
|
||||
// Dies geschieht innerhalb derselben Transaktion.
|
||||
if let Statement::CreateTable { name, .. } | Statement::AlterTable { name, .. } =
|
||||
statement
|
||||
{
|
||||
let table_name = name.0.last().unwrap().value.clone();
|
||||
let trigger_manager = crate::trigger_manager::TriggerManager::new(&tx);
|
||||
trigger_manager
|
||||
.setup_triggers_for_table(&table_name)
|
||||
.map_err(|e| {
|
||||
format!("Trigger-Setup-Fehler für Tabelle '{}': {}", table_name, e)
|
||||
})?;
|
||||
}
|
||||
}
|
||||
tx.commit().map_err(|e| e.to_string())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Diese Methode wendet die Transformation auf ein einzelnes Statement an.
|
||||
fn transform_statement(&self, statement: &mut Statement) -> Result<(), String> {
|
||||
let mut visitor = TombstoneVisitor;
|
||||
// `visit` durchläuft den AST und ruft die entsprechenden `visit_*_mut` Methoden auf.
|
||||
statement.visit(&mut visitor);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct TombstoneVisitor;
|
||||
|
||||
impl TombstoneVisitor {
|
||||
fn is_audited_table(&self, table_name: &str) -> bool {
|
||||
!EXCLUDED_TABLES.contains(&table_name.to_lowercase().as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl VisitorMut for TombstoneVisitor {
|
||||
type Break = ();
|
||||
|
||||
// Diese Methode wird für jedes Statement im AST aufgerufen
|
||||
fn visit_statement_mut(&mut self, stmt: &mut Statement) -> ControlFlow<Self::Break> {
|
||||
match stmt {
|
||||
// Fall 1: CREATE TABLE
|
||||
Statement::CreateTable { name, columns, .. } => {
|
||||
let table_name = name.0.last().unwrap().value.as_str();
|
||||
if self.is_audited_table(table_name) {
|
||||
// Füge die 'tombstone'-Spalte hinzu, wenn sie nicht existiert
|
||||
if !columns
|
||||
.iter()
|
||||
.any(|c| c.name.value.to_lowercase() == TOMBSTONE_COLUMN_NAME)
|
||||
{
|
||||
columns.push(ColumnDef {
|
||||
name: Ident::new(TOMBSTONE_COLUMN_NAME),
|
||||
data_type: DataType::Integer,
|
||||
collation: None,
|
||||
options: vec![], // Default ist 0
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fall 2: DELETE
|
||||
Statement::Delete(del_stmt) => {
|
||||
// Wandle das DELETE-Statement in ein UPDATE-Statement um
|
||||
let new_update = Statement::Update {
|
||||
table: del_stmt.from.clone(),
|
||||
assignments: vec![],
|
||||
value: Box::new(Expr::Value(Value::Number("1".to_string(), false))),
|
||||
from: None,
|
||||
selection: del_stmt.selection.clone(),
|
||||
returning: None,
|
||||
};
|
||||
// Ersetze das aktuelle Statement im AST
|
||||
*stmt = new_update;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Setze die Traversierung für untergeordnete Knoten fort (z.B. SELECTs)
|
||||
visit_mut::walk_statement_mut(self, stmt)
|
||||
}
|
||||
|
||||
// Diese Methode wird für jede Query (auch Subqueries) aufgerufen
|
||||
fn visit_query_mut(&mut self, query: &mut Query) -> ControlFlow<Self::Break> {
|
||||
// Zuerst rekursiv in die Tiefe gehen, um innere Queries zuerst zu bearbeiten
|
||||
visit_mut::walk_query_mut(self, query);
|
||||
|
||||
// Dann die WHERE-Klausel der aktuellen Query anpassen
|
||||
if let Some(from_clause) = query.body.as_select_mut().map(|s| &mut s.from) {
|
||||
// (Hier würde eine komplexere Logik zur Analyse der Joins und Tabellen stehen)
|
||||
// Vereinfacht nehmen wir an, wir fügen es für die erste Tabelle hinzu.
|
||||
let table_name = if let Some(relation) = from_clause.get_mut(0) {
|
||||
// Diese Logik muss verfeinert werden, um Aliase etc. zu behandeln
|
||||
relation.relation.to_string()
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
|
||||
if self.is_audited_table(&table_name) {
|
||||
let tombstone_check = Expr::BinaryOp {
|
||||
left: Box::new(Expr::Identifier(Ident::new(TOMBSTONE_COLUMN_NAME))),
|
||||
op: sqlparser::ast::BinaryOperator::Eq,
|
||||
right: Box::new(Expr::Value(Value::Number("0".to_string(), false))),
|
||||
};
|
||||
|
||||
let existing_selection = query.selection.take();
|
||||
let new_selection = match existing_selection {
|
||||
Some(expr) => Expr::BinaryOp {
|
||||
left: Box::new(expr),
|
||||
op: sqlparser::ast::BinaryOperator::And,
|
||||
right: Box::new(tombstone_check),
|
||||
},
|
||||
None => tombstone_check,
|
||||
};
|
||||
query.selection = Some(Box::new(new_selection));
|
||||
}
|
||||
}
|
||||
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
124
src-tauri/src/crdt/trigger.rs
Normal file
124
src-tauri/src/crdt/trigger.rs
Normal file
@ -0,0 +1,124 @@
|
||||
// In src-tauri/src/trigger_manager.rs -> impl<'a> TriggerManager<'a>
|
||||
|
||||
// In einem neuen Modul, z.B. src-tauri/src/trigger_manager.rs
|
||||
use crate::sql_proxy::ColumnInfo;
|
||||
use rusqlite::{Result, Transaction};
|
||||
|
||||
pub struct TriggerManager<'a> {
|
||||
tx: &'a Transaction<'a>,
|
||||
}
|
||||
|
||||
impl<'a> TriggerManager<'a> {
|
||||
pub fn new(tx: &'a Transaction<'a>) -> Self {
|
||||
Self { tx }
|
||||
}
|
||||
|
||||
// Die Hauptfunktion, die alles einrichtet
|
||||
pub fn setup_triggers_for_table(&self, table_name: &str) -> Result<()> {
|
||||
let columns = self.get_table_schema(table_name)?;
|
||||
let pk_cols: Vec<_> = columns
|
||||
.iter()
|
||||
.filter(|c| c.is_pk)
|
||||
.map(|c| c.name.as_str())
|
||||
.collect();
|
||||
let other_cols: Vec<_> = columns
|
||||
.iter()
|
||||
.filter(|c| !c.is_pk && c.name != "tombstone")
|
||||
.map(|c| c.name.as_str())
|
||||
.collect();
|
||||
|
||||
let drop_sql = self.generate_drop_triggers_sql(table_name);
|
||||
let insert_sql = self.generate_insert_trigger_sql(table_name, &pk_cols, &other_cols);
|
||||
let update_sql = self.generate_update_trigger_sql(table_name, &pk_cols, &other_cols);
|
||||
|
||||
self.tx.execute_batch(&drop_sql)?;
|
||||
self.tx.execute_batch(&insert_sql)?;
|
||||
self.tx.execute_batch(&update_sql)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_table_schema(&self, table_name: &str) -> Result<Vec<ColumnInfo>> {
|
||||
let sql = format!("PRAGMA table_info('{}')", table_name);
|
||||
let mut stmt = self.tx.prepare(&sql)?;
|
||||
let rows = stmt.query_map(|row| {
|
||||
let pk_val: i64 = row.get(5)?;
|
||||
Ok(ColumnInfo {
|
||||
name: row.get(1)?,
|
||||
is_pk: pk_val > 0,
|
||||
})
|
||||
})?;
|
||||
|
||||
let mut columns = Vec::new();
|
||||
for row_result in rows {
|
||||
columns.push(row_result?);
|
||||
}
|
||||
Ok(columns)
|
||||
}
|
||||
|
||||
//... Implementierung der SQL-Generierungsfunktionen...
|
||||
|
||||
fn generate_update_trigger_sql(&self, table_name: &str, pks: &[&str], cols: &[&str]) -> String {
|
||||
// Erstellt dynamisch die Key-Value-Paare für das JSON-Objekt des Primärschlüssels.
|
||||
let pk_json_payload_new = pks
|
||||
.iter()
|
||||
.map(|pk| format!("'{}', NEW.\"{}\"", pk, pk))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
|
||||
let pk_json_payload_old = pks
|
||||
.iter()
|
||||
.map(|pk| format!("'{}', OLD.\"{}\"", pk, pk))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
|
||||
// Erstellt die einzelnen INSERT-Anweisungen für jede Spalte
|
||||
let column_updates = cols.iter().map(|col| format!(
|
||||
r#"
|
||||
-- Protokolliere die Spaltenänderung, wenn sie stattgefunden hat und es kein Soft-Delete ist
|
||||
INSERT INTO crdt_log (hlc_timestamp, op_type, table_name, row_pk, column_name, value, old_value)
|
||||
SELECT
|
||||
'placeholder_hlc', -- TODO: HLC-Funktion hier aufrufen
|
||||
'UPDATE',
|
||||
'{table}',
|
||||
json_object({pk_payload_new}),
|
||||
'{column}',
|
||||
json_object('value', NEW."{column}"),
|
||||
json_object('value', OLD."{column}")
|
||||
WHERE
|
||||
NEW."{column}" IS NOT OLD."{column}"
|
||||
"#,
|
||||
table = table_name,
|
||||
pk_payload_new = pk_json_payload_new,
|
||||
column = col
|
||||
)).collect::<Vec<_>>().join("\n");
|
||||
|
||||
// Erstellt die Logik für den Soft-Delete
|
||||
let delete_logic = format!(
|
||||
r#"
|
||||
-- Protokolliere den Soft-Delete
|
||||
INSERT INTO crdt_log (hlc_timestamp, op_type, table_name, row_pk)
|
||||
SELECT
|
||||
'placeholder_hlc', -- TODO: HLC-Funktion hier aufrufen
|
||||
'DELETE',
|
||||
'{table}',
|
||||
json_object({pk_payload_old})
|
||||
WHERE
|
||||
OLD.{tombstone_col} = 0
|
||||
"#,
|
||||
table = table_name,
|
||||
pk_payload_old = pk_json_payload_old
|
||||
);
|
||||
|
||||
// Kombiniert alles zu einem einzigen Trigger
|
||||
format!(
|
||||
"CREATE TRIGGER IF NOT EXISTS {table_name}_crdt_update
|
||||
AFTER UPDATE ON {table_name}
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
{column_updates}
|
||||
{delete_logic}
|
||||
END;"
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -6,8 +6,8 @@ use rusqlite::{
|
||||
Connection, OpenFlags, ToSql,
|
||||
};
|
||||
use serde_json::Value as JsonValue;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use std::{fs, path::PathBuf};
|
||||
use tauri::State;
|
||||
// --- Hilfsfunktion: Konvertiert JSON Value zu etwas, das rusqlite versteht ---
|
||||
// Diese Funktion ist etwas knifflig wegen Ownership und Lifetimes.
|
||||
@ -168,7 +168,13 @@ pub fn open_and_init_db(path: &str, key: &str, create: bool) -> Result<Connectio
|
||||
OpenFlags::SQLITE_OPEN_READ_WRITE
|
||||
};
|
||||
|
||||
let conn = Connection::open_with_flags(path, flags).map_err(|e| e.to_string())?;
|
||||
let conn = Connection::open_with_flags(path, flags).map_err(|e| {
|
||||
format!(
|
||||
"Dateiii gibt es nicht: {}. Habe nach {} gesucht",
|
||||
e.to_string(),
|
||||
path
|
||||
)
|
||||
})?;
|
||||
conn.pragma_update(None, "key", key)
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@ pub mod core;
|
||||
|
||||
use rusqlite::Connection;
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::FromStr;
|
||||
@ -58,9 +59,14 @@ pub fn create_encrypted_database(
|
||||
app_handle.path().resource_dir()
|
||||
);
|
||||
|
||||
let resource_path = app_handle
|
||||
/* let resource_path = app_handle
|
||||
.path()
|
||||
.resolve("database/vault.db", BaseDirectory::Resource)
|
||||
.map_err(|e| format!("Fehler beim Auflösen des Ressourcenpfads: {}", e))?; */
|
||||
|
||||
let resource_path = app_handle
|
||||
.path()
|
||||
.resolve("temp_vault.db", BaseDirectory::AppLocalData)
|
||||
.map_err(|e| format!("Fehler beim Auflösen des Ressourcenpfads: {}", e))?;
|
||||
|
||||
// Prüfen, ob die Ressourcendatei existiert
|
||||
@ -72,12 +78,16 @@ pub fn create_encrypted_database(
|
||||
}
|
||||
|
||||
// Sicherstellen, dass das Zielverzeichnis existiert
|
||||
if let Some(parent) = Path::new(&path).parent() {
|
||||
/* if let Some(parent) = Path::new(&path).parent() {
|
||||
if !parent.exists() {
|
||||
std::fs::create_dir_all(parent)
|
||||
.map_err(|e| format!("Fehler beim Erstellen des Zielverzeichnisses: {}", e))?;
|
||||
}
|
||||
std::fs::create_dir_all(parent).map_err(|e| {
|
||||
format!(
|
||||
"Fehler beim Erstellen des Zielverzeichnisses: {}\n mit Fehler {}",
|
||||
path, e
|
||||
)
|
||||
})?;
|
||||
}
|
||||
} */
|
||||
|
||||
let target = Path::new(&path);
|
||||
if target.exists() & target.is_file() {
|
||||
@ -167,14 +177,23 @@ pub fn create_encrypted_database(
|
||||
Ok(format!("Verschlüsselte CRDT-Datenbank erstellt",))
|
||||
}
|
||||
|
||||
use tauri_plugin_dialog::{Dialog, DialogExt, MessageDialogKind};
|
||||
#[tauri::command]
|
||||
pub fn open_encrypted_database(
|
||||
app_handle: AppHandle,
|
||||
path: String,
|
||||
key: String,
|
||||
state: State<'_, DbConnection>,
|
||||
) -> Result<String, String> {
|
||||
/* let vault_path = app_handle
|
||||
.path()
|
||||
.resolve(format!("vaults/{}", path), BaseDirectory::AppLocalData)
|
||||
.map_err(|e| format!("Fehler {}", e))?
|
||||
.into_os_string()
|
||||
.into_string()
|
||||
.unwrap(); */
|
||||
if !std::path::Path::new(&path).exists() {
|
||||
return Err("File not found ".into());
|
||||
return Err(format!("File not found {}", path).into());
|
||||
}
|
||||
|
||||
let conn =
|
||||
|
||||
@ -1,63 +0,0 @@
|
||||
// src-tauri/src/sql_proxy.rs
|
||||
|
||||
use rusqlite::Connection;
|
||||
use sqlparser::ast::Statement;
|
||||
use sqlparser::dialect::SQLiteDialect;
|
||||
use sqlparser::parser::Parser;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
// Der Schema-Cache wird später benötigt, um zu wissen, welche Tabellen eine 'tombstone'-Spalte haben.
|
||||
// Für den Anfang lassen wir ihn leer.
|
||||
pub struct SchemaCache {
|
||||
// TODO: z.B. HashMap<String, Vec<String>> für Tabellen und ihre Spalten
|
||||
}
|
||||
|
||||
impl SchemaCache {
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
// TODO: Methoden zum Befüllen und Abfragen des Caches
|
||||
}
|
||||
|
||||
// Die Hauptstruktur unseres Proxys
|
||||
pub struct SqlProxy {
|
||||
// Wir benötigen eine threadsichere Referenz auf den Schema-Cache
|
||||
schema_cache: Arc<Mutex<SchemaCache>>,
|
||||
}
|
||||
|
||||
impl SqlProxy {
|
||||
pub fn new(schema_cache: Arc<Mutex<SchemaCache>>) -> Self {
|
||||
Self { schema_cache }
|
||||
}
|
||||
|
||||
// Die zentrale Ausführungsfunktion
|
||||
pub fn execute(&self, sql: &str, conn: &Connection) -> Result<(), String> {
|
||||
// 1. Parsen des SQL-Strings in einen AST
|
||||
let dialect = SQLiteDialect {};
|
||||
let mut ast =
|
||||
Parser::parse_sql(&dialect, sql).map_err(|e| format!("SQL-Parse-Fehler: {}", e))?;
|
||||
|
||||
// Sicherstellen, dass wir nur eine Anweisung haben
|
||||
if ast.len() != 1 {
|
||||
return Err("Nur einzelne SQL-Anweisungen werden unterstützt.".to_string());
|
||||
}
|
||||
let statement = &mut ast;
|
||||
|
||||
// 2. Umschreiben des AST (Logik folgt in Abschnitt 2)
|
||||
self.transform_statement(statement)?;
|
||||
|
||||
// 3. Ausführen der (möglicherweise modifizierten) Anweisung
|
||||
let final_sql = statement.to_string();
|
||||
conn.execute(&final_sql)
|
||||
.map_err(|e| format!("DB-Ausführungsfehler: {}", e))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Platzhalter für die Transformationslogik
|
||||
fn transform_statement(&self, statement: &mut Statement) -> Result<(), String> {
|
||||
// HIER KOMMT DIE MAGIE HIN
|
||||
// TODO: Implementierung der `CREATE TABLE`, `DELETE` und `SELECT` Transformationen
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,5 @@
|
||||
//mod browser;
|
||||
mod android_storage;
|
||||
mod database;
|
||||
mod extension;
|
||||
mod models;
|
||||
@ -44,13 +45,15 @@ pub fn run() {
|
||||
})
|
||||
.manage(DbConnection(Arc::new(Mutex::new(None))))
|
||||
.manage(ExtensionState::default())
|
||||
.plugin(tauri_plugin_notification::init())
|
||||
.plugin(tauri_plugin_dialog::init())
|
||||
.plugin(tauri_plugin_fs::init())
|
||||
.plugin(tauri_plugin_http::init())
|
||||
.plugin(tauri_plugin_notification::init())
|
||||
.plugin(tauri_plugin_opener::init())
|
||||
.plugin(tauri_plugin_os::init())
|
||||
.plugin(tauri_plugin_persisted_scope::init())
|
||||
.plugin(tauri_plugin_store::Builder::new().build())
|
||||
.plugin(tauri_plugin_android_fs::init())
|
||||
//.plugin(tauri_plugin_sql::Builder::new().build())
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
database::create_encrypted_database,
|
||||
@ -63,6 +66,9 @@ pub fn run() {
|
||||
extension::copy_directory,
|
||||
extension::database::extension_sql_execute,
|
||||
extension::database::extension_sql_select,
|
||||
android_storage::request_storage_permission,
|
||||
android_storage::has_storage_permission,
|
||||
android_storage::get_external_storage_paths,
|
||||
])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
|
||||
@ -55,7 +55,7 @@
|
||||
"icons/icon.icns",
|
||||
"icons/icon.ico"
|
||||
],
|
||||
"resources": ["database/vault.db", "resources/"],
|
||||
"resources": ["database/vault.db"],
|
||||
|
||||
"linux": {
|
||||
"appimage": {
|
||||
|
||||
@ -69,6 +69,9 @@ import { save } from '@tauri-apps/plugin-dialog'
|
||||
import { onKeyStroke } from '@vueuse/core'
|
||||
import { useVaultStore } from '~/stores/vault'
|
||||
import { vaultDatabaseSchema } from './schema'
|
||||
import { BaseDirectory, readFile, writeFile } from '@tauri-apps/plugin-fs'
|
||||
import { resolveResource } from '@tauri-apps/api/path'
|
||||
//import { convertFileSrc } from "@tauri-apps/api/tauri";
|
||||
|
||||
onKeyStroke('Enter', (e) => {
|
||||
e.preventDefault()
|
||||
@ -123,12 +126,22 @@ const onCreateAsync = async () => {
|
||||
|
||||
open.value = false
|
||||
try {
|
||||
const template_vault_path = await resolveResource('database/vault.db')
|
||||
|
||||
const template_vault = await readFile(template_vault_path)
|
||||
|
||||
database.path = await save({
|
||||
defaultPath: database.name.endsWith('.db')
|
||||
? database.name
|
||||
: `${database.name}.db`,
|
||||
})
|
||||
|
||||
if (!database.path) return
|
||||
|
||||
await writeFile('temp_vault.db', template_vault, {
|
||||
baseDir: BaseDirectory.AppLocalData,
|
||||
})
|
||||
|
||||
console.log('data', database)
|
||||
|
||||
if (database.path && database.password) {
|
||||
@ -146,7 +159,7 @@ const onCreateAsync = async () => {
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
add({ type: 'error', text: JSON.stringify(error) })
|
||||
add({ type: 'error', text: `${error}` })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
<UiTextGradient>HaexVault</UiTextGradient>
|
||||
</template>
|
||||
</i18n-t>
|
||||
|
||||
Path1: {{ test }}
|
||||
<div class="text-sm">{{ props.path ?? database.path }}</div>
|
||||
</template>
|
||||
|
||||
@ -41,6 +41,15 @@
|
||||
<script setup lang="ts">
|
||||
import { open as openVault } from '@tauri-apps/plugin-dialog'
|
||||
import { vaultDatabaseSchema } from './schema'
|
||||
import {
|
||||
BaseDirectory,
|
||||
copyFile,
|
||||
mkdir,
|
||||
exists,
|
||||
readFile,
|
||||
writeFile,
|
||||
stat,
|
||||
} from '@tauri-apps/plugin-fs'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
@ -96,6 +105,7 @@ const onLoadDatabase = async () => {
|
||||
],
|
||||
})
|
||||
|
||||
console.log('onLoadDatabase', database.path)
|
||||
if (!database.path) return
|
||||
|
||||
open.value = true
|
||||
@ -118,13 +128,17 @@ const onOpenDatabase = async () => {
|
||||
database.password,
|
||||
)
|
||||
|
||||
if (!pathCheck.success || !passwordCheck.success || !path) {
|
||||
/* if (!pathCheck.success || !passwordCheck.success || !path) {
|
||||
add({
|
||||
type: 'error',
|
||||
text: `Params falsch. Path: ${pathCheck.error} | Password: ${passwordCheck.error}`,
|
||||
})
|
||||
return
|
||||
}
|
||||
} */
|
||||
|
||||
//const vaultName = await copyDatabaseInAppDirectoryAsync(path)
|
||||
|
||||
//if (!vaultName) return
|
||||
|
||||
const vaultId = await openAsync({
|
||||
path,
|
||||
@ -159,6 +173,31 @@ const onOpenDatabase = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
const test = ref()
|
||||
const copyDatabaseInAppDirectoryAsync = async (source: string) => {
|
||||
const vaultName = getFileName(source)
|
||||
const vaultsDirExists = await exists('vaults', {
|
||||
baseDir: BaseDirectory.AppLocalData,
|
||||
})
|
||||
//convertFileSrc
|
||||
if (!vaultsDirExists) {
|
||||
await mkdir('vaults', {
|
||||
baseDir: BaseDirectory.AppLocalData,
|
||||
})
|
||||
}
|
||||
|
||||
test.value = `source: ${source} - target: vaults/${vaultName}`
|
||||
console.log('copyDatabaseInAppDirectoryAsync', `vaults/${vaultName}`)
|
||||
|
||||
const sourceFile = await readFile(source)
|
||||
await writeFile(`vaults/HaexVault.db`, sourceFile, {
|
||||
baseDir: BaseDirectory.AppLocalData,
|
||||
})
|
||||
/* await copyFile(source, `vaults/HaexVault.db`, {
|
||||
toPathBaseDir: BaseDirectory.AppLocalData,
|
||||
}) */
|
||||
return vaultName
|
||||
}
|
||||
const onAbort = () => {
|
||||
initDatabase()
|
||||
open.value = false
|
||||
|
||||
@ -21,6 +21,9 @@
|
||||
v-model:open="passwordPromptOpen"
|
||||
:path="vaultPath"
|
||||
/>
|
||||
|
||||
<UiButton @click="requesty()">Storage Request</UiButton>
|
||||
res: {{ res }}
|
||||
</div>
|
||||
|
||||
<div
|
||||
@ -41,7 +44,7 @@
|
||||
>
|
||||
<button
|
||||
class="link link-accent flex items-center no-underline justify-between text-nowrap text-sm md:text-base shrink w-full py-2 px-4"
|
||||
@click=";(passwordPromptOpen = true), (vaultPath = vault.path)"
|
||||
@click=";((passwordPromptOpen = true), (vaultPath = vault.path))"
|
||||
>
|
||||
<span class="block md:hidden">
|
||||
{{ vault.name }}
|
||||
@ -91,6 +94,18 @@ const { syncLastVaultsAsync, removeVaultAsync } = useLastVaultStore()
|
||||
const { lastVaults } = storeToRefs(useLastVaultStore())
|
||||
|
||||
await syncLastVaultsAsync()
|
||||
|
||||
const res = ref()
|
||||
|
||||
const storage = useAndroidStorage()
|
||||
const requesty = async () => {
|
||||
try {
|
||||
res.value = await storage.requestStoragePermission()
|
||||
res.value += ' wat the fuk'
|
||||
} catch (error) {
|
||||
res.value = error
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<i18n lang="json">
|
||||
|
||||
@ -5,6 +5,8 @@
|
||||
v-bind="extension"
|
||||
:key="extension.id"
|
||||
/>
|
||||
<UiButton @click="requesty()">Storage Request</UiButton>
|
||||
res: {{ res }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -13,5 +15,17 @@ definePageMeta({
|
||||
name: 'vaultOverview',
|
||||
})
|
||||
|
||||
const storage = useAndroidStorage()
|
||||
const extensionStore = useExtensionsStore()
|
||||
|
||||
const res = ref()
|
||||
|
||||
const requesty = async () => {
|
||||
try {
|
||||
res.value = await storage.requestStoragePermission()
|
||||
res.value += ' wat the fuk'
|
||||
} catch (error) {
|
||||
res.value = error
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -51,8 +51,8 @@ export const useVaultStore = defineStore('vaultStore', () => {
|
||||
if (result !== 'success') throw new Error(result)
|
||||
|
||||
const vaultId = await getVaultIdAsync(path)
|
||||
const seperator = platform() === 'windows' ? '\\' : '/'
|
||||
const fileName = path.split(seperator).pop()
|
||||
|
||||
const fileName = getFileName(path)
|
||||
|
||||
openVaults.value = {
|
||||
...openVaults.value,
|
||||
|
||||
38
src/utils/androidStorage.ts
Normal file
38
src/utils/androidStorage.ts
Normal file
@ -0,0 +1,38 @@
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
|
||||
export const useAndroidStorage = () => {
|
||||
const requestStoragePermission = async (): Promise<string> => {
|
||||
try {
|
||||
return await invoke(
|
||||
'plugin:android-fs|openManageAllFilesAccessPermissionSettings',
|
||||
)
|
||||
} catch (error) {
|
||||
console.error('Failed to request storage permission:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
const hasStoragePermission = async (): Promise<boolean> => {
|
||||
try {
|
||||
return await invoke('has_storage_permission')
|
||||
} catch (error) {
|
||||
console.error('Failed to check storage permission:', error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
const getExternalStoragePaths = async (): Promise<string[]> => {
|
||||
try {
|
||||
return await invoke('get_external_storage_paths')
|
||||
} catch (error) {
|
||||
console.error('Failed to get storage paths:', error)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
requestStoragePermission,
|
||||
hasStoragePermission,
|
||||
getExternalStoragePaths,
|
||||
}
|
||||
}
|
||||
@ -1,3 +1,4 @@
|
||||
import { platform } from '@tauri-apps/plugin-os'
|
||||
import type { LocationQueryValue, RouteLocationRawI18n } from 'vue-router'
|
||||
|
||||
export const bytesToBase64DataUrlAsync = async (
|
||||
@ -67,7 +68,7 @@ export const readableFileSize = (sizeInByte: number | string = 0) => {
|
||||
export const getSingleRouteParam = (
|
||||
param: string | string[] | LocationQueryValue | LocationQueryValue[],
|
||||
): string => {
|
||||
const _param = Array.isArray(param) ? param.at(0) ?? '' : param ?? ''
|
||||
const _param = Array.isArray(param) ? (param.at(0) ?? '') : (param ?? '')
|
||||
//console.log('getSingleRouteParam found:', _param, param)
|
||||
return decodeURIComponent(_param)
|
||||
}
|
||||
@ -230,3 +231,8 @@ export const areObjectsEqual = (valueA: unknown, valueB: unknown): boolean => {
|
||||
// 5. Wenn die Schleife durchläuft, sind die Objekte gleich
|
||||
return true
|
||||
}
|
||||
|
||||
export const getFileName = (fullPath: string) => {
|
||||
const seperator = platform() === 'windows' ? '\\' : '/'
|
||||
return fullPath.split(seperator).pop()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user