wip: refactor

This commit is contained in:
2025-01-02 09:58:42 +07:00
parent d53e75b775
commit 51b392a845
11 changed files with 94 additions and 188 deletions

108
Cargo.lock generated
View File

@@ -1202,8 +1202,6 @@ dependencies = [
"dirs 5.0.1", "dirs 5.0.1",
"gpui", "gpui",
"itertools 0.13.0", "itertools 0.13.0",
"keyring",
"keyring-search",
"nostr-sdk", "nostr-sdk",
"random_name_generator", "random_name_generator",
"reqwest_client", "reqwest_client",
@@ -1415,30 +1413,6 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a" checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a"
[[package]]
name = "dbus"
version = "0.9.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bb21987b9fb1613058ba3843121dd18b163b254d8a6e797e144cbac14d96d1b"
dependencies = [
"libc",
"libdbus-sys",
"winapi",
]
[[package]]
name = "dbus-secret-service"
version = "4.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b42a16374481d92aed73ae45b1f120207d8e71d24fb89f357fadbd8f946fd84b"
dependencies = [
"dbus",
"futures-util",
"num",
"once_cell",
"rand",
]
[[package]] [[package]]
name = "derive_more" name = "derive_more"
version = "0.99.18" version = "0.99.18"
@@ -2887,35 +2861,6 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]]
name = "keyring"
version = "3.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f8fe839464d4e4b37d756d7e910063696af79a7e877282cb1825e4ec5f10833"
dependencies = [
"byteorder",
"dbus-secret-service",
"log",
"security-framework 2.11.1",
"security-framework 3.1.0",
"windows-sys 0.59.0",
]
[[package]]
name = "keyring-search"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fba83ff0a0efb658afeaaa6de89c7abd3ccd34333f5a36d5dae417334fcd488"
dependencies = [
"byteorder",
"lazy_static",
"linux-keyutils",
"regex",
"secret-service",
"security-framework 2.11.1",
"windows-sys 0.52.0",
]
[[package]] [[package]]
name = "khronos-egl" name = "khronos-egl"
version = "6.0.0" version = "6.0.0"
@@ -2957,15 +2902,6 @@ version = "0.2.169"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
[[package]]
name = "libdbus-sys"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06085512b750d640299b79be4bad3d2fa90a9c00b1fd9e1b46364f66f0485c72"
dependencies = [
"pkg-config",
]
[[package]] [[package]]
name = "libfuzzer-sys" name = "libfuzzer-sys"
version = "0.4.8" version = "0.4.8"
@@ -3022,16 +2958,6 @@ dependencies = [
"syn 2.0.93", "syn 2.0.93",
] ]
[[package]]
name = "linux-keyutils"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "761e49ec5fd8a5a463f9b84e877c373d888935b71c6be78f3767fe2ae6bed18e"
dependencies = [
"bitflags 2.6.0",
"libc",
]
[[package]] [[package]]
name = "linux-raw-sys" name = "linux-raw-sys"
version = "0.3.8" version = "0.3.8"
@@ -4711,7 +4637,7 @@ dependencies = [
"openssl-probe", "openssl-probe",
"rustls-pki-types", "rustls-pki-types",
"schannel", "schannel",
"security-framework 3.1.0", "security-framework",
] ]
[[package]] [[package]]
@@ -4874,38 +4800,6 @@ dependencies = [
"cc", "cc",
] ]
[[package]]
name = "secret-service"
version = "4.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4d35ad99a181be0a60ffcbe85d680d98f87bdc4d7644ade319b87076b9dbfd4"
dependencies = [
"aes",
"cbc",
"futures-util",
"generic-array",
"hkdf",
"num",
"once_cell",
"rand",
"serde",
"sha2",
"zbus 4.4.0",
]
[[package]]
name = "security-framework"
version = "2.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
dependencies = [
"bitflags 2.6.0",
"core-foundation 0.9.4",
"core-foundation-sys",
"libc",
"security-framework-sys",
]
[[package]] [[package]]
name = "security-framework" name = "security-framework"
version = "3.1.0" version = "3.1.0"

View File

@@ -29,12 +29,6 @@ tracing = "0.1.40"
anyhow = "1.0.44" anyhow = "1.0.44"
smallvec = "1.13.2" smallvec = "1.13.2"
rust-embed = "8.5.0" rust-embed = "8.5.0"
keyring-search = "1.2.0"
keyring = { version = "3", features = [
"apple-native",
"windows-native",
"sync-secret-service",
] }
[profile.release] [profile.release]
codegen-units = 1 codegen-units = 1

