diff --git a/package.json b/package.json index 595a9727..419766bc 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,8 @@ "@vueuse/core": "^13.6.0", "lodash-es": "^4.17.21", "lucide-vue-next": "^0.539.0", - "vue": "^3.5.13" + "vue": "^3.5.13", + "vue3-markdown-it": "^1.0.10" }, "devDependencies": { "@tailwindcss/postcss": "^4.1.11", diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 1df38675..86e9f855 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -9,8 +9,10 @@ dependencies = [ "chrono", "dirs", "fern", + "futures-util", "log", "regex", + "reqwest 0.11.27", "serde", "serde_json", "tauri", @@ -565,6 +567,16 @@ dependencies = [ "version_check", ] +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation" version = "0.10.1" @@ -588,9 +600,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" dependencies = [ "bitflags 2.9.1", - "core-foundation", + "core-foundation 0.10.1", "core-graphics-types", - "foreign-types", + "foreign-types 0.5.0", "libc", ] @@ -601,7 +613,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ "bitflags 2.9.1", - "core-foundation", + "core-foundation 0.10.1", "libc", ] @@ -888,7 +900,7 @@ dependencies = [ "rustc_version", "toml 0.9.5", "vswhom", - "winreg", + "winreg 0.55.0", ] [[package]] @@ -1030,6 +1042,15 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared 0.1.1", +] + [[package]] name = "foreign-types" version = "0.5.0" @@ -1037,7 +1058,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" dependencies = [ "foreign-types-macros", - "foreign-types-shared", + "foreign-types-shared 0.3.1", ] [[package]] @@ -1051,6 +1072,12 @@ dependencies = [ "syn 2.0.104", ] +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "foreign-types-shared" version = "0.3.1" @@ -1467,6 +1494,25 @@ dependencies = [ "syn 2.0.104", ] +[[package]] +name = "h2" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.12", + "indexmap 2.10.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -1515,6 +1561,17 @@ dependencies = [ "match_token", ] +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http" version = "1.3.1" @@ -1526,6 +1583,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http 0.2.12", + "pin-project-lite", +] + [[package]] name = "http-body" version = "1.0.1" @@ -1533,7 +1601,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http", + "http 1.3.1", ] [[package]] @@ -1544,8 +1612,8 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http", - "http-body", + "http 1.3.1", + "http-body 1.0.1", "pin-project-lite", ] @@ -1555,6 +1623,36 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http 0.2.12", + "http-body 0.4.6", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.5.10", + "tokio", + "tower-service", + "tracing", + "want", +] + [[package]] name = "hyper" version = "1.6.0" @@ -1564,8 +1662,8 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http", - "http-body", + "http 1.3.1", + "http-body 1.0.1", "httparse", "itoa", "pin-project-lite", @@ -1574,6 +1672,19 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper 0.14.32", + "native-tls", + "tokio", + "tokio-native-tls", +] + [[package]] name = "hyper-util" version = "0.1.16" @@ -1585,14 +1696,14 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "http", - "http-body", - "hyper", + "http 1.3.1", + "http-body 1.0.1", + "hyper 1.6.0", "ipnet", "libc", "percent-encoding", "pin-project-lite", - "socket2", + "socket2 0.6.0", "tokio", "tower-service", "tracing", @@ -2112,6 +2223,23 @@ dependencies = [ "windows-sys 0.60.2", ] +[[package]] +name = "native-tls" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "ndk" version = "0.9.0" @@ -2445,6 +2573,50 @@ dependencies = [ "pathdiff", ] +[[package]] +name = "openssl" +version = "0.10.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" +dependencies = [ + "bitflags 2.9.1", + "cfg-if", + "foreign-types 0.3.2", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-sys" +version = "0.9.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "option-ext" version = "0.2.0" @@ -3055,6 +3227,48 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "reqwest" +version = "0.11.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +dependencies = [ + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.32", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 0.1.2", + "system-configuration", + "tokio", + "tokio-native-tls", + "tokio-util", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", + "winreg 0.50.0", +] + [[package]] name = "reqwest" version = "0.12.22" @@ -3065,10 +3279,10 @@ dependencies = [ "bytes", "futures-core", "futures-util", - "http", - "http-body", + "http 1.3.1", + "http-body 1.0.1", "http-body-util", - "hyper", + "hyper 1.6.0", "hyper-util", "js-sys", "log", @@ -3077,7 +3291,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 1.0.2", "tokio", "tokio-util", "tower", @@ -3143,6 +3357,15 @@ dependencies = [ "windows-sys 0.60.2", ] +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + [[package]] name = "rustversion" version = "1.0.21" @@ -3164,6 +3387,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "schemars" version = "0.8.22" @@ -3227,6 +3459,29 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.9.1", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "selectors" version = "0.24.0" @@ -3501,6 +3756,16 @@ version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +[[package]] +name = "socket2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "socket2" version = "0.6.0" @@ -3520,7 +3785,7 @@ dependencies = [ "bytemuck", "cfg_aliases", "core-graphics", - "foreign-types", + "foreign-types 0.5.0", "js-sys", "log", "objc2 0.5.2", @@ -3635,6 +3900,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + [[package]] name = "sync_wrapper" version = "1.0.2" @@ -3655,6 +3926,27 @@ dependencies = [ "syn 2.0.104", ] +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation 0.9.4", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "system-deps" version = "6.2.2" @@ -3675,7 +3967,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49c380ca75a231b87b6c9dd86948f035012e7171d1a7c40a9c2890489a7ffd8a" dependencies = [ "bitflags 2.9.1", - "core-foundation", + "core-foundation 0.10.1", "core-graphics", "crossbeam-channel", "dispatch", @@ -3739,7 +4031,7 @@ dependencies = [ "glob", "gtk", "heck 0.5.0", - "http", + "http 1.3.1", "jni", "libc", "log", @@ -3752,7 +4044,7 @@ dependencies = [ "percent-encoding", "plist", "raw-window-handle", - "reqwest", + "reqwest 0.12.22", "serde", "serde_json", "serde_repr", @@ -3946,7 +4238,7 @@ dependencies = [ "cookie", "dpi", "gtk", - "http", + "http 1.3.1", "jni", "objc2 0.6.1", "objc2-ui-kit", @@ -3966,7 +4258,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe653a2fbbef19fe898efc774bc52c8742576342a33d3d028c189b57eb1d2439" dependencies = [ "gtk", - "http", + "http 1.3.1", "jni", "log", "objc2 0.6.1", @@ -3999,7 +4291,7 @@ dependencies = [ "dunce", "glob", "html5ever", - "http", + "http 1.3.1", "infer", "json-patch", "kuchikiki", @@ -4153,11 +4445,21 @@ dependencies = [ "pin-project-lite", "signal-hook-registry", "slab", - "socket2", + "socket2 0.6.0", "tracing", "windows-sys 0.59.0", ] +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + [[package]] name = "tokio-util" version = "0.7.16" @@ -4282,7 +4584,7 @@ dependencies = [ "futures-core", "futures-util", "pin-project-lite", - "sync_wrapper", + "sync_wrapper 1.0.2", "tokio", "tower-layer", "tower-service", @@ -4297,8 +4599,8 @@ dependencies = [ "bitflags 2.9.1", "bytes", "futures-util", - "http", - "http-body", + "http 1.3.1", + "http-body 1.0.1", "iri-string", "pin-project-lite", "tower", @@ -4501,6 +4803,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version-compare" version = "0.2.0" @@ -4964,6 +5272,24 @@ dependencies = [ "windows-targets 0.42.2", ] +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.59.0" @@ -4997,6 +5323,21 @@ dependencies = [ "windows_x86_64_msvc 0.42.2", ] +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + [[package]] name = "windows-targets" version = "0.52.6" @@ -5054,6 +5395,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" @@ -5072,6 +5419,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" @@ -5090,6 +5443,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -5120,6 +5479,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_i686_msvc" version = "0.52.6" @@ -5138,6 +5503,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" @@ -5156,6 +5527,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" @@ -5174,6 +5551,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -5204,6 +5587,16 @@ dependencies = [ "memchr", ] +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + [[package]] name = "winreg" version = "0.55.0" @@ -5244,7 +5637,7 @@ dependencies = [ "gdkx11", "gtk", "html5ever", - "http", + "http 1.3.1", "javascriptcore-rs", "jni", "kuchikiki", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 73e1847f..b268c274 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -28,3 +28,5 @@ log = "0.4" fern = "0.7.1" dirs = "6.0.0" regex = "1.11.1" +reqwest = { version = "0.11", features = ["json", "stream"] } +futures-util = "0.3" diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index d3e6f92b..4c3cb477 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -9,6 +9,7 @@ mod logger; mod plugin; mod plugins; mod setup; +mod update; mod utils; use crate::execution::{ @@ -23,6 +24,7 @@ use crate::utils::logger::{ use config::{get_app_config, get_config_path, init_config, update_app_config}; use log::info; use plugins::PluginManager; +use update::{check_for_updates, start_update}; fn main() { tauri::Builder::default() @@ -70,7 +72,10 @@ fn main() { // 配置相关命令 get_app_config, update_app_config, - get_config_path + get_config_path, + // 更新相关命令 + check_for_updates, + start_update, ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); diff --git a/src-tauri/src/setup/menus/app.rs b/src-tauri/src/setup/menus/app.rs index 92efcd57..59d25d83 100644 --- a/src-tauri/src/setup/menus/app.rs +++ b/src-tauri/src/setup/menus/app.rs @@ -9,6 +9,8 @@ pub fn create_app_submenu(app: &AppHandle) -> tauri::Result> .id("about") .build(app)?; + let update_item = MenuItemBuilder::new("检查更新").id("update").build(app)?; + let settings_item = MenuItemBuilder::new("设置") .id("settings") .accelerator("CmdOrCtrl+,") @@ -27,6 +29,8 @@ pub fn create_app_submenu(app: &AppHandle) -> tauri::Result> let app_submenu = SubmenuBuilder::new(app, "CodeForge") .item(&about_item) .separator() + .item(&update_item) + .separator() .item(&settings_item) .separator() .item(&restart_item) @@ -41,6 +45,9 @@ pub fn handle_app_menu_event(app: &AppHandle, event_id: &str) { "about" => { let _event = app.emit("show-about", ()); } + "update" => { + let _event = app.emit("show-update", ()); + } "settings" => { let _event = app.emit("show-settings", ()); } diff --git a/src-tauri/src/update.rs b/src-tauri/src/update.rs new file mode 100644 index 00000000..d9fb36e3 --- /dev/null +++ b/src-tauri/src/update.rs @@ -0,0 +1,268 @@ +use log::{error, info}; +use serde::{Deserialize, Serialize}; +use std::time::SystemTime; +use tauri::{AppHandle, Emitter, command}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct UpdateInfo { + pub version: String, + pub date: String, + pub notes: String, + pub size: u64, + pub url: String, +} + +#[derive(Debug, Serialize)] +struct UpdateProgress { + progress: f64, + speed: u64, + status: String, +} + +#[derive(Debug, Deserialize)] +struct GitHubRelease { + tag_name: String, + published_at: String, + body: String, + assets: Vec, +} + +#[derive(Debug, Deserialize)] +struct GitHubAsset { + name: String, + size: u64, + browser_download_url: String, +} + +// 检查更新命令 +#[command] +pub async fn check_for_updates() -> Result, String> { + let repo_owner = "devlive-community"; + let repo_name = "codeforge"; + + info!("检查更新 -> 检查更新中..."); + let current_version = env!("CARGO_PKG_VERSION"); + + match get_latest_release(repo_owner, repo_name).await { + Ok(release) => { + let latest_version = release.tag_name.trim_start_matches('v'); + + if version_is_newer(latest_version, current_version) { + if let Some(asset) = get_platform_asset(&release.assets) { + Ok(Some(UpdateInfo { + version: latest_version.to_string(), + date: release.published_at, + notes: release.body, + size: asset.size, + url: asset.browser_download_url.clone(), + })) + } else { + error!("检查更新 -> 未找到适合当前平台的更新文件"); + Err("未找到适合当前平台的更新文件".to_string()) + } + } else { + info!("检查更新 -> 没有更新"); + Ok(None) + } + } + Err(e) => Err(format!("检查更新失败: {}", e)), + } +} + +// 开始更新命令 +#[command] +pub async fn start_update(update_info: UpdateInfo, app_handle: AppHandle) -> Result<(), String> { + let app_handle_clone = app_handle.clone(); + info!("检查更新 -> 开始更新: {}", update_info.version); + + tokio::spawn(async move { + let app_handle_for_error = app_handle_clone.clone(); + if let Err(e) = do_update(update_info, app_handle_clone).await { + info!("检查更新 -> 更新失败: {}", e); + let error_data = serde_json::json!({ "error": e.to_string() }); + let _ = app_handle_for_error.emit("update-error", &error_data); + } + }); + + Ok(()) +} + +// 获取最新版本 +async fn get_latest_release( + owner: &str, + repo: &str, +) -> Result> { + let url = format!( + "https://api.github.com/repos/{}/{}/releases/latest", + owner, repo + ); + info!("检查更新 -> 获取最新版本: {}", url); + + let client = reqwest::Client::new(); + let response = client + .get(&url) + .header("User-Agent", "CodeForge-Updater") + .send() + .await?; + + if !response.status().is_success() { + error!("检查更新 -> 获取最新版本失败: {}", response.status()); + return Err(format!("GitHub API 错误: {}", response.status()).into()); + } + + let release: GitHubRelease = response.json().await?; + info!("检查更新 -> 最新版本: {}", release.tag_name); + Ok(release) +} + +// 查找平台对应的文件 +fn get_platform_asset(assets: &[GitHubAsset]) -> Option<&GitHubAsset> { + let os = std::env::consts::OS; + info!("检查更新 -> 当前平台: {}", os); + + for asset in assets { + let name = asset.name.to_lowercase(); + + let matches = match os { + "windows" => name.contains("windows") || name.contains("win") || name.ends_with(".exe"), + "macos" => name.contains("macos") || name.contains("darwin") || name.ends_with(".dmg"), + "linux" => name.contains("linux") || name.ends_with(".appimage"), + _ => false, + }; + + if matches { + info!("检查更新 -> 匹配更新文件: {}", asset.name); + return Some(asset); + } + } + + // 如果没找到匹配的,返回第一个 + assets.first() +} + +// 版本比较 +fn version_is_newer(new_version: &str, current_version: &str) -> bool { + info!( + "检查更新 -> 当前版本: {} 最新版本: {}", + current_version, new_version + ); + let new_parts: Vec = new_version + .split('.') + .filter_map(|s| s.parse().ok()) + .collect(); + let current_parts: Vec = current_version + .split('.') + .filter_map(|s| s.parse().ok()) + .collect(); + + for i in 0..std::cmp::max(new_parts.len(), current_parts.len()) { + let new_part = new_parts.get(i).unwrap_or(&0); + let current_part = current_parts.get(i).unwrap_or(&0); + + match new_part.cmp(current_part) { + std::cmp::Ordering::Greater => return true, + std::cmp::Ordering::Less => return false, + std::cmp::Ordering::Equal => continue, + } + } + + false +} + +// 执行更新 +async fn do_update( + update_info: UpdateInfo, + app_handle: AppHandle, +) -> Result<(), Box> { + // 创建临时目录 + info!("检查更新 -> 创建临时目录"); + let temp_dir = std::env::temp_dir().join("codeforge_update"); + std::fs::create_dir_all(&temp_dir)?; + + let file_name = format!("update_{}.exe", update_info.version); + let download_path = temp_dir.join(&file_name); + + info!("检查更新 -> 下载更新文件: {}", update_info.url); + // 下载文件 + let client = reqwest::Client::new(); + let response = client.get(&update_info.url).send().await?; + + if !response.status().is_success() { + error!("检查更新 -> 下载失败: {}", response.status()); + return Err(format!("下载失败: {}", response.status()).into()); + } + + let total_size = response.content_length().unwrap_or(update_info.size); + let mut downloaded = 0u64; + let mut file = std::fs::File::create(&download_path)?; + let start_time = SystemTime::now(); + + use std::io::Write; + let mut stream = response.bytes_stream(); + use futures_util::StreamExt; + + info!("检查更新 -> 开始下载"); + while let Some(chunk) = stream.next().await { + let chunk = chunk?; + file.write_all(&chunk)?; + downloaded += chunk.len() as u64; + + // 计算进度 + let progress = (downloaded as f64 / total_size as f64) * 70.0; + let elapsed = start_time.elapsed().unwrap_or_default().as_secs_f64(); + let speed = if elapsed > 0.0 { + (downloaded as f64 / elapsed) as u64 + } else { + 0 + }; + + info!("检查更新 -> 下载进度: {:.2}%", progress); + // 发送进度 + let progress_data = UpdateProgress { + progress, + speed, + status: "downloading".to_string(), + }; + let _ = app_handle.emit("update-progress", &progress_data); + + // 避免过于频繁的更新 + if downloaded % (512 * 1024) == 0 { + tokio::time::sleep(tokio::time::Duration::from_millis(50)).await; + } + } + + file.flush()?; + drop(file); + + info!("检查更新 -> 安装更新文件: {}", update_info.version); + for i in 71..=100 { + let progress_data = UpdateProgress { + progress: i as f64, + speed: 0, + status: "installing".to_string(), + }; + + info!("检查更新 -> 安装进度: {:.2}%", progress_data.progress); + let _ = app_handle.emit("update-progress", &progress_data); + tokio::time::sleep(tokio::time::Duration::from_millis(30)).await; + } + + // 执行安装 + do_install(&download_path).await?; + + // 完成 + let complete_data = serde_json::json!({}); + let _ = app_handle.emit("update-complete", &complete_data); + + Ok(()) +} + +// 安装更新 +async fn do_install( + update_path: &std::path::Path, +) -> Result<(), Box> { + let current_exe = std::env::current_exe()?; + std::fs::copy(update_path, ¤t_exe)?; + + Ok(()) +} diff --git a/src/App.vue b/src/App.vue index ebca0f15..fba64584 100644 --- a/src/App.vue +++ b/src/App.vue @@ -4,8 +4,8 @@ :env-installed="envInfo.installed" :supported-languages="supportedLanguages" :current-language="currentLanguage" - @run-code="runCode" - @stop-code="stopCode" + @run-code="() => runCode(currentLanguage, envInfo.installed, envInfo.language)" + @stop-code="() => stopCode(currentLanguage)" @clear-output="clearOutput" @language-change="handleLanguageChange" @show-settings="showSettings = true"> @@ -46,15 +46,16 @@ + + + diff --git a/src/components/AppHeader.vue b/src/components/AppHeader.vue index 91be1e81..cbbc8530 100644 --- a/src/components/AppHeader.vue +++ b/src/components/AppHeader.vue @@ -1,40 +1,35 @@