6 Commits
Author SHA1 Message Date
reya 853ab7a60e chore: bump version 2025-09-13 10:18:33 +07:00
reya d38e70ecbf chore: update deps 2025-09-13 07:51:33 +07:00
reyaandGitHub b142982ab1 chore: refactor event fetching (#148)
* use stream for nip65 and nip17 relays fetching

* .
2025-09-13 07:42:17 +07:00
reyaandGitHub 2ea2519e8b feat: resend failed messages (#147)
* .

* .

* fix

* fix

* update

* fix

* .

* .
2025-09-12 17:07:57 +07:00
reyaandGitHub 2ea5feaf4b chore: improve handling of user profiles (#146)
* resubscribe metadata for all pubkeys

* .
2025-09-10 10:06:45 +07:00
reya 4ec7530b91 chore: update deps 2025-09-10 08:21:43 +07:00
14 changed files with 609 additions and 441 deletions
+1 -1
View File
@@ -157,7 +157,7 @@ jobs:
uses: softprops/action-gh-release@v2 uses: softprops/action-gh-release@v2
with: with:
tag_name: ${{ steps.version.outputs.tag }} tag_name: ${{ steps.version.outputs.tag }}
name: Release ${{ steps.version.outputs.tag }} name: ${{ steps.version.outputs.tag }}
draft: true draft: true
prerelease: false prerelease: false
generate_release_notes: true generate_release_notes: true
Generated
+173 -152
View File
@@ -76,12 +76,6 @@ dependencies = [
"equator", "equator",
] ]
[[package]]
name = "android-tzdata"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
[[package]] [[package]]
name = "android_system_properties" name = "android_system_properties"
version = "0.1.5" version = "0.1.5"
@@ -176,9 +170,27 @@ dependencies = [
"zbus", "zbus",
] ]
[[package]]
name = "ashpd"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da0986d5b4f0802160191ad75f8d33ada000558757db3defb70299ca95d9fcbd"
dependencies = [
"async-fs",
"async-net",
"enumflags2",
"futures-channel",
"futures-util",
"rand 0.9.2",
"serde",
"serde_repr",
"url",
"zbus",
]
[[package]] [[package]]
name = "assets" name = "assets"
version = "0.2.5" version = "0.2.6"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"gpui", "gpui",
@@ -261,7 +273,7 @@ dependencies = [
"futures-lite 2.6.1", "futures-lite 2.6.1",
"parking", "parking",
"polling", "polling",
"rustix 1.0.8", "rustix 1.1.2",
"slab", "slab",
"windows-sys 0.60.2", "windows-sys 0.60.2",
] ]
@@ -303,7 +315,7 @@ dependencies = [
"cfg-if", "cfg-if",
"event-listener", "event-listener",
"futures-lite 2.6.1", "futures-lite 2.6.1",
"rustix 1.0.8", "rustix 1.1.2",
] ]
[[package]] [[package]]
@@ -329,7 +341,7 @@ dependencies = [
"cfg-if", "cfg-if",
"futures-core", "futures-core",
"futures-io", "futures-io",
"rustix 1.0.8", "rustix 1.1.2",
"signal-hook-registry", "signal-hook-registry",
"slab", "slab",
"windows-sys 0.60.2", "windows-sys 0.60.2",
@@ -416,7 +428,7 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
[[package]] [[package]]
name = "auto_update" name = "auto_update"
version = "0.2.5" version = "0.2.6"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"cargo-packager-updater", "cargo-packager-updater",
@@ -460,9 +472,9 @@ dependencies = [
[[package]] [[package]]
name = "aws-lc-rs" name = "aws-lc-rs"
version = "1.13.3" version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c953fe1ba023e6b7730c0d4b031d06f267f23a46167dcbd40316644b10a17ba" checksum = "94b8ff6c09cd57b16da53641caa860168b88c172a5ee163b0288d3d6eea12786"
dependencies = [ dependencies = [
"aws-lc-sys", "aws-lc-sys",
"zeroize", "zeroize",
@@ -470,11 +482,11 @@ dependencies = [
[[package]] [[package]]
name = "aws-lc-sys" name = "aws-lc-sys"
version = "0.30.0" version = "0.31.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbfd150b5dbdb988bcc8fb1fe787eb6b7ee6180ca24da683b61ea5405f3d43ff" checksum = "0e44d16778acaf6a9ec9899b92cebd65580b83f685446bf2e1f5d3d732f99dcd"
dependencies = [ dependencies = [
"bindgen 0.69.5", "bindgen 0.72.1",
"cc", "cc",
"cmake", "cmake",
"dunce", "dunce",
@@ -525,32 +537,29 @@ checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d"
[[package]] [[package]]
name = "bindgen" name = "bindgen"
version = "0.69.5" version = "0.71.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3"
dependencies = [ dependencies = [
"bitflags 2.9.4", "bitflags 2.9.4",
"cexpr", "cexpr",
"clang-sys", "clang-sys",
"itertools 0.12.1", "itertools 0.13.0",
"lazy_static",
"lazycell",
"log", "log",
"prettyplease", "prettyplease",
"proc-macro2", "proc-macro2",
"quote", "quote",
"regex", "regex",
"rustc-hash 1.1.0", "rustc-hash 2.1.1",
"shlex", "shlex",
"syn 2.0.106", "syn 2.0.106",
"which",
] ]
[[package]] [[package]]
name = "bindgen" name = "bindgen"
version = "0.71.1" version = "0.72.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895"
dependencies = [ dependencies = [
"bitflags 2.9.4", "bitflags 2.9.4",
"cexpr", "cexpr",
@@ -903,9 +912,9 @@ dependencies = [
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.2.36" version = "1.2.37"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5252b3d2648e5eedbc1a6f501e3c795e07025c1e93bbf8bbdd6eef7f447a6d54" checksum = "65193589c6404eb80b450d618eaf9a2cafaaafd57ecce47370519ef674a7bd44"
dependencies = [ dependencies = [
"find-msvc-tools", "find-msvc-tools",
"jobserver", "jobserver",
@@ -985,16 +994,15 @@ dependencies = [
[[package]] [[package]]
name = "chrono" name = "chrono"
version = "0.4.41" version = "0.4.42"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2"
dependencies = [ dependencies = [
"android-tzdata",
"iana-time-zone", "iana-time-zone",
"js-sys", "js-sys",
"num-traits", "num-traits",
"wasm-bindgen", "wasm-bindgen",
"windows-link 0.1.3", "windows-link 0.2.0",
] ]
[[package]] [[package]]
@@ -1021,7 +1029,7 @@ dependencies = [
[[package]] [[package]]
name = "client_keys" name = "client_keys"
version = "0.2.5" version = "0.2.6"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"global", "global",
@@ -1123,7 +1131,7 @@ dependencies = [
[[package]] [[package]]
name = "collections" name = "collections"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#0ef7ee172fd8dd4d0638a9731140cb3a74344918" source = "git+https://github.com/zed-industries/zed#ded646760467d653fd57ee3ef4fc1edcfafba6ae"
dependencies = [ dependencies = [
"indexmap", "indexmap",
"rustc-hash 2.1.1", "rustc-hash 2.1.1",
@@ -1158,7 +1166,7 @@ dependencies = [
[[package]] [[package]]
name = "common" name = "common"
version = "0.2.5" version = "0.2.6"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"chrono", "chrono",
@@ -1231,7 +1239,7 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
[[package]] [[package]]
name = "coop" name = "coop"
version = "0.2.5" version = "0.2.6"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"assets", "assets",
@@ -1564,7 +1572,7 @@ dependencies = [
[[package]] [[package]]
name = "derive_refineable" name = "derive_refineable"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#0ef7ee172fd8dd4d0638a9731140cb3a74344918" source = "git+https://github.com/zed-industries/zed#ded646760467d653fd57ee3ef4fc1edcfafba6ae"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -1826,12 +1834,12 @@ dependencies = [
[[package]] [[package]]
name = "errno" name = "errno"
version = "0.3.13" version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [ dependencies = [
"libc", "libc",
"windows-sys 0.60.2", "windows-sys 0.61.0",
] ]
[[package]] [[package]]
@@ -2342,7 +2350,7 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc257fdb4038301ce4b9cd1b3b51704509692bb3ff716a410cbd07925d9dae55" checksum = "fc257fdb4038301ce4b9cd1b3b51704509692bb3ff716a410cbd07925d9dae55"
dependencies = [ dependencies = [
"rustix 1.0.8", "rustix 1.1.2",
"windows-targets 0.52.6", "windows-targets 0.52.6",
] ]
@@ -2369,7 +2377,7 @@ dependencies = [
"js-sys", "js-sys",
"libc", "libc",
"r-efi", "r-efi",
"wasi 0.14.4+wasi-0.2.4", "wasi 0.14.5+wasi-0.2.4",
"wasm-bindgen", "wasm-bindgen",
] ]
@@ -2397,7 +2405,7 @@ checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
[[package]] [[package]]
name = "global" name = "global"
version = "0.2.5" version = "0.2.6"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"dirs 5.0.1", "dirs 5.0.1",
@@ -2490,11 +2498,11 @@ dependencies = [
[[package]] [[package]]
name = "gpui" name = "gpui"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#0ef7ee172fd8dd4d0638a9731140cb3a74344918" source = "git+https://github.com/zed-industries/zed#ded646760467d653fd57ee3ef4fc1edcfafba6ae"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"as-raw-xcb-connection", "as-raw-xcb-connection",
"ashpd", "ashpd 0.11.0",
"async-task", "async-task",
"bindgen 0.71.1", "bindgen 0.71.1",
"blade-graphics", "blade-graphics",
@@ -2584,7 +2592,7 @@ dependencies = [
[[package]] [[package]]
name = "gpui_macros" name = "gpui_macros"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#0ef7ee172fd8dd4d0638a9731140cb3a74344918" source = "git+https://github.com/zed-industries/zed#ded646760467d653fd57ee3ef4fc1edcfafba6ae"
dependencies = [ dependencies = [
"heck 0.5.0", "heck 0.5.0",
"proc-macro2", "proc-macro2",
@@ -2596,7 +2604,7 @@ dependencies = [
[[package]] [[package]]
name = "gpui_tokio" name = "gpui_tokio"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#0ef7ee172fd8dd4d0638a9731140cb3a74344918" source = "git+https://github.com/zed-industries/zed#ded646760467d653fd57ee3ef4fc1edcfafba6ae"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"gpui", "gpui",
@@ -2773,15 +2781,6 @@ dependencies = [
"digest", "digest",
] ]
[[package]]
name = "home"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf"
dependencies = [
"windows-sys 0.59.0",
]
[[package]] [[package]]
name = "http" name = "http"
version = "1.3.1" version = "1.3.1"
@@ -2819,7 +2818,7 @@ dependencies = [
[[package]] [[package]]
name = "http_client" name = "http_client"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#0ef7ee172fd8dd4d0638a9731140cb3a74344918" source = "git+https://github.com/zed-industries/zed#ded646760467d653fd57ee3ef4fc1edcfafba6ae"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bytes", "bytes",
@@ -2839,7 +2838,7 @@ dependencies = [
[[package]] [[package]]
name = "http_client_tls" name = "http_client_tls"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#0ef7ee172fd8dd4d0638a9731140cb3a74344918" source = "git+https://github.com/zed-industries/zed#ded646760467d653fd57ee3ef4fc1edcfafba6ae"
dependencies = [ dependencies = [
"rustls", "rustls",
"rustls-platform-verifier", "rustls-platform-verifier",
@@ -2942,16 +2941,16 @@ dependencies = [
[[package]] [[package]]
name = "i18n" name = "i18n"
version = "0.2.5" version = "0.2.6"
dependencies = [ dependencies = [
"rust-i18n", "rust-i18n",
] ]
[[package]] [[package]]
name = "iana-time-zone" name = "iana-time-zone"
version = "0.1.63" version = "0.1.64"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb"
dependencies = [ dependencies = [
"android_system_properties", "android_system_properties",
"core-foundation-sys", "core-foundation-sys",
@@ -2959,7 +2958,7 @@ dependencies = [
"js-sys", "js-sys",
"log", "log",
"wasm-bindgen", "wasm-bindgen",
"windows-core 0.61.2", "windows-core 0.62.0",
] ]
[[package]] [[package]]
@@ -3142,9 +3141,9 @@ checksum = "d0263a3d970d5c054ed9312c0057b4f3bde9c0b33836d3637361d4a9e6e7a408"
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "2.11.0" version = "2.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9" checksum = "206a8042aec68fa4a62e8d3f7aa4ceb508177d9324faf261e1959e495b7a1921"
dependencies = [ dependencies = [
"equivalent", "equivalent",
"hashbrown 0.15.5", "hashbrown 0.15.5",
@@ -3374,12 +3373,6 @@ dependencies = [
"spin", "spin",
] ]
[[package]]
name = "lazycell"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]] [[package]]
name = "leak" name = "leak"
version = "0.1.2" version = "0.1.2"
@@ -3484,9 +3477,9 @@ checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
[[package]] [[package]]
name = "linux-raw-sys" name = "linux-raw-sys"
version = "0.9.4" version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
[[package]] [[package]]
name = "litemap" name = "litemap"
@@ -3536,9 +3529,9 @@ dependencies = [
[[package]] [[package]]
name = "lru" name = "lru"
version = "0.16.0" version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86ea4e65087ff52f3862caff188d489f1fab49a0cb09e01b2e3f1a617b10aaed" checksum = "bfe949189f46fabb938b3a9a0be30fdd93fd8a09260da863399a8cf3db756ec8"
[[package]] [[package]]
name = "lru-slab" name = "lru-slab"
@@ -3548,9 +3541,9 @@ checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154"
[[package]] [[package]]
name = "lyon" name = "lyon"
version = "1.0.1" version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91e7f9cda98b5430809e63ca5197b06c7d191bf7e26dfc467d5a3f0290e2a74f" checksum = "dbcb7d54d54c8937364c9d41902d066656817dce1e03a44e5533afebd1ef4352"
dependencies = [ dependencies = [
"lyon_algorithms", "lyon_algorithms",
"lyon_tessellation", "lyon_tessellation",
@@ -3558,9 +3551,9 @@ dependencies = [
[[package]] [[package]]
name = "lyon_algorithms" name = "lyon_algorithms"
version = "1.0.5" version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f13c9be19d257c7d37e70608ed858e8eab4b2afcea2e3c9a622e892acbf43c08" checksum = "f4c0829e28c4f336396f250d850c3987e16ce6db057ffe047ce0dd54aab6b647"
dependencies = [ dependencies = [
"lyon_path", "lyon_path",
"num-traits", "num-traits",
@@ -3568,9 +3561,9 @@ dependencies = [
[[package]] [[package]]
name = "lyon_geom" name = "lyon_geom"
version = "1.0.6" version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8af69edc087272df438b3ee436c4bb6d7c04aa8af665cfd398feae627dbd8570" checksum = "ce9333c02ea4517fd31207f126124352ad59975218c114c55dbb8f9d56fd4b45"
dependencies = [ dependencies = [
"arrayvec", "arrayvec",
"euclid", "euclid",
@@ -3579,9 +3572,9 @@ dependencies = [
[[package]] [[package]]
name = "lyon_path" name = "lyon_path"
version = "1.0.7" version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0047f508cd7a85ad6bad9518f68cce7b1bf6b943fb71f6da0ee3bc1e8cb75f25" checksum = "1aeca86bcfd632a15984ba029b539ffb811e0a70bf55e814ef8b0f54f506fdeb"
dependencies = [ dependencies = [
"lyon_geom", "lyon_geom",
"num-traits", "num-traits",
@@ -3589,9 +3582,9 @@ dependencies = [
[[package]] [[package]]
name = "lyon_tessellation" name = "lyon_tessellation"
version = "1.0.15" version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "579d42360a4b09846eff2feef28f538696c7d6c7439bfa65874ff3cbe0951b2c" checksum = "f3f586142e1280335b1bc89539f7c97dd80f08fc43e9ab1b74ef0a42b04aa353"
dependencies = [ dependencies = [
"float_next_after", "float_next_after",
"lyon_path", "lyon_path",
@@ -3636,7 +3629,7 @@ dependencies = [
[[package]] [[package]]
name = "media" name = "media"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#0ef7ee172fd8dd4d0638a9731140cb3a74344918" source = "git+https://github.com/zed-industries/zed#ded646760467d653fd57ee3ef4fc1edcfafba6ae"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bindgen 0.71.1", "bindgen 0.71.1",
@@ -3874,17 +3867,17 @@ checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8"
[[package]] [[package]]
name = "normpath" name = "normpath"
version = "1.3.0" version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8911957c4b1549ac0dc74e30db9c8b0e66ddcd6d7acc33098f4c63a64a6d7ed" checksum = "c178369371fd7db523726931e50d430b560e3059665abc537ba3277e9274c9c4"
dependencies = [ dependencies = [
"windows-sys 0.59.0", "windows-sys 0.61.0",
] ]
[[package]] [[package]]
name = "nostr" name = "nostr"
version = "0.43.0" version = "0.43.0"
source = "git+https://github.com/rust-nostr/nostr#53751050e317e1b6ab91b80b1dff4c867a519b38" source = "git+https://github.com/rust-nostr/nostr#b1016f439ef1da5f8fdeae14368f5b7340414389"
dependencies = [ dependencies = [
"aes", "aes",
"base64", "base64",
@@ -3908,7 +3901,7 @@ dependencies = [
[[package]] [[package]]
name = "nostr-connect" name = "nostr-connect"
version = "0.43.0" version = "0.43.0"
source = "git+https://github.com/rust-nostr/nostr#53751050e317e1b6ab91b80b1dff4c867a519b38" source = "git+https://github.com/rust-nostr/nostr#b1016f439ef1da5f8fdeae14368f5b7340414389"
dependencies = [ dependencies = [
"async-utility", "async-utility",
"nostr", "nostr",
@@ -3920,7 +3913,7 @@ dependencies = [
[[package]] [[package]]
name = "nostr-database" name = "nostr-database"
version = "0.43.0" version = "0.43.0"
source = "git+https://github.com/rust-nostr/nostr#53751050e317e1b6ab91b80b1dff4c867a519b38" source = "git+https://github.com/rust-nostr/nostr#b1016f439ef1da5f8fdeae14368f5b7340414389"
dependencies = [ dependencies = [
"flatbuffers", "flatbuffers",
"lru", "lru",
@@ -3931,7 +3924,7 @@ dependencies = [
[[package]] [[package]]
name = "nostr-lmdb" name = "nostr-lmdb"
version = "0.43.0" version = "0.43.0"
source = "git+https://github.com/rust-nostr/nostr#53751050e317e1b6ab91b80b1dff4c867a519b38" source = "git+https://github.com/rust-nostr/nostr#b1016f439ef1da5f8fdeae14368f5b7340414389"
dependencies = [ dependencies = [
"async-utility", "async-utility",
"flume", "flume",
@@ -3945,7 +3938,7 @@ dependencies = [
[[package]] [[package]]
name = "nostr-relay-pool" name = "nostr-relay-pool"
version = "0.43.0" version = "0.43.0"
source = "git+https://github.com/rust-nostr/nostr#53751050e317e1b6ab91b80b1dff4c867a519b38" source = "git+https://github.com/rust-nostr/nostr#b1016f439ef1da5f8fdeae14368f5b7340414389"
dependencies = [ dependencies = [
"async-utility", "async-utility",
"async-wsocket", "async-wsocket",
@@ -3962,7 +3955,7 @@ dependencies = [
[[package]] [[package]]
name = "nostr-sdk" name = "nostr-sdk"
version = "0.43.0" version = "0.43.0"
source = "git+https://github.com/rust-nostr/nostr#53751050e317e1b6ab91b80b1dff4c867a519b38" source = "git+https://github.com/rust-nostr/nostr#b1016f439ef1da5f8fdeae14368f5b7340414389"
dependencies = [ dependencies = [
"async-utility", "async-utility",
"nostr", "nostr",
@@ -4259,12 +4252,12 @@ checksum = "b4ce411919553d3f9fa53a0880544cda985a112117a0444d5ff1e870a893d6ea"
[[package]] [[package]]
name = "oo7" name = "oo7"
version = "0.4.3" version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6cb23d3ec3527d65a83be1c1795cb883c52cfa57147d42acc797127df56fc489" checksum = "e3299dd401feaf1d45afd8fd1c0586f10fcfb22f244bb9afa942cec73503b89d"
dependencies = [ dependencies = [
"aes", "aes",
"ashpd", "ashpd 0.12.0",
"async-fs", "async-fs",
"async-io", "async-io",
"async-lock", "async-lock",
@@ -4609,7 +4602,7 @@ dependencies = [
"concurrent-queue", "concurrent-queue",
"hermit-abi", "hermit-abi",
"pin-project-lite", "pin-project-lite",
"rustix 1.0.8", "rustix 1.1.2",
"windows-sys 0.60.2", "windows-sys 0.60.2",
] ]
@@ -5076,7 +5069,7 @@ dependencies = [
[[package]] [[package]]
name = "refineable" name = "refineable"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#0ef7ee172fd8dd4d0638a9731140cb3a74344918" source = "git+https://github.com/zed-industries/zed#ded646760467d653fd57ee3ef4fc1edcfafba6ae"
dependencies = [ dependencies = [
"derive_refineable", "derive_refineable",
"workspace-hack", "workspace-hack",
@@ -5113,7 +5106,7 @@ checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001"
[[package]] [[package]]
name = "registry" name = "registry"
version = "0.2.5" version = "0.2.6"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"common", "common",
@@ -5230,7 +5223,7 @@ dependencies = [
[[package]] [[package]]
name = "reqwest_client" name = "reqwest_client"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#0ef7ee172fd8dd4d0638a9731140cb3a74344918" source = "git+https://github.com/zed-industries/zed#ded646760467d653fd57ee3ef4fc1edcfafba6ae"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bytes", "bytes",
@@ -5429,15 +5422,15 @@ dependencies = [
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "1.0.8" version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e"
dependencies = [ dependencies = [
"bitflags 2.9.4", "bitflags 2.9.4",
"errno", "errno",
"libc", "libc",
"linux-raw-sys 0.9.4", "linux-raw-sys 0.11.0",
"windows-sys 0.60.2", "windows-sys 0.61.0",
] ]
[[package]] [[package]]
@@ -5465,7 +5458,7 @@ dependencies = [
"openssl-probe", "openssl-probe",
"rustls-pki-types", "rustls-pki-types",
"schannel", "schannel",
"security-framework 3.3.0", "security-framework 3.4.0",
] ]
[[package]] [[package]]
@@ -5502,7 +5495,7 @@ dependencies = [
"rustls-native-certs", "rustls-native-certs",
"rustls-platform-verifier-android", "rustls-platform-verifier-android",
"rustls-webpki", "rustls-webpki",
"security-framework 3.3.0", "security-framework 3.4.0",
"security-framework-sys", "security-framework-sys",
"webpki-root-certs 0.26.11", "webpki-root-certs 0.26.11",
"windows-sys 0.59.0", "windows-sys 0.59.0",
@@ -5516,9 +5509,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f"
[[package]] [[package]]
name = "rustls-webpki" name = "rustls-webpki"
version = "0.103.4" version = "0.103.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" checksum = "b5a37813727b78798e53c2bec3f5e8fe12a6d6f8389bf9ca7802add4c9905ad8"
dependencies = [ dependencies = [
"aws-lc-rs", "aws-lc-rs",
"ring", "ring",
@@ -5614,11 +5607,11 @@ dependencies = [
[[package]] [[package]]
name = "schannel" name = "schannel"
version = "0.1.27" version = "0.1.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1"
dependencies = [ dependencies = [
"windows-sys 0.59.0", "windows-sys 0.61.0",
] ]
[[package]] [[package]]
@@ -5735,9 +5728,9 @@ dependencies = [
[[package]] [[package]]
name = "security-framework" name = "security-framework"
version = "3.3.0" version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80fb1d92c5028aa318b4b8bd7302a5bfcf48be96a37fc6fc790f806b0004ee0c" checksum = "60b369d18893388b345804dc0007963c99b7d665ae71d275812d828c6f089640"
dependencies = [ dependencies = [
"bitflags 2.9.4", "bitflags 2.9.4",
"core-foundation 0.10.1", "core-foundation 0.10.1",
@@ -5748,9 +5741,9 @@ dependencies = [
[[package]] [[package]]
name = "security-framework-sys" name = "security-framework-sys"
version = "2.14.0" version = "2.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0"
dependencies = [ dependencies = [
"core-foundation-sys", "core-foundation-sys",
"libc", "libc",
@@ -5765,7 +5758,7 @@ checksum = "0f7d95a54511e0c7be3f51e8867aa8cf35148d7b9445d44de2f943e2b206e749"
[[package]] [[package]]
name = "semantic_version" name = "semantic_version"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#0ef7ee172fd8dd4d0638a9731140cb3a74344918" source = "git+https://github.com/zed-industries/zed#ded646760467d653fd57ee3ef4fc1edcfafba6ae"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"serde", "serde",
@@ -5900,7 +5893,7 @@ dependencies = [
[[package]] [[package]]
name = "settings" name = "settings"
version = "0.2.5" version = "0.2.6"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"global", "global",
@@ -5967,7 +5960,7 @@ dependencies = [
[[package]] [[package]]
name = "signer_proxy" name = "signer_proxy"
version = "0.2.5" version = "0.2.6"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"atomic-destructor", "atomic-destructor",
@@ -6206,7 +6199,7 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]] [[package]]
name = "sum_tree" name = "sum_tree"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#0ef7ee172fd8dd4d0638a9731140cb3a74344918" source = "git+https://github.com/zed-industries/zed#ded646760467d653fd57ee3ef4fc1edcfafba6ae"
dependencies = [ dependencies = [
"arrayvec", "arrayvec",
"log", "log",
@@ -6476,15 +6469,15 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
[[package]] [[package]]
name = "tempfile" name = "tempfile"
version = "3.21.0" version = "3.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15b61f8f20e3a6f7e0649d825294eaf317edce30f82cf6026e7e4cb9222a7d1e" checksum = "84fa4d11fadde498443cca10fd3ac23c951f0dc59e080e9f4b93d4df4e4eea53"
dependencies = [ dependencies = [
"fastrand 2.3.0", "fastrand 2.3.0",
"getrandom 0.3.3", "getrandom 0.3.3",
"once_cell", "once_cell",
"rustix 1.0.8", "rustix 1.1.2",
"windows-sys 0.60.2", "windows-sys 0.61.0",
] ]
[[package]] [[package]]
@@ -6509,7 +6502,7 @@ dependencies = [
[[package]] [[package]]
name = "theme" name = "theme"
version = "0.2.5" version = "0.2.6"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"gpui", "gpui",
@@ -6671,7 +6664,7 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]] [[package]]
name = "title_bar" name = "title_bar"
version = "0.2.5" version = "0.2.6"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"common", "common",
@@ -7042,7 +7035,7 @@ dependencies = [
[[package]] [[package]]
name = "ui" name = "ui"
version = "0.2.5" version = "0.2.6"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"common", "common",
@@ -7105,9 +7098,9 @@ checksum = "ce61d488bcdc9bc8b5d1772c404828b17fc481c0a582b5581e95fb233aef503e"
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.18" version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"
[[package]] [[package]]
name = "unicode-linebreak" name = "unicode-linebreak"
@@ -7236,7 +7229,7 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
[[package]] [[package]]
name = "util" name = "util"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#0ef7ee172fd8dd4d0638a9731140cb3a74344918" source = "git+https://github.com/zed-industries/zed#ded646760467d653fd57ee3ef4fc1edcfafba6ae"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-fs", "async-fs",
@@ -7405,9 +7398,18 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]] [[package]]
name = "wasi" name = "wasi"
version = "0.14.4+wasi-0.2.4" version = "0.14.5+wasi-0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88a5f4a424faf49c3c2c344f166f0662341d470ea185e939657aaff130f0ec4a" checksum = "a4494f6290a82f5fe584817a676a34b9d6763e8d9d18204009fb31dceca98fd4"
dependencies = [
"wasip2",
]
[[package]]
name = "wasip2"
version = "1.0.0+wasi-0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03fa2761397e5bd52002cd7e73110c71af2109aca4e521a9f40473fe685b0a24"
dependencies = [ dependencies = [
"wit-bindgen", "wit-bindgen",
] ]
@@ -7511,7 +7513,7 @@ checksum = "673a33c33048a5ade91a6b139580fa174e19fb0d23f396dca9fa15f2e1e49b35"
dependencies = [ dependencies = [
"cc", "cc",
"downcast-rs", "downcast-rs",
"rustix 1.0.8", "rustix 1.1.2",
"scoped-tls", "scoped-tls",
"smallvec", "smallvec",
"wayland-sys", "wayland-sys",
@@ -7524,7 +7526,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c66a47e840dc20793f2264eb4b3e4ecb4b75d91c0dd4af04b456128e0bdd449d" checksum = "c66a47e840dc20793f2264eb4b3e4ecb4b75d91c0dd4af04b456128e0bdd449d"
dependencies = [ dependencies = [
"bitflags 2.9.4", "bitflags 2.9.4",
"rustix 1.0.8", "rustix 1.1.2",
"wayland-backend", "wayland-backend",
"wayland-scanner", "wayland-scanner",
] ]
@@ -7535,7 +7537,7 @@ version = "0.31.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "447ccc440a881271b19e9989f75726d60faa09b95b0200a9b7eb5cc47c3eeb29" checksum = "447ccc440a881271b19e9989f75726d60faa09b95b0200a9b7eb5cc47c3eeb29"
dependencies = [ dependencies = [
"rustix 1.0.8", "rustix 1.1.2",
"wayland-client", "wayland-client",
"xcursor", "xcursor",
] ]
@@ -7666,18 +7668,6 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3" checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3"
[[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 0.38.44",
]
[[package]] [[package]]
name = "whoami" name = "whoami"
version = "1.6.1" version = "1.6.1"
@@ -7790,6 +7780,19 @@ dependencies = [
"windows-strings 0.4.2", "windows-strings 0.4.2",
] ]
[[package]]
name = "windows-core"
version = "0.62.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57fe7168f7de578d2d8a05b07fd61870d2e73b4020e9f49aa00da8471723497c"
dependencies = [
"windows-implement 0.60.0",
"windows-interface 0.59.1",
"windows-link 0.2.0",
"windows-result 0.4.0",
"windows-strings 0.5.0",
]
[[package]] [[package]]
name = "windows-future" name = "windows-future"
version = "0.2.1" version = "0.2.1"
@@ -7907,6 +7910,15 @@ dependencies = [
"windows-link 0.1.3", "windows-link 0.1.3",
] ]
[[package]]
name = "windows-result"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f"
dependencies = [
"windows-link 0.2.0",
]
[[package]] [[package]]
name = "windows-strings" name = "windows-strings"
version = "0.3.1" version = "0.3.1"
@@ -7925,6 +7937,15 @@ dependencies = [
"windows-link 0.1.3", "windows-link 0.1.3",
] ]
[[package]]
name = "windows-strings"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda"
dependencies = [
"windows-link 0.2.0",
]
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.45.0" version = "0.45.0"
@@ -8306,7 +8327,7 @@ dependencies = [
"as-raw-xcb-connection", "as-raw-xcb-connection",
"gethostname", "gethostname",
"libc", "libc",
"rustix 1.0.8", "rustix 1.1.2",
"x11rb-protocol", "x11rb-protocol",
"xcursor", "xcursor",
] ]
@@ -8324,7 +8345,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af3a19837351dc82ba89f8a125e22a3c475f05aba604acc023d62b2739ae2909" checksum = "af3a19837351dc82ba89f8a125e22a3c475f05aba604acc023d62b2739ae2909"
dependencies = [ dependencies = [
"libc", "libc",
"rustix 1.0.8", "rustix 1.1.2",
] ]
[[package]] [[package]]
@@ -8441,9 +8462,9 @@ dependencies = [
[[package]] [[package]]
name = "zbus" name = "zbus"
version = "5.10.0" version = "5.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67a073be99ace1adc48af593701c8015cd9817df372e14a1a6b0ee8f8bf043be" checksum = "2d07e46d035fb8e375b2ce63ba4e4ff90a7f73cf2ffb0138b29e1158d2eaadf7"
dependencies = [ dependencies = [
"async-broadcast", "async-broadcast",
"async-executor", "async-executor",
@@ -8474,9 +8495,9 @@ dependencies = [
[[package]] [[package]]
name = "zbus_macros" name = "zbus_macros"
version = "5.10.0" version = "5.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e80cd713a45a49859dcb648053f63265f4f2851b6420d47a958e5697c68b131" checksum = "57e797a9c847ed3ccc5b6254e8bcce056494b375b511b3d6edcec0aeb4defaca"
dependencies = [ dependencies = [
"proc-macro-crate", "proc-macro-crate",
"proc-macro2", "proc-macro2",
+1 -1
View File
@@ -4,7 +4,7 @@ members = ["crates/*"]
default-members = ["crates/coop"] default-members = ["crates/coop"]
[workspace.package] [workspace.package]
version = "0.2.6" version = "0.2.7"
edition = "2021" edition = "2021"
publish = false publish = false
+1 -1
View File
@@ -14,7 +14,7 @@ product-name = "Coop"
description = "Chat Freely, Stay Private on Nostr" description = "Chat Freely, Stay Private on Nostr"
identifier = "su.reya.coop" identifier = "su.reya.coop"
category = "SocialNetworking" category = "SocialNetworking"
version = "0.2.6" version = "0.2.7"
out-dir = "../../dist" out-dir = "../../dist"
before-packaging-command = "cargo build --release" before-packaging-command = "cargo build --release"
resources = ["Cargo.toml", "src"] resources = ["Cargo.toml", "src"]
+1 -1
View File
@@ -2,7 +2,7 @@ use std::sync::Mutex;
use gpui::{actions, App}; use gpui::{actions, App};
actions!(coop, [DarkMode, Settings, Logout, Quit]); actions!(coop, [ReloadMetadata, DarkMode, Settings, Logout, Quit]);
actions!(sidebar, [Reload, RelayStatus]); actions!(sidebar, [Reload, RelayStatus]);
pub fn load_embedded_fonts(cx: &App) { pub fn load_embedded_fonts(cx: &App) {
+167 -136
View File
@@ -42,7 +42,7 @@ use ui::notification::Notification;
use ui::popup_menu::PopupMenuExt; use ui::popup_menu::PopupMenuExt;
use ui::{h_flex, v_flex, ContextModal, Disableable, IconName, Root, Sizable, StyledExt}; use ui::{h_flex, v_flex, ContextModal, Disableable, IconName, Root, Sizable, StyledExt};
use crate::actions::{DarkMode, Logout, Settings}; use crate::actions::{DarkMode, Logout, ReloadMetadata, Settings};
use crate::views::compose::compose_button; use crate::views::compose::compose_button;
use crate::views::setup_relay::setup_nip17_relay; use crate::views::setup_relay::setup_nip17_relay;
use crate::views::{ use crate::views::{
@@ -64,18 +64,22 @@ pub fn new_account(window: &mut Window, cx: &mut App) {
} }
pub struct ChatSpace { pub struct ChatSpace {
// Workspace // App's Title Bar
title_bar: Entity<TitleBar>, title_bar: Entity<TitleBar>,
// App's Dock Area
dock: Entity<DockArea>, dock: Entity<DockArea>,
// Temporarily store all authentication requests // All authentication requests
auth_requests: HashMap<AuthRequest, bool>, auth_requests: HashMap<RelayUrl, AuthRequest>,
// Local state to determine if the user has set up NIP-17 relays // Local state to determine if the user has set up NIP-17 relays
has_nip17_relays: bool, nip17_relays: bool,
// System // All subscriptions for observing the app state
_subscriptions: SmallVec<[Subscription; 3]>, _subscriptions: SmallVec<[Subscription; 3]>,
// All long running tasks
_tasks: SmallVec<[Task<()>; 5]>, _tasks: SmallVec<[Task<()>; 5]>,
} }
@@ -182,7 +186,7 @@ impl ChatSpace {
dock, dock,
title_bar, title_bar,
auth_requests: HashMap::new(), auth_requests: HashMap::new(),
has_nip17_relays: true, nip17_relays: true,
_subscriptions: subscriptions, _subscriptions: subscriptions,
_tasks: tasks, _tasks: tasks,
} }
@@ -212,67 +216,60 @@ impl ChatSpace {
async fn observe_signer() { async fn observe_signer() {
let client = nostr_client(); let client = nostr_client();
let ingester = ingester(); let ingester = ingester();
let stream_timeout = Duration::from_secs(5);
let loop_duration = Duration::from_secs(1); let loop_duration = Duration::from_secs(1);
let mut is_sent_signal = false;
let mut identity: Option<PublicKey> = None;
loop { loop {
if let Some(public_key) = identity { let Ok(signer) = client.signer().await else {
let nip65 = Filter::new().kind(Kind::RelayList).author(public_key); smol::Timer::after(loop_duration).await;
continue;
};
if client.database().count(nip65).await.unwrap_or(0) > 0 { let Ok(public_key) = signer.get_public_key().await else {
let dm_relays = Filter::new().kind(Kind::InboxRelays).author(public_key); smol::Timer::after(loop_duration).await;
continue;
match client.database().query(dm_relays).await { };
Ok(events) => {
if let Some(event) = events.first_owned() {
let relay_urls = nip17::extract_relay_list(&event).collect_vec();
if relay_urls.is_empty() {
if !is_sent_signal {
ingester.send(Signal::DmRelayNotFound).await;
is_sent_signal = true;
}
} else {
break;
}
} else if !is_sent_signal {
ingester.send(Signal::DmRelayNotFound).await;
is_sent_signal = true;
} else {
break;
}
}
Err(e) => {
log::error!("Database query error: {e}");
if !is_sent_signal {
ingester.send(Signal::DmRelayNotFound).await;
is_sent_signal = true;
}
}
}
} else {
log::error!("Database error.");
break;
}
} else {
// Wait for signer set
if let Ok(signer) = client.signer().await {
if let Ok(public_key) = signer.get_public_key().await {
identity = Some(public_key);
// Notify the app that the signer has been set. // Notify the app that the signer has been set.
ingester.send(Signal::SignerSet(public_key)).await; ingester.send(Signal::SignerSet(public_key)).await;
// Subscribe to the NIP-65 relays for the public key. // Subscribe to the NIP-65 relays for the public key.
if let Err(e) = Self::fetch_nip65_relays(public_key).await { let filter = Filter::new()
log::error!("Failed to fetch NIP-65 relays: {e}"); .kind(Kind::RelayList)
} .author(public_key)
} .limit(1);
}
}
smol::Timer::after(loop_duration).await; match client
.stream_events_from(BOOTSTRAP_RELAYS, filter, stream_timeout)
.await
{
Ok(mut stream) => {
let mut processed_ids = HashSet::new();
if let Some(event) = stream.next().await {
if processed_ids.insert(event.id) {
// Fetch user's metadata event
Self::fetch_single_event(Kind::Metadata, event.pubkey).await;
// Fetch user's contact list event
Self::fetch_single_event(Kind::ContactList, event.pubkey).await;
// Fetch user's inbox relays event
Self::fetch_nip17_relays(event.pubkey).await;
break;
}
} else {
ingester.send(Signal::DmRelayNotFound).await;
}
}
Err(e) => {
log::error!("Error fetching NIP-17 Relay: {e:?}");
ingester.send(Signal::DmRelayNotFound).await;
}
};
break;
} }
} }
@@ -391,39 +388,6 @@ impl ChatSpace {
} }
match event.kind { match event.kind {
Kind::RelayList => {
if let Ok(true) = Self::is_self_event(&event).await {
// Fetch user's metadata event
Self::fetch_single_event(Kind::Metadata, event.pubkey).await;
// Fetch user's contact list event
Self::fetch_single_event(Kind::ContactList, event.pubkey).await;
// Fetch user's inbox relays event
Self::fetch_single_event(Kind::InboxRelays, event.pubkey).await;
}
}
Kind::InboxRelays => {
if let Ok(true) = Self::is_self_event(&event).await {
let relays = nip17::extract_relay_list(&event).collect_vec();
if !relays.is_empty() {
for relay in relays.clone().into_iter() {
if client.add_relay(relay).await.is_err() {
let notice = Notice::RelayFailed(relay.clone());
ingester.send(Signal::Notice(notice)).await;
}
if client.connect_relay(relay).await.is_err() {
let notice = Notice::RelayFailed(relay.clone());
ingester.send(Signal::Notice(notice)).await;
}
}
// Subscribe to gift wrap events only in the current user's NIP-17 relays
Self::fetch_gift_wrap(relays, event.pubkey).await;
}
}
}
Kind::ContactList => { Kind::ContactList => {
if let Ok(true) = Self::is_self_event(&event).await { if let Ok(true) = Self::is_self_event(&event).await {
let public_keys = event.tags.public_keys().copied().collect_vec(); let public_keys = event.tags.public_keys().copied().collect_vec();
@@ -439,7 +403,10 @@ impl ChatSpace {
} }
} }
Kind::Metadata => { Kind::Metadata => {
ingester.send(Signal::Metadata(event.into_owned())).await; if let Ok(metadata) = Metadata::from_json(&event.content) {
let profile = Profile::new(event.pubkey, metadata);
ingester.send(Signal::Metadata(profile)).await;
}
} }
Kind::GiftWrap => { Kind::GiftWrap => {
Self::unwrap_gift_wrap(&event, pubkey_tx).await; Self::unwrap_gift_wrap(&event, pubkey_tx).await;
@@ -558,9 +525,9 @@ impl ChatSpace {
this.set_unwrapping_status(status, cx); this.set_unwrapping_status(status, cx);
}); });
} }
Signal::Metadata(event) => { Signal::Metadata(profile) => {
registry.update(cx, |this, cx| { registry.update(cx, |this, cx| {
this.insert_or_update_person(event, cx); this.insert_or_update_person(profile, cx);
}); });
} }
Signal::Message((gift_wrap_id, event)) => { Signal::Message((gift_wrap_id, event)) => {
@@ -570,7 +537,7 @@ impl ChatSpace {
} }
Signal::DmRelayNotFound => { Signal::DmRelayNotFound => {
view.update(cx, |this, cx| { view.update(cx, |this, cx| {
this.set_no_nip17_relays(cx); this.set_required_relays(cx);
}) })
.ok(); .ok();
} }
@@ -603,6 +570,49 @@ impl ChatSpace {
} }
} }
pub async fn fetch_nip17_relays(public_key: PublicKey) {
let client = nostr_client();
let ingester = ingester();
let filter = Filter::new()
.kind(Kind::InboxRelays)
.author(public_key)
.limit(1);
match client.stream_events(filter, Duration::from_secs(5)).await {
Ok(mut stream) => {
let mut processed_ids = HashSet::new();
if let Some(event) = stream.next().await {
if processed_ids.insert(event.id) {
let relays = nip17::extract_relay_list(&event).collect_vec();
if !relays.is_empty() {
for relay in relays.clone().into_iter() {
if client.add_relay(relay).await.is_err() {
let notice = Notice::RelayFailed(relay.clone());
ingester.send(Signal::Notice(notice)).await;
}
if client.connect_relay(relay).await.is_err() {
let notice = Notice::RelayFailed(relay.clone());
ingester.send(Signal::Notice(notice)).await;
}
}
// Subscribe to gift wrap events only in the current user's NIP-17 relays
Self::fetch_gift_wrap(relays, event.pubkey).await;
}
}
} else {
ingester.send(Signal::DmRelayNotFound).await;
}
}
Err(e) => {
log::error!("Error fetching NIP-17 Relay: {e:?}");
ingester.send(Signal::DmRelayNotFound).await;
}
};
}
pub async fn fetch_gift_wrap(relays: Vec<&RelayUrl>, public_key: PublicKey) { pub async fn fetch_gift_wrap(relays: Vec<&RelayUrl>, public_key: PublicKey) {
let client = nostr_client(); let client = nostr_client();
let sub_id = css().gift_wrap_sub_id.clone(); let sub_id = css().gift_wrap_sub_id.clone();
@@ -617,23 +627,6 @@ impl ChatSpace {
} }
} }
/// Fetches NIP-65 relay list for a given public key
pub async fn fetch_nip65_relays(public_key: PublicKey) -> Result<(), Error> {
let client = nostr_client();
let css = css();
let filter = Filter::new()
.kind(Kind::RelayList)
.author(public_key)
.limit(1);
client
.subscribe_to(BOOTSTRAP_RELAYS, filter, css.auto_close_opts)
.await?;
Ok(())
}
/// Fetches metadata for a list of public keys /// Fetches metadata for a list of public keys
async fn fetch_metadata_for_pubkeys(public_keys: HashSet<PublicKey>) { async fn fetch_metadata_for_pubkeys(public_keys: HashSet<PublicKey>) {
if public_keys.is_empty() { if public_keys.is_empty() {
@@ -725,11 +718,9 @@ impl ChatSpace {
match event.created_at >= css.init_at { match event.created_at >= css.init_at {
// New message: send a signal to notify the UI // New message: send a signal to notify the UI
true => { true => {
// Prevent notification if the event was sent by Coop smol::Timer::after(Duration::from_millis(200)).await;
if !css.sent_ids.read().await.contains(&target.id) {
ingester.send(Signal::Message((target.id, event))).await; ingester.send(Signal::Message((target.id, event))).await;
} }
}
// Old message: Coop is probably processing the user's messages during initial load // Old message: Coop is probably processing the user's messages during initial load
false => { false => {
css.gift_wrap_processing.store(true, Ordering::Release); css.gift_wrap_processing.store(true, Ordering::Release);
@@ -939,20 +930,20 @@ impl ChatSpace {
} }
fn reopen_auth_request(&mut self, window: &mut Window, cx: &mut Context<Self>) { fn reopen_auth_request(&mut self, window: &mut Window, cx: &mut Context<Self>) {
for req in self.auth_requests.clone().into_iter() { for (_, request) in self.auth_requests.clone().into_iter() {
self.open_auth_request(req.0, window, cx); self.open_auth_request(request, window, cx);
} }
} }
fn push_auth_request(&mut self, req: &AuthRequest, cx: &mut Context<Self>) { fn push_auth_request(&mut self, req: &AuthRequest, cx: &mut Context<Self>) {
self.auth_requests.insert(req.to_owned(), false); self.auth_requests.insert(req.url.clone(), req.to_owned());
cx.notify(); cx.notify();
} }
fn sending_auth_request(&mut self, challenge: &str, cx: &mut Context<Self>) { fn sending_auth_request(&mut self, challenge: &str, cx: &mut Context<Self>) {
for (req, status) in self.auth_requests.iter_mut() { for (_, req) in self.auth_requests.iter_mut() {
if req.challenge == challenge { if req.challenge == challenge {
*status = true; req.sending = true;
cx.notify(); cx.notify();
} }
} }
@@ -962,16 +953,16 @@ impl ChatSpace {
if let Some(req) = self if let Some(req) = self
.auth_requests .auth_requests
.iter() .iter()
.find(|(req, _)| req.challenge == challenge) .find(|(_, req)| req.challenge == challenge)
{ {
req.1.to_owned() req.1.sending
} else { } else {
false false
} }
} }
fn remove_auth_request(&mut self, challenge: &str, cx: &mut Context<Self>) { fn remove_auth_request(&mut self, challenge: &str, cx: &mut Context<Self>) {
self.auth_requests.retain(|r, _| r.challenge != challenge); self.auth_requests.retain(|_, r| r.challenge != challenge);
cx.notify(); cx.notify();
} }
@@ -1023,8 +1014,8 @@ impl ChatSpace {
}); });
} }
fn set_no_nip17_relays(&mut self, cx: &mut Context<Self>) { fn set_required_relays(&mut self, cx: &mut Context<Self>) {
self.has_nip17_relays = false; self.nip17_relays = false;
cx.notify(); cx.notify();
} }
@@ -1051,21 +1042,15 @@ impl ChatSpace {
cx.spawn_in(window, async move |this, cx| { cx.spawn_in(window, async move |this, cx| {
if let Ok((secret, profile)) = task.await { if let Ok((secret, profile)) = task.await {
cx.update(|window, cx| { this.update_in(cx, |this, window, cx| {
this.update(cx, |this, cx| {
this.set_account_layout(secret, profile, window, cx); this.set_account_layout(secret, profile, window, cx);
}) })
.ok(); .ok();
})
.ok();
} else { } else {
cx.update(|window, cx| { this.update_in(cx, |this, window, cx| {
this.update(cx, |this, cx| {
this.set_onboarding_layout(window, cx); this.set_onboarding_layout(window, cx);
}) })
.ok(); .ok();
})
.ok();
} }
}) })
.detach(); .detach();
@@ -1090,6 +1075,50 @@ impl ChatSpace {
} }
} }
fn on_reload_metadata(
&mut self,
_ev: &ReloadMetadata,
window: &mut Window,
cx: &mut Context<Self>,
) {
let task: Task<Result<(), Error>> = cx.background_spawn(async move {
let client = nostr_client();
let css = css();
let filter = Filter::new().kind(Kind::PrivateDirectMessage);
let pubkeys: Vec<PublicKey> = client
.database()
.query(filter)
.await?
.into_iter()
.flat_map(|event| event.all_pubkeys())
.unique()
.collect();
let filter = Filter::new()
.kind(Kind::Metadata)
.limit(pubkeys.len())
.authors(pubkeys);
client
.subscribe_to(BOOTSTRAP_RELAYS, filter, css.auto_close_opts)
.await?;
Ok(())
});
cx.spawn_in(window, async move |_, cx| {
if task.await.is_ok() {
cx.update(|window, cx| {
window.push_notification(t!("common.refreshed"), cx);
})
.ok();
}
})
.detach();
}
fn on_sign_out(&mut self, _e: &Logout, _window: &mut Window, cx: &mut Context<Self>) { fn on_sign_out(&mut self, _e: &Logout, _window: &mut Window, cx: &mut Context<Self>) {
cx.background_spawn(async move { cx.background_spawn(async move {
let client = nostr_client(); let client = nostr_client();
@@ -1236,7 +1265,6 @@ impl ChatSpace {
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> impl IntoElement { ) -> impl IntoElement {
let proxy = AppSettings::get_proxy_user_avatars(cx); let proxy = AppSettings::get_proxy_user_avatars(cx);
let is_auto_auth = AppSettings::read_global(cx).is_auto_auth();
let updating = AutoUpdater::read_global(cx).status.is_updating(); let updating = AutoUpdater::read_global(cx).status.is_updating();
let updated = AutoUpdater::read_global(cx).status.is_updated(); let updated = AutoUpdater::read_global(cx).status.is_updated();
let auth_requests = self.auth_requests.len(); let auth_requests = self.auth_requests.len();
@@ -1275,7 +1303,7 @@ impl ChatSpace {
}), }),
) )
}) })
.when(auth_requests > 0 && !is_auto_auth, |this| { .when(auth_requests > 0, |this| {
this.child( this.child(
h_flex() h_flex()
.id("requests") .id("requests")
@@ -1295,7 +1323,7 @@ impl ChatSpace {
})), })),
) )
}) })
.when(!self.has_nip17_relays, |this| { .when(!self.nip17_relays, |this| {
this.child(setup_nip17_relay(t!("relays.button"))) this.child(setup_nip17_relay(t!("relays.button")))
}) })
.child( .child(
@@ -1309,6 +1337,8 @@ impl ChatSpace {
this.menu(t!("user.dark_mode"), Box::new(DarkMode)) this.menu(t!("user.dark_mode"), Box::new(DarkMode))
.menu(t!("user.settings"), Box::new(Settings)) .menu(t!("user.settings"), Box::new(Settings))
.separator() .separator()
.menu(t!("user.reload_metadata"), Box::new(ReloadMetadata))
.separator()
.menu(t!("user.sign_out"), Box::new(Logout)) .menu(t!("user.sign_out"), Box::new(Logout))
}), }),
) )
@@ -1429,6 +1459,7 @@ impl Render for ChatSpace {
.on_action(cx.listener(Self::on_dark_mode)) .on_action(cx.listener(Self::on_dark_mode))
.on_action(cx.listener(Self::on_sign_out)) .on_action(cx.listener(Self::on_sign_out))
.on_action(cx.listener(Self::on_open_profile)) .on_action(cx.listener(Self::on_open_profile))
.on_action(cx.listener(Self::on_reload_metadata))
.relative() .relative()
.size_full() .size_full()
.child( .child(
+99 -54
View File
@@ -24,7 +24,7 @@ use smallvec::{smallvec, SmallVec};
use smol::fs; use smol::fs;
use theme::ActiveTheme; use theme::ActiveTheme;
use ui::avatar::Avatar; use ui::avatar::Avatar;
use ui::button::{Button, ButtonVariants}; use ui::button::{Button, ButtonRounded, ButtonVariants};
use ui::dock_area::panel::{Panel, PanelEvent}; use ui::dock_area::panel::{Panel, PanelEvent};
use ui::emoji_picker::EmojiPicker; use ui::emoji_picker::EmojiPicker;
use ui::input::{InputEvent, InputState, TextInput}; use ui::input::{InputEvent, InputState, TextInput};
@@ -307,6 +307,38 @@ impl Chat {
.detach(); .detach();
} }
fn resend_message(&mut self, id: &EventId, window: &mut Window, cx: &mut Context<Self>) {
if let Some(reports) = self.reports_by_id.get(id).cloned() {
if let Some(message) = self.message(id) {
let backup = AppSettings::get_backup_messages(cx);
let id_clone = id.to_owned();
let message = message.content.to_owned();
let task = self.room.read(cx).resend(reports, message, backup, cx);
cx.spawn_in(window, async move |this, cx| {
match task.await {
Ok(reports) => {
this.update(cx, |this, cx| {
this.reports_by_id.entry(id_clone).and_modify(|this| {
*this = reports;
});
cx.notify();
})
.ok();
}
Err(e) => {
cx.update(|window, cx| {
window.push_notification(e.to_string(), cx);
})
.ok();
}
};
})
.detach();
}
}
}
/// Check if a message failed to send by its ID /// Check if a message failed to send by its ID
fn is_sent_failed(&self, id: &EventId) -> bool { fn is_sent_failed(&self, id: &EventId) -> bool {
self.reports_by_id self.reports_by_id
@@ -609,7 +641,23 @@ impl Chat {
}) })
.child(text) .child(text)
.when(is_sent_failed, |this| { .when(is_sent_failed, |this| {
this.child(self.render_message_reports(&id, cx)) this.child(
h_flex()
.gap_1()
.child(self.render_message_reports(&id, cx))
.child(
Button::new(SharedString::from(id.to_hex()))
.label(t!("common.resend"))
.danger()
.xsmall()
.rounded(ButtonRounded::Full)
.on_click(cx.listener(
move |this, _, window, cx| {
this.resend_message(&id, window, cx);
},
)),
),
)
}), }),
), ),
) )
@@ -677,15 +725,17 @@ impl Chat {
} }
fn render_message_sent(&self, id: &EventId, _cx: &Context<Self>) -> impl IntoElement { fn render_message_sent(&self, id: &EventId, _cx: &Context<Self>) -> impl IntoElement {
div().id("").child(shared_t!("chat.sent")).when_some( div()
self.sent_reports(id).cloned(), .id(SharedString::from(id.to_hex()))
|this, reports| { .child(shared_t!("chat.sent"))
.when_some(self.sent_reports(id).cloned(), |this, reports| {
this.on_click(move |_e, window, cx| { this.on_click(move |_e, window, cx| {
let reports = reports.clone(); let reports = reports.clone();
window.open_modal(cx, move |this, _window, cx| { window.open_modal(cx, move |this, _window, cx| {
this.title(shared_t!("chat.reports")).child( this.show_close(true)
v_flex().pb_4().gap_4().children({ .title(shared_t!("chat.reports"))
.child(v_flex().pb_4().gap_4().children({
let mut items = Vec::with_capacity(reports.len()); let mut items = Vec::with_capacity(reports.len());
for report in reports.iter() { for report in reports.iter() {
@@ -693,30 +743,29 @@ impl Chat {
} }
items items
}), }))
)
}); });
}) })
}, })
)
} }
fn render_message_reports(&self, id: &EventId, cx: &Context<Self>) -> impl IntoElement { fn render_message_reports(&self, id: &EventId, cx: &Context<Self>) -> impl IntoElement {
h_flex() h_flex()
.id("") .id(SharedString::from(id.to_hex()))
.gap_1() .gap_0p5()
.text_color(cx.theme().danger_foreground) .text_color(cx.theme().danger_foreground)
.text_xs() .text_xs()
.italic() .italic()
.child(Icon::new(IconName::Info).small()) .child(Icon::new(IconName::Info).xsmall())
.child(shared_t!("chat.sent_failed")) .child(shared_t!("chat.sent_failed"))
.when_some(self.sent_reports(id).cloned(), |this, reports| { .when_some(self.sent_reports(id).cloned(), |this, reports| {
this.on_click(move |_e, window, cx| { this.on_click(move |_e, window, cx| {
let reports = reports.clone(); let reports = reports.clone();
window.open_modal(cx, move |this, _window, cx| { window.open_modal(cx, move |this, _window, cx| {
this.title(shared_t!("chat.reports")).child( this.show_close(true)
v_flex().pb_4().gap_4().children({ .title(shared_t!("chat.reports"))
.child(v_flex().gap_4().pb_4().w_full().children({
let mut items = Vec::with_capacity(reports.len()); let mut items = Vec::with_capacity(reports.len());
for report in reports.iter() { for report in reports.iter() {
@@ -724,8 +773,7 @@ impl Chat {
} }
items items
}), }))
)
}); });
}) })
}) })
@@ -739,6 +787,7 @@ impl Chat {
v_flex() v_flex()
.gap_2() .gap_2()
.w_full()
.child( .child(
h_flex() h_flex()
.gap_2() .gap_2()
@@ -752,7 +801,7 @@ impl Chat {
.child(name.clone()), .child(name.clone()),
), ),
) )
.when(report.nip17_relays_not_found, |this| { .when(report.relays_not_found, |this| {
this.child( this.child(
h_flex() h_flex()
.flex_wrap() .flex_wrap()
@@ -773,7 +822,7 @@ impl Chat {
), ),
) )
}) })
.when_some(report.local_error.clone(), |this, error| { .when_some(report.error.clone(), |this, error| {
this.child( this.child(
h_flex() h_flex()
.flex_wrap() .flex_wrap()
@@ -788,38 +837,36 @@ impl Chat {
.child(div().flex_1().w_full().text_center().child(error)), .child(div().flex_1().w_full().text_center().child(error)),
) )
}) })
.when_some(report.output.clone(), |this, output| { .when_some(report.status.clone(), |this, output| {
this.child( this.child(
v_flex() v_flex()
.gap_2() .gap_2()
.text_xs() .w_full()
.children({ .children({
let mut items = Vec::with_capacity(output.failed.len()); let mut items = Vec::with_capacity(output.failed.len());
for (url, msg) in output.failed.into_iter() { for (url, msg) in output.failed.into_iter() {
items.push( items.push(
h_flex() v_flex()
.gap_1() .gap_0p5()
.justify_between() .py_1()
.text_sm() .px_2()
.w_full()
.rounded(cx.theme().radius)
.bg(cx.theme().elevated_surface_background)
.child( .child(
div() div()
.flex_1() .text_xs()
.py_0p5() .font_semibold()
.px_2() .line_height(relative(1.25))
.bg(cx.theme().elevated_surface_background) .child(SharedString::from(url.to_string())),
.rounded_sm()
.child(url.to_string()),
) )
.child( .child(
div() div()
.flex_1() .text_sm()
.py_0p5()
.px_2()
.bg(cx.theme().danger_background)
.text_color(cx.theme().danger_foreground) .text_color(cx.theme().danger_foreground)
.rounded_sm() .line_height(relative(1.25))
.child(msg.to_string()), .child(SharedString::from(msg.to_string())),
), ),
) )
} }
@@ -831,27 +878,25 @@ impl Chat {
for url in output.success.into_iter() { for url in output.success.into_iter() {
items.push( items.push(
h_flex() v_flex()
.gap_1() .gap_0p5()
.justify_between() .py_1()
.text_sm() .px_2()
.w_full()
.rounded(cx.theme().radius)
.bg(cx.theme().elevated_surface_background)
.child( .child(
div() div()
.flex_1() .text_xs()
.py_0p5() .font_semibold()
.px_2() .line_height(relative(1.25))
.bg(cx.theme().elevated_surface_background) .child(SharedString::from(url.to_string())),
.rounded_sm()
.child(url.to_string()),
) )
.child( .child(
div() div()
.flex_1() .text_sm()
.py_0p5()
.px_2()
.bg(cx.theme().secondary_background)
.text_color(cx.theme().secondary_foreground) .text_color(cx.theme().secondary_foreground)
.rounded_sm() .line_height(relative(1.25))
.child(shared_t!("chat.sent_success")), .child(shared_t!("chat.sent_success")),
), ),
) )
@@ -921,7 +966,7 @@ impl Chat {
let path: SharedString = url.to_string().into(); let path: SharedString = url.to_string().into();
div() div()
.id("") .id(SharedString::from(url.to_string()))
.relative() .relative()
.w_16() .w_16()
.child( .child(
+9 -2
View File
@@ -164,7 +164,7 @@ impl EditProfile {
.detach(); .detach();
} }
pub fn set_metadata(&mut self, cx: &mut Context<Self>) -> Task<Result<Option<Event>, Error>> { pub fn set_metadata(&mut self, cx: &mut Context<Self>) -> Task<Result<Option<Profile>, Error>> {
let avatar = self.avatar_input.read(cx).value().to_string(); let avatar = self.avatar_input.read(cx).value().to_string();
let name = self.name_input.read(cx).value().to_string(); let name = self.name_input.read(cx).value().to_string();
let bio = self.bio_input.read(cx).value().to_string(); let bio = self.bio_input.read(cx).value().to_string();
@@ -189,7 +189,14 @@ impl EditProfile {
cx.background_spawn(async move { cx.background_spawn(async move {
let client = nostr_client(); let client = nostr_client();
let output = client.set_metadata(&new_metadata).await?; let output = client.set_metadata(&new_metadata).await?;
let event = client.database().event_by_id(&output.val).await?; let event = client
.database()
.event_by_id(&output.val)
.await?
.map(|event| {
let metadata = Metadata::from_json(&event.content).unwrap_or_default();
Profile::new(event.pubkey, metadata)
});
Ok(event) Ok(event)
}) })
+6 -6
View File
@@ -41,28 +41,28 @@ impl Preferences {
fn open_edit_profile(&self, window: &mut Window, cx: &mut Context<Self>) { fn open_edit_profile(&self, window: &mut Window, cx: &mut Context<Self>) {
let view = edit_profile::init(window, cx); let view = edit_profile::init(window, cx);
let weak_view = view.downgrade(); let weak_view = view.downgrade();
let title = SharedString::new(t!("profile.title"));
window.open_modal(cx, move |modal, _window, _cx| { window.open_modal(cx, move |modal, _window, _cx| {
let weak_view = weak_view.clone(); let weak_view = weak_view.clone();
modal modal
.confirm() .confirm()
.title(title.clone()) .title(shared_t!("profile.title"))
.child(view.clone()) .child(view.clone())
.button_props(ModalButtonProps::default().ok_text(t!("common.update"))) .button_props(ModalButtonProps::default().ok_text(t!("common.update")))
.on_ok(move |_, window, cx| { .on_ok(move |_, window, cx| {
weak_view weak_view
.update(cx, |this, cx| { .update(cx, |this, cx| {
let set_metadata = this.set_metadata(cx); let set_metadata = this.set_metadata(cx);
let registry = Registry::global(cx);
cx.spawn_in(window, async move |_, cx| { cx.spawn_in(window, async move |_, cx| {
match set_metadata.await { match set_metadata.await {
Ok(event) => { Ok(profile) => {
if let Some(event) = event { if let Some(profile) = profile {
cx.update(|_, cx| { cx.update(|_, cx| {
Registry::global(cx).update(cx, |this, cx| { registry.update(cx, |this, cx| {
this.insert_or_update_person(event, cx); this.insert_or_update_person(profile, cx);
}); });
}) })
.ok(); .ok();
+1 -1
View File
@@ -37,7 +37,7 @@ pub const NOSTR_CONNECT_RELAY: &str = "wss://relay.nsec.app";
pub const RELAY_RETRY: u64 = 2; pub const RELAY_RETRY: u64 = 2;
/// Default retry count for sending messages /// Default retry count for sending messages
pub const SEND_RETRY: u64 = 5; pub const SEND_RETRY: u64 = 10;
/// Default timeout (in seconds) for Nostr Connect /// Default timeout (in seconds) for Nostr Connect
pub const NOSTR_CONNECT_TIMEOUT: u64 = 200; pub const NOSTR_CONNECT_TIMEOUT: u64 = 200;
+6 -4
View File
@@ -13,16 +13,18 @@ use crate::paths::support_dir;
pub mod constants; pub mod constants;
pub mod paths; pub mod paths;
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct AuthRequest { pub struct AuthRequest {
pub challenge: String,
pub url: RelayUrl, pub url: RelayUrl,
pub challenge: String,
pub sending: bool,
} }
impl AuthRequest { impl AuthRequest {
pub fn new(challenge: impl Into<String>, url: RelayUrl) -> Self { pub fn new(challenge: impl Into<String>, url: RelayUrl) -> Self {
Self { Self {
challenge: challenge.into(), challenge: challenge.into(),
sending: false,
url, url,
} }
} }
@@ -68,8 +70,8 @@ pub enum Signal {
/// A signal to notify UI that the browser proxy service is down /// A signal to notify UI that the browser proxy service is down
ProxyDown, ProxyDown,
/// A signal to notify UI that a new metadata event has been received /// A signal to notify UI that a new profile has been received
Metadata(Event), Metadata(Profile),
/// A signal to notify UI that a new gift wrap event has been received /// A signal to notify UI that a new gift wrap event has been received
Message((EventId, Event)), Message((EventId, Event)),
+9 -11
View File
@@ -155,21 +155,19 @@ impl Registry {
} }
/// Insert or update a person /// Insert or update a person
pub fn insert_or_update_person(&mut self, event: Event, cx: &mut App) { pub fn insert_or_update_person(&mut self, profile: Profile, cx: &mut App) {
let public_key = event.pubkey; let public_key = profile.public_key();
let Ok(metadata) = Metadata::from_json(event.content) else {
// Invalid metadata, no need to process further.
return;
};
if let Some(person) = self.persons.get(&public_key) { match self.persons.get(&public_key) {
Some(person) => {
person.update(cx, |this, cx| { person.update(cx, |this, cx| {
*this = Profile::new(public_key, metadata); *this = profile;
cx.notify(); cx.notify();
}); });
} else { }
self.persons None => {
.insert(public_key, cx.new(|_| Profile::new(public_key, metadata))); self.persons.insert(public_key, cx.new(|_| profile));
}
} }
} }
+125 -65
View File
@@ -1,4 +1,5 @@
use std::cmp::Ordering; use std::cmp::Ordering;
use std::collections::{HashMap, HashSet};
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::time::Duration; use std::time::Duration;
@@ -16,45 +17,51 @@ use crate::Registry;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct SendReport { pub struct SendReport {
pub receiver: PublicKey, pub receiver: PublicKey,
pub output: Option<Output<EventId>>, pub tags: Option<Vec<Tag>>,
pub local_error: Option<SharedString>, pub status: Option<Output<EventId>>,
pub nip17_relays_not_found: bool, pub error: Option<SharedString>,
pub relays_not_found: bool,
} }
impl SendReport { impl SendReport {
pub fn output(receiver: PublicKey, output: Output<EventId>) -> Self { pub fn new(receiver: PublicKey) -> Self {
Self { Self {
receiver, receiver,
output: Some(output), status: None,
local_error: None, error: None,
nip17_relays_not_found: false, tags: None,
relays_not_found: false,
} }
} }
pub fn error(receiver: PublicKey, error: impl Into<SharedString>) -> Self { pub fn not_found(mut self) -> Self {
Self { self.relays_not_found = true;
receiver, self
output: None,
local_error: Some(error.into()),
nip17_relays_not_found: false,
}
} }
pub fn nip17_relays_not_found(receiver: PublicKey) -> Self { pub fn error(mut self, error: impl Into<SharedString>) -> Self {
Self { self.error = Some(error.into());
receiver, self.relays_not_found = false;
output: None, self
local_error: None,
nip17_relays_not_found: true,
} }
pub fn status(mut self, output: Output<EventId>) -> Self {
self.status = Some(output);
self.relays_not_found = false;
self
}
pub fn tags(mut self, tags: &Vec<Tag>) -> Self {
self.tags = Some(tags.to_owned());
self
} }
pub fn is_relay_error(&self) -> bool { pub fn is_relay_error(&self) -> bool {
self.local_error.is_some() || self.nip17_relays_not_found self.error.is_some() || self.relays_not_found
} }
pub fn is_sent_success(&self) -> bool { pub fn is_sent_success(&self) -> bool {
if let Some(output) = self.output.as_ref() { if let Some(output) = self.status.as_ref() {
!output.success.is_empty() !output.success.is_empty()
} else { } else {
false false
@@ -338,19 +345,21 @@ impl Room {
cx.background_spawn(async move { cx.background_spawn(async move {
let client = nostr_client(); let client = nostr_client();
let public_key = members[members.len() - 1];
let filter = Filter::new() let sent = Filter::new()
.kind(Kind::PrivateDirectMessage) .kind(Kind::PrivateDirectMessage)
.authors(members.clone()) .author(public_key)
.pubkeys(members.clone()); .pubkeys(members.clone());
let events: Vec<Event> = client let recv = Filter::new()
.database() .kind(Kind::PrivateDirectMessage)
.query(filter) .authors(members)
.await? .pubkey(public_key);
.into_iter()
.filter(|ev| ev.compare_pubkeys(&members)) let sent_events = client.database().query(sent).await?;
.collect(); let recv_events = client.database().query(recv).await?;
let events: Vec<Event> = sent_events.merge(recv_events).into_iter().collect();
Ok(events) Ok(events)
}) })
@@ -398,17 +407,7 @@ impl Room {
event event
} }
/// Sends a message to all members in the background task /// Create a task to sends a message to all members in the background
///
/// # Arguments
///
/// * `content` - The content of the message to send
/// * `cx` - The App context
///
/// # Returns
///
/// A Task that resolves to Result<Vec<String>, Error> where the
/// strings contain error messages for any failed sends
pub fn send_in_background( pub fn send_in_background(
&self, &self,
content: &str, content: &str,
@@ -422,20 +421,21 @@ impl Room {
let mut public_keys = self.members.clone(); let mut public_keys = self.members.clone();
cx.background_spawn(async move { cx.background_spawn(async move {
let css = css();
let client = nostr_client(); let client = nostr_client();
let signer = client.signer().await?; let signer = client.signer().await?;
let public_key = signer.get_public_key().await?; let public_key = signer.get_public_key().await?;
let mut tags = public_keys let mut tags: Vec<Tag> = public_keys
.iter() .iter()
.filter_map(|pubkey| { .filter_map(|&this| {
if pubkey != &public_key { if this != public_key {
Some(Tag::public_key(*pubkey)) Some(Tag::public_key(this))
} else { } else {
None None
} }
}) })
.collect_vec(); .collect();
// Add event reference if it's present (replying to another event) // Add event reference if it's present (replying to another event)
if replies.len() == 1 { if replies.len() == 1 {
@@ -468,44 +468,50 @@ impl Room {
// Stored all send errors // Stored all send errors
let mut reports = vec![]; let mut reports = vec![];
for receiver in public_keys.into_iter() { for pubkey in public_keys.into_iter() {
match client match client
.send_private_msg(receiver, &content, tags.clone()) .send_private_msg(pubkey, &content, tags.clone())
.await .await
{ {
Ok(output) => { Ok(output) => {
if output let id = output.id().to_owned();
.failed let auth_required = output.failed.iter().any(|m| m.1.starts_with("auth-"));
.iter() let report = SendReport::new(pubkey).status(output).tags(&tags);
.any(|(_, msg)| msg.starts_with("auth-required:"))
{
let id = output.id();
if auth_required {
// Wait for authenticated and resent event successfully // Wait for authenticated and resent event successfully
for attempt in 0..=SEND_RETRY { for attempt in 0..=SEND_RETRY {
// Check if event was successfully resent // Check if event was successfully resent
if let Some(output) = if let Some(output) = css
css().resent_ids.read().await.iter().find(|o| o.id() == id) .resent_ids
.read()
.await
.iter()
.find(|e| e.id() == &id)
.cloned()
{ {
reports.push(SendReport::output(receiver, output.to_owned())); let output = SendReport::new(pubkey).status(output).tags(&tags);
reports.push(output);
break; break;
} }
// Check if retry limit exceeded
if attempt == SEND_RETRY { if attempt == SEND_RETRY {
reports.push(report);
break; break;
} }
smol::Timer::after(Duration::from_secs(1)).await; smol::Timer::after(Duration::from_millis(1200)).await;
} }
} else { } else {
reports.push(SendReport::output(receiver, output)); reports.push(report);
} }
} }
Err(e) => { Err(e) => {
if let nostr_sdk::client::Error::PrivateMsgRelaysNotFound = e { if let nostr_sdk::client::Error::PrivateMsgRelaysNotFound = e {
reports.push(SendReport::nip17_relays_not_found(receiver)); reports.push(SendReport::new(pubkey).not_found().tags(&tags));
} else { } else {
reports.push(SendReport::error(receiver, e.to_string())); reports.push(SendReport::new(pubkey).error(e.to_string()).tags(&tags));
} }
} }
} }
@@ -518,13 +524,14 @@ impl Room {
.await .await
{ {
Ok(output) => { Ok(output) => {
reports.push(SendReport::output(public_key, output)); reports.push(SendReport::new(public_key).status(output).tags(&tags));
} }
Err(e) => { Err(e) => {
if let nostr_sdk::client::Error::PrivateMsgRelaysNotFound = e { if let nostr_sdk::client::Error::PrivateMsgRelaysNotFound = e {
reports.push(SendReport::nip17_relays_not_found(public_key)); reports.push(SendReport::new(public_key).not_found());
} else { } else {
reports.push(SendReport::error(public_key, e.to_string())); reports
.push(SendReport::new(public_key).error(e.to_string()).tags(&tags));
} }
} }
} }
@@ -533,4 +540,57 @@ impl Room {
Ok(reports) Ok(reports)
}) })
} }
/// Create a task to resend a failed message
pub fn resend(
&self,
reports: Vec<SendReport>,
message: String,
backup: bool,
cx: &App,
) -> Task<Result<Vec<SendReport>, Error>> {
cx.background_spawn(async move {
let client = nostr_client();
let mut resend_reports = vec![];
let mut resend_tag = vec![];
for report in reports.into_iter() {
if let Some(output) = report.status {
let id = output.id();
let urls: Vec<&RelayUrl> = output.failed.keys().collect();
if let Some(event) = client.database().event_by_id(id).await? {
for url in urls.into_iter() {
let relay = client.pool().relay(url).await?;
let id = relay.send_event(&event).await?;
let resent: Output<EventId> = Output {
val: id,
success: HashSet::from([url.to_owned()]),
failed: HashMap::new(),
};
resend_reports.push(SendReport::new(report.receiver).status(resent));
}
if let Some(tags) = report.tags {
resend_tag.extend(tags);
}
}
}
}
// Only send a backup message to current user if sent successfully to others
if backup && !resend_reports.is_empty() {
let signer = client.signer().await?;
let public_key = signer.get_public_key().await?;
let output = client
.send_private_msg(public_key, message, resend_tag)
.await?;
resend_reports.push(SendReport::new(public_key).status(output));
}
Ok(resend_reports)
})
}
} }
+5 -1
View File
@@ -49,6 +49,8 @@ common:
en: "Relay URL is not valid." en: "Relay URL is not valid."
recommended: recommended:
en: "Recommended:" en: "Recommended:"
resend:
en: "Resend"
auto_update: auto_update:
updating: updating:
@@ -58,9 +60,11 @@ auto_update:
user: user:
dark_mode: dark_mode:
en: "Dark Mode" en: "Dark mode"
settings: settings:
en: "Settings" en: "Settings"
reload_metadata:
en: "Reload metadata"
sign_out: sign_out:
en: "Sign out" en: "Sign out"