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

View File

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

View File

@@ -1,5 +1,5 @@
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 NEW_MESSAGE_SUB_ID: &str = "listen_new_giftwrap";
pub const ALL_MESSAGES_SUB_ID: &str = "listen_all_giftwraps";

View File

@@ -13,22 +13,25 @@ use tokio::{
sync::{mpsc, Mutex},
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::{
account::AccountRegistry,
chat::ChatRegistry,
metadata::MetadataRegistry,
signal::{Signal, SignalRegistry},
};
use views::app::AppView;
pub mod asset;
pub mod constants;
pub mod states;
pub mod utils;
pub mod views;
mod asset;
mod constants;
mod states;
mod utils;
mod views;
actions!(main_menu, [Quit]);
actions!(app, [ReloadMetadata]);
@@ -128,8 +131,7 @@ async fn main() {
// Send event back to channel
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)
}
}
@@ -138,13 +140,13 @@ async fn main() {
Err(e) => println!("Unwrap error: {}", e),
}
} 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)
}
}
} else if let RelayMessage::EndOfStoredEvents(subscription_id) = message {
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)
}
}
@@ -211,6 +213,36 @@ async fn main() {
// Set quit action
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 {
let (tx, rx) = smol::channel::unbounded::<Signal>();
@@ -227,12 +259,12 @@ async fn main() {
while let Ok(signal) = rx.recv().await {
match signal {
Signal::RecvEose(_) => {
Signal::Eose => {
_ = async_cx.update_global::<ChatRegistry, _>(|state, _| {
state.update();
});
}
Signal::RecvEvent(event) => {
Signal::Event(event) => {
let metadata = async_cx
.background_executor()
.spawn(async move {
@@ -248,7 +280,7 @@ async fn main() {
state.push(event, metadata);
});
}
Signal::RecvMetadata(public_key) => {
Signal::Metadata(public_key) => {
let metadata = async_cx
.background_executor()
.spawn(async move {
@@ -264,7 +296,6 @@ async fn main() {
state.seen(public_key, metadata);
});
}
_ => {}
}
}
})

View File

@@ -10,6 +10,7 @@ use crate::{
pub struct AccountRegistry {
public_key: Option<PublicKey>,
pub(crate) is_loading: bool,
}
impl Global for AccountRegistry {}
@@ -58,6 +59,10 @@ impl AccountRegistry {
.detach();
}
pub fn set_loading(&mut self) {
self.is_loading = false
}
pub fn get(&self) -> Option<PublicKey> {
self.public_key
}
@@ -71,6 +76,9 @@ impl AccountRegistry {
}
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());
}
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>) {
let mut seens = self.seens.lock().unwrap();

View File

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

View File

@@ -1,32 +1,6 @@
use chrono::{Duration, Local, TimeZone};
use keyring::Entry;
use keyring_search::{Limit, List, Search};
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 {
let hex: Vec<String> = public_keys
.iter()

View File

@@ -4,8 +4,9 @@ use serde::Deserialize;
use std::sync::Arc;
use ui::{
dock::{DockArea, DockItem, DockPlacement},
indicator::Indicator,
theme::Theme,
Root, TitleBar,
Root, Sizable, TitleBar,
};
use super::{
@@ -143,10 +144,20 @@ impl Render for AppView {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
let modal_layer = Root::render_modal_layer(cx);
let notification_layer = Root::render_notification_layer(cx);
let state = cx.global::<AccountRegistry>();
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
.child(
TitleBar::new()

View File

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