feat: portable version of hoppscotch-agent (#4468)

This commit is contained in:
Shreyas
2024-10-24 15:46:20 +05:30
committed by GitHub
parent f52219bb95
commit bd7bd97809
14 changed files with 1018 additions and 148 deletions

View File

@@ -3,11 +3,10 @@
"devenv": {
"locked": {
"dir": "src/modules",
"lastModified": 1727098005,
"lastModified": 1729277673,
"owner": "cachix",
"repo": "devenv",
"rev": "f318d27a4637aff765a378106d82dfded124c3b3",
"treeHash": "c77efa71afb25615542aed9d7e805a3b6216b6a2",
"rev": "3c3ab087b53d3e4699a43018ac71b5e1091ed73d",
"type": "github"
},
"original": {
@@ -25,11 +24,10 @@
"rust-analyzer-src": "rust-analyzer-src"
},
"locked": {
"lastModified": 1727159616,
"lastModified": 1728973961,
"owner": "nix-community",
"repo": "fenix",
"rev": "4306d494985e00719573bbdeb863c27c6d83dc9c",
"treeHash": "53136d2b5e6c46a3abe585771e60cd0646f69cf7",
"rev": "d6a9ff4d1e60c347a23bc96ccdb058d37a810541",
"type": "github"
},
"original": {
@@ -45,7 +43,6 @@
"owner": "edolstra",
"repo": "flake-compat",
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
"treeHash": "2addb7b71a20a25ea74feeaf5c2f6a6b30898ecb",
"type": "github"
},
"original": {
@@ -66,7 +63,6 @@
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
"treeHash": "ca14199cabdfe1a06a7b1654c76ed49100a689f9",
"type": "github"
},
"original": {
@@ -77,11 +73,10 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1727089097,
"lastModified": 1729265718,
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "568bfef547c14ca438c56a0bece08b8bb2b71a9c",
"treeHash": "2c4d922ed00a8d8d8b136ad40a904239e071dfc3",
"rev": "ccc0c2126893dd20963580b6478d1a10a4512185",
"type": "github"
},
"original": {
@@ -93,11 +88,10 @@
},
"nixpkgs-stable": {
"locked": {
"lastModified": 1726969270,
"lastModified": 1729181673,
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "23cbb250f3bf4f516a2d0bf03c51a30900848075",
"treeHash": "f150876866adcc3af432c103db116c2f516f49b1",
"rev": "4eb33fe664af7b41a4c446f87d20c9a0a6321fa3",
"type": "github"
},
"original": {
@@ -117,11 +111,10 @@
"nixpkgs-stable": "nixpkgs-stable"
},
"locked": {
"lastModified": 1726745158,
"lastModified": 1729104314,
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"rev": "4e743a6920eab45e8ba0fbe49dc459f1423a4b74",
"treeHash": "56fbe2a9610b3ad9163a74011131e7624f6b3b81",
"rev": "3c3e88f0f544d6bb54329832616af7eb971b6be6",
"type": "github"
},
"original": {
@@ -141,11 +134,10 @@
"rust-analyzer-src": {
"flake": false,
"locked": {
"lastModified": 1727104575,
"lastModified": 1729259624,
"owner": "rust-lang",
"repo": "rust-analyzer",
"rev": "3d0343251fe084b335b55c17a52bb4a3527b1bd0",
"treeHash": "67f4408ff2f6d7099cecc1dac6389b199fd980f9",
"rev": "3ddfb0da474bdf243a655a5d785de9b59c7f1397",
"type": "github"
},
"original": {

View File

@@ -0,0 +1,25 @@
# Enable static linking for C runtime library on Windows.
#
# Rust uses the msvc toolchain on Windows,
# which by default dynamically links the C runtime (CRT) to the binary.
#
# This creates a runtime dependency on the Visual C++ Redistributable (`vcredist`),
# meaning the target machine must have `vcredist` installed for the application to run.
#
# Since `portable` version doesn't have an installer,
# we can't rely on it to install dependencies, so this config.
#
# Basically:
# - The `+crt-static` flag instructs the Rust compiler to statically link the C runtime for Windows builds.\
# - To avoids runtime errors related to missing `vcredist` installations.
# - Results in a larger binary size because the runtime is bundled directly into the executable.
#
# For MSVC targets specifically, it will compile code with `/MT` or static linkage.
# See: - RFC 1721: https://rust-lang.github.io/rfcs/1721-crt-static.html
# - Rust Reference - Runtime: https://doc.rust-lang.org/reference/runtime.html
# - MSVC Linking Options: https://docs.microsoft.com/en-us/cpp/build/reference/md-mt-ld-use-run-time-library
# - Rust Issue #37406: https://github.com/rust-lang/rust/issues/37406
# - Tauri Issue #3048: https://github.com/tauri-apps/tauri/issues/3048
# - Rust Linkage: https://doc.rust-lang.org/reference/linkage.html
[target.'cfg(windows)']
rustflags = ["-C", "target-feature=+crt-static"]

View File

@@ -155,6 +155,12 @@ dependencies = [
"derive_arbitrary",
]
[[package]]
name = "ascii"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16"
[[package]]
name = "ashpd"
version = "0.9.2"
@@ -165,7 +171,7 @@ dependencies = [
"futures-channel",
"futures-util",
"rand 0.8.5",
"raw-window-handle",
"raw-window-handle 0.6.2",
"serde",
"serde_repr",
"tokio",
@@ -210,6 +216,43 @@ dependencies = [
"pin-project-lite",
]
[[package]]
name = "async-compression"
version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0cb8f1d480b0ea3783ab015936d2a55c87e219676f0c0b7dec61494043f21857"
dependencies = [
"flate2",
"futures-core",
"memchr",
"pin-project-lite",
"tokio",
]
[[package]]
name = "async-executor"
version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec"
dependencies = [
"async-task",
"concurrent-queue",
"fastrand",
"futures-lite",
"slab",
]
[[package]]
name = "async-fs"
version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a"
dependencies = [
"async-lock",
"blocking",
"futures-lite",
]
[[package]]
name = "async-io"
version = "2.3.4"
@@ -708,6 +751,22 @@ dependencies = [
"inout",
]
[[package]]
name = "cocoa"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6140449f97a6e97f9511815c5632d84c8aacf8ac271ad77c559218161a1373c"
dependencies = [
"bitflags 1.3.2",
"block",
"cocoa-foundation 0.1.2",
"core-foundation 0.9.4",
"core-graphics 0.23.2",
"foreign-types 0.5.0",
"libc",
"objc",
]
[[package]]
name = "cocoa"
version = "0.26.0"
@@ -716,14 +775,28 @@ checksum = "f79398230a6e2c08f5c9760610eb6924b52aa9e7950a619602baba59dcbbdbb2"
dependencies = [
"bitflags 2.6.0",
"block",
"cocoa-foundation",
"core-foundation",
"core-graphics",
"cocoa-foundation 0.2.0",
"core-foundation 0.10.0",
"core-graphics 0.24.0",
"foreign-types 0.5.0",
"libc",
"objc",
]
[[package]]
name = "cocoa-foundation"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7"
dependencies = [
"bitflags 1.3.2",
"block",
"core-foundation 0.9.4",
"core-graphics-types 0.1.3",
"libc",
"objc",
]
[[package]]
name = "cocoa-foundation"
version = "0.2.0"
@@ -732,8 +805,8 @@ checksum = "e14045fb83be07b5acf1c0884b2180461635b433455fa35d1cd6f17f1450679d"
dependencies = [
"bitflags 2.6.0",
"block",
"core-foundation",
"core-graphics-types",
"core-foundation 0.10.0",
"core-graphics-types 0.2.0",
"libc",
"objc",
]
@@ -779,6 +852,44 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
[[package]]
name = "cookie"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747"
dependencies = [
"percent-encoding",
"time",
"version_check",
]
[[package]]
name = "cookie_store"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4934e6b7e8419148b6ef56950d277af8561060b56afd59e2aadf98b59fce6baa"
dependencies = [
"cookie",
"idna 0.5.0",
"log",
"publicsuffix",
"serde",
"serde_derive",
"serde_json",
"time",
"url",
]
[[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.0"
@@ -795,6 +906,19 @@ version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "core-graphics"
version = "0.23.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081"
dependencies = [
"bitflags 1.3.2",
"core-foundation 0.9.4",
"core-graphics-types 0.1.3",
"foreign-types 0.5.0",
"libc",
]
[[package]]
name = "core-graphics"
version = "0.24.0"
@@ -802,12 +926,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1"
dependencies = [
"bitflags 2.6.0",
"core-foundation",
"core-graphics-types",
"core-foundation 0.10.0",
"core-graphics-types 0.2.0",
"foreign-types 0.5.0",
"libc",
]
[[package]]
name = "core-graphics-types"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf"
dependencies = [
"bitflags 1.3.2",
"core-foundation 0.9.4",
"libc",
]
[[package]]
name = "core-graphics-types"
version = "0.2.0"
@@ -815,7 +950,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb"
dependencies = [
"bitflags 2.6.0",
"core-foundation",
"core-foundation 0.10.0",
"libc",
]
@@ -1010,6 +1145,12 @@ dependencies = [
"serde",
]
[[package]]
name = "data-url"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a"
[[package]]
name = "deranged"
version = "0.3.11"
@@ -1083,6 +1224,16 @@ dependencies = [
"dirs-sys 0.4.1",
]
[[package]]
name = "dirs-next"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
dependencies = [
"cfg-if",
"dirs-sys-next",
]
[[package]]
name = "dirs-sys"
version = "0.3.7"
@@ -1106,6 +1257,17 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "dirs-sys-next"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
dependencies = [
"libc",
"redox_users",
"winapi",
]
[[package]]
name = "dispatch"
version = "0.2.0"
@@ -1197,6 +1359,12 @@ version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125"
[[package]]
name = "either"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "embed-resource"
version = "2.5.0"
@@ -1932,6 +2100,15 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "home"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "hoppscotch-agent"
version = "0.1.1"
@@ -1947,6 +2124,7 @@ dependencies = [
"lazy_static",
"log",
"mockito",
"native-dialog",
"rand 0.8.5",
"serde",
"serde_json",
@@ -1954,14 +2132,18 @@ dependencies = [
"tauri-build",
"tauri-plugin-autostart",
"tauri-plugin-dialog",
"tauri-plugin-http",
"tauri-plugin-shell",
"tauri-plugin-single-instance",
"tauri-plugin-store",
"tauri-plugin-updater",
"tempfile",
"thiserror",
"tokio",
"tokio-util",
"tower-http",
"uuid",
"winreg 0.52.0",
"x25519-dalek",
]
@@ -2145,6 +2327,16 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "idna"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6"
dependencies = [
"unicode-bidi",
"unicode-normalization",
]
[[package]]
name = "idna"
version = "0.5.0"
@@ -2247,6 +2439,15 @@ version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "itertools"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "0.4.8"
@@ -2545,6 +2746,12 @@ version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "minisign-verify"
version = "0.2.2"
@@ -2617,6 +2824,29 @@ dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "native-dialog"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84e7038885d2aeab236bd60da9e159a5967b47cde3292da3b15ff1bec27c039f"
dependencies = [
"ascii",
"block",
"cocoa 0.25.0",
"core-foundation 0.9.4",
"dirs-next",
"objc",
"objc-foundation",
"objc_id",
"once_cell",
"raw-window-handle 0.5.2",
"thiserror",
"versions",
"wfd",
"which",
"winapi",
]
[[package]]
name = "ndk"
version = "0.9.0"
@@ -2628,7 +2858,7 @@ dependencies = [
"log",
"ndk-sys",
"num_enum",
"raw-window-handle",
"raw-window-handle 0.6.2",
"thiserror",
]
@@ -2671,6 +2901,16 @@ version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
[[package]]
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]]
name = "num-conv"
version = "0.1.0"
@@ -2716,6 +2956,17 @@ dependencies = [
"malloc_buf",
]
[[package]]
name = "objc-foundation"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
dependencies = [
"block",
"objc",
"objc_id",
]
[[package]]
name = "objc-sys"
version = "0.3.5"
@@ -2935,6 +3186,15 @@ dependencies = [
"objc2-foundation",
]
[[package]]
name = "objc_id"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b"
dependencies = [
"objc",
]
[[package]]
name = "object"
version = "0.36.5"
@@ -3409,6 +3669,22 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "psl-types"
version = "2.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac"
[[package]]
name = "publicsuffix"
version = "2.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96a8c1bda5ae1af7f99a2962e49df150414a43d62404644d98dd5c3a93d07457"
dependencies = [
"idna 0.3.0",
"psl-types",
]
[[package]]
name = "quick-xml"
version = "0.32.0"
@@ -3565,6 +3841,12 @@ dependencies = [
"rand_core 0.5.1",
]
[[package]]
name = "raw-window-handle"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9"
[[package]]
name = "raw-window-handle"
version = "0.6.2"
@@ -3626,10 +3908,15 @@ version = "0.12.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b"
dependencies = [
"async-compression",
"base64 0.22.1",
"bytes",
"cookie",
"cookie_store",
"encoding_rs",
"futures-core",
"futures-util",
"h2",
"http",
"http-body",
"http-body-util",
@@ -3651,6 +3938,7 @@ dependencies = [
"serde_json",
"serde_urlencoded",
"sync_wrapper 1.0.1",
"system-configuration",
"tokio",
"tokio-rustls",
"tokio-util",
@@ -3680,7 +3968,7 @@ dependencies = [
"objc2",
"objc2-app-kit",
"objc2-foundation",
"raw-window-handle",
"raw-window-handle 0.6.2",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
@@ -4121,14 +4409,14 @@ checksum = "18051cdd562e792cad055119e0cdb2cfc137e44e3987532e0f9659a77931bb08"
dependencies = [
"bytemuck",
"cfg_aliases",
"core-graphics",
"core-graphics 0.24.0",
"foreign-types 0.5.0",
"js-sys",
"log",
"objc2",
"objc2-foundation",
"objc2-quartz-core",
"raw-window-handle",
"raw-window-handle 0.6.2",
"redox_syscall",
"wasm-bindgen",
"web-sys",
@@ -4265,6 +4553,27 @@ dependencies = [
"futures-core",
]
[[package]]
name = "system-configuration"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
dependencies = [
"bitflags 2.6.0",
"core-foundation 0.9.4",
"system-configuration-sys",
]
[[package]]
name = "system-configuration-sys"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "system-deps"
version = "6.2.2"
@@ -4285,9 +4594,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0dbbebe82d02044dfa481adca1550d6dd7bd16e086bc34fa0fbecceb5a63751"
dependencies = [
"bitflags 2.6.0",
"cocoa",
"core-foundation",
"core-graphics",
"cocoa 0.26.0",
"core-foundation 0.10.0",
"core-graphics 0.24.0",
"crossbeam-channel",
"dispatch",
"dlopen2",
@@ -4306,7 +4615,7 @@ dependencies = [
"objc",
"once_cell",
"parking_lot",
"raw-window-handle",
"raw-window-handle 0.6.2",
"scopeguard",
"tao-macros",
"unicode-segmentation",
@@ -4373,7 +4682,7 @@ dependencies = [
"objc2-foundation",
"percent-encoding",
"plist",
"raw-window-handle",
"raw-window-handle 0.6.2",
"reqwest",
"serde",
"serde_json",
@@ -4498,7 +4807,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4307310e1d2c09ab110235834722e7c2b85099b683e1eb7342ab351b0be5ada3"
dependencies = [
"log",
"raw-window-handle",
"raw-window-handle 0.6.2",
"rfd",
"serde",
"serde_json",
@@ -4530,6 +4839,28 @@ dependencies = [
"uuid",
]
[[package]]
name = "tauri-plugin-http"
version = "2.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c752aee1b00ec3c4d4f440095995d9bd2c640b478f2067d1fba388900b82eb96"
dependencies = [
"data-url",
"http",
"regex",
"reqwest",
"schemars",
"serde",
"serde_json",
"tauri",
"tauri-plugin",
"tauri-plugin-fs",
"thiserror",
"tokio",
"url",
"urlpattern",
]
[[package]]
name = "tauri-plugin-shell"
version = "2.0.2"
@@ -4551,6 +4882,21 @@ dependencies = [
"tokio",
]
[[package]]
name = "tauri-plugin-single-instance"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a25ac834491d089699a2bc9266a662faf373c9f779f05a2235bc6e4d9e61769a"
dependencies = [
"log",
"serde",
"serde_json",
"tauri",
"thiserror",
"windows-sys 0.59.0",
"zbus",
]
[[package]]
name = "tauri-plugin-store"
version = "2.1.0"
@@ -4607,7 +4953,7 @@ dependencies = [
"gtk",
"http",
"jni",
"raw-window-handle",
"raw-window-handle 0.6.2",
"serde",
"serde_json",
"tauri-utils",
@@ -4630,7 +4976,7 @@ dependencies = [
"objc2-app-kit",
"objc2-foundation",
"percent-encoding",
"raw-window-handle",
"raw-window-handle 0.6.2",
"softbuffer",
"tao",
"tauri-runtime",
@@ -4977,7 +5323,7 @@ version = "0.19.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c92af36a182b46206723bdf8a7942e20838cde1cf062e5b97854d57eb01763b"
dependencies = [
"core-graphics",
"core-graphics 0.24.0",
"crossbeam-channel",
"dirs 5.0.1",
"libappindicator",
@@ -5112,7 +5458,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c"
dependencies = [
"form_urlencoded",
"idna",
"idna 0.5.0",
"percent-encoding",
"serde",
]
@@ -5179,6 +5525,16 @@ version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "versions"
version = "5.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c73a36bc44e3039f51fbee93e39f41225f6b17b380eb70cc2aab942df06b34dd"
dependencies = [
"itertools",
"nom",
]
[[package]]
name = "vswhom"
version = "0.1.0"
@@ -5469,6 +5825,28 @@ dependencies = [
"windows-core 0.58.0",
]
[[package]]
name = "wfd"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e713040b67aae5bf1a0ae3e1ebba8cc29ab2b90da9aa1bff6e09031a8a41d7a8"
dependencies = [
"libc",
"winapi",
]
[[package]]
name = "which"
version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
dependencies = [
"either",
"home",
"once_cell",
"rustix",
]
[[package]]
name = "winapi"
version = "0.3.9"
@@ -5509,7 +5887,7 @@ dependencies = [
"objc2",
"objc2-app-kit",
"objc2-foundation",
"raw-window-handle",
"raw-window-handle 0.6.2",
"windows-sys 0.59.0",
"windows-version",
]
@@ -5876,7 +6254,7 @@ dependencies = [
"objc2-web-kit",
"once_cell",
"percent-encoding",
"raw-window-handle",
"raw-window-handle 0.6.2",
"sha2",
"soup3",
"tao-macros",
@@ -5951,9 +6329,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b8e3d6ae3342792a6cc2340e4394334c7402f3d793b390d2c5494a4032b3030"
dependencies = [
"async-broadcast",
"async-executor",
"async-fs",
"async-io",
"async-lock",
"async-process",
"async-recursion",
"async-task",
"async-trait",
"blocking",
"derivative",
"enumflags2",
"event-listener",

View File

@@ -17,7 +17,7 @@ tauri-build = { version = "2.0.1", features = [] }
[dependencies]
tauri = { version = "2.0.4", features = ["tray-icon", "image-png"] }
tauri-plugin-shell = "2.0.1"
tauri-plugin-autostart = "2.0.1"
tauri-plugin-autostart = { version = "2.0.1", optional = true }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
tokio = { version = "1.40.0", features = ["full"] }
@@ -40,6 +40,17 @@ aes-gcm = { version = "0.10.3", features = ["aes"] }
tauri-plugin-updater = "2.0.2"
tauri-plugin-dialog = "2.0.1"
lazy_static = "1.5.0"
tauri-plugin-single-instance = "2.0.1"
tauri-plugin-http = { version = "2.0.1", features = ["gzip"] }
native-dialog = "0.7.0"
[target.'cfg(windows)'.dependencies]
tempfile = { version = "3.13.0" }
winreg = { version = "0.52.0", optional = true }
[dev-dependencies]
mockito = "1.5.0"
[features]
default = ["tauri-plugin-autostart"]
portable = ["winreg"]

View File

@@ -4,6 +4,17 @@
"description": "Capability for the main window",
"windows": ["main", "test"],
"permissions": [
{
"identifier": "http:default",
"allow": [
{
"url": "https://*.tauri.app"
},
{
"url": "https://*.microsoft.*"
}
]
},
"core:default",
"shell:allow-open",
"core:window:allow-close",

View File

@@ -0,0 +1,58 @@
use native_dialog::{MessageDialog, MessageType};
pub fn panic(msg: &str) {
const FATAL_ERROR: &str = "Fatal error";
MessageDialog::new()
.set_type(MessageType::Error)
.set_title(FATAL_ERROR)
.set_text(msg)
.show_alert()
.unwrap_or_default();
log::error!("{}: {}", FATAL_ERROR, msg);
panic!("{}: {}", FATAL_ERROR, msg);
}
pub fn info(msg: &str) {
log::info!("{}", msg);
MessageDialog::new()
.set_type(MessageType::Info)
.set_title("Info")
.set_text(msg)
.show_alert()
.unwrap_or_default();
}
pub fn warn(msg: &str) {
log::warn!("{}", msg);
MessageDialog::new()
.set_type(MessageType::Warning)
.set_title("Warning")
.set_text(msg)
.show_alert()
.unwrap_or_default();
}
pub fn error(msg: &str) {
log::error!("{}", msg);
MessageDialog::new()
.set_type(MessageType::Error)
.set_title("Error")
.set_text(msg)
.show_alert()
.unwrap_or_default();
}
pub fn confirm(title: &str, msg: &str, icon: MessageType) -> bool {
MessageDialog::new()
.set_type(icon)
.set_title(title)
.set_text(msg)
.show_confirm()
.unwrap_or_default()
}

View File

@@ -1,4 +1,5 @@
pub mod controller;
pub mod dialog;
pub mod error;
pub mod model;
pub mod route;
@@ -7,13 +8,17 @@ pub mod state;
pub mod tray;
pub mod updater;
pub mod util;
pub mod webview;
use state::AppState;
use log::{error, info};
use std::sync::Arc;
use tauri::{Listener, Manager, WebviewWindowBuilder};
use tauri::{Emitter, Listener, Manager, WebviewWindowBuilder};
use tauri_plugin_updater::UpdaterExt;
use tokio_util::sync::CancellationToken;
use model::Payload;
use state::AppState;
#[tauri::command]
async fn get_otp(state: tauri::State<'_, Arc<AppState>>) -> Result<Option<String>, ()> {
Ok(state.active_registration_code.read().await.clone())
@@ -23,53 +28,79 @@ async fn get_otp(state: tauri::State<'_, Arc<AppState>>) -> Result<Option<String
pub fn run() {
env_logger::init();
// The installer takes care of installing `WebView`,
// this check is only required for portable variant.
#[cfg(all(feature = "portable", windows))]
webview::init_webview();
let cancellation_token = CancellationToken::new();
let server_cancellation_token = cancellation_token.clone();
tauri::Builder::default()
// NOTE: Currently, plugins run in the order they were added in to the builder,
// so `tauri_plugin_single_instance` needs to be registered first.
// See: https://github.com/tauri-apps/plugins-workspace/tree/v2/plugins/single-instance
.plugin(tauri_plugin_single_instance::init(|app, args, cwd| {
info!("{}, {args:?}, {cwd}", app.package_info().name);
app.emit("single-instance", Payload::new(args, cwd))
.unwrap();
// Application is already running, bring it to foreground.
if let Some(window) = app.get_webview_window("main") {
let _ = window.show();
let _ = window.set_focus();
} else {
error!("Failed to get `main` window");
}
}))
.plugin(tauri_plugin_store::Builder::new().build())
.setup(move |app| {
let app_handle = app.app_handle();
#[cfg(desktop)]
#[cfg(all(desktop, not(feature = "portable")))]
{
use tauri_plugin_autostart::MacosLauncher;
use tauri_plugin_autostart::ManagerExt;
let _ = app.handle().plugin(tauri_plugin_autostart::init(
MacosLauncher::LaunchAgent,
None
None,
));
let autostart_manager = app.autolaunch();
println!("autostart enabled: {}", autostart_manager.is_enabled().unwrap());
println!(
"autostart enabled: {}",
autostart_manager.is_enabled().unwrap()
);
if !autostart_manager.is_enabled().unwrap() {
let _ = autostart_manager.enable();
println!("autostart updated: {}", autostart_manager.is_enabled().unwrap());
println!(
"autostart updated: {}",
autostart_manager.is_enabled().unwrap()
);
}
};
#[cfg(desktop)]
{
let _ = app.handle()
.plugin(tauri_plugin_updater::Builder::new() .build());
let _ = app
.handle()
.plugin(tauri_plugin_updater::Builder::new().build());
let _ = app.handle()
.plugin(tauri_plugin_dialog::init());
let _ = app.handle().plugin(tauri_plugin_dialog::init());
let updater = app.updater_builder()
.build()
.unwrap();
let updater = app.updater_builder().build().unwrap();
let app_handle_ref = app_handle.clone();
let app_handle_ref = app_handle.clone();
tauri::async_runtime::spawn_blocking(|| {
tauri::async_runtime::block_on(async {
tauri::async_runtime::spawn_blocking(|| {
tauri::async_runtime::block_on(async {
updater::check_and_install_updates(app_handle_ref, updater).await;
})
});
})
});
};
let app_state = Arc::new(AppState::new(app_handle.clone())?);
@@ -81,8 +112,7 @@ pub fn run() {
let server_app_handle = app_handle.clone();
tauri::async_runtime::spawn(async move {
server::run_server(app_state, server_cancellation_token, server_app_handle)
.await;
server::run_server(app_state, server_cancellation_token, server_app_handle).await;
});
#[cfg(all(desktop))]
@@ -94,8 +124,9 @@ pub fn run() {
// Blocks the app from populating the macOS dock
#[cfg(target_os = "macos")]
{
app_handle.set_activation_policy(tauri::ActivationPolicy::Accessory)
.unwrap();
app_handle
.set_activation_policy(tauri::ActivationPolicy::Accessory)
.unwrap();
};
let app_handle_ref = app_handle.clone();
@@ -103,36 +134,33 @@ pub fn run() {
app_handle.listen("registration_received", move |_| {
WebviewWindowBuilder::from_config(
&app_handle_ref,
&app_handle_ref.config().app.windows[0]
&app_handle_ref.config().app.windows[0],
)
.unwrap()
.build()
.unwrap()
.show()
.unwrap();
.unwrap()
.build()
.unwrap()
.show()
.unwrap();
});
Ok(())
})
.manage(cancellation_token)
.on_window_event(|window, event| {
match &event {
tauri::WindowEvent::CloseRequested { .. } => {
let app_state = window.state::<Arc<AppState>>();
match &event {
tauri::WindowEvent::CloseRequested { .. } => {
let app_state = window.state::<Arc<AppState>>();
let mut current_code =
app_state.active_registration_code.blocking_write();
let mut current_code = app_state.active_registration_code.blocking_write();
if current_code.is_some() {
*current_code = None;
}
},
_ => {}
};
if current_code.is_some() {
*current_code = None;
}
}
_ => {}
};
})
.invoke_handler(tauri::generate_handler![
get_otp
])
.invoke_handler(tauri::generate_handler![get_otp])
.build(tauri::generate_context!())
.expect("error while building tauri application")
.run(|app_handle, event| match event {

View File

@@ -1,6 +1,19 @@
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
/// Single instance payload.
#[derive(Clone, Serialize)]
pub struct Payload {
args: Vec<String>,
cwd: String,
}
impl Payload {
pub fn new(args: Vec<String>, cwd: String) -> Self {
Self { args, cwd }
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct HandshakeResponse {
#[allow(non_snake_case)]

View File

@@ -1,39 +1,67 @@
#[cfg(desktop)]
use tauri::Manager;
use tauri_plugin_dialog::DialogExt;
use tauri_plugin_dialog::MessageDialogButtons;
use tauri_plugin_dialog::MessageDialogKind;
#[cfg(feature = "portable")]
use {crate::dialog, crate::util, native_dialog::MessageType};
pub async fn check_and_install_updates(
app: tauri::AppHandle,
updater: tauri_plugin_updater::Updater,
) {
use tauri::Manager;
use tauri_plugin_dialog::DialogExt;
use tauri_plugin_dialog::MessageDialogButtons;
use tauri_plugin_dialog::MessageDialogKind;
let update = updater.check().await;
if let Ok(Some(update)) = update {
let do_update = app
.dialog()
.message(format!(
"Update to {} is available!{}",
update.version,
update
.body
.clone()
.map(|body| format!("\n\nRelease Notes: {}", body))
.unwrap_or("".into())
))
.title("Update Available")
.kind(MessageDialogKind::Info)
.buttons(MessageDialogButtons::OkCancelCustom(
"Update".to_string(),
"Cancel".to_string(),
))
.blocking_show();
#[cfg(not(feature = "portable"))]
{
let do_update = app
.dialog()
.message(format!(
"Update to {} is available!{}",
update.version,
update
.body
.clone()
.map(|body| format!("\n\nRelease Notes: {}", body))
.unwrap_or("".into())
))
.title("Update Available")
.kind(MessageDialogKind::Info)
.buttons(MessageDialogButtons::OkCancelCustom(
"Update".to_string(),
"Cancel".to_string(),
))
.blocking_show();
if do_update {
let _ = update.download_and_install(|_, _| {}, || {}).await;
if do_update {
let _ = update.download_and_install(|_, _| {}, || {}).await;
tauri::process::restart(&app.env());
tauri::process::restart(&app.env());
}
}
#[cfg(feature = "portable")]
{
let download_url = "https://hoppscotch.com/download";
let message = format!(
"An update (version {}) is available for the Hoppscotch Agent.\n\nPlease download the latest portable version from our website.",
update.version
);
dialog::info(&message);
if dialog::confirm(
"Open Download Page",
"Would you like to open the download page in your browser?",
MessageType::Info,
) {
if let None = util::open_link(download_url) {
dialog::error(&format!(
"Failed to open download page. Please visit {}",
download_url
));
}
}
}
}
}

View File

@@ -1,40 +1,86 @@
use std::process::{Command, Stdio};
use aes_gcm::{aead::Aead, AeadCore, Aes256Gcm, KeyInit};
use axum::{body::Body, response::{IntoResponse, Response}};
use axum::{
body::Body,
response::{IntoResponse, Response},
};
use rand::rngs::OsRng;
use serde::Serialize;
#[derive(Debug)]
pub struct EncryptedJson<T: Serialize> {
pub key_b16: String,
pub data: T
}
pub fn open_link(link: &str) -> Option<()> {
let null = Stdio::null();
impl<T> IntoResponse for EncryptedJson<T> where T: Serialize {
fn into_response(self) -> Response {
let serialized_response = serde_json::to_vec(&self.data)
.expect("Failed serializing response to vec for encryption");
#[cfg(target_os = "windows")]
{
Command::new("rundll32")
.args(["url.dll,FileProtocolHandler", link])
.stdout(null)
.spawn()
.ok()
.map(|_| ())
}
let key: [u8; 32] = base16::decode(&self.key_b16)
.unwrap()
[0..32]
.try_into()
.unwrap();
#[cfg(target_os = "macos")]
{
Command::new("open")
.arg(link)
.stdout(null)
.spawn()
.ok()
.map(|_| ())
}
let cipher = Aes256Gcm::new(&key.into());
#[cfg(target_os = "linux")]
{
Command::new("xdg-open")
.arg(link)
.stdout(null)
.spawn()
.ok()
.map(|_| ())
}
let nonce = Aes256Gcm::generate_nonce(&mut OsRng);
let nonce_b16 = base16::encode_lower(&nonce);
let encrypted_response = cipher.encrypt(&nonce, serialized_response.as_slice())
.expect("Failed encrypting response");
let mut response = Response::new(Body::from(encrypted_response));
let response_headers = response.headers_mut();
response_headers.insert("Content-Type", "application/octet-stream".parse().unwrap());
response_headers.insert("X-Hopp-Nonce", nonce_b16.parse().unwrap());
response
#[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))]
{
None
}
}
#[derive(Debug)]
pub struct EncryptedJson<T: Serialize> {
pub key_b16: String,
pub data: T,
}
impl<T> IntoResponse for EncryptedJson<T>
where
T: Serialize,
{
fn into_response(self) -> Response {
let serialized_response = serde_json::to_vec(&self.data)
.expect("Failed serializing response to vec for encryption");
let key: [u8; 32] = base16::decode(&self.key_b16).unwrap()[0..32]
.try_into()
.unwrap();
let cipher = Aes256Gcm::new(&key.into());
let nonce = Aes256Gcm::generate_nonce(&mut OsRng);
let nonce_b16 = base16::encode_lower(&nonce);
let encrypted_response = cipher
.encrypt(&nonce, serialized_response.as_slice())
.expect("Failed encrypting response");
let mut response = Response::new(Body::from(encrypted_response));
let response_headers = response.headers_mut();
response_headers.insert("Content-Type", "application/octet-stream".parse().unwrap());
response_headers.insert("X-Hopp-Nonce", nonce_b16.parse().unwrap());
response
}
}

View File

@@ -0,0 +1,15 @@
use std::io;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum WebViewError {
#[error("Failed to open URL: {0}")]
UrlOpen(#[from] io::Error),
#[error("Failed to download WebView2 installer: {0}")]
Download(String),
#[error("WebView2 installation failed: {0}")]
Installation(String),
#[error("Failed during request: {0}")]
Request(#[from] tauri_plugin_http::reqwest::Error),
}

View File

@@ -0,0 +1,212 @@
/// The WebView2 Runtime is a critical dependency for Tauri applications on Windows.
/// We need to check for its presence, see [Source: GitHub Issue #59 - Portable windows build](https://github.com/tauri-apps/tauri-action/issues/59#issuecomment-827142638)
///
/// > "Tauri requires an installer if you define app resources, external binaries or running on environments that do not have Webview2 runtime installed. So I don't think it's a good idea to have a "portable" option since a Tauri binary itself isn't 100% portable."
///
/// The approach for checking WebView2 installation is based on Microsoft's official documentation, which states:
///
/// > ###### Detect if a WebView2 Runtime is already installed
/// >
/// > To verify that a WebView2 Runtime is installed, use one of the following approaches:
/// >
/// > * Approach 1: Inspect the `pv (REG_SZ)` regkey for the WebView2 Runtime at both of the following registry locations. The `HKEY_LOCAL_MACHINE` regkey is used for _per-machine_ install. The `HKEY_CURRENT_USER` regkey is used for _per-user_ install.
/// >
/// > For WebView2 applications, at least one of these regkeys must be present and defined with a version greater than 0.0.0.0. If neither regkey exists, or if only one of these regkeys exists but its value is `null`, an empty string, or 0.0.0.0, this means that the WebView2 Runtime isn't installed on the client. Inspect these regkeys to detect whether the WebView2 Runtime is installed, and to get the version of the WebView2 Runtime. Find `pv (REG_SZ)` at the following two locations.
/// >
/// > The two registry locations to inspect on 64-bit Windows:
/// >
/// > ```
/// > HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}
/// >
/// > HKEY_CURRENT_USER\Software\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}
/// > ```
/// >
/// > The two registry locations to inspect on 32-bit Windows:
/// >
/// > ```
/// > HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}
/// >
/// > HKEY_CURRENT_USER\Software\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}
/// > ```
/// >
/// > * Approach 2: Run [GetAvailableCoreWebView2BrowserVersionString](/microsoft-edge/webview2/reference/win32/webview2-idl#getavailablecorewebview2browserversionstring) and evaluate whether the `versionInfo` is `nullptr`. `nullptr` indicates that the WebView2 Runtime isn't installed. This API returns version information for the WebView2 Runtime or for any installed preview channels of Microsoft Edge (Beta, Dev, or Canary).
///
/// See: https://learn.microsoft.com/en-us/microsoft-edge/webview2/concepts/distribution?tabs=dotnetcsharp#detect-if-a-webview2-runtime-is-already-installed
///
/// Our implementation uses Approach 1, checking both the 32-bit (WOW6432Node) and 64-bit registry locations
/// to make sure we have critical dependencis compatibility with different system architectures.
pub mod error;
use std::{io, ops::Not};
use native_dialog::MessageType;
use crate::{dialog, util};
use error::WebViewError;
#[cfg(windows)]
use {
std::io::Cursor,
std::process::Command,
tauri_plugin_http::reqwest,
tempfile::TempDir,
winreg::{
enums::{HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE},
RegKey,
},
};
const TAURI_WEBVIEW_REF: &str = "https://v2.tauri.app/references/webview-versions/";
const WINDOWS_WEBVIEW_REF: &str =
"https://developer.microsoft.com/microsoft-edge/webview2/#download-section";
fn is_available() -> bool {
#[cfg(windows)]
{
const KEY_WOW64: &str = r"SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}";
const KEY: &str =
r"SOFTWARE\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}";
let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
let hkcu = RegKey::predef(HKEY_CURRENT_USER);
[
hklm.open_subkey(KEY_WOW64),
hkcu.open_subkey(KEY_WOW64),
hklm.open_subkey(KEY),
hkcu.open_subkey(KEY),
]
.into_iter()
.any(|result| result.is_ok())
}
#[cfg(not(windows))]
{
true
}
}
fn open_install_website() -> Result<(), WebViewError> {
let url = if cfg!(windows) {
WINDOWS_WEBVIEW_REF
} else {
TAURI_WEBVIEW_REF
};
util::open_link(url).map(|_| ()).ok_or_else(|| {
WebViewError::UrlOpen(io::Error::new(
io::ErrorKind::Other,
"Failed to open browser to WebView download section",
))
})
}
#[cfg(windows)]
async fn install() -> Result<(), WebViewError> {
const WEBVIEW2_BOOTSTRAPPER_URL: &str = "https://go.microsoft.com/fwlink/p/?LinkId=2124703";
const DEFAULT_FILENAME: &str = "MicrosoftEdgeWebview2Setup.exe";
let client = reqwest::Client::builder()
.user_agent("Hoppscotch Agent")
.gzip(true)
.build()?;
let response = client.get(WEBVIEW2_BOOTSTRAPPER_URL).send().await?;
if !response.status().is_success() {
return Err(WebViewError::Download(format!(
"Failed to download WebView2 bootstrapper. Status: {}",
response.status()
)));
}
let filename =
get_filename_from_response(&response).unwrap_or_else(|| DEFAULT_FILENAME.to_owned());
let tmp_dir = TempDir::with_prefix("WebView-setup-")?;
let installer_path = tmp_dir.path().join(filename);
let content = response.bytes().await?;
{
let mut file = std::fs::File::create(&installer_path)?;
io::copy(&mut Cursor::new(content), &mut file)?;
}
let status = Command::new(&installer_path).args(["/install"]).status()?;
if !status.success() {
return Err(WebViewError::Installation(format!(
"Installer exited with code `{}`.",
status.code().unwrap_or(-1)
)));
}
Ok(())
}
#[cfg(windows)]
fn get_filename_from_response(response: &reqwest::Response) -> Option<String> {
response
.headers()
.get("content-disposition")
.and_then(|value| value.to_str().ok())
.and_then(|value| value.split("filename=").last())
.map(|name| name.trim().replace('\"', ""))
.or_else(|| {
response
.url()
.path_segments()
.and_then(|segments| segments.last())
.map(|name| name.to_string())
})
.filter(|name| !name.is_empty())
}
#[cfg(not(windows))]
async fn install() -> Result<(), WebViewError> {
Err(WebViewError::Installation(
"Unable to auto-install WebView. Please refer to https://v2.tauri.app/references/webview-versions/".to_string(),
))
}
pub fn init_webview() {
if is_available() {
return;
}
if dialog::confirm(
"WebView Error",
"WebView is required for this application to work.\n\n\
Do you want to install it?",
MessageType::Error,
)
.not()
{
log::warn!("Declined to setup WebView.");
std::process::exit(1);
}
if let Err(e) = tauri::async_runtime::block_on(install()) {
dialog::error(&format!(
"Failed to install WebView: {}\n\n\
Please install it manually from webpage that should open when you click 'Ok'.\n\n\
If that doesn't work, please visit Microsoft Edge Webview2 download section.",
e
));
if let Err(e) = open_install_website() {
log::warn!("Failed to launch WebView website:\n{}", e);
}
std::process::exit(1);
}
if is_available().not() {
dialog::panic(
"Unable to setup WebView:\n\n\
Please install it manually and relaunch the application.\n\
https://developer.microsoft.com/microsoft-edge/webview2/#download-section",
);
}
}

View File

@@ -28,7 +28,7 @@
"csp": null
}
},
"bundle": {
"bundle": {
"active": true,
"targets": "all",
"icon": [
@@ -40,10 +40,9 @@
],
"createUpdaterArtifacts": true
},
"plugins" : {
"plugins": {
"updater": {
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDRBQzgxQjc3MzJCMjZENEMKUldSTWJiSXlkeHZJU3EvQW1abFVlREVhRDNlM0ZhOVJYaHN4M0FpbXZhcUFzSVdVbG84RWhPa1AK",
"endpoints": [
"https://releases.hoppscotch.com/hoppscotch-agent.json"
]

View File

@@ -0,0 +1,48 @@
{
"$schema": "https://schema.tauri.app/config/2.0.0-rc",
"productName": "Hoppscotch Agent Portable",
"version": "0.1.1",
"identifier": "io.hoppscotch.agent",
"build": {
"beforeDevCommand": "pnpm dev",
"devUrl": "http://localhost:1420",
"beforeBuildCommand": "pnpm build",
"frontendDist": "../dist"
},
"app": {
"windows": [
{
"title": "Hoppscotch Agent Portable",
"width": 600,
"height": 400,
"center": true,
"resizable": false,
"maximizable": false,
"minimizable": false,
"focus": true,
"alwaysOnTop": true,
"create": false
}
],
"security": {
"csp": null
}
},
"bundle": {
"active": false,
"targets": "all",
"icon": [
"icons/32x32.png",
"icons/128x128.png",
"icons/128x128@2x.png",
"icons/icon.icns",
"icons/icon.ico"
],
"createUpdaterArtifacts": false
},
"plugins": {
"updater": {
"active": false
}
}
}