feat: add deeplink, and handle oauth callback (#99)

* init attempt

* fix build

* feat: deep link

* feat: deep-link

* register schema to macos

* chore: remove verbose logging

* feat: add request_access_token

---------

Co-authored-by: rain <15911122312@163.com>
This commit is contained in:
Medcl
2025-01-10 14:59:03 +08:00
committed by GitHub
parent 40527b3a6c
commit efb92b15ca
12 changed files with 592 additions and 172 deletions

View File

@@ -14,6 +14,7 @@
"@react-oauth/google": "^0.12.1",
"@tauri-apps/api": ">=2.0.0",
"@tauri-apps/plugin-autostart": "~2",
"@tauri-apps/plugin-deep-link": "^2.2.0",
"@tauri-apps/plugin-global-shortcut": "~2.0.0",
"@tauri-apps/plugin-http": "~2.0.1",
"@tauri-apps/plugin-os": "^2.0.0",

23
pnpm-lock.yaml generated
View File

@@ -20,6 +20,9 @@ importers:
'@tauri-apps/plugin-autostart':
specifier: ~2
version: 2.2.0
'@tauri-apps/plugin-deep-link':
specifier: ^2.2.0
version: 2.2.0
'@tauri-apps/plugin-global-shortcut':
specifier: ~2.0.0
version: 2.0.0
@@ -548,55 +551,46 @@ packages:
resolution: {integrity: sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA==}
cpu: [arm]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm-musleabihf@4.24.0':
resolution: {integrity: sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw==}
cpu: [arm]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-arm64-gnu@4.24.0':
resolution: {integrity: sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA==}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm64-musl@4.24.0':
resolution: {integrity: sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw==}
cpu: [arm64]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-powerpc64le-gnu@4.24.0':
resolution: {integrity: sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw==}
cpu: [ppc64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-riscv64-gnu@4.24.0':
resolution: {integrity: sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg==}
cpu: [riscv64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-s390x-gnu@4.24.0':
resolution: {integrity: sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g==}
cpu: [s390x]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-gnu@4.24.0':
resolution: {integrity: sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A==}
cpu: [x64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-musl@4.24.0':
resolution: {integrity: sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ==}
cpu: [x64]
os: [linux]
libc: [musl]
'@rollup/rollup-win32-arm64-msvc@4.24.0':
resolution: {integrity: sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ==}
@@ -655,28 +649,24 @@ packages:
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@tauri-apps/cli-linux-arm64-musl@2.0.3':
resolution: {integrity: sha512-I4MVD7nf6lLLRmNQPpe5beEIFM6q7Zkmh77ROA5BNu/+vHNL5kiTMD+bmd10ZL2r753A6pO7AvqkIxcBuIl0tg==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
libc: [musl]
'@tauri-apps/cli-linux-x64-gnu@2.0.3':
resolution: {integrity: sha512-C6Jkx2zZGKkoi+sg5FK9GoH/0EvAaOgrZfF5azV5EALGba46g7VpWcZgp9zFUd7K2IzTi+0OOY8TQ2OVfKZgew==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
libc: [glibc]
'@tauri-apps/cli-linux-x64-musl@2.0.3':
resolution: {integrity: sha512-qi4ghmTfSAl+EEUDwmwI9AJUiOLNSmU1RgiGgcPRE+7A/W+Am9UnxYySAiRbB/gJgTl9sj/pqH5Y9duP1/sqHg==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
libc: [musl]
'@tauri-apps/cli-win32-arm64-msvc@2.0.3':
resolution: {integrity: sha512-UXxHkYmFesC97qVmZre4vY7oDxRDtC2OeKNv0bH+iSnuUp/ROxzJYGyaelnv9Ybvgl4YVqDCnxgB28qMM938TA==}
@@ -704,6 +694,9 @@ packages:
'@tauri-apps/plugin-autostart@2.2.0':
resolution: {integrity: sha512-TzVcDZdOvdot0avkpstUWJKKEl4cyxLpFB9DZZRW5zH8k+Bv8IVJmO0zyYuw+7oKlGdHOINbD/7Je7GHMViw5w==}
'@tauri-apps/plugin-deep-link@2.2.0':
resolution: {integrity: sha512-H6mkxr2KZ3XJcKL44tiq6cOjCw9DL8OgU1xjn3j26Qsn+H/roPFiyhR7CHuB8Ar+sQFj4YVlfmJwtBajK2FETQ==}
'@tauri-apps/plugin-global-shortcut@2.0.0':
resolution: {integrity: sha512-pnB4CUwFVjg4twtBSxoLJ4uLFTYxsvOdC1zIbG581pYzhYatOl6mjB+ijD5SSXgiS/jNoqMcfkOF9PWAisurew==}
@@ -2738,6 +2731,10 @@ snapshots:
dependencies:
'@tauri-apps/api': 2.0.2
'@tauri-apps/plugin-deep-link@2.2.0':
dependencies:
'@tauri-apps/api': 2.0.2
'@tauri-apps/plugin-global-shortcut@2.0.0':
dependencies:
'@tauri-apps/api': 2.0.2

372
src-tauri/Cargo.lock generated
View File

@@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
version = 4
[[package]]
name = "addr2line"
@@ -72,6 +72,18 @@ dependencies = [
"futures-core",
]
[[package]]
name = "async-broadcast"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532"
dependencies = [
"event-listener 5.3.1",
"event-listener-strategy",
"futures-core",
"pin-project-lite",
]
[[package]]
name = "async-channel"
version = "2.3.1"
@@ -109,6 +121,17 @@ dependencies = [
"futures-lite 1.13.0",
]
[[package]]
name = "async-fs"
version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a"
dependencies = [
"async-lock 3.4.0",
"blocking",
"futures-lite 2.5.0",
]
[[package]]
name = "async-io"
version = "1.13.0"
@@ -185,6 +208,25 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "async-process"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb"
dependencies = [
"async-channel",
"async-io 2.4.0",
"async-lock 3.4.0",
"async-signal",
"async-task",
"blocking",
"cfg-if",
"event-listener 5.3.1",
"futures-lite 2.5.0",
"rustix 0.38.37",
"tracing",
]
[[package]]
name = "async-recursion"
version = "1.1.1"
@@ -547,10 +589,12 @@ dependencies = [
"tauri",
"tauri-build",
"tauri-plugin-autostart",
"tauri-plugin-deep-link",
"tauri-plugin-global-shortcut",
"tauri-plugin-http",
"tauri-plugin-oauth",
"tauri-plugin-shell",
"tauri-plugin-single-instance",
"tauri-plugin-theme",
"tauri-plugin-websocket",
]
@@ -604,6 +648,26 @@ dependencies = [
"crossbeam-utils",
]
[[package]]
name = "const-random"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359"
dependencies = [
"const-random-macro",
]
[[package]]
name = "const-random-macro"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e"
dependencies = [
"getrandom 0.2.15",
"once_cell",
"tiny-keccak",
]
[[package]]
name = "convert_case"
version = "0.4.0"
@@ -721,6 +785,12 @@ version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
[[package]]
name = "crunchy"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]]
name = "crypto-common"
version = "0.1.6"
@@ -950,6 +1020,15 @@ dependencies = [
"syn 2.0.90",
]
[[package]]
name = "dlv-list"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f"
dependencies = [
"const-random",
]
[[package]]
name = "dpi"
version = "0.1.1"
@@ -1015,6 +1094,12 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "endi"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf"
[[package]]
name = "enumflags2"
version = "0.7.10"
@@ -1504,7 +1589,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc"
dependencies = [
"heck 0.4.1",
"proc-macro-crate 2.0.2",
"proc-macro-crate 2.0.0",
"proc-macro-error",
"proc-macro2",
"quote",
@@ -1632,6 +1717,12 @@ version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hashbrown"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
[[package]]
name = "hashbrown"
version = "0.15.0"
@@ -2277,6 +2368,19 @@ dependencies = [
"memoffset 0.7.1",
]
[[package]]
name = "nix"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
dependencies = [
"bitflags 2.6.0",
"cfg-if",
"cfg_aliases",
"libc",
"memoffset 0.9.1",
]
[[package]]
name = "nodrop"
version = "0.1.14"
@@ -2313,7 +2417,7 @@ version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56"
dependencies = [
"proc-macro-crate 2.0.2",
"proc-macro-crate 1.3.1",
"proc-macro2",
"quote",
"syn 2.0.90",
@@ -2578,6 +2682,16 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]]
name = "ordered-multimap"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49203cdcae0030493bad186b28da2fa25645fa276a51b6fec8010d281e02ef79"
dependencies = [
"dlv-list",
"hashbrown 0.14.5",
]
[[package]]
name = "ordered-stream"
version = "0.2.0"
@@ -2917,14 +3031,22 @@ dependencies = [
[[package]]
name = "proc-macro-crate"
version = "2.0.2"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24"
checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8"
dependencies = [
"toml_datetime",
"toml_edit 0.20.2",
]
[[package]]
name = "proc-macro-crate"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b"
dependencies = [
"toml_edit 0.22.22",
]
[[package]]
name = "proc-macro-error"
version = "1.0.4"
@@ -3228,7 +3350,7 @@ dependencies = [
"wasm-streams",
"web-sys",
"webpki-roots",
"windows-registry",
"windows-registry 0.2.0",
]
[[package]]
@@ -3246,6 +3368,17 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "rust-ini"
version = "0.21.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e310ef0e1b6eeb79169a1171daf9abcb87a2e17c03bee2c4bb100b55c75409f"
dependencies = [
"cfg-if",
"ordered-multimap",
"trim-in-place",
]
[[package]]
name = "rustc-demangle"
version = "0.1.24"
@@ -4034,6 +4167,26 @@ dependencies = [
"thiserror 2.0.6",
]
[[package]]
name = "tauri-plugin-deep-link"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35d51ffd286073414d26353bcfc9e83e3cd63f96fa7f7a912f92f2118e5de5a6"
dependencies = [
"dunce",
"rust-ini",
"serde",
"serde_json",
"tauri",
"tauri-plugin",
"tauri-utils",
"thiserror 2.0.6",
"tracing",
"url",
"windows-registry 0.3.0",
"windows-result",
]
[[package]]
name = "tauri-plugin-fs"
version = "2.0.3"
@@ -4127,6 +4280,21 @@ dependencies = [
"tokio",
]
[[package]]
name = "tauri-plugin-single-instance"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f36019ee9832dc99e4450bb55a21cfad8633b19c2c18bd17c7741939b070ede"
dependencies = [
"serde",
"serde_json",
"tauri",
"thiserror 2.0.6",
"tracing",
"windows-sys 0.59.0",
"zbus 4.4.0",
]
[[package]]
name = "tauri-plugin-theme"
version = "2.1.2"
@@ -4367,7 +4535,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7abbcf9173afc80733c20b7e27a30bc9284d6535bdbde2a70904032de63e16e8"
dependencies = [
"futures-lite 1.13.0",
"zbus",
"zbus 3.15.2",
]
[[package]]
name = "tiny-keccak"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
dependencies = [
"crunchy",
]
[[package]]
@@ -4478,9 +4655,9 @@ dependencies = [
[[package]]
name = "toml_datetime"
version = "0.6.3"
version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b"
checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
dependencies = [
"serde",
]
@@ -4495,7 +4672,7 @@ dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
"winnow",
"winnow 0.5.40",
]
[[package]]
@@ -4508,7 +4685,18 @@ dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
"winnow",
"winnow 0.5.40",
]
[[package]]
name = "toml_edit"
version = "0.22.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
dependencies = [
"indexmap 2.6.0",
"toml_datetime",
"winnow 0.6.22",
]
[[package]]
@@ -4569,6 +4757,12 @@ dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "trim-in-place"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "343e926fc669bc8cde4fa3129ab681c63671bae288b1f1081ceee6d9d37904fc"
[[package]]
name = "try-lock"
version = "0.2.5"
@@ -5053,7 +5247,7 @@ dependencies = [
"windows-implement",
"windows-interface",
"windows-result",
"windows-strings",
"windows-strings 0.1.0",
"windows-targets 0.52.6",
]
@@ -5086,7 +5280,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0"
dependencies = [
"windows-result",
"windows-strings",
"windows-strings 0.1.0",
"windows-targets 0.52.6",
]
[[package]]
name = "windows-registry"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bafa604f2104cf5ae2cc2db1dee84b7e6a5d11b05f737b60def0ffdc398cbc0a"
dependencies = [
"windows-result",
"windows-strings 0.2.0",
"windows-targets 0.52.6",
]
@@ -5109,6 +5314,15 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-strings"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "978d65aedf914c664c510d9de43c8fd85ca745eaff1ed53edf409b479e441663"
dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-sys"
version = "0.45.0"
@@ -5341,6 +5555,15 @@ dependencies = [
"memchr",
]
[[package]]
name = "winnow"
version = "0.6.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39281189af81c07ec09db316b302a3e67bf9bd7cbf6c820b50e35fee9c2fa980"
dependencies = [
"memchr",
]
[[package]]
name = "winreg"
version = "0.10.1"
@@ -5440,12 +5663,12 @@ version = "3.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "675d170b632a6ad49804c8cf2105d7c31eddd3312555cffd4b740e08e97c25e6"
dependencies = [
"async-broadcast",
"async-broadcast 0.5.1",
"async-executor",
"async-fs",
"async-fs 1.6.0",
"async-io 1.13.0",
"async-lock 2.8.0",
"async-process",
"async-process 1.8.1",
"async-recursion",
"async-task",
"async-trait",
@@ -5458,7 +5681,7 @@ dependencies = [
"futures-sink",
"futures-util",
"hex",
"nix",
"nix 0.26.4",
"once_cell",
"ordered-stream",
"rand 0.8.5",
@@ -5470,9 +5693,47 @@ dependencies = [
"uds_windows",
"winapi",
"xdg-home",
"zbus_macros",
"zbus_names",
"zvariant",
"zbus_macros 3.15.2",
"zbus_names 2.6.1",
"zvariant 3.15.2",
]
[[package]]
name = "zbus"
version = "4.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb97012beadd29e654708a0fdb4c84bc046f537aecfde2c3ee0a9e4b4d48c725"
dependencies = [
"async-broadcast 0.7.2",
"async-executor",
"async-fs 2.1.2",
"async-io 2.4.0",
"async-lock 3.4.0",
"async-process 2.3.0",
"async-recursion",
"async-task",
"async-trait",
"blocking",
"enumflags2",
"event-listener 5.3.1",
"futures-core",
"futures-sink",
"futures-util",
"hex",
"nix 0.29.0",
"ordered-stream",
"rand 0.8.5",
"serde",
"serde_repr",
"sha1",
"static_assertions",
"tracing",
"uds_windows",
"windows-sys 0.52.0",
"xdg-home",
"zbus_macros 4.4.0",
"zbus_names 3.0.0",
"zvariant 4.2.0",
]
[[package]]
@@ -5486,7 +5747,20 @@ dependencies = [
"quote",
"regex",
"syn 1.0.109",
"zvariant_utils",
"zvariant_utils 1.0.1",
]
[[package]]
name = "zbus_macros"
version = "4.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "267db9407081e90bbfa46d841d3cbc60f59c0351838c4bc65199ecd79ab1983e"
dependencies = [
"proc-macro-crate 3.2.0",
"proc-macro2",
"quote",
"syn 2.0.90",
"zvariant_utils 2.1.0",
]
[[package]]
@@ -5497,7 +5771,18 @@ checksum = "437d738d3750bed6ca9b8d423ccc7a8eb284f6b1d6d4e225a0e4e6258d864c8d"
dependencies = [
"serde",
"static_assertions",
"zvariant",
"zvariant 3.15.2",
]
[[package]]
name = "zbus_names"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c"
dependencies = [
"serde",
"static_assertions",
"zvariant 4.2.0",
]
[[package]]
@@ -5538,7 +5823,20 @@ dependencies = [
"libc",
"serde",
"static_assertions",
"zvariant_derive",
"zvariant_derive 3.15.2",
]
[[package]]
name = "zvariant"
version = "4.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2084290ab9a1c471c38fc524945837734fbf124487e105daec2bb57fd48c81fe"
dependencies = [
"endi",
"enumflags2",
"serde",
"static_assertions",
"zvariant_derive 4.2.0",
]
[[package]]
@@ -5551,7 +5849,20 @@ dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
"zvariant_utils",
"zvariant_utils 1.0.1",
]
[[package]]
name = "zvariant_derive"
version = "4.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73e2ba546bda683a90652bac4a279bc146adad1386f25379cf73200d2002c449"
dependencies = [
"proc-macro-crate 3.2.0",
"proc-macro2",
"quote",
"syn 2.0.90",
"zvariant_utils 2.1.0",
]
[[package]]
@@ -5564,3 +5875,14 @@ dependencies = [
"quote",
"syn 1.0.109",
]
[[package]]
name = "zvariant_utils"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c51bcff7cc3dbb5055396bcf774748c3dab426b4b8659046963523cee4808340"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.90",
]

View File

@@ -28,6 +28,8 @@ tauri-plugin-websocket = "2"
tauri-plugin-theme = "2.1.2"
tauri-plugin-oauth = { git = "https://github.com/FabianLars/tauri-plugin-oauth", branch = "v2" }
tauri-plugin-deep-link = "2.0.0"
tauri-plugin-single-instance = "2.0.0"
# tauri-nspanel = { git = "https://github.com/ahkohd/tauri-nspanel", branch = "v2" }

View File

@@ -6,5 +6,23 @@
<string>Request camera access for WebRTC</string>
<key>NSMicrophoneUsageDescription</key>
<string>Request microphone access for WebRTC</string>
<key>CFBundleIdentifier</key>
<string>rs.coco.app</string>
<key>NSPrefPaneIconLabel</key>
<string>coco-ai</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>rs.coco.app</string>
<key>CFBundleURLSchemes</key>
<array>
<string>coco</string>
</array>
</dict>
</array>
</dict>
</plist>

View File

@@ -46,6 +46,9 @@
"global-shortcut:allow-unregister-all",
"theme:default",
"oauth:allow-start",
"deep-link:allow-get-current",
"deep-link:default",
"deep-link:allow-register",
{
"identifier": "http:default",
"allow": [

View File

@@ -8,6 +8,8 @@ use tauri_plugin_global_shortcut::{GlobalShortcutExt, Shortcut};
mod autostart;
use autostart::{change_autostart, enable_autostart};
use tauri_plugin_deep_link::DeepLinkExt;
#[cfg(target_os = "macos")]
use tauri::ActivationPolicy;
@@ -60,6 +62,12 @@ struct ThemeChangedPayload {
is_dark_mode: bool,
}
#[derive(Clone, serde::Serialize)]
struct Payload {
args: Vec<String>,
cwd: String,
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
let mut ctx = tauri::generate_context!();
@@ -74,6 +82,12 @@ pub fn run() {
None,
))
.plugin(tauri_plugin_theme::init(ctx.config_mut()))
.plugin(tauri_plugin_deep_link::init())
.plugin(tauri_plugin_single_instance::init(|app, argv, cwd| {
// println!("{}, {argv:?}, {cwd}", app.package_info().name);
app.emit("single-instance", Payload { args: argv, cwd })
.unwrap();
}))
.invoke_handler(tauri::generate_handler![
greet,
change_window_height,
@@ -103,6 +117,13 @@ pub fn run() {
}
});
#[cfg(any(target_os = "linux", all(debug_assertions, windows)))]
app.deep_link().register_all()?;
app.deep_link().on_open_url(|event| {
dbg!(event.urls());
});
Ok(())
})
.run(ctx)

View File

@@ -78,9 +78,22 @@
"resources": ["assets", "icons"]
},
"plugins": {
"features": {
"protocol": ["all"]
},
"window": {},
"websocket": {},
"shell": {},
"globalShortcut": {}
"globalShortcut": {},
"deep-link": {
"schema": "coco",
"mobile": [
{ "host": "app.infini.cloud", "pathPrefix": ["/open"] },
{ "host": "localhost:9000" }
],
"desktop": {
"schemes": ["coco"]
}
}
}
}

View File

@@ -1,7 +1,6 @@
import { fetch } from "@tauri-apps/plugin-http";
import { clientEnv } from "@/utils/env";
import { useAuthStore } from "@/stores/authStore";
interface FetchRequestConfig {
url: string;
@@ -36,7 +35,8 @@ export const tauriFetch = async <T = any>({
baseURL = clientEnv.COCO_SERVER_URL
}: FetchRequestConfig): Promise<FetchResponse<T>> => {
console.log(11111111, baseURL)
const { auth } = useAuthStore();
const { state } = JSON.parse(localStorage.getItem("auth-store") || "")
console.log(23333333333, state)
try {
url = baseURL + url;
@@ -44,7 +44,7 @@ export const tauriFetch = async <T = any>({
headers["Content-Type"] = "application/json";
}
headers["X-API-TOKEN"] = auth?.token || "";
headers["X-API-TOKEN"] = state.auth?.token || "";
const fetchPromise = fetch(url, {
method,

View File

@@ -1,26 +1,29 @@
import { useState, useEffect } from "react";
import { Cloud } from "lucide-react";
import { v4 as uuidv4 } from "uuid";
import { useNavigate } from "react-router-dom";
import { invoke } from "@tauri-apps/api/core";
import { listen } from "@tauri-apps/api/event";
import { getCurrentWindow } from "@tauri-apps/api/window";
import * as shell from "@tauri-apps/plugin-shell";
import { UserProfile } from "./UserProfile";
import { DataSourcesList } from "./DataSourcesList";
import { Sidebar } from "./Sidebar";
import { ConnectService } from "./ConnectService";
// import { OpenBrowserURL } from "@/utils/index";
import { OpenBrowserURL } from "@/utils/index";
import { useAppStore } from "@/stores/appStore";
import { useAuthStore } from "@/stores/authStore";
import callbackTemplate from "@/components/Auth/callback.template";
import { tauriFetch } from "@/api/tauriFetchClient";
import {
onOpenUrl,
getCurrent as getCurrentDeepLinkUrls,
} from "@tauri-apps/plugin-deep-link";
export default function CocoCloud() {
const appStore = useAppStore();
const [isLogin] = useState(false);
const [lastUrl, setLastUrl] = useState<string | null>(null);
const [error, setError] = useState<string | null>(null);
const [info, setInfo] = useState<string | null>(null);
const [info2, setInfo2] = useState<string | null>(null);
const [isConnect] = useState(true);
const app_uid = useAppStore((state) => state.app_uid);
@@ -29,106 +32,36 @@ export default function CocoCloud() {
const { auth, setAuth } = useAuthStore();
const navigate = useNavigate();
const [loading, setLoading] = useState(false);
useEffect(() => {
let unsubscribe: (() => void) | undefined;
const setupAuthListener = async () => {
try {
if (!auth) {
// Replace the current route with signin
// navigate("/signin", { replace: true });
}
} catch (error) {
console.error("Failed to set up auth listener:", error);
}
};
setupAuthListener();
// Clean up logic on unmount
return () => {
const cleanup = async () => {
try {
await invoke("plugin:oauth|stop");
} catch (e) {
// Ignore errors if no server is running
}
if (unsubscribe) {
unsubscribe();
}
};
cleanup();
};
}, [auth]);
async function signIn() {
let res: (url: URL) => void;
try {
const stopListening = await listen(
// "oauth://url",
"coco://oauth_callback",
(data: { payload: string }) => {
console.log(111, data.payload);
// if (!data.payload.includes("provider")) {
// return;
// }
const urlObject = new URL(data.payload);
res(urlObject);
}
);
// Stop any existing OAuth server first
try {
await invoke("plugin:oauth|stop");
} catch (e) {
// Ignore errors if no server is running
}
const port: string = await invoke("plugin:oauth|start", {
config: {
response: callbackTemplate,
headers: {
"Content-Type": "text/html; charset=utf-8",
"Cache-Control": "no-store, no-cache, must-revalidate",
Pragma: "no-cache",
},
// Add a cleanup function to stop the server after handling the request
cleanup: true,
},
});
let uid = app_uid;
if (!uid) {
uid = uuidv4();
setAppUid(uid);
}
await shell.open(
`${endpoint_http}/sso/login?provider=coco-cloud&product=coco&request_id=${uid}&port=${port}`
);
const url = await new Promise<URL>((r) => {
res = r;
});
stopListening();
const code = url.searchParams.get("code");
const provider = url.searchParams.get("provider");
if (!code || provider !== "coco-cloud") {
throw new Error("Invalid token or expires");
}
const getProfile = async () => {
const response: any = await tauriFetch({
url: `/auth/request_access_token?request_id=${uid}`,
url: `/profile`,
method: "GET",
baseURL: appStore.endpoint_http,
});
console.log("getProfile", response);
setInfo2(JSON.stringify(response))
}
const handleOAuthCallback = async (
code: string | null,
provider: string | null
) => {
if (!code) {
setError("No authorization code received");
return;
}
// mock
// code = "d11feeab43f6c3e48a43"
// provider = "coco-cloud"
try {
console.log("Handling OAuth callback:", { code, provider });
const response: any = await tauriFetch({
url: `/auth/request_access_token?request_id=${app_uid}`,
method: "GET",
baseURL: appStore.endpoint_http,
headers: {
@@ -136,31 +69,84 @@ export default function CocoCloud() {
},
});
// { "access_token":xxx, "expire_at": "unix_timestamp_in_s" }
console.log("response", response);
setInfo(JSON.stringify(response))
getProfile()
await setAuth({
token: response?.access_token,
expires: response?.expire_at,
token: response.data?.access_token,
expires: response.data?.expire_at,
plan: { upgraded: false, last_checked: 0 },
});
getCurrentWindow()
.setFocus()
.catch(() => {});
return navigate("/ui/settings");
} catch (error) {
} catch (e) {
console.error("Sign in failed:", error);
await setAuth(undefined);
throw error;
} finally {
setLoading(false);
}
};
const handleUrl = (url: string) => {
try {
const urlObject = new URL(url);
console.error("1111111:", urlObject);
switch (urlObject.pathname) {
case "oauth_callback":
const code = urlObject.searchParams.get("code");
const provider = urlObject.searchParams.get("provider");
handleOAuthCallback(code, provider);
break;
default:
console.log("Unhandled deep link path:", urlObject.pathname);
}
setLastUrl(url);
} catch (err) {
console.error("Failed to parse URL:", err);
setError("Invalid URL format");
}
};
// Fetch the initial deep link intent
useEffect(() => {
// coco://oauth_calback?code=&provider=
// handleOAuthCallback("cu0bpu53q95r66at2010", "coco-cloud");
//
getCurrentDeepLinkUrls()
.then((urls) => {
console.error("22222 URLs:", urls);
if (urls && urls.length > 0) {
handleUrl(urls[0]);
console.error("URLs:", urls);
}
})
.catch((err) => {
console.error("Failed to get initial URLs:", err);
setError("Failed to get initial URLs");
});
const unlisten = onOpenUrl((urls) => handleUrl(urls[0]));
return () => {
unlisten.then((fn) => fn());
};
}, []);
function LoginClick() {
let uid = app_uid;
if (!uid) {
uid = uuidv4();
setAppUid(uid);
}
async function initializeUser() {
// let uid = app_uid;
// if (!uid) {
// uid = uuidv4();
// setAppUid(uid);
// }
// const response = await fetch("/api/register", {
// method: "POST",
// headers: { "Content-Type": "application/json" },
@@ -168,22 +154,12 @@ export default function CocoCloud() {
// });
// const { token } = await response.json();
// localStorage.setItem("auth_token", token);
// OpenBrowserURL(
// `https://app.coco.rs/sso/login?provider=coco-cloud&request_id=${uid}`
// );
OpenBrowserURL(
`${endpoint_http}/sso/login/github?provider=coco-cloud&product=coco&request_id=${uid}`
);
setLoading(true);
try {
await signIn();
} catch (error) {
console.error(error);
} finally {
setLoading(false);
}
}
function LoginClick() {
initializeUser();
}
return (
@@ -191,6 +167,30 @@ export default function CocoCloud() {
<Sidebar />
<main className="flex-1">
<div>
{error && (
<div className="text-red-500 dark:text-red-400">Error: {error}</div>
)}
{lastUrl && (
<div className="text-gray-700 dark:text-gray-300">
Last opened URL: {lastUrl}
</div>
)}
{info && (
<div className="text-gray-700 dark:text-gray-300">
Info : {info}
</div>
)}
{info2 && (
<div className="text-gray-700 dark:text-gray-300">
info2 : {info2}
</div>
)}
</div>
{isConnect ? (
<div className="max-w-4xl mx-auto px-4 py-8">
<div className="flex items-center justify-between mb-8">
@@ -230,7 +230,7 @@ export default function CocoCloud() {
<h2 className="text-lg font-medium text-gray-900 mb-4">
Account Information
</h2>
{isLogin ? (
{auth ? (
<UserProfile name="Rain" email="an121245@gmail.com" />
) : (
<button
@@ -242,7 +242,7 @@ export default function CocoCloud() {
)}
</div>
{isLogin ? <DataSourcesList /> : null}
{auth ? <DataSourcesList /> : null}
</div>
) : (
<ConnectService />

View File

@@ -42,6 +42,10 @@ export default function LoginPage() {
return (
<div className="min-h-screen bg-black flex justify-center">
<a href="coco://oauth_callback?code=ctvracbq50ke7o4qksj0&provider=coco-cloud">
In order to continue, please click here to launch Coco AI
</a>
<div className="min-h-screen container py-[30px] relative overflow-hidden">
{/* Background Image */}
<div className="absolute top-[60px] inset-0 z-0">

View File

@@ -1,5 +1,9 @@
import { create } from "zustand";
import { persist } from "zustand/middleware";
import { listen, emit } from '@tauri-apps/api/event';
const AUTH_CHANGE_EVENT = 'auth-changed';
const USERINFO_CHANGE_EVENT = 'userInfo-changed';
export type Plan = {
upgraded: boolean;
@@ -15,20 +19,55 @@ export type AuthStore = {
export type IAuthStore = {
auth: AuthStore | undefined;
userInfo: any;
setAuth: (auth: AuthStore | undefined) => void;
resetAuth: () => void;
initializeListeners: () => void;
};
export const useAuthStore = create<IAuthStore>()(
persist(
(set) => ({
auth: undefined,
setAuth: (auth) => set({ auth }),
resetAuth: () => set({ auth: undefined }),
userInfo: {},
setAuth: async (auth) => {
set({ auth })
await emit(AUTH_CHANGE_EVENT, {
auth
});
},
resetAuth: async () => {
set({ auth: undefined })
await emit(AUTH_CHANGE_EVENT, {
auth: undefined
});
},
setUserInfo: async (userInfo: any) => {
set({ userInfo })
await emit(USERINFO_CHANGE_EVENT, {
userInfo
});
},
initializeListeners: () => {
listen(AUTH_CHANGE_EVENT, (event: any) => {
const { auth } = event.payload;
set({ auth });
});
listen(USERINFO_CHANGE_EVENT, (event: any) => {
const { userInfo } = event.payload;
set({ userInfo });
});
},
}),
{
name: "auth-store",
partialize: (state) => ({ auth: state.auth }),
partialize: (state) => ({
auth: state.auth,
userInfo: state.userInfo
}),
}
)
);