From 2815c4540983d3a11fd1a542beb5b2d63e53e539 Mon Sep 17 00:00:00 2001 From: LynithDev <61880709+LynithDev@users.noreply.github.com> Date: Sat, 29 Mar 2025 10:26:01 +0100 Subject: [PATCH] refactor: Base stuff done --- Cargo.lock | 436 +++++++++++++++--- Cargo.toml | 9 +- packages/core_new/Cargo.toml | 17 +- packages/core_new/diesel.toml | 8 - packages/core_new/migrations/.keep | 0 .../2025-03-23-145113_init/down.sql | 1 - .../up.sql => 20250324184844_init.sql} | 0 packages/core_new/package.json | 2 +- packages/core_new/sqlx_guide.md | 14 + packages/core_new/src/api/ingress.rs | 37 ++ packages/core_new/src/api/mod.rs | 2 + packages/core_new/src/api/proxy/message.rs | 59 +++ packages/core_new/src/api/proxy/mod.rs | 20 + packages/core_new/src/api/proxy/proxy_cli.rs | 45 ++ .../core_new/src/api/proxy/proxy_tauri.rs | 63 +++ packages/core_new/src/bin/dirs.rs | 2 +- packages/core_new/src/constants.rs | 1 - packages/core_new/src/error.rs | 19 +- packages/core_new/src/io/mod.rs | 3 - packages/core_new/src/lib.rs | 14 +- packages/core_new/src/schema.rs | 80 ---- packages/core_new/src/store/db.rs | 32 ++ packages/core_new/src/{io => store}/dirs.rs | 16 +- packages/core_new/src/store/ingress.rs | 144 ++++++ packages/core_new/src/store/mod.rs | 10 + packages/core_new/src/store/proxy.rs | 40 ++ packages/core_new/src/store/settings.rs | 74 +++ packages/core_new/src/{ => store}/state.rs | 21 +- packages/core_new/src/utils/io.rs | 185 ++++++++ packages/core_new/src/utils/mod.rs | 1 + packages/scripts/setup.ps1 | 2 +- packages/scripts/setup.sh | 4 +- 32 files changed, 1181 insertions(+), 180 deletions(-) delete mode 100644 packages/core_new/diesel.toml delete mode 100644 packages/core_new/migrations/.keep delete mode 100644 packages/core_new/migrations/2025-03-23-145113_init/down.sql rename packages/core_new/migrations/{2025-03-23-145113_init/up.sql => 20250324184844_init.sql} (100%) create mode 100644 packages/core_new/sqlx_guide.md create mode 100644 packages/core_new/src/api/ingress.rs create mode 100644 packages/core_new/src/api/mod.rs create mode 100644 packages/core_new/src/api/proxy/message.rs create mode 100644 packages/core_new/src/api/proxy/mod.rs create mode 100644 packages/core_new/src/api/proxy/proxy_cli.rs create mode 100644 packages/core_new/src/api/proxy/proxy_tauri.rs delete mode 100644 packages/core_new/src/io/mod.rs delete mode 100644 packages/core_new/src/schema.rs create mode 100644 packages/core_new/src/store/db.rs rename packages/core_new/src/{io => store}/dirs.rs (88%) create mode 100644 packages/core_new/src/store/ingress.rs create mode 100644 packages/core_new/src/store/mod.rs create mode 100644 packages/core_new/src/store/proxy.rs create mode 100644 packages/core_new/src/store/settings.rs rename packages/core_new/src/{ => store}/state.rs (69%) create mode 100644 packages/core_new/src/utils/io.rs create mode 100644 packages/core_new/src/utils/mod.rs diff --git a/Cargo.lock b/Cargo.lock index ab2a6d98..890a6c8a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -429,6 +429,15 @@ dependencies = [ "system-deps", ] +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + [[package]] name = "atomic-waker" version = "1.1.2" @@ -1124,6 +1133,15 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "crossbeam-queue" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.20" @@ -1340,42 +1358,6 @@ dependencies = [ "syn 2.0.87", ] -[[package]] -name = "diesel" -version = "2.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "470eb10efc8646313634c99bb1593f402a6434cbd86e266770c6e39219adb86a" -dependencies = [ - "chrono", - "diesel_derives", - "libsqlite3-sys", - "serde_json", - "time", - "uuid 0.8.2", -] - -[[package]] -name = "diesel_derives" -version = "2.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a93958254b70bea63b4187ff73d10180599d9d8d177071b7f91e6da4e0c0ad55" -dependencies = [ - "diesel_table_macro_syntax", - "dsl_auto_type", - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "diesel_table_macro_syntax" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "209c735641a413bc68c4923a9d6ad4bcb3ca306b794edaa7eb0b3228a99ffb25" -dependencies = [ - "syn 2.0.87", -] - [[package]] name = "digest" version = "0.10.7" @@ -1520,6 +1502,12 @@ dependencies = [ "const-random", ] +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + [[package]] name = "dotenvy" version = "0.15.7" @@ -1540,20 +1528,6 @@ dependencies = [ "serde", ] -[[package]] -name = "dsl_auto_type" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139ae9aca7527f85f26dd76483eb38533fd84bd571065da1739656ef71c5ff5b" -dependencies = [ - "darling", - "either", - "heck 0.5.0", - "proc-macro2", - "quote", - "syn 2.0.87", -] - [[package]] name = "dtoa" version = "1.0.9" @@ -1624,6 +1598,9 @@ name = "either" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +dependencies = [ + "serde", +] [[package]] name = "elliptic-curve" @@ -1739,6 +1716,17 @@ version = "3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5d9305ccc6942a704f4335694ecd3de2ea531b114ac2d51f5f843750787a92f" +[[package]] +name = "etcetera" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +dependencies = [ + "cfg-if", + "home", + "windows-sys 0.48.0", +] + [[package]] name = "event-listener" version = "5.3.1" @@ -1854,6 +1842,8 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" dependencies = [ + "futures-core", + "futures-sink", "spin", ] @@ -1863,6 +1853,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "foreign-types" version = "0.5.0" @@ -1960,6 +1956,17 @@ dependencies = [ "futures-util", ] +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot", +] + [[package]] name = "futures-io" version = "0.3.30" @@ -2403,6 +2410,26 @@ dependencies = [ "allocator-api2", ] +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + +[[package]] +name = "hashlink" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +dependencies = [ + "hashbrown 0.15.2", +] + [[package]] name = "heck" version = "0.4.1" @@ -3031,6 +3058,9 @@ name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] [[package]] name = "lebe" @@ -3113,6 +3143,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "libm" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" + [[package]] name = "libmimalloc-sys" version = "0.1.39" @@ -3153,10 +3189,11 @@ dependencies = [ [[package]] name = "libsqlite3-sys" -version = "0.31.0" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad8935b44e7c13394a179a438e0cebba0fe08fe01b54f152e29a93b5cf993fd4" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" dependencies = [ + "cc", "pkg-config", "vcpkg", ] @@ -3272,6 +3309,16 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + [[package]] name = "md5" version = "0.7.0" @@ -3548,6 +3595,23 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand 0.8.5", + "smallvec", + "zeroize", +] + [[package]] name = "num-conv" version = "0.1.0" @@ -3574,6 +3638,17 @@ 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-rational" version = "0.4.2" @@ -3592,6 +3667,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -3878,7 +3954,7 @@ dependencies = [ "chrono", "dirs 5.0.1", "discord-rich-presence", - "dotenvy", + "dotenvy 0.15.7 (git+https://github.com/allan2/dotenvy/?rev=db0d6aa8fc8d1b0ddbfe94b5c833372e463eb1c5)", "flate2", "futures", "indicatif", @@ -3981,14 +4057,16 @@ dependencies = [ name = "onelauncher_new" version = "0.1.0-alpha.2" dependencies = [ + "anyhow", + "async-compression", + "async-trait", "async_zip", "base64 0.22.1", "bytes", "chrono", - "diesel", "dirs 5.0.1", "discord-rich-presence", - "flate2", + "dunce", "futures", "indicatif", "interpulse", @@ -4007,6 +4085,7 @@ dependencies = [ "sha1_smol", "sha2", "specta", + "sqlx", "sysinfo", "tauri", "tauri-specta", @@ -4395,6 +4474,17 @@ dependencies = [ "futures-io", ] +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + [[package]] name = "pkcs8" version = "0.10.2" @@ -5018,6 +5108,26 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422" +[[package]] +name = "rsa" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core 0.6.4", + "signature", + "spki", + "subtle", + "zeroize", +] + [[package]] name = "rust-argon2" version = "1.0.0" @@ -5505,6 +5615,9 @@ name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +dependencies = [ + "serde", +] [[package]] name = "socket2" @@ -5643,6 +5756,201 @@ dependencies = [ "der", ] +[[package]] +name = "sqlx" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4410e73b3c0d8442c5f99b425d7a435b5ee0ae4167b3196771dd3f7a01be745f" +dependencies = [ + "sqlx-core", + "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", +] + +[[package]] +name = "sqlx-core" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a007b6936676aa9ab40207cde35daab0a04b823be8ae004368c0793b96a61e0" +dependencies = [ + "bytes", + "chrono", + "crc", + "crossbeam-queue", + "either", + "event-listener", + "futures-core", + "futures-intrusive", + "futures-io", + "futures-util", + "hashbrown 0.15.2", + "hashlink", + "indexmap 2.5.0", + "log", + "memchr", + "once_cell", + "percent-encoding", + "serde", + "serde_json", + "sha2", + "smallvec", + "thiserror 2.0.12", + "tokio", + "tokio-stream", + "tracing", + "url", + "uuid 1.10.0", +] + +[[package]] +name = "sqlx-macros" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3112e2ad78643fef903618d78cf0aec1cb3134b019730edb039b69eaf531f310" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn 2.0.87", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e9f90acc5ab146a99bf5061a7eb4976b573f560bc898ef3bf8435448dd5e7ad" +dependencies = [ + "dotenvy 0.15.7 (registry+https://github.com/rust-lang/crates.io-index)", + "either", + "heck 0.5.0", + "hex", + "once_cell", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2", + "sqlx-core", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", + "syn 2.0.87", + "tempfile", + "tokio", + "url", +] + +[[package]] +name = "sqlx-mysql" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4560278f0e00ce64938540546f59f590d60beee33fffbd3b9cd47851e5fff233" +dependencies = [ + "atoi", + "base64 0.22.1", + "bitflags 2.6.0", + "byteorder", + "bytes", + "chrono", + "crc", + "digest", + "dotenvy 0.15.7 (registry+https://github.com/rust-lang/crates.io-index)", + "either", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "generic-array", + "hex", + "hkdf", + "hmac", + "itoa 1.0.11", + "log", + "md-5", + "memchr", + "once_cell", + "percent-encoding", + "rand 0.8.5", + "rsa", + "serde", + "sha1", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror 2.0.12", + "tracing", + "uuid 1.10.0", + "whoami", +] + +[[package]] +name = "sqlx-postgres" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5b98a57f363ed6764d5b3a12bfedf62f07aa16e1856a7ddc2a0bb190a959613" +dependencies = [ + "atoi", + "base64 0.22.1", + "bitflags 2.6.0", + "byteorder", + "chrono", + "crc", + "dotenvy 0.15.7 (registry+https://github.com/rust-lang/crates.io-index)", + "etcetera", + "futures-channel", + "futures-core", + "futures-util", + "hex", + "hkdf", + "hmac", + "home", + "itoa 1.0.11", + "log", + "md-5", + "memchr", + "once_cell", + "rand 0.8.5", + "serde", + "serde_json", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror 2.0.12", + "tracing", + "uuid 1.10.0", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f85ca71d3a5b24e64e1d08dd8fe36c6c95c339a896cc33068148906784620540" +dependencies = [ + "atoi", + "chrono", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "serde_urlencoded", + "sqlx-core", + "tracing", + "url", + "uuid 1.10.0", +] + [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -5681,6 +5989,17 @@ dependencies = [ "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 = "stronghold-derive" version = "1.0.0" @@ -6636,6 +6955,7 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -6861,6 +7181,12 @@ 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" diff --git a/Cargo.toml b/Cargo.toml index 3ae0f5ad..1f30d19b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -126,10 +126,12 @@ md5 = { version = "0.7.0" } bytes = { version = "1.7" } # # ============= UTILITY ============= # # -diesel = { version = "2.2.0", features = [ +sqlx = { version = "0.8", features = [ + "runtime-tokio", "sqlite", - "returning_clauses_for_sqlite_3_35", - "serde_json", + "macros", + "derive", + "migrate", "uuid", "chrono" ] } @@ -149,6 +151,7 @@ lazy_static = { version = "1.5" } indicatif = { version = "0.17" } futures = { version = "0.3" } async-recursion = { version = "1.1" } +async-trait = { version = "0.1" } sysinfo = { version = "0.31", features = [ "serde" ] } sys-info = { version = "0.9" } whoami = { version = "1.5" } diff --git a/packages/core_new/Cargo.toml b/packages/core_new/Cargo.toml index d90db739..162c1db2 100644 --- a/packages/core_new/Cargo.toml +++ b/packages/core_new/Cargo.toml @@ -14,10 +14,16 @@ authors = { workspace = true } path = "src/lib.rs" [features] -default = [] -tauri = [ "dep:tauri", "dep:tauri-specta", "specta" ] +default = [ "cli" ] +tauri = [ + "dep:tauri", + "dep:tauri-specta", + "specta", + "gui" +] specta = [ "dep:specta" ] cli = [ "dep:indicatif" ] +gui = [] [lints] workspace = true @@ -39,12 +45,13 @@ serde_repr = { workspace = true } serde_with = { workspace = true } # utils -diesel = { workspace = true } +sqlx = { workspace = true } tokio = { workspace = true } tokio-stream = { workspace = true } futures = { workspace = true } uuid = { workspace = true } thiserror = { workspace = true } +anyhow = { workspace = true } chrono = { workspace = true } reqwest = { workspace = true } regex = { workspace = true } @@ -53,6 +60,7 @@ whoami = { workspace = true } lazy_static = { workspace = true } rand = { workspace = true } url = { workspace = true } +async-trait = { workspace = true } # integration discord-rich-presence = { workspace = true } @@ -69,7 +77,8 @@ async_zip = { workspace = true } dirs = { workspace = true } bytes = { workspace = true } base64 = { workspace = true } -flate2 = { workspace = true } +async-compression = { workspace = true } +dunce = { workspace = true } # features[tauri] tauri = { workspace = true, optional = true } diff --git a/packages/core_new/diesel.toml b/packages/core_new/diesel.toml deleted file mode 100644 index ec74534e..00000000 --- a/packages/core_new/diesel.toml +++ /dev/null @@ -1,8 +0,0 @@ -# For documentation on how to configure this file, -# see https://diesel.rs/guides/configuring-diesel-cli - -[print_schema] -file = "src/schema.rs" -custom_type_derives = [ "diesel::query_builder::QueryId", "Clone" ] - - diff --git a/packages/core_new/migrations/.keep b/packages/core_new/migrations/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/packages/core_new/migrations/2025-03-23-145113_init/down.sql b/packages/core_new/migrations/2025-03-23-145113_init/down.sql deleted file mode 100644 index 252135e7..00000000 --- a/packages/core_new/migrations/2025-03-23-145113_init/down.sql +++ /dev/null @@ -1 +0,0 @@ --- this is the init migration, it is not reversible \ No newline at end of file diff --git a/packages/core_new/migrations/2025-03-23-145113_init/up.sql b/packages/core_new/migrations/20250324184844_init.sql similarity index 100% rename from packages/core_new/migrations/2025-03-23-145113_init/up.sql rename to packages/core_new/migrations/20250324184844_init.sql diff --git a/packages/core_new/package.json b/packages/core_new/package.json index ac009afa..016a37a4 100644 --- a/packages/core_new/package.json +++ b/packages/core_new/package.json @@ -13,6 +13,6 @@ "scripts": { "cargo": "cargo", "binary": "cargo run --bin", - "diesel": "diesel" + "sqlx": "sqlx" } } diff --git a/packages/core_new/sqlx_guide.md b/packages/core_new/sqlx_guide.md new file mode 100644 index 00000000..932d65b3 --- /dev/null +++ b/packages/core_new/sqlx_guide.md @@ -0,0 +1,14 @@ +# Connecting to database on *nix +```bash +export DATABASE_URL=sqlite:/path/to/user_data.db +``` + +# Connecting to database on Windows +```cmd +set DATABASE_URL=sqlite:C:\\path\\to\\user_data.db +``` + +# Connecting to database on Windows (PowerShell) +```powershell +$env:DATABASE_URL="sqlite:C:\\path\\to\\user_data.db" +``` diff --git a/packages/core_new/src/api/ingress.rs b/packages/core_new/src/api/ingress.rs new file mode 100644 index 00000000..93b8f335 --- /dev/null +++ b/packages/core_new/src/api/ingress.rs @@ -0,0 +1,37 @@ +use crate::{store::{ingress::{IngressId, IngressType}, State}, LauncherResult}; + +pub async fn init_ingress( + ingress_type: IngressType, + message: &str, + total: f64, +) -> LauncherResult { + let state = State::get().await?; + let processor = &state.ingress_processor; + + let id = processor.create(ingress_type, message.to_string(), total).await?; + + Ok(id) +} + +pub async fn send_ingress(id: IngressId) -> LauncherResult<()> { + let state = State::get().await?; + let processor = &state.ingress_processor; + + processor.send(id.0).await?; + Ok(()) +} + +pub async fn update_ingress(id: IngressId, current: f64) -> LauncherResult<()> { + let state = State::get().await?; + let processor = &state.ingress_processor; + + processor.update(id.0, current).await +} + +pub async fn finish_ingress(id: IngressId) -> LauncherResult<()> { + let state = State::get().await?; + let processor = &state.ingress_processor; + + processor.finish(id.0).await?; + Ok(()) +} \ No newline at end of file diff --git a/packages/core_new/src/api/mod.rs b/packages/core_new/src/api/mod.rs new file mode 100644 index 00000000..649515a3 --- /dev/null +++ b/packages/core_new/src/api/mod.rs @@ -0,0 +1,2 @@ +pub mod ingress; +pub mod proxy; \ No newline at end of file diff --git a/packages/core_new/src/api/proxy/message.rs b/packages/core_new/src/api/proxy/message.rs new file mode 100644 index 00000000..ce9d55d8 --- /dev/null +++ b/packages/core_new/src/api/proxy/message.rs @@ -0,0 +1,59 @@ +use serde::Serialize; + +#[cfg_attr(feature = "tauri", derive(tauri_specta::Event))] +#[cfg_attr(feature = "specta", derive(specta::Type))] +#[derive(Serialize, Debug, Clone)] +pub struct MessagePayload { + pub level: MessageLevel, + pub message: String, +} + +#[cfg_attr(feature = "specta", derive(specta::Type))] +#[derive(Serialize, Debug, Clone)] +pub enum MessageLevel { + Info, + Warning, + Error, +} + +#[macro_export] +macro_rules! send_warning { + ($($message:tt)*) => {{ + tokio::spawn(async move { + let _ = match $crate::store::proxy::ProxyState::get() { + Ok(proxy) => { + let payload = $crate::api::proxy::message::MessagePayload { + level: $crate::api::proxy::message::MessageLevel::Warning, + message: format!($($message)*), + }; + let _ = proxy.send_message(payload).await; + }, + Err(err) => { + tracing::warn!($($message)*); + tracing::warn!("failed to send warning: {}", err); + }, + }; + }) + }}; +} + +#[macro_export] +macro_rules! send_error { + ($($message:tt)*) => {{ + tokio::spawn(async move { + let _ = match $crate::store::proxy::ProxyState::get() { + Ok(proxy) => { + let payload = $crate::api::proxy::message::MessagePayload { + level: $crate::api::proxy::message::MessageLevel::Error, + message: format!($($message)*), + }; + let _ = proxy.send_message(payload).await; + }, + Err(err) => { + tracing::error!($($message)*); + tracing::error!("failed to send error: {}", err); + }, + }; + }) + }}; +} diff --git a/packages/core_new/src/api/proxy/mod.rs b/packages/core_new/src/api/proxy/mod.rs new file mode 100644 index 00000000..f4cdffb2 --- /dev/null +++ b/packages/core_new/src/api/proxy/mod.rs @@ -0,0 +1,20 @@ +pub mod message; + +#[cfg(feature = "tauri")] +pub mod proxy_tauri; + +#[cfg(feature = "cli")] +pub mod proxy_cli; + +#[async_trait::async_trait] +pub trait LauncherProxy: Send + Sync { + async fn send_ingress(&self, ingress: crate::store::ingress::IngressPayload) -> crate::LauncherResult<()>; + async fn send_message(&self, message: message::MessagePayload) -> crate::LauncherResult<()>; + + #[cfg(feature = "gui")] + fn hide_main_window(&self) -> crate::LauncherResult<()>; + + #[cfg(feature = "gui")] + fn show_main_window(&self) -> crate::LauncherResult<()>; +} + diff --git a/packages/core_new/src/api/proxy/proxy_cli.rs b/packages/core_new/src/api/proxy/proxy_cli.rs new file mode 100644 index 00000000..b4ee7eb4 --- /dev/null +++ b/packages/core_new/src/api/proxy/proxy_cli.rs @@ -0,0 +1,45 @@ +use std::collections::HashMap; + +use indicatif::ProgressBar; +use tokio::sync::RwLock; +use uuid::Uuid; + +use crate::{store::{ingress::IngressPayload, State}, LauncherResult}; + +use super::LauncherProxy; + +#[derive(Default)] +pub struct ProxyCli { + ingress_feeds: RwLock>, +} + +impl ProxyCli { + #[must_use] + pub fn new() -> Self { + Self::default() + } +} + +#[async_trait::async_trait] +impl LauncherProxy for ProxyCli { + + async fn send_ingress(&self, ingress: IngressPayload) -> LauncherResult<()> { + let feeds = self.ingress_feeds.write().await; + + if let Some(progress) = feeds.get(&ingress.id) { + // progress.set_position(ingress.percent as u64); + // TODO: customize progress bar + } else { + let progress = ProgressBar::new(ingress.total as u64); + progress.set_message(ingress.message.clone()); + progress.set_position(0); + } + Ok(()) + } + + async fn send_message(&self, message: crate::api::proxy::message::MessagePayload) -> LauncherResult<()> { + println!("[{:?}] {:?}", message.level, message.message); + Ok(()) + } + +} diff --git a/packages/core_new/src/api/proxy/proxy_tauri.rs b/packages/core_new/src/api/proxy/proxy_tauri.rs new file mode 100644 index 00000000..3fd44627 --- /dev/null +++ b/packages/core_new/src/api/proxy/proxy_tauri.rs @@ -0,0 +1,63 @@ +use tauri::{AppHandle, Emitter, Manager}; +use tauri_specta::Event; +use tracing::{error, warn}; + +use crate::{store::ingress::IngressPayload, LauncherResult}; + +use super::{message::{MessageLevel, MessagePayload}, LauncherProxy}; + +#[derive(Debug)] +pub struct ProxyTauri { + handle: AppHandle, +} + +impl ProxyTauri { + #[must_use] + pub const fn new(handle: AppHandle) -> Self { + Self { + handle + } + } +} + +#[async_trait::async_trait] +impl LauncherProxy for ProxyTauri { + async fn send_ingress(&self, ingress: IngressPayload) -> LauncherResult<()> { + self.handle + .emit(IngressPayload::NAME, ingress) + .map_err(Into::into) + } + + async fn send_message(&self, message: MessagePayload) -> LauncherResult<()> { + match message.level { + MessageLevel::Info => {}, + MessageLevel::Warning => warn!("{}", message.message), + MessageLevel::Error => error!("{}", message.message), + }; + + self.handle + .emit(MessagePayload::NAME, message) + .map_err(Into::into) + } + + #[tracing::instrument] + fn hide_main_window(&self) -> LauncherResult<()> { + if let Some(window) = self.handle.get_webview_window("main") { + Ok(window.hide()?) + } else { + warn!("main window not found"); + Ok(()) + } + } + + #[tracing::instrument] + fn show_main_window(&self) -> LauncherResult<()> { + if let Some(window) = self.handle.get_webview_window("main") { + Ok(window.show()?) + } else { + warn!("main window not found"); + Ok(()) + } + } + +} \ No newline at end of file diff --git a/packages/core_new/src/bin/dirs.rs b/packages/core_new/src/bin/dirs.rs index 65efff24..fa5ee4de 100644 --- a/packages/core_new/src/bin/dirs.rs +++ b/packages/core_new/src/bin/dirs.rs @@ -1,4 +1,4 @@ -use onelauncher_new::io::Dirs; +use onelauncher_new::store::Dirs; #[tokio::main] async fn main() { diff --git a/packages/core_new/src/constants.rs b/packages/core_new/src/constants.rs index be93c344..20b17852 100644 --- a/packages/core_new/src/constants.rs +++ b/packages/core_new/src/constants.rs @@ -1,7 +1,6 @@ //! **`OneLauncher` Constants** //! //! Public constant variables and strings that are used throughout the launcher. -//! Can be shared publically, any secrets should be stored in [`crate::store::credentials`]. // =========== Core Metadata =========== /// The name of the launcher. diff --git a/packages/core_new/src/error.rs b/packages/core_new/src/error.rs index a8dcf180..bf68aee2 100644 --- a/packages/core_new/src/error.rs +++ b/packages/core_new/src/error.rs @@ -1,7 +1,24 @@ #[derive(thiserror::Error, Debug)] pub enum LauncherError { #[error(transparent)] - DirError(#[from] crate::io::DirectoryError), + DirError(#[from] crate::store::DirectoryError), + #[error(transparent)] + IOError(#[from] crate::utils::io::IOError), + #[error(transparent)] + IngressError(#[from] crate::store::ingress::IngressError), + + #[error(transparent)] + SerdeError(#[from] serde_json::Error), + #[error(transparent)] + DbError(#[from] sqlx::Error), + #[error(transparent)] + DbMigrationError(#[from] sqlx::migrate::MigrateError), + #[error(transparent)] + AnyhowError(#[from] anyhow::Error), + + #[cfg(feature = "tauri")] + #[error(transparent)] + TauriError(#[from] tauri::Error), } pub type LauncherResult = Result; \ No newline at end of file diff --git a/packages/core_new/src/io/mod.rs b/packages/core_new/src/io/mod.rs deleted file mode 100644 index bef7224a..00000000 --- a/packages/core_new/src/io/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod dirs; - -pub use dirs::*; \ No newline at end of file diff --git a/packages/core_new/src/lib.rs b/packages/core_new/src/lib.rs index 28aed3b1..a0f90c92 100644 --- a/packages/core_new/src/lib.rs +++ b/packages/core_new/src/lib.rs @@ -1,16 +1,10 @@ -// Private (accessible by crate only) modules - -// Modules which are not re-exported -pub mod io; pub mod constants; -pub mod schema; +pub mod utils; +pub mod store; +pub mod api; -// Modules which are re-exported -mod state; mod error; mod logger; -// Re-exported modules -pub use state::State; -pub use error::*; +pub use error::{LauncherResult, LauncherError}; pub use logger::start_logger; \ No newline at end of file diff --git a/packages/core_new/src/schema.rs b/packages/core_new/src/schema.rs deleted file mode 100644 index 2afe6797..00000000 --- a/packages/core_new/src/schema.rs +++ /dev/null @@ -1,80 +0,0 @@ -// @generated automatically by Diesel CLI. - -diesel::table! { - cluster_groups (id) { - id -> Integer, - name -> Text, - } -} - -diesel::table! { - clusters (path) { - path -> Text, - created_at -> Integer, - updated_at -> Integer, - group_id -> Nullable, - name -> Text, - mc_version -> Text, - mc_loader -> Text, - mc_loader_version -> Nullable, - last_played -> Nullable, - overall_played -> Nullable, - icon_url -> Nullable, - setting_profile_name -> Nullable, - linked_pack_id -> Nullable, - linked_pack_version -> Nullable, - } -} - -diesel::table! { - java_versions (id) { - id -> Integer, - major_version -> Integer, - display_name -> Text, - absolute_path -> Text, - full_version -> Text, - } -} - -diesel::table! { - packages (file_name, type_id) { - file_name -> Text, - display_name -> Text, - display_version -> Text, - type_id -> Integer, - provider_id -> Integer, - provider_version -> Text, - mc_versions -> Text, - mc_loader -> Text, - hash -> Text, - icon_url -> Nullable, - } -} - -diesel::table! { - setting_profiles (name) { - name -> Text, - java_id -> Nullable, - res_w -> Nullable, - res_h -> Nullable, - force_fullscreen -> Nullable, - mem_max -> Nullable, - launch_args -> Nullable, - launch_env -> Nullable, - hook_pre -> Nullable, - hook_wrapper -> Nullable, - hook_post -> Nullable, - } -} - -diesel::joinable!(clusters -> cluster_groups (group_id)); -diesel::joinable!(clusters -> setting_profiles (setting_profile_name)); -diesel::joinable!(setting_profiles -> java_versions (java_id)); - -diesel::allow_tables_to_appear_in_same_query!( - cluster_groups, - clusters, - java_versions, - packages, - setting_profiles, -); diff --git a/packages/core_new/src/store/db.rs b/packages/core_new/src/store/db.rs new file mode 100644 index 00000000..7e72c977 --- /dev/null +++ b/packages/core_new/src/store/db.rs @@ -0,0 +1,32 @@ +use std::path::PathBuf; + +use chrono::Duration; +use sqlx::{migrate::MigrateDatabase, sqlite::SqlitePoolOptions, Sqlite, SqlitePool}; + +use crate::LauncherResult; + +use super::Dirs; + +pub async fn create_pool_from_path(path: PathBuf) -> LauncherResult { + let protocol = String::from("sqlite:"); + let connection_str = protocol + path.to_str().expect("invalid path used for sqlite connection"); + + if !Sqlite::database_exists(&connection_str).await? { + + Sqlite::create_database(&connection_str).await?; + } + + let pool = SqlitePoolOptions::new() + .max_connections(40) + .idle_timeout(Some(Duration::hours(6).to_std().unwrap())) + .connect(&connection_str).await?; + + sqlx::migrate!().run(&pool).await?; + + Ok(pool) +} + +pub async fn create_pool() -> LauncherResult { + let path = Dirs::get().await?.db_file(); + create_pool_from_path(path).await +} \ No newline at end of file diff --git a/packages/core_new/src/io/dirs.rs b/packages/core_new/src/store/dirs.rs similarity index 88% rename from packages/core_new/src/io/dirs.rs rename to packages/core_new/src/store/dirs.rs index fc57233c..43d089ac 100644 --- a/packages/core_new/src/io/dirs.rs +++ b/packages/core_new/src/store/dirs.rs @@ -2,7 +2,7 @@ use std::path::PathBuf; use tokio::sync::OnceCell; -use crate::{constants, LauncherResult}; +use crate::{constants, utils, LauncherResult}; /// The static [`OnceCell>`] for storing the global directory state. /// Should be initialized as soon as possible (preferably before logging) @@ -20,7 +20,7 @@ impl Dirs { } fn initialize() -> LauncherResult { - let base_dir = env_path("LAUNCHER_DIR") + let base_dir = utils::io::env_path("LAUNCHER_DIR") .or_else(|| Some(dirs::data_dir()?.join(constants::NAME))) .ok_or(DirectoryError::BaseDir)?; @@ -41,11 +41,20 @@ impl Dirs { self.base_dir().join("logs") } + + // --- FILES --- + #[must_use] pub fn db_file(&self) -> PathBuf { self.base_dir().join("user_data.db") } + #[must_use] + pub fn settings_file(&self) -> PathBuf { + self.base_dir().join("settings.json") + } + + // --- GAME DIRECTORIES --- /// Get the `config_dir/metadata` folder within the core config directory. #[inline] @@ -85,6 +94,3 @@ pub enum DirectoryError { BaseDir, } -pub fn env_path(name: &str) -> Option { - std::env::var_os(name).map(PathBuf::from) -} \ No newline at end of file diff --git a/packages/core_new/src/store/ingress.rs b/packages/core_new/src/store/ingress.rs new file mode 100644 index 00000000..64df0f3b --- /dev/null +++ b/packages/core_new/src/store/ingress.rs @@ -0,0 +1,144 @@ +use std::collections::HashMap; + +use serde::Serialize; +use tokio::sync::RwLock; +use uuid::Uuid; + +use crate::LauncherResult; + +use super::{proxy::ProxyState, State}; + +#[derive(Default)] +pub struct IngressProcessor { + ingress_feeds: RwLock>, +} + +#[derive(Debug, thiserror::Error)] +pub enum IngressError { + #[error("ingress not found")] + NotFound, +} + +impl IngressProcessor { + #[must_use] + pub fn new() -> Self { + Self { + ingress_feeds: RwLock::new(HashMap::new()), + } + } + + pub async fn create(&self, ingress_type: IngressType, message: String, total: f64) -> LauncherResult { + let mut feeds = self.ingress_feeds.write().await; + + let uuid = Uuid::new_v4(); + let ingress = Ingress { + id: IngressId(uuid), + message, + ingress_type, + total, + current: 0.0, + last_sent: 0.0, + }; + + feeds.insert(uuid, ingress); + + self.send(uuid).await?; + + Ok(IngressId(uuid)) + } + + pub async fn update(&self, id: Uuid, current: f64) -> LauncherResult<()> { + let mut feeds = self.ingress_feeds.write().await; + let ingress = feeds.get_mut(&id).ok_or_else(|| IngressError::NotFound)?; + ingress.current = current; + + Ok(()) + } + + pub async fn send(&self, id: Uuid) -> LauncherResult<()> { + let feeds = self.ingress_feeds.read().await; + let ingress = feeds.get(&id).ok_or_else(|| IngressError::NotFound)?; + + let proxy = ProxyState::get()?; + proxy.send_ingress(IngressPayload { + id: ingress.id.0, + message: ingress.message.clone(), + ingress_type: ingress.ingress_type.clone(), + percent: Some(ingress.current / ingress.total), + total: ingress.total, + }).await?; + + Ok(()) + } + + pub async fn finish(&self, uuid: Uuid) -> LauncherResult { + let mut feeds = self.ingress_feeds.write().await; + Ok(feeds.remove(&uuid).ok_or_else(|| IngressError::NotFound)?) + } +} + + +#[derive(Debug, Clone)] +pub struct IngressId(pub Uuid); + +#[derive(Debug, Clone)] +pub struct Ingress { + pub id: IngressId, + pub message: String, + pub ingress_type: IngressType, + pub total: f64, + pub current: f64, + pub last_sent: f64, +} + +#[cfg_attr(feature = "tauri", derive(tauri_specta::Event))] +#[cfg_attr(feature = "specta", derive(specta::Type))] +#[derive(Serialize, Debug, Clone)] +pub struct IngressPayload { + pub id: Uuid, + pub message: String, + pub ingress_type: IngressType, + pub percent: Option, + pub total: f64, +} + +#[cfg_attr(feature = "specta", derive(specta::Type))] +#[derive(Serialize, Debug, Clone)] +pub enum IngressType { + Download { + file_name: String, + } +} + +impl Drop for IngressId { + #[clippy::has_significant_drop] + fn drop(&mut self) { + let ingress_uuid = self.0; + tokio::spawn(async move { + let result: LauncherResult<()> = async { + let state = State::get().await?; + let processor = &state.ingress_processor; + + let ingress = processor.finish(ingress_uuid).await?; + + let proxy = ProxyState::get()?; + + proxy.send_ingress(IngressPayload { + id: ingress.id.0, + message: "Completed".into(), + ingress_type: ingress.ingress_type, + percent: None, + total: ingress.total, + }).await?; + + tracing::trace!("exited at {}% for ingress {:?}", ingress.current / ingress.total * 100.0, ingress_uuid); + + Ok(()) + }.await; + + if let Err(e) = result { + tracing::error!("failed to finish ingress: {:?}", e); + } + }); + } +} \ No newline at end of file diff --git a/packages/core_new/src/store/mod.rs b/packages/core_new/src/store/mod.rs new file mode 100644 index 00000000..37528f39 --- /dev/null +++ b/packages/core_new/src/store/mod.rs @@ -0,0 +1,10 @@ +pub(super) mod db; +pub mod ingress; +pub mod proxy; +mod dirs; +mod settings; +mod state; + +pub use dirs::*; +pub use settings::*; +pub use state::*; \ No newline at end of file diff --git a/packages/core_new/src/store/proxy.rs b/packages/core_new/src/store/proxy.rs new file mode 100644 index 00000000..cfad055b --- /dev/null +++ b/packages/core_new/src/store/proxy.rs @@ -0,0 +1,40 @@ +use std::{ops::Deref, sync::Arc}; + +use anyhow::anyhow; +use tokio::sync::OnceCell; + +use crate::{api::proxy::LauncherProxy, LauncherResult}; + +static PROXY_STATE: OnceCell> = OnceCell::const_new(); + +pub struct ProxyState { + inner: Box, +} + +impl Deref for ProxyState { + type Target = Box; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl ProxyState { + pub async fn initialize(proxy: Box) -> LauncherResult> { + PROXY_STATE + .get_or_try_init(|| async { + Ok(Arc::new(Self { + inner: proxy, + })) + }) + .await + .cloned() + } + + pub fn get() -> LauncherResult> { + Ok(PROXY_STATE + .get() + .ok_or_else(|| anyhow!("proxy state not initialized")) + .cloned()?) + } +} \ No newline at end of file diff --git a/packages/core_new/src/store/settings.rs b/packages/core_new/src/store/settings.rs new file mode 100644 index 00000000..3c167366 --- /dev/null +++ b/packages/core_new/src/store/settings.rs @@ -0,0 +1,74 @@ +use serde::{Deserialize, Serialize}; +use sqlx::prelude::FromRow; + +use crate::{send_warning, utils::io, LauncherResult}; + +use super::Dirs; + +#[cfg_attr(feature = "specta", derive(specta::Type))] +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(default)] +pub struct Settings { + pub global_game_settings: SettingsProfile, + pub allow_parallel_running_clusters: bool, + pub enable_gamemode: bool, + pub discord_enabled: bool, + pub settings_version: u32, +} + +impl Default for Settings { + fn default() -> Self { + Self { + global_game_settings: SettingsProfile { + name: "Global".into(), + ..Default::default() + }, + allow_parallel_running_clusters: false, + discord_enabled: false, + enable_gamemode: false, + settings_version: 2, + } + } +} + +impl Settings { + pub async fn new() -> Self { + match Self::read().await { + Ok(settings) => settings, + Err(err) => { + send_warning!("Failed to read settings file: {}", err); + Self::default() + }, + } + } + + async fn read() -> LauncherResult { + let path = Dirs::get().await?.settings_file(); + let data = io::read(path).await?; + Ok(serde_json::from_slice(&data)?) + } + + pub async fn save(&self) -> LauncherResult<()> { + let path = Dirs::get().await?.settings_file(); + let data = serde_json::to_string_pretty(self)?; + io::write(path, data).await?; + + Ok(()) + } +} + +#[cfg_attr(feature = "specta", derive(specta::Type))] +#[derive(Default, Debug, Clone, Serialize, Deserialize, FromRow)] +pub struct SettingsProfile { + pub name: String, + pub java_id: Option, + pub res_w: Option, + pub res_h: Option, + pub force_fullscreen: Option, + pub mem_max: Option, + pub launch_args: Option, + pub launch_env: Option, + pub hook_pre: Option, + pub hook_wrapper: Option, + pub hook_post: Option, +} \ No newline at end of file diff --git a/packages/core_new/src/state.rs b/packages/core_new/src/store/state.rs similarity index 69% rename from packages/core_new/src/state.rs rename to packages/core_new/src/store/state.rs index b8130374..29f27a4f 100644 --- a/packages/core_new/src/state.rs +++ b/packages/core_new/src/store/state.rs @@ -1,14 +1,19 @@ use std::sync::Arc; +use sqlx::SqlitePool; use tokio::sync::{OnceCell, RwLock}; use crate::LauncherResult; +use super::{ingress::IngressProcessor, Settings}; + /// The static [`OnceCell>`] for storing the global runtime launcher state. static LAUNCHER_STATE: OnceCell> = OnceCell::const_new(); pub struct State { - + pub ingress_processor: IngressProcessor, + pub settings: Settings, + pub db: SqlitePool, } impl State { @@ -32,9 +37,19 @@ impl State { .await) } - async fn initialize() -> LauncherResult> { - Ok(RwLock::new(Self { + pub fn initialized() -> bool { + LAUNCHER_STATE.initialized() + } + async fn initialize() -> LauncherResult> { + let ingress_processor = IngressProcessor::new(); + let settings = Settings::new().await; + let db = super::db::create_pool().await?; + + Ok(RwLock::new(Self { + ingress_processor, + settings, + db, })) } } \ No newline at end of file diff --git a/packages/core_new/src/utils/io.rs b/packages/core_new/src/utils/io.rs new file mode 100644 index 00000000..3cd807c3 --- /dev/null +++ b/packages/core_new/src/utils/io.rs @@ -0,0 +1,185 @@ +use async_compression::tokio::bufread::GzipDecoder; +use tokio::io::AsyncReadExt; + +/// A wrapper around generic and unhelpful [`std::io::Error`] messages. +#[derive(Debug, thiserror::Error)] +pub enum IOError { + /// A wrapped [`std::io::Error`] along with the path involved in the error. + #[error("error acessing path: {source}, path: {path}")] + IOErrorWrapper { + #[source] + source: std::io::Error, + path: String, + }, + /// A wrapped [`zip::result::ZipError`]. + #[error(transparent)] + ZipError(#[from] zip::result::ZipError), + /// A wrapped [`std::io::Error`]. + #[error(transparent)] + IOError(#[from] std::io::Error), +} + +impl> From<(P, std::io::Error)> for IOError { + fn from((path, source): (P, std::io::Error)) -> Self { + Self::IOErrorWrapper { + source, + path: path.as_ref().to_string_lossy().to_string(), + } + } +} + +#[derive(Debug, thiserror::Error)] +#[error("received a non UTF-8 path: ", .0.to_string_lossy())] +pub struct NonUtf8PathError(pub Box); + +/// Attempts to parse a path taken from an environment variable. Returns `None` if the variable is not set. +pub fn env_path(name: &str) -> Option { + std::env::var_os(name).map(std::path::PathBuf::from) +} + +/// An OS specific wrapper of [`std::fs::canonicalize`], but on Windows it outputs the most compatible form of a path instead of UNC. +pub fn canonicalize(path: impl AsRef) -> Result { + let path = path.as_ref(); + dunce::canonicalize(path).map_err(|e| IOError::IOErrorWrapper { + source: e, + path: path.to_string_lossy().to_string(), + }) +} + +/// Returns a stream over the entries within a directory. +pub async fn read_dir(path: impl AsRef) -> Result { + let path = path.as_ref(); + tokio::fs::read_dir(path) + .await + .map_err(|e| IOError::IOErrorWrapper { + source: e, + path: path.to_string_lossy().to_string(), + }) +} + +/// Creates a directory if they are missing. +pub async fn create_dir(path: impl AsRef) -> Result<(), IOError> { + let path = path.as_ref(); + if path.exists() { + return Ok(()); + } + + tokio::fs::create_dir(path) + .await + .map_err(|e| IOError::IOErrorWrapper { + source: e, + path: path.to_string_lossy().to_string(), + }) +} + +/// Recursively creates a directory and all of its parent components if they are missing. +pub async fn create_dir_all(path: impl AsRef) -> Result<(), IOError> { + let path = path.as_ref(); + tokio::fs::create_dir_all(path) + .await + .map_err(|e| IOError::IOErrorWrapper { + source: e, + path: path.to_string_lossy().to_string(), + }) +} + +/// Removes a directory at this path, after removing all its contents. Use carefully! +pub async fn remove_dir_all(path: impl AsRef) -> Result<(), IOError> { + let path = path.as_ref(); + tokio::fs::remove_dir_all(path) + .await + .map_err(|e| IOError::IOErrorWrapper { + source: e, + path: path.to_string_lossy().to_string(), + }) +} + +/// Creates a future which will open a gzip compressed file for reading and read the entire contents into a string and return said string. +pub async fn read_gz_to_string(path: impl AsRef) -> Result { + let mut f = tokio::fs::File::open(path).await?; + let mut buf = vec![]; + f.read_to_end(&mut buf).await?; + + let mut decoder = GzipDecoder::new(buf.as_slice()); + let mut dst = String::new(); + decoder.read_to_string(&mut dst).await?; + + Ok(dst) +} + +/// Creates a future which will open a file for reading and read the entire contents into a string and return said string. +pub async fn read_to_string(path: impl AsRef) -> Result { + let path = path.as_ref(); + tokio::fs::read_to_string(path) + .await + .map_err(|e| IOError::IOErrorWrapper { + source: e, + path: path.to_string_lossy().to_string(), + }) +} + +/// Reads the entire contents of a file into a bytes vector. +pub async fn read(path: impl AsRef) -> Result, IOError> { + let path = path.as_ref(); + tokio::fs::read(path) + .await + .map_err(|e| IOError::IOErrorWrapper { + source: e, + path: path.to_string_lossy().to_string(), + }) +} + +/// Asynchrously write to a tempfile that is then transferred to an official [`AsRef`]. +pub async fn write( + path: impl AsRef, + data: impl AsRef<[u8]>, +) -> Result<(), IOError> { + let path = path.as_ref(); + tokio::fs::write(path, data) + .await + .map_err(|e| IOError::IOErrorWrapper { + source: e, + path: path.to_string_lossy().to_string(), + }) +} + +/// Renames a file or directory to a new name, replacing the original file if `to` already exists. +pub async fn rename( + from: impl AsRef, + to: impl AsRef, +) -> Result<(), IOError> { + let from = from.as_ref(); + let to = to.as_ref(); + tokio::fs::rename(from, to) + .await + .map_err(|e| IOError::IOErrorWrapper { + source: e, + path: from.to_string_lossy().to_string(), + }) +} + +/// Copies the contents of one file to another. This function will also copy the permission bits of the original file to the destination file. This function will overwrite the contents of to. +pub async fn copy( + from: impl AsRef, + to: impl AsRef, +) -> Result { + let from = from.as_ref(); + let to = to.as_ref(); + tokio::fs::copy(from, to) + .await + .map_err(|e| IOError::IOErrorWrapper { + source: e, + path: from.to_string_lossy().to_string(), + }) +} + +/// Removes a file from the filesystem. +pub async fn remove_file(path: impl AsRef) -> Result<(), IOError> { + let path = path.as_ref(); + tokio::fs::remove_file(path) + .await + .map_err(|e| IOError::IOErrorWrapper { + source: e, + path: path.to_string_lossy().to_string(), + }) +} \ No newline at end of file diff --git a/packages/core_new/src/utils/mod.rs b/packages/core_new/src/utils/mod.rs new file mode 100644 index 00000000..678b90ea --- /dev/null +++ b/packages/core_new/src/utils/mod.rs @@ -0,0 +1 @@ +pub mod io; \ No newline at end of file diff --git a/packages/scripts/setup.ps1 b/packages/scripts/setup.ps1 index 4bf8138c..fcf91cc6 100644 --- a/packages/scripts/setup.ps1 +++ b/packages/scripts/setup.ps1 @@ -199,7 +199,7 @@ https://learn.microsoft.com/windows/package-manager/winget/ Write-Host Write-Host 'Installing Rust tools...' -ForegroundColor Yellow cargo install cargo-watch - cargo install diesel_cli --no-default-features --features sqlite + cargo install sqlx-cli if ($LASTEXITCODE -ne 0) { Exit-WithError 'Failed to install Rust tools' } diff --git a/packages/scripts/setup.sh b/packages/scripts/setup.sh index 3235fdc3..8c35af75 100755 --- a/packages/scripts/setup.sh +++ b/packages/scripts/setup.sh @@ -183,10 +183,8 @@ esac # installs cargo-watch for development purposes if [ "${CI:-}" != "true" ]; then echo "installing rust tools..." - _tools="cargo-watch" + _tools="cargo-watch sqlx-cli" echo "$_tools" | xargs cargo install - - cargo install diesel_cli --no-default-features --features sqlite fi echo 'your machine has been setup for onelauncher development!'