View File

@@ -16,8 +16,6 @@ reqwest_client.workspace = true
tokio.workspace = true tokio.workspace = true
nostr-sdk.workspace = true nostr-sdk.workspace = true
keyring-search.workspace = true
keyring.workspace = true
anyhow.workspace = true anyhow.workspace = true
serde.workspace = true serde.workspace = true
serde_json.workspace = true serde_json.workspace = true

View File

@@ -1,5 +1,5 @@
pub const KEYRING_SERVICE: &str = "Coop Safe Storage"; pub const KEYRING_SERVICE: &str = "Coop Safe Storage";
pub const APP_NAME: &str = "coop"; pub const APP_NAME: &str = "Coop";
pub const FAKE_SIG: &str = "f9e79d141c004977192d05a86f81ec7c585179c371f7350a5412d33575a2a356433f58e405c2296ed273e2fe0aafa25b641e39cc4e1f3f261ebf55bce0cbac83"; pub const FAKE_SIG: &str = "f9e79d141c004977192d05a86f81ec7c585179c371f7350a5412d33575a2a356433f58e405c2296ed273e2fe0aafa25b641e39cc4e1f3f261ebf55bce0cbac83";
pub const NEW_MESSAGE_SUB_ID: &str = "listen_new_giftwrap"; pub const NEW_MESSAGE_SUB_ID: &str = "listen_new_giftwrap";
pub const ALL_MESSAGES_SUB_ID: &str = "listen_all_giftwraps"; pub const ALL_MESSAGES_SUB_ID: &str = "listen_all_giftwraps";

View File

