From 60bca49200472d2da672f11d48d4557cc4b4ed3d Mon Sep 17 00:00:00 2001 From: reya Date: Sat, 6 Sep 2025 20:55:11 +0700 Subject: [PATCH] chore: update deps and refactor the event loop --- Cargo.lock | 185 +++++++++++++++--------- Cargo.toml | 1 + crates/coop/Cargo.toml | 1 + crates/coop/src/chatspace.rs | 207 +++++++++++++-------------- crates/coop/src/views/onboarding.rs | 3 +- crates/coop/src/views/sidebar/mod.rs | 11 +- crates/global/Cargo.toml | 3 +- crates/global/src/constants.rs | 3 - crates/global/src/lib.rs | 24 ++-- crates/registry/src/lib.rs | 42 +++--- 10 files changed, 259 insertions(+), 221 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0afd32e..42d3f51 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -655,7 +655,7 @@ checksum = "6099cdc01846bc367c4e7dd630dc5966dccf36b652fae7a74e17b640411a91b2" [[package]] name = "blade-graphics" version = "0.6.0" -source = "git+https://github.com/kvark/blade?rev=e0ec4e720957edd51b945b64dd85605ea54bcfe5#e0ec4e720957edd51b945b64dd85605ea54bcfe5" +source = "git+https://github.com/kvark/blade?rev=bfa594ea697d4b6326ea29f747525c85ecf933b9#bfa594ea697d4b6326ea29f747525c85ecf933b9" dependencies = [ "ash", "ash-window", @@ -688,7 +688,7 @@ dependencies = [ [[package]] name = "blade-macros" version = "0.3.0" -source = "git+https://github.com/kvark/blade?rev=e0ec4e720957edd51b945b64dd85605ea54bcfe5#e0ec4e720957edd51b945b64dd85605ea54bcfe5" +source = "git+https://github.com/kvark/blade?rev=bfa594ea697d4b6326ea29f747525c85ecf933b9#bfa594ea697d4b6326ea29f747525c85ecf933b9" dependencies = [ "proc-macro2", "quote", @@ -698,7 +698,7 @@ dependencies = [ [[package]] name = "blade-util" version = "0.2.0" -source = "git+https://github.com/kvark/blade?rev=e0ec4e720957edd51b945b64dd85605ea54bcfe5#e0ec4e720957edd51b945b64dd85605ea54bcfe5" +source = "git+https://github.com/kvark/blade?rev=bfa594ea697d4b6326ea29f747525c85ecf933b9#bfa594ea697d4b6326ea29f747525c85ecf933b9" dependencies = [ "blade-graphics", "bytemuck", @@ -903,9 +903,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.35" +version = "1.2.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "590f9024a68a8c40351881787f1934dc11afd69090f5edb6831464694d836ea3" +checksum = "5252b3d2648e5eedbc1a6f501e3c795e07025c1e93bbf8bbdd6eef7f447a6d54" dependencies = [ "find-msvc-tools", "jobserver", @@ -1123,7 +1123,7 @@ dependencies = [ [[package]] name = "collections" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#2a7761fe172217213c8092c52a42bfa0898b2688" +source = "git+https://github.com/zed-industries/zed#84f166fc85e1675fb76183ad6f212891d596c38d" dependencies = [ "indexmap", "rustc-hash 2.1.1", @@ -1239,6 +1239,7 @@ dependencies = [ "client_keys", "common", "dirs 5.0.1", + "flume", "futures", "global", "gpui", @@ -1563,7 +1564,7 @@ dependencies = [ [[package]] name = "derive_refineable" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#2a7761fe172217213c8092c52a42bfa0898b2688" +source = "git+https://github.com/zed-industries/zed#84f166fc85e1675fb76183ad6f212891d596c38d" dependencies = [ "proc-macro2", "quote", @@ -1903,6 +1904,26 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "fax" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05de7d48f37cd6730705cbca900770cab77a89f413d23e100ad7fad7795a0ab" +dependencies = [ + "fax_derive", +] + +[[package]] +name = "fax_derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + [[package]] name = "fdeflate" version = "0.3.7" @@ -1946,9 +1967,9 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e178e4fba8a2726903f6ba98a6d221e76f9c12c650d5dc0e6afdc50677b49650" +checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d" [[package]] name = "flatbuffers" @@ -2348,7 +2369,7 @@ dependencies = [ "js-sys", "libc", "r-efi", - "wasi 0.14.3+wasi-0.2.4", + "wasi 0.14.4+wasi-0.2.4", "wasm-bindgen", ] @@ -2380,9 +2401,8 @@ version = "0.2.5" dependencies = [ "anyhow", "dirs 5.0.1", - "futures", + "flume", "log", - "nostr-connect", "nostr-sdk", "rustls", "smol", @@ -2470,7 +2490,7 @@ dependencies = [ [[package]] name = "gpui" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#2a7761fe172217213c8092c52a42bfa0898b2688" +source = "git+https://github.com/zed-industries/zed#84f166fc85e1675fb76183ad6f212891d596c38d" dependencies = [ "anyhow", "as-raw-xcb-connection", @@ -2522,7 +2542,7 @@ dependencies = [ "pathfinder_geometry", "postage", "profiling", - "rand 0.8.5", + "rand 0.9.2", "raw-window-handle", "refineable", "resvg", @@ -2564,7 +2584,7 @@ dependencies = [ [[package]] name = "gpui_macros" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#2a7761fe172217213c8092c52a42bfa0898b2688" +source = "git+https://github.com/zed-industries/zed#84f166fc85e1675fb76183ad6f212891d596c38d" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -2576,7 +2596,7 @@ dependencies = [ [[package]] name = "gpui_tokio" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#2a7761fe172217213c8092c52a42bfa0898b2688" +source = "git+https://github.com/zed-industries/zed#84f166fc85e1675fb76183ad6f212891d596c38d" dependencies = [ "anyhow", "gpui", @@ -2799,7 +2819,7 @@ dependencies = [ [[package]] name = "http_client" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#2a7761fe172217213c8092c52a42bfa0898b2688" +source = "git+https://github.com/zed-industries/zed#84f166fc85e1675fb76183ad6f212891d596c38d" dependencies = [ "anyhow", "bytes", @@ -2819,7 +2839,7 @@ dependencies = [ [[package]] name = "http_client_tls" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#2a7761fe172217213c8092c52a42bfa0898b2688" +source = "git+https://github.com/zed-industries/zed#84f166fc85e1675fb76183ad6f212891d596c38d" dependencies = [ "rustls", "rustls-platform-verifier", @@ -3076,9 +3096,9 @@ dependencies = [ [[package]] name = "image" -version = "0.25.6" +version = "0.25.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db35664ce6b9810857a38a906215e75a9c879f0696556a39f59c62829710251a" +checksum = "529feb3e6769d234375c4cf1ee2ce713682b8e76538cb13f9fc23e1400a591e7" dependencies = [ "bytemuck", "byteorder-lite", @@ -3086,8 +3106,9 @@ dependencies = [ "exr", "gif", "image-webp", + "moxcms", "num-traits", - "png", + "png 0.18.0", "qoi", "ravif", "rayon", @@ -3313,17 +3334,11 @@ dependencies = [ "libc", ] -[[package]] -name = "jpeg-decoder" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00810f1d8b74be64b13dbf3db89ac67740615d6c891f0e7b6179326533011a07" - [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "0c0b063578492ceec17683ef2f8c5e89121fbd0b172cbc280635ab7567db2738" dependencies = [ "once_cell", "wasm-bindgen", @@ -3502,9 +3517,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.27" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" dependencies = [ "serde", "value-bag", @@ -3621,7 +3636,7 @@ dependencies = [ [[package]] name = "media" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#2a7761fe172217213c8092c52a42bfa0898b2688" +source = "git+https://github.com/zed-industries/zed#84f166fc85e1675fb76183ad6f212891d596c38d" dependencies = [ "anyhow", "bindgen 0.71.1", @@ -3737,6 +3752,16 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "moxcms" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd32fa8935aeadb8a8a6b6b351e40225570a37c43de67690383d87ef170cd08" +dependencies = [ + "num-traits", + "pxfm", +] + [[package]] name = "naga" version = "25.0.1" @@ -3859,7 +3884,7 @@ dependencies = [ [[package]] name = "nostr" version = "0.43.0" -source = "git+https://github.com/rust-nostr/nostr#762b6f71bbd003caf4ca90393b12f6a42a00c610" +source = "git+https://github.com/rust-nostr/nostr#1c66cfdc883e79ecc36e12c50bfce9e286f8c951" dependencies = [ "aes", "base64", @@ -3883,7 +3908,7 @@ dependencies = [ [[package]] name = "nostr-connect" version = "0.43.0" -source = "git+https://github.com/rust-nostr/nostr#762b6f71bbd003caf4ca90393b12f6a42a00c610" +source = "git+https://github.com/rust-nostr/nostr#1c66cfdc883e79ecc36e12c50bfce9e286f8c951" dependencies = [ "async-utility", "nostr", @@ -3895,7 +3920,7 @@ dependencies = [ [[package]] name = "nostr-database" version = "0.43.0" -source = "git+https://github.com/rust-nostr/nostr#762b6f71bbd003caf4ca90393b12f6a42a00c610" +source = "git+https://github.com/rust-nostr/nostr#1c66cfdc883e79ecc36e12c50bfce9e286f8c951" dependencies = [ "flatbuffers", "lru", @@ -3906,7 +3931,7 @@ dependencies = [ [[package]] name = "nostr-lmdb" version = "0.43.0" -source = "git+https://github.com/rust-nostr/nostr#762b6f71bbd003caf4ca90393b12f6a42a00c610" +source = "git+https://github.com/rust-nostr/nostr#1c66cfdc883e79ecc36e12c50bfce9e286f8c951" dependencies = [ "async-utility", "flume", @@ -3920,7 +3945,7 @@ dependencies = [ [[package]] name = "nostr-relay-pool" version = "0.43.0" -source = "git+https://github.com/rust-nostr/nostr#762b6f71bbd003caf4ca90393b12f6a42a00c610" +source = "git+https://github.com/rust-nostr/nostr#1c66cfdc883e79ecc36e12c50bfce9e286f8c951" dependencies = [ "async-utility", "async-wsocket", @@ -3937,7 +3962,7 @@ dependencies = [ [[package]] name = "nostr-sdk" version = "0.43.0" -source = "git+https://github.com/rust-nostr/nostr#762b6f71bbd003caf4ca90393b12f6a42a00c610" +source = "git+https://github.com/rust-nostr/nostr#1c66cfdc883e79ecc36e12c50bfce9e286f8c951" dependencies = [ "async-utility", "nostr", @@ -4561,6 +4586,19 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "png" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97baced388464909d42d89643fe4361939af9b7ce7a31ee32a168f832a70f2a0" +dependencies = [ + "bitflags 2.9.4", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + [[package]] name = "polling" version = "3.10.0" @@ -4711,6 +4749,15 @@ dependencies = [ "cc", ] +[[package]] +name = "pxfm" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "376f733579ac4d3b9fbf0afca99bf8f6b698d541118affca554d0b86f73c2470" +dependencies = [ + "num-traits", +] + [[package]] name = "qoi" version = "0.4.1" @@ -5029,7 +5076,7 @@ dependencies = [ [[package]] name = "refineable" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#2a7761fe172217213c8092c52a42bfa0898b2688" +source = "git+https://github.com/zed-industries/zed#84f166fc85e1675fb76183ad6f212891d596c38d" dependencies = [ "derive_refineable", "workspace-hack", @@ -5183,7 +5230,7 @@ dependencies = [ [[package]] name = "reqwest_client" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#2a7761fe172217213c8092c52a42bfa0898b2688" +source = "git+https://github.com/zed-industries/zed#84f166fc85e1675fb76183ad6f212891d596c38d" dependencies = [ "anyhow", "bytes", @@ -5718,7 +5765,7 @@ checksum = "0f7d95a54511e0c7be3f51e8867aa8cf35148d7b9445d44de2f943e2b206e749" [[package]] name = "semantic_version" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#2a7761fe172217213c8092c52a42bfa0898b2688" +source = "git+https://github.com/zed-industries/zed#84f166fc85e1675fb76183ad6f212891d596c38d" dependencies = [ "anyhow", "serde", @@ -6159,7 +6206,7 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "sum_tree" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#2a7761fe172217213c8092c52a42bfa0898b2688" +source = "git+https://github.com/zed-industries/zed#84f166fc85e1675fb76183ad6f212891d596c38d" dependencies = [ "arrayvec", "log", @@ -6520,13 +6567,16 @@ dependencies = [ [[package]] name = "tiff" -version = "0.9.1" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" +checksum = "af9605de7fee8d9551863fd692cce7637f548dbd9db9180fcc07ccc6d26c336f" dependencies = [ + "fax", "flate2", - "jpeg-decoder", + "half", + "quick-error", "weezl", + "zune-jpeg", ] [[package]] @@ -6579,7 +6629,7 @@ dependencies = [ "bytemuck", "cfg-if", "log", - "png", + "png 0.17.16", "tiny-skia-path", ] @@ -7186,7 +7236,7 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "util" version = "0.1.0" -source = "git+https://github.com/zed-industries/zed#2a7761fe172217213c8092c52a42bfa0898b2688" +source = "git+https://github.com/zed-industries/zed#84f166fc85e1675fb76183ad6f212891d596c38d" dependencies = [ "anyhow", "async-fs", @@ -7355,9 +7405,9 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" -version = "0.14.3+wasi-0.2.4" +version = "0.14.4+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a51ae83037bdd272a9e28ce236db8c07016dd0d50c27038b3f407533c030c95" +checksum = "88a5f4a424faf49c3c2c344f166f0662341d470ea185e939657aaff130f0ec4a" dependencies = [ "wit-bindgen", ] @@ -7370,21 +7420,22 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "7e14915cadd45b529bb8d1f343c4ed0ac1de926144b746e2710f9cd05df6603b" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", + "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +checksum = "e28d1ba982ca7923fd01448d5c30c6864d0a14109560296a162f80f305fb93bb" dependencies = [ "bumpalo", "log", @@ -7396,9 +7447,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.50" +version = "0.4.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +checksum = "0ca85039a9b469b38336411d6d6ced91f3fc87109a2a27b0c197663f5144dffe" dependencies = [ "cfg-if", "js-sys", @@ -7409,9 +7460,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "7c3d463ae3eff775b0c45df9da45d68837702ac35af998361e2c84e7c5ec1b0d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -7419,9 +7470,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "7bb4ce89b08211f923caf51d527662b75bdc9c9c7aab40f86dcb9fb85ac552aa" dependencies = [ "proc-macro2", "quote", @@ -7432,9 +7483,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "f143854a3b13752c6950862c906306adb27c7e839f7414cec8fea35beab624c1" dependencies = [ "unicode-ident", ] @@ -7539,9 +7590,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.77" +version = "0.3.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +checksum = "77e4b637749ff0d92b8fad63aa1f7cff3cbe125fd49c175cd6345e7272638b12" dependencies = [ "js-sys", "wasm-bindgen", @@ -8195,9 +8246,9 @@ dependencies = [ [[package]] name = "wit-bindgen" -version = "0.45.0" +version = "0.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052283831dbae3d879dc7f51f3d92703a316ca49f91540417d38591826127814" +checksum = "5c573471f125075647d03df72e026074b7203790d41351cd6edc96f46bcccd36" [[package]] name = "workspace-hack" @@ -8550,9 +8601,9 @@ dependencies = [ [[package]] name = "zune-jpeg" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc1f7e205ce79eb2da3cd71c5f55f3589785cb7c79f6a03d1c8d1491bda5d089" +checksum = "29ce2c8a9384ad323cf564b67da86e21d3cfdff87908bc1223ed5c99bc792713" dependencies = [ "zune-core", ] diff --git a/Cargo.toml b/Cargo.toml index c7d8014..2648446 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,7 @@ itertools = "0.13.0" log = "0.4" oneshot = "0.1.10" reqwest = { version = "0.12", features = ["multipart", "stream", "json"] } +flume = { version = "0.11.1", default-features = false, features = ["async", "select"] } rust-embed = "8.5.0" rust-i18n = "3" serde = { version = "1.0", features = ["derive"] } diff --git a/crates/coop/Cargo.toml b/crates/coop/Cargo.toml index abd0179..898b869 100644 --- a/crates/coop/Cargo.toml +++ b/crates/coop/Cargo.toml @@ -59,6 +59,7 @@ smallvec.workspace = true smol.workspace = true futures.workspace = true oneshot.workspace = true +flume.workspace = true webbrowser.workspace = true tracing-subscriber = { version = "0.3.18", features = ["fmt"] } diff --git a/crates/coop/src/chatspace.rs b/crates/coop/src/chatspace.rs index e6ce61e..602744a 100644 --- a/crates/coop/src/chatspace.rs +++ b/crates/coop/src/chatspace.rs @@ -9,11 +9,12 @@ use auto_update::AutoUpdater; use client_keys::ClientKeys; use common::display::ReadableProfile; use common::event::EventUtils; +use flume::{Receiver, Sender}; use global::constants::{ ACCOUNT_IDENTIFIER, BOOTSTRAP_RELAYS, DEFAULT_SIDEBAR_WIDTH, METADATA_BATCH_LIMIT, METADATA_BATCH_TIMEOUT, SEARCH_RELAYS, }; -use global::{css, ingester, nostr_client, AuthRequest, Notice, Signal}; +use global::{css, ingester, nostr_client, AuthRequest, Notice, Signal, UnwrappingStatus}; use gpui::prelude::FluentBuilder; use gpui::{ div, px, rems, App, AppContext, AsyncWindowContext, Axis, Context, Entity, InteractiveElement, @@ -28,7 +29,6 @@ use registry::{Registry, RegistryEvent}; use settings::AppSettings; use signer_proxy::{BrowserSignerProxy, BrowserSignerProxyOptions}; use smallvec::{smallvec, SmallVec}; -use smol::channel::{Receiver, Sender}; use theme::{ActiveTheme, Theme, ThemeMode}; use title_bar::TitleBar; use ui::actions::OpenProfile; @@ -40,7 +40,6 @@ use ui::dock_area::{ClosePanel, DockArea, DockItem}; use ui::modal::ModalButtonProps; use ui::notification::Notification; use ui::popup_menu::PopupMenuExt; -use ui::tooltip::Tooltip; use ui::{h_flex, v_flex, ContextModal, IconName, Root, Sizable, StyledExt}; use crate::actions::{DarkMode, Logout, Settings}; @@ -69,20 +68,20 @@ pub struct ChatSpace { dock: Entity, auth_requests: Vec<(String, RelayUrl)>, has_nip17_relays: bool, - _subscriptions: SmallVec<[Subscription; 2]>, - _tasks: SmallVec<[Task<()>; 3]>, + _subscriptions: SmallVec<[Subscription; 3]>, + _tasks: SmallVec<[Task<()>; 5]>, } impl ChatSpace { pub fn new(window: &mut Window, cx: &mut Context) -> Self { - let registry = Registry::global(cx); let client_keys = ClientKeys::global(cx); + let registry = Registry::global(cx); + let status = registry.read(cx).unwrapping_status.clone(); let title_bar = cx.new(|_| TitleBar::new()); let dock = cx.new(|cx| DockArea::new(window, cx)); - let (pubkey_tx, pubkey_rx) = smol::channel::bounded::(1024); - + let (pubkey_tx, pubkey_rx) = flume::bounded::(1024); let mut subscriptions = smallvec![]; let mut tasks = smallvec![]; @@ -97,6 +96,31 @@ impl ChatSpace { }), ); + subscriptions.push( + // Observe the global registry + cx.observe_in(&status, window, move |this, status, window, cx| { + let registry = Registry::global(cx); + let status = status.read(cx); + let all_panels = this.get_all_panel_ids(cx); + + match status { + UnwrappingStatus::Processing => { + registry.update(cx, |this, cx| { + this.load_rooms(window, cx); + this.refresh_rooms(all_panels, cx); + }); + } + UnwrappingStatus::Complete => { + registry.update(cx, |this, cx| { + this.load_rooms(window, cx); + this.refresh_rooms(all_panels, cx); + }); + } + _ => {} + }; + }), + ); + subscriptions.push( // Subscribe to open chat room requests cx.subscribe_in(®istry, window, move |this, _, event, window, cx| { @@ -181,7 +205,7 @@ impl ChatSpace { async fn observe_signer() { let client = nostr_client(); let ingester = ingester(); - let loop_duration = Duration::from_millis(500); + let loop_duration = Duration::from_secs(1); let mut is_sent_signal = false; let mut identity: Option = None; @@ -212,17 +236,16 @@ impl ChatSpace { break; } } - Err(_) => { + Err(e) => { + log::error!("Database query error: {e}"); if !is_sent_signal { ingester.send(Signal::DmRelayNotFound).await; is_sent_signal = true; } } } - } else if !is_sent_signal { - ingester.send(Signal::DmRelayNotFound).await; - is_sent_signal = true; } else { + log::error!("Database error."); break; } } else { @@ -250,13 +273,15 @@ impl ChatSpace { let client = nostr_client(); let css = css(); let ingester = ingester(); - let loop_duration = Duration::from_secs(10); - let mut total_notify = 0; + let loop_duration = Duration::from_secs(20); + let mut is_start_processing = false; + let mut total_loops = 0; loop { if client.has_signer().await { if css.gift_wrap_processing.load(Ordering::Acquire) { - ingester.send(Signal::EventProcessing).await; + is_start_processing = true; + total_loops += 1; // Reset gift wrap processing flag let _ = css.gift_wrap_processing.compare_exchange( @@ -265,11 +290,19 @@ impl ChatSpace { Ordering::Release, Ordering::Relaxed, ); + + let signal = Signal::GiftWrapProcess(UnwrappingStatus::Processing); + ingester.send(signal).await; } else { - // Only send signal to ingester a maximum of three times - if total_notify <= 3 { - ingester.send(Signal::EventProcessed(true)).await; - total_notify += 1; + // Only run further if we are already processing + // Wait until after 3 loops to prevent exiting early while events are still being processed + if is_start_processing && total_loops >= 3 { + let signal = Signal::GiftWrapProcess(UnwrappingStatus::Complete); + ingester.send(signal).await; + + // Reset the counter + is_start_processing = false; + total_loops = 0; } } } @@ -293,7 +326,7 @@ impl ChatSpace { loop { let futs = smol::future::or( async move { - if let Ok(public_key) = rx.recv().await { + if let Ok(public_key) = rx.recv_async().await { BatchEvent::PublicKey(public_key) } else { BatchEvent::Closed @@ -336,7 +369,6 @@ impl ChatSpace { let auto_close = SubscribeAutoCloseOptions::default().exit_policy(ReqExitPolicy::ExitOnEOSE); - let mut event_counter = 0; let mut processed_events: HashSet = HashSet::new(); let mut challenges: HashSet> = HashSet::new(); let mut notifications = client.notifications(); @@ -406,25 +438,15 @@ impl ChatSpace { ingester.send(Signal::Metadata(event.into_owned())).await; } Kind::GiftWrap => { - // Mark gift wrap event as currently being processed - css.gift_wrap_processing.store(true, Ordering::Release); - - // Process the gift wrap event - Self::unwrap_gift_wrap_event(&event, pubkey_tx).await; - - // Trigger a partial UI reload if at least 50 events have been processed - if event_counter >= 20 { - ingester.send(Signal::EventProcessed(false)).await; - event_counter = 0; - } - event_counter += 1; + Self::unwrap_gift_wrap(&event, pubkey_tx).await; } _ => {} } } RelayMessage::EndOfStoredEvents(subscription_id) => { if *subscription_id == css.gift_wrap_sub_id { - ingester.send(Signal::EventProcessed(false)).await; + let signal = Signal::GiftWrapProcess(UnwrappingStatus::Processing); + ingester.send(signal).await; } } RelayMessage::Auth { challenge } => { @@ -443,9 +465,7 @@ impl ChatSpace { // Keep track of events that need to be resent match MachineReadablePrefix::parse(&message) { Some(MachineReadablePrefix::AuthRequired) => { - if client.has_signer().await { - css.resend_queue.write().await.insert(event_id, relay_url); - }; + css.resend_queue.write().await.insert(event_id, relay_url); } Some(_) => {} None => {} @@ -463,7 +483,7 @@ impl ChatSpace { let signals = ingester.signals(); let mut is_open_proxy_modal = false; - while let Ok(signal) = signals.recv().await { + while let Ok(signal) = signals.recv_async().await { cx.update(|window, cx| { let registry = Registry::global(cx); let settings = AppSettings::global(cx); @@ -486,7 +506,7 @@ impl ChatSpace { // Load all chat rooms registry.update(cx, |this, cx| { this.set_identity(public_key, cx); - this.load_rooms(false, window, cx); + this.load_rooms(window, cx); }); } Signal::SignerUnset => { @@ -531,36 +551,21 @@ impl ChatSpace { .ok(); } } - // Notify the user that the gift wrap still processing - Signal::EventProcessing => { + Signal::GiftWrapProcess(status) => { registry.update(cx, |this, cx| { - this.set_loading(true, cx); + this.set_unwrapping_status(status, cx); }); } - Signal::EventProcessed(finish) => { - registry.update(cx, |this, cx| { - // Load all chat rooms in the database - this.load_rooms(finish, window, cx); - - // Send a signal to refresh all opened rooms' messages - if let Some(ids) = ChatSpace::all_panels(window, cx) { - this.refresh_rooms(ids, cx); - } - }); - } - // Add the new metadata to the registry or update the existing one Signal::Metadata(event) => { registry.update(cx, |this, cx| { this.insert_or_update_person(event, cx); }); } - // Convert the gift wrapped message to a message Signal::Message((gift_wrap_id, event)) => { registry.update(cx, |this, cx| { this.event_to_message(gift_wrap_id, event, window, cx); }); } - // Notify the user that the DM relay is not set Signal::DmRelayNotFound => { view.update(cx, |this, cx| { this.set_no_nip17_relays(cx); @@ -702,52 +707,46 @@ impl ChatSpace { } /// Unwraps a gift-wrapped event and processes its contents. - async fn unwrap_gift_wrap_event(gift: &Event, pubkey_tx: &Sender) -> bool { + async fn unwrap_gift_wrap(target: &Event, pubkey_tx: &Sender) { let client = nostr_client(); let ingester = ingester(); let css = css(); - let mut is_cached = false; + let mut message: Option = None; - let event = match Self::get_unwrapped_event(gift.id).await { - Ok(event) => { - is_cached = true; - event + if let Ok(event) = Self::get_unwrapped_event(target.id).await { + message = Some(event); + } else if let Ok(unwrapped) = client.unwrap_gift_wrap(target).await { + // Sign the unwrapped event with a RANDOM KEYS + if let Ok(event) = unwrapped.rumor.sign_with_keys(&Keys::generate()) { + // Save this event to the database for future use. + if let Err(e) = Self::set_unwrapped_event(target.id, &event).await { + log::warn!("Failed to cache unwrapped event: {e}") + } + + message = Some(event); } - Err(_) => { - match client.unwrap_gift_wrap(gift).await { - Ok(unwrap) => { - // Sign the unwrapped event with a RANDOM KEYS - let Ok(unwrapped) = unwrap.rumor.sign_with_keys(&Keys::generate()) else { - log::error!("Failed to sign event"); - return false; - }; + } - // Save this event to the database for future use. - if let Err(e) = Self::set_unwrapped_event(gift.id, &unwrapped).await { - log::warn!("Failed to cache unwrapped event: {e}") - } + if let Some(event) = message { + // Send all pubkeys to the metadata batch to sync data + for public_key in event.all_pubkeys() { + pubkey_tx.send_async(public_key).await.ok(); + } - unwrapped - } - Err(e) => { - log::error!("Failed to unwrap event: {e}"); - return false; + match event.created_at >= css.init_at { + // New message: send a signal to notify the UI + true => { + // Prevent notification if the event was sent by Coop + if !css.sent_ids.read().await.contains(&target.id) { + ingester.send(Signal::Message((target.id, event))).await; } } + // Old message: Coop is probably processing the user's messages during initial load + false => { + css.gift_wrap_processing.store(true, Ordering::Release); + } } - }; - - // Send all pubkeys to the metadata batch to sync data - for public_key in event.all_pubkeys() { - pubkey_tx.send(public_key).await.ok(); } - - // Send a notify to GPUI if this is a new message - if event.created_at >= css.init_at { - ingester.send(Signal::Message((gift.id, event))).await; - } - - is_cached } fn process_registry_event( @@ -1202,26 +1201,23 @@ impl ChatSpace { cx: &Context, ) -> impl IntoElement { let registry = Registry::read_global(cx); - let loading = registry.loading; + let status = registry.unwrapping_status.read(cx); h_flex() .gap_2() + .h_6() .w_full() .child(compose_button()) - .when(loading, |this| { + .when(status != &UnwrappingStatus::Complete, |this| { this.child( h_flex() - .id("downloading") .px_2() .h_6() .gap_1() .text_xs() .rounded_full() .bg(cx.theme().surface_background) - .child(shared_t!("loading.label")) - .tooltip(|window, cx| { - Tooltip::new(t!("loading.tooltip"), window, cx).into() - }), + .child(shared_t!("loading.label")), ) }) } @@ -1366,17 +1362,8 @@ impl ChatSpace { }); } - pub(crate) fn all_panels(window: &mut Window, cx: &mut App) -> Option> { - let Some(Some(root)) = window.root::() else { - return None; - }; - - let Ok(chatspace) = root.read(cx).view().clone().downcast::() else { - return None; - }; - - let ids: Vec = chatspace - .read(cx) + fn get_all_panel_ids(&self, cx: &App) -> Option> { + let ids: Vec = self .dock .read(cx) .items diff --git a/crates/coop/src/views/onboarding.rs b/crates/coop/src/views/onboarding.rs index 4952a03..62c84a3 100644 --- a/crates/coop/src/views/onboarding.rs +++ b/crates/coop/src/views/onboarding.rs @@ -148,7 +148,8 @@ impl Onboarding { client.set_signer(signer).await; } Err(e) => { - cx.update(|window, cx| { + log::warn!("Nostr Connect instance (QR Code) is timeout. TODO: fix this"); + this.update_in(cx, |_, window, cx| { window.push_notification( Notification::error(e.to_string()).title("Nostr Connect"), cx, diff --git a/crates/coop/src/views/sidebar/mod.rs b/crates/coop/src/views/sidebar/mod.rs index 2650456..67bee8b 100644 --- a/crates/coop/src/views/sidebar/mod.rs +++ b/crates/coop/src/views/sidebar/mod.rs @@ -6,7 +6,7 @@ use anyhow::{anyhow, Error}; use common::debounced_delay::DebouncedDelay; use common::display::{ReadableTimestamp, TextUtils}; use global::constants::{BOOTSTRAP_RELAYS, SEARCH_RELAYS}; -use global::nostr_client; +use global::{nostr_client, UnwrappingStatus}; use gpui::prelude::FluentBuilder; use gpui::{ div, uniform_list, AnyElement, App, AppContext, Context, Entity, EventEmitter, FocusHandle, @@ -33,7 +33,6 @@ mod list_item; const FIND_DELAY: u64 = 600; const FIND_LIMIT: usize = 10; -const TOTAL_SKELETONS: usize = 3; pub fn init(window: &mut Window, cx: &mut App) -> Entity { Sidebar::new(window, cx) @@ -587,7 +586,6 @@ impl Focusable for Sidebar { impl Render for Sidebar { fn render(&mut self, _window: &mut Window, cx: &mut Context) -> impl IntoElement { let registry = Registry::read_global(cx); - let loading = registry.loading; // Get rooms from either search results or the chat registry let rooms = if let Some(results) = self.local_result.read(cx).as_ref() { @@ -606,10 +604,9 @@ impl Render for Sidebar { // Get total rooms count let mut total_rooms = rooms.len(); - // If loading in progress - // Add 3 skeletons to the room list - if loading { - total_rooms += TOTAL_SKELETONS; + // Add 3 dummy rooms to display as skeletons + if registry.unwrapping_status.read(cx) != &UnwrappingStatus::Complete { + total_rooms += 3 } v_flex() diff --git a/crates/global/Cargo.toml b/crates/global/Cargo.toml index 9500109..8f6a194 100644 --- a/crates/global/Cargo.toml +++ b/crates/global/Cargo.toml @@ -5,11 +5,10 @@ edition.workspace = true publish.workspace = true [dependencies] -nostr-connect.workspace = true nostr-sdk.workspace = true dirs.workspace = true smol.workspace = true -futures.workspace = true +flume.workspace = true log.workspace = true anyhow.workspace = true diff --git a/crates/global/src/constants.rs b/crates/global/src/constants.rs index cae6f46..668ba55 100644 --- a/crates/global/src/constants.rs +++ b/crates/global/src/constants.rs @@ -51,9 +51,6 @@ pub const METADATA_BATCH_LIMIT: usize = 100; /// Maximum timeout for grouping metadata requests. (milliseconds) pub const METADATA_BATCH_TIMEOUT: u64 = 300; -/// Maximum timeout for waiting for finish (seconds) -pub const WAIT_FOR_FINISH: u64 = 60; - /// Default width of the sidebar. pub const DEFAULT_SIDEBAR_WIDTH: f32 = 240.; diff --git a/crates/global/src/lib.rs b/crates/global/src/lib.rs index bd8ad7e..691b5c7 100644 --- a/crates/global/src/lib.rs +++ b/crates/global/src/lib.rs @@ -3,10 +3,9 @@ use std::sync::atomic::AtomicBool; use std::sync::OnceLock; use std::time::Duration; -use nostr_connect::prelude::*; +use flume::{Receiver, Sender}; use nostr_sdk::prelude::*; use paths::nostr_file; -use smol::channel::{Receiver, Sender}; use smol::lock::RwLock; use crate::paths::support_dir; @@ -46,6 +45,14 @@ impl Notice { } } +#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord)] +pub enum UnwrappingStatus { + #[default] + Initialized, + Processing, + Complete, +} + /// Signals sent through the global event channel to notify UI #[derive(Debug)] pub enum Signal { @@ -67,11 +74,8 @@ pub enum Signal { /// A signal to notify UI that a new gift wrap event has been received Message((EventId, Event)), - /// A signal to notify UI that gift wrap events still processing - EventProcessing, - - /// A signal to notify UI that gift wrap events have been processed - EventProcessed(bool), + /// A signal to notify UI that gift wrap process status has changed + GiftWrapProcess(UnwrappingStatus), /// A signal to notify UI that no DM relay for current user was found DmRelayNotFound, @@ -94,7 +98,7 @@ impl Default for Ingester { impl Ingester { pub fn new() -> Self { - let (tx, rx) = smol::channel::bounded::(2048); + let (tx, rx) = flume::bounded::(2048); Self { rx, tx } } @@ -103,7 +107,7 @@ impl Ingester { } pub async fn send(&self, signal: Signal) { - if let Err(e) = self.tx.send(signal).await { + if let Err(e) = self.tx.send_async(signal).await { log::error!("Failed to send signal: {e}"); } } @@ -131,7 +135,7 @@ impl CoopSimpleStorage { Self { init_at: Timestamp::now(), gift_wrap_sub_id: SubscriptionId::new("inbox"), - gift_wrap_processing: AtomicBool::new(true), + gift_wrap_processing: AtomicBool::new(false), sent_ids: RwLock::new(HashSet::new()), resent_ids: RwLock::new(Vec::new()), resend_queue: RwLock::new(HashMap::new()), diff --git a/crates/registry/src/lib.rs b/crates/registry/src/lib.rs index 9f2e0da..1f9024a 100644 --- a/crates/registry/src/lib.rs +++ b/crates/registry/src/lib.rs @@ -5,7 +5,7 @@ use anyhow::Error; use common::event::EventUtils; use fuzzy_matcher::skim::SkimMatcherV2; use fuzzy_matcher::FuzzyMatcher; -use global::nostr_client; +use global::{nostr_client, UnwrappingStatus}; use gpui::{App, AppContext, Context, Entity, EventEmitter, Global, Task, WeakEntity, Window}; use itertools::Itertools; use nostr_sdk::prelude::*; @@ -41,10 +41,8 @@ pub struct Registry { /// Collection of all persons (user profiles) pub persons: HashMap>, - /// Indicates if rooms are currently being loaded - /// - /// Always equal to `true` when the app starts - pub loading: bool, + /// Status of the unwrapping process + pub unwrapping_status: Entity, /// Public Key of the current user pub identity: Option, @@ -73,6 +71,7 @@ impl Registry { /// Create a new Registry instance pub(crate) fn new(cx: &mut Context) -> Self { + let unwrapping_status = cx.new(|_| UnwrappingStatus::default()); let mut tasks = smallvec![]; let load_local_persons: Task, Error>> = @@ -104,10 +103,10 @@ impl Registry { ); Self { + unwrapping_status, rooms: vec![], persons: HashMap::new(), identity: None, - loading: true, _tasks: tasks, } } @@ -244,15 +243,17 @@ impl Registry { } /// Set the loading status of the registry. - pub fn set_loading(&mut self, status: bool, cx: &mut Context) { - self.loading = status; - cx.notify(); + pub fn set_unwrapping_status(&mut self, status: UnwrappingStatus, cx: &mut Context) { + self.unwrapping_status.update(cx, |this, cx| { + *this = status; + cx.notify(); + }); } /// Reset the registry. pub fn reset(&mut self, cx: &mut Context) { - // Reset the loading status (default: true) - self.loading = true; + // Reset the unwrapping status + self.set_unwrapping_status(UnwrappingStatus::default(), cx); // Clear the current identity self.identity = None; @@ -264,7 +265,7 @@ impl Registry { } /// Load all rooms from the database. - pub fn load_rooms(&mut self, finish: bool, window: &mut Window, cx: &mut Context) { + pub fn load_rooms(&mut self, window: &mut Window, cx: &mut Context) { log::info!("Starting to load chat rooms..."); // Get the contact bypass setting @@ -342,9 +343,6 @@ impl Registry { Ok(rooms) => { this.update_in(cx, move |_, window, cx| { cx.defer_in(window, move |this, _window, cx| { - if finish { - this.set_loading(false, cx); - } this.extend_rooms(rooms, cx); this.sort(cx); }); @@ -405,12 +403,14 @@ impl Registry { } /// Refresh messages for a room in the global registry - pub fn refresh_rooms(&mut self, ids: Vec, cx: &mut Context) { - for room in self.rooms.iter() { - if ids.contains(&room.read(cx).id) { - room.update(cx, |this, cx| { - this.emit_refresh(cx); - }); + pub fn refresh_rooms(&mut self, ids: Option>, cx: &mut Context) { + if let Some(ids) = ids { + for room in self.rooms.iter() { + if ids.contains(&room.read(cx).id) { + room.update(cx, |this, cx| { + this.emit_refresh(cx); + }); + } } } }