@@ -13,22 +13,25 @@ use tokio::{
sync::{mpsc, Mutex}, sync::{mpsc, Mutex},
time::sleep, time::sleep,
}; };
use ui::Root;
use constants::{ALL_MESSAGES_SUB_ID, APP_NAME, FAKE_SIG, METADATA_DELAY, NEW_MESSAGE_SUB_ID}; use constants::{
ALL_MESSAGES_SUB_ID, APP_NAME, FAKE_SIG, KEYRING_SERVICE, METADATA_DELAY, NEW_MESSAGE_SUB_ID,
};
use ui::Root;
use views::app::AppView;
use states::{ use states::{
account::AccountRegistry, account::AccountRegistry,
chat::ChatRegistry, chat::ChatRegistry,
metadata::MetadataRegistry, metadata::MetadataRegistry,
signal::{Signal, SignalRegistry}, signal::{Signal, SignalRegistry},
}; };
use views::app::AppView;
pub mod asset; mod asset;
pub mod constants; mod constants;
pub mod states; mod states;
pub mod utils; mod utils;
pub mod views; mod views;
actions!(main_menu, [Quit]); actions!(main_menu, [Quit]);
actions!(app, [ReloadMetadata]); actions!(app, [ReloadMetadata]);
@@ -128,8 +131,7 @@ async fn main() {
// Send event back to channel // Send event back to channel
if subscription_id == new_message { if subscription_id == new_message {
if let Err(e) = signal_tx.send(Signal::RecvEvent(ev)).await if let Err(e) = signal_tx.send(Signal::Event(ev)).await {
{
println!("Send error: {}", e) println!("Send error: {}", e)
} }
} }
@@ -138,13 +140,13 @@ async fn main() {
Err(e) => println!("Unwrap error: {}", e), Err(e) => println!("Unwrap error: {}", e),
} }
} else if event.kind == Kind::Metadata { } else if event.kind == Kind::Metadata {
if let Err(e) = signal_tx.send(Signal::RecvMetadata(event.pubkey)).await { if let Err(e) = signal_tx.send(Signal::Metadata(event.pubkey)).await {
println!("Send error: {}", e) println!("Send error: {}", e)
} }
} }
} else if let RelayMessage::EndOfStoredEvents(subscription_id) = message { } else if let RelayMessage::EndOfStoredEvents(subscription_id) = message {
if subscription_id == all_messages { if subscription_id == all_messages {
if let Err(e) = signal_tx.send(Signal::RecvEose(subscription_id)).await { if let Err(e) = signal_tx.send(Signal::Eose).await {
println!("Send error: {}", e) println!("Send error: {}", e)
} }
} }
@@ -211,6 +213,36 @@ async fn main() {
// Set quit action // Set quit action
cx.on_action(quit); cx.on_action(quit);
cx.spawn(|async_cx| {
let task = cx.read_credentials(KEYRING_SERVICE);
async move {
if let Ok(res) = task.await {
if let Some((npub, secret)) = res {
let public_key = PublicKey::from_bech32(&npub).unwrap();
let hex = String::from_utf8(secret).unwrap();
let keys = Keys::parse(&hex).unwrap();
_ = client.set_signer(keys).await;
// Update global state
_ = async_cx.update_global::<AccountRegistry, _>(|state, _cx| {
state.set_user(Some(public_key));
state.set_loading();
});
} else {
_ = async_cx.update_global::<AccountRegistry, _>(|state, _| {
state.set_loading();
});
}
} else {
_ = async_cx.update_global::<AccountRegistry, _>(|state, _| {
state.set_loading();
});
}
}
})
.detach();
cx.spawn(|async_cx| async move { cx.spawn(|async_cx| async move {
let (tx, rx) = smol::channel::unbounded::<Signal>(); let (tx, rx) = smol::channel::unbounded::<Signal>();
@@ -227,12 +259,12 @@ async fn main() {
while let Ok(signal) = rx.recv().await { while let Ok(signal) = rx.recv().await {
match signal { match signal {
Signal::RecvEose(_) => { Signal::Eose => {
_ = async_cx.update_global::<ChatRegistry, _>(|state, _| { _ = async_cx.update_global::<ChatRegistry, _>(|state, _| {
state.update(); state.update();
}); });
} }
Signal::RecvEvent(event) => { Signal::Event(event) => {
let metadata = async_cx let metadata = async_cx
.background_executor() .background_executor()
.spawn(async move { .spawn(async move {
@@ -248,7 +280,7 @@ async fn main() {
state.push(event, metadata); state.push(event, metadata);
}); });
} }
Signal::RecvMetadata(public_key) => { Signal::Metadata(public_key) => {
let metadata = async_cx let metadata = async_cx
.background_executor() .background_executor()
.spawn(async move { .spawn(async move {
@@ -264,7 +296,6 @@ async fn main() {
state.seen(public_key, metadata); state.seen(public_key, metadata);
}); });
} }
_ => {}
} }
} }
}) })

View File

@@ -10,6 +10,7 @@ use crate::{
pub struct AccountRegistry { pub struct AccountRegistry {
public_key: Option<PublicKey>, public_key: Option<PublicKey>,
pub(crate) is_loading: bool,
} }
impl Global for AccountRegistry {} impl Global for AccountRegistry {}
@@ -58,6 +59,10 @@ impl AccountRegistry {
.detach(); .detach();
} }
pub fn set_loading(&mut self) {
self.is_loading = false
}
pub fn get(&self) -> Option<PublicKey> { pub fn get(&self) -> Option<PublicKey> {
self.public_key self.public_key
} }
@@ -71,6 +76,9 @@ impl AccountRegistry {
} }
fn new() -> Self { fn new() -> Self {
Self { public_key: None } Self {
public_key: None,
is_loading: true,
}
} }
} }

View File

@@ -17,10 +17,6 @@ impl MetadataRegistry {
cx.set_global(Self::new()); cx.set_global(Self::new());
} }
pub fn contains(&self, public_key: PublicKey) -> bool {
self.seens.lock().unwrap().contains(&public_key)
}
pub fn seen(&mut self, public_key: PublicKey, metadata: Option<Metadata>) { pub fn seen(&mut self, public_key: PublicKey, metadata: Option<Metadata>) {
let mut seens = self.seens.lock().unwrap(); let mut seens = self.seens.lock().unwrap();

View File

@@ -5,14 +5,12 @@ use tokio::sync::mpsc::UnboundedSender;
#[derive(Clone)] #[derive(Clone)]
pub enum Signal { pub enum Signal {
/// Request metadata
ReqMetadata(PublicKey),
/// Receive metadata /// Receive metadata
RecvMetadata(PublicKey), Metadata(PublicKey),
/// Receive EOSE
RecvEose(SubscriptionId),
/// Receive event /// Receive event
RecvEvent(Event), Event(Event),
/// Receive EOSE
Eose,
} }
pub struct SignalRegistry { pub struct SignalRegistry {

View File

@@ -1,32 +1,6 @@
use chrono::{Duration, Local, TimeZone}; use chrono::{Duration, Local, TimeZone};
use keyring::Entry;
use keyring_search::{Limit, List, Search};
use nostr_sdk::prelude::*; use nostr_sdk::prelude::*;
use crate::constants::KEYRING_SERVICE;
pub fn get_all_accounts_from_keyring() -> Vec<PublicKey> {
let search = Search::new().expect("Keyring not working.");
let results = search.by_service("Coop Safe Storage");
let list = List::list_credentials(&results, Limit::All);
let accounts: Vec<PublicKey> = list
.split_whitespace()
.filter(|v| v.starts_with("npub1") && !v.ends_with("coop"))
.filter_map(|i| PublicKey::from_bech32(i).ok())
.collect();
accounts
}
pub fn get_keys_by_account(public_key: PublicKey) -> Result<Keys, anyhow::Error> {
let bech32 = public_key.to_bech32()?;
let entry = Entry::new(KEYRING_SERVICE, &bech32)?;
let password = entry.get_password()?;
let keys = Keys::parse(&password)?;
Ok(keys)
}
pub fn get_room_id(owner: &PublicKey, public_keys: &[PublicKey]) -> String { pub fn get_room_id(owner: &PublicKey, public_keys: &[PublicKey]) -> String {
let hex: Vec<String> = public_keys let hex: Vec<String> = public_keys
.iter() .iter()

View File

@@ -4,8 +4,9 @@ use serde::Deserialize;
use std::sync::Arc; use std::sync::Arc;
use ui::{ use ui::{
dock::{DockArea, DockItem, DockPlacement}, dock::{DockArea, DockItem, DockPlacement},
indicator::Indicator,
theme::Theme, theme::Theme,
Root, TitleBar, Root, Sizable, TitleBar,
}; };
use super::{ use super::{
@@ -143,10 +144,20 @@ impl Render for AppView {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement { fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
let modal_layer = Root::render_modal_layer(cx); let modal_layer = Root::render_modal_layer(cx);
let notification_layer = Root::render_notification_layer(cx); let notification_layer = Root::render_notification_layer(cx);
let state = cx.global::<AccountRegistry>();
let mut content = div().size_full().flex().flex_col(); let mut content = div().size_full().flex().flex_col();
if cx.global::<AccountRegistry>().is_user_logged_in() { if state.is_loading {
content = content.child(div()).child(
div()
.flex_1()
.flex()
.items_center()
.justify_center()
.child(Indicator::new().small()),
)
} else if state.is_user_logged_in() {
content = content content = content
.child( .child(
TitleBar::new() TitleBar::new()

View File

@@ -1,6 +1,4 @@
use async_utility::task::spawn;
use gpui::*; use gpui::*;
use keyring::Entry;
use nostr_sdk::prelude::*; use nostr_sdk::prelude::*;
use ui::{ use ui::{
input::{InputEvent, TextInput}, input::{InputEvent, TextInput},
@@ -34,26 +32,30 @@ impl Onboarding {
fn save_keys(content: &str, cx: &mut ViewContext<Self>) -> anyhow::Result<(), anyhow::Error> { fn save_keys(content: &str, cx: &mut ViewContext<Self>) -> anyhow::Result<(), anyhow::Error> {
let keys = Keys::parse(content)?; let keys = Keys::parse(content)?;
let public_key = keys.public_key(); let public_key = keys.public_key();
let bech32 = public_key.to_bech32().unwrap(); let bech32 = public_key.to_bech32()?;
let secret = keys.secret_key().to_secret_hex(); let secret = keys.secret_key().to_secret_hex();
let entry = Entry::new(KEYRING_SERVICE, &bech32).unwrap(); let mut async_cx = cx.to_async();
let view_id = cx.entity_id();
// Save secret key to keyring cx.foreground_executor()
entry.set_password(&secret)?; .spawn({
let client = get_client();
let task = cx.write_credentials(KEYRING_SERVICE, &bech32, secret.as_bytes());
// Update signer async move {
spawn(async move { if task.await.is_ok() {
get_client().set_signer(keys).await; _ = client.set_signer(keys).await;
}); // Update global state
_ = async_cx.update_global::<AccountRegistry, _>(|state, cx| {
// Update globals state state.set_user(Some(public_key));
cx.update_global::<AccountRegistry, _>(|state, cx| { cx.notify(Some(view_id));
state.set_user(Some(public_key)); });
cx.notify(); }
}); }
})
.detach();
Ok(()) Ok(())
} }