wip: handle events

This commit is contained in:
2025-12-14 08:58:33 +07:00
parent af740f462c
commit dd2f940e33
9 changed files with 143 additions and 154 deletions

66
Cargo.lock generated
View File

@@ -1050,9 +1050,9 @@ dependencies = [
[[package]]
name = "cmake"
version = "0.1.55"
version = "0.1.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d49d74c227b6cc9f3c51a2c7c667a05b6453f7f0f952a5f8e4493bb9e731d68e"
checksum = "b042e5d8a74ae91bb0961acd039822472ec99f8ab0948cbf6d1369588f8be586"
dependencies = [
"cc",
]
@@ -1131,7 +1131,7 @@ dependencies = [
[[package]]
name = "collections"
version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#e860252185bbefc30b1a9a051167a42c549bd6b0"
source = "git+https://github.com/zed-industries/zed#0283bfb04949295086b5ce6c892defa9c3ecc008"
dependencies = [
"indexmap",
"rustc-hash 2.1.1",
@@ -1520,7 +1520,7 @@ dependencies = [
[[package]]
name = "derive_refineable"
version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#e860252185bbefc30b1a9a051167a42c549bd6b0"
source = "git+https://github.com/zed-industries/zed#0283bfb04949295086b5ce6c892defa9c3ecc008"
dependencies = [
"proc-macro2",
"quote",
@@ -1789,7 +1789,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
"windows-sys 0.59.0",
"windows-sys 0.61.2",
]
[[package]]
@@ -1985,6 +1985,17 @@ dependencies = [
"spin 0.9.8",
]
[[package]]
name = "flume"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e139bc46ca777eb5efaf62df0ab8cc5fd400866427e56c68b22e414e53bd3be"
dependencies = [
"futures-core",
"futures-sink",
"spin 0.9.8",
]
[[package]]
name = "fnv"
version = "1.0.7"
@@ -2391,7 +2402,7 @@ dependencies = [
[[package]]
name = "gpui"
version = "0.2.2"
source = "git+https://github.com/zed-industries/zed#e860252185bbefc30b1a9a051167a42c549bd6b0"
source = "git+https://github.com/zed-industries/zed#0283bfb04949295086b5ce6c892defa9c3ecc008"
dependencies = [
"anyhow",
"as-raw-xcb-connection",
@@ -2422,7 +2433,7 @@ dependencies = [
"embed-resource",
"etagere",
"filedescriptor",
"flume",
"flume 0.11.1",
"foreign-types 0.5.0",
"futures",
"gpui_macros",
@@ -2551,7 +2562,7 @@ dependencies = [
[[package]]
name = "gpui_macros"
version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#e860252185bbefc30b1a9a051167a42c549bd6b0"
source = "git+https://github.com/zed-industries/zed#0283bfb04949295086b5ce6c892defa9c3ecc008"
dependencies = [
"heck 0.5.0",
"proc-macro2",
@@ -2562,7 +2573,7 @@ dependencies = [
[[package]]
name = "gpui_tokio"
version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#e860252185bbefc30b1a9a051167a42c549bd6b0"
source = "git+https://github.com/zed-industries/zed#0283bfb04949295086b5ce6c892defa9c3ecc008"
dependencies = [
"anyhow",
"gpui",
@@ -2789,7 +2800,7 @@ dependencies = [
[[package]]
name = "http_client"
version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#e860252185bbefc30b1a9a051167a42c549bd6b0"
source = "git+https://github.com/zed-industries/zed#0283bfb04949295086b5ce6c892defa9c3ecc008"
dependencies = [
"anyhow",
"async-compression",
@@ -2814,7 +2825,7 @@ dependencies = [
[[package]]
name = "http_client_tls"
version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#e860252185bbefc30b1a9a051167a42c549bd6b0"
source = "git+https://github.com/zed-industries/zed#0283bfb04949295086b5ce6c892defa9c3ecc008"
dependencies = [
"rustls",
"rustls-platform-verifier",
@@ -3505,6 +3516,7 @@ dependencies = [
"assets",
"common",
"dirs 5.0.1",
"flume 0.12.0",
"futures",
"gpui",
"gpui-component",
@@ -3658,7 +3670,7 @@ dependencies = [
[[package]]
name = "media"
version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#e860252185bbefc30b1a9a051167a42c549bd6b0"
source = "git+https://github.com/zed-industries/zed#0283bfb04949295086b5ce6c892defa9c3ecc008"
dependencies = [
"anyhow",
"bindgen",
@@ -3965,7 +3977,7 @@ version = "0.44.0"
source = "git+https://github.com/rust-nostr/nostr#8ef9fb157cc4c895c80bfba8fc9c5f0879aba36c"
dependencies = [
"async-utility",
"flume",
"flume 0.11.1",
"heed",
"nostr",
"nostr-database",
@@ -4047,7 +4059,7 @@ version = "0.50.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
dependencies = [
"windows-sys 0.59.0",
"windows-sys 0.61.2",
]
[[package]]
@@ -4528,7 +4540,7 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
[[package]]
name = "perf"
version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#e860252185bbefc30b1a9a051167a42c549bd6b0"
source = "git+https://github.com/zed-industries/zed#0283bfb04949295086b5ce6c892defa9c3ecc008"
dependencies = [
"collections",
"serde",
@@ -4913,7 +4925,7 @@ dependencies = [
"once_cell",
"socket2",
"tracing",
"windows-sys 0.59.0",
"windows-sys 0.60.2",
]
[[package]]
@@ -5146,7 +5158,7 @@ dependencies = [
[[package]]
name = "refineable"
version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#e860252185bbefc30b1a9a051167a42c549bd6b0"
source = "git+https://github.com/zed-industries/zed#0283bfb04949295086b5ce6c892defa9c3ecc008"
dependencies = [
"derive_refineable",
]
@@ -5227,7 +5239,7 @@ dependencies = [
[[package]]
name = "reqwest_client"
version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#e860252185bbefc30b1a9a051167a42c549bd6b0"
source = "git+https://github.com/zed-industries/zed#0283bfb04949295086b5ce6c892defa9c3ecc008"
dependencies = [
"anyhow",
"bytes",
@@ -5426,7 +5438,7 @@ dependencies = [
"errno",
"libc",
"linux-raw-sys 0.11.0",
"windows-sys 0.59.0",
"windows-sys 0.61.2",
]
[[package]]
@@ -6206,7 +6218,7 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "sum_tree"
version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#e860252185bbefc30b1a9a051167a42c549bd6b0"
source = "git+https://github.com/zed-industries/zed#0283bfb04949295086b5ce6c892defa9c3ecc008"
dependencies = [
"arrayvec",
"log",
@@ -6455,7 +6467,7 @@ dependencies = [
"getrandom 0.3.4",
"once_cell",
"rustix 1.1.2",
"windows-sys 0.59.0",
"windows-sys 0.61.2",
]
[[package]]
@@ -7162,7 +7174,7 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
[[package]]
name = "util"
version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#e860252185bbefc30b1a9a051167a42c549bd6b0"
source = "git+https://github.com/zed-industries/zed#0283bfb04949295086b5ce6c892defa9c3ecc008"
dependencies = [
"anyhow",
"async-fs",
@@ -7198,7 +7210,7 @@ dependencies = [
[[package]]
name = "util_macros"
version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#e860252185bbefc30b1a9a051167a42c549bd6b0"
source = "git+https://github.com/zed-industries/zed#0283bfb04949295086b5ce6c892defa9c3ecc008"
dependencies = [
"perf",
"quote",
@@ -7620,7 +7632,7 @@ version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
dependencies = [
"windows-sys 0.48.0",
"windows-sys 0.61.2",
]
[[package]]
@@ -8681,7 +8693,7 @@ dependencies = [
[[package]]
name = "zlog"
version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#e860252185bbefc30b1a9a051167a42c549bd6b0"
source = "git+https://github.com/zed-industries/zed#0283bfb04949295086b5ce6c892defa9c3ecc008"
dependencies = [
"anyhow",
"chrono",
@@ -8692,7 +8704,7 @@ dependencies = [
[[package]]
name = "ztracing"
version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#e860252185bbefc30b1a9a051167a42c549bd6b0"
source = "git+https://github.com/zed-industries/zed#0283bfb04949295086b5ce6c892defa9c3ecc008"
dependencies = [
"tracing",
"tracing-subscriber",
@@ -8703,7 +8715,7 @@ dependencies = [
[[package]]
name = "ztracing_macro"
version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#e860252185bbefc30b1a9a051167a42c549bd6b0"
source = "git+https://github.com/zed-industries/zed#0283bfb04949295086b5ce6c892defa9c3ecc008"
[[package]]
name = "zune-core"

View File

@@ -4,7 +4,7 @@ use anyhow::Error;
use gpui::{App, AppContext, Context, Entity, Global, Subscription, Task};
use nostr_sdk::prelude::*;
use smallvec::{smallvec, SmallVec};
use state::NostrRegistry;
use state::client;
pub fn init(cx: &mut App) {
Account::set_global(cx.new(Account::new), cx);
@@ -48,9 +48,6 @@ impl Account {
/// Create a new account instance
fn new(cx: &mut Context<Self>) -> Self {
let nostr = NostrRegistry::global(cx);
let client = nostr.read(cx).client();
// Collect command line arguments
let args: Vec<String> = env::args().collect();
let account = args.get(1).and_then(|s| Keys::parse(s).ok());
@@ -67,7 +64,9 @@ impl Account {
// Set the signer
cx.background_executor()
.await_on_background(async move {
let client = client();
client.set_signer(keys).await;
log::info!("Signer is set");
})
.await;
@@ -109,10 +108,8 @@ impl Account {
}
fn init(&mut self, public_key: PublicKey, cx: &mut Context<Self>) {
let nostr = NostrRegistry::global(cx);
let client = nostr.read(cx).client();
let task: Task<Result<(), Error>> = cx.background_spawn(async move {
let client = client();
let opts = SubscribeAutoCloseOptions::default().exit_policy(ReqExitPolicy::ExitOnEOSE);
// Construct a filter to get the user's metadata

View File

@@ -34,3 +34,4 @@ futures.workspace = true
oneshot.workspace = true
tracing-subscriber = { version = "0.3.18", features = ["fmt"] }
flume = { version = "0.12", default-features = false, features = ["async", "select"] }

View File

@@ -27,8 +27,3 @@ pub fn load_embedded_fonts(cx: &App) {
.add_fonts(embedded_fonts.into_inner().unwrap())
.unwrap();
}
pub fn quit(_: &Quit, cx: &mut App) {
log::info!("Gracefully quitting the application . . .");
cx.quit();
}

View File

@@ -1,15 +1,15 @@
use std::sync::Arc;
use assets::Assets;
use common::{APP_ID, CLIENT_NAME};
use common::{APP_ID, BOOTSTRAP_RELAYS, CLIENT_NAME, SEARCH_RELAYS};
use gpui::{
point, px, size, AppContext, Application, Bounds, KeyBinding, Menu, MenuItem, SharedString,
TitlebarOptions, WindowBackgroundAppearance, WindowBounds, WindowDecorations, WindowKind,
WindowOptions,
point, px, size, AppContext, Application, Bounds, SharedString, TitlebarOptions,
WindowBackgroundAppearance, WindowBounds, WindowDecorations, WindowKind, WindowOptions,
};
use gpui_component::Root;
use state::client;
use crate::actions::{load_embedded_fonts, quit, Quit};
use crate::actions::load_embedded_fonts;
use crate::workspace::Workspace;
mod actions;
@@ -29,28 +29,32 @@ fn main() {
.with_assets(Assets)
.with_http_client(Arc::new(reqwest_client::ReqwestClient::new()));
// Initialize the nostr client
let client = client();
// Establish connection to all bootstrap relays
app.background_executor()
.spawn_with_priority(gpui::Priority::High, async move {
// Add bootstrap relays to the relay pool
for url in BOOTSTRAP_RELAYS {
client.add_relay(url).await.ok();
}
// Add search relays to the relay pool
for url in SEARCH_RELAYS {
client.add_relay(url).await.ok();
}
// Connect to all added relays
client.connect().await;
})
.detach();
// Run application
app.run(move |cx| {
// Load embedded fonts in assets/fonts
load_embedded_fonts(cx);
// Register the `quit` function
cx.on_action(quit);
// Register the `quit` function with CMD+Q (macOS)
#[cfg(target_os = "macos")]
cx.bind_keys([KeyBinding::new("cmd-q", Quit, None)]);
// Register the `quit` function with Super+Q (others)
#[cfg(not(target_os = "macos"))]
cx.bind_keys([KeyBinding::new("super-q", Quit, None)]);
// Set menu items
cx.set_menus(vec![Menu {
name: "Lume".into(),
items: vec![MenuItem::action("Quit", Quit)],
}]);
// Set up the window bounds
let bounds = Bounds::centered(None, size(px(920.0), px(700.0)), cx);
@@ -83,9 +87,6 @@ fn main() {
// Initialize themes
themes::init(cx);
// Initialize app state
state::init(cx);
// Initialize account
account::init(cx);

View File

@@ -1,6 +1,6 @@
use gpui::{
div, App, AppContext, Context, Entity, EventEmitter, FocusHandle, Focusable, IntoElement,
ParentElement, Render, Window,
ParentElement, Render, SharedString, Window,
};
use gpui_component::dock::{Panel, PanelEvent};
@@ -24,6 +24,10 @@ impl Panel for Startup {
fn panel_name(&self) -> &'static str {
"Startup"
}
fn title(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
SharedString::from("Welcome")
}
}
impl EventEmitter<PanelEvent> for Startup {}

View File

@@ -1,14 +1,17 @@
use std::sync::Arc;
use account::Account;
use anyhow::Error;
use common::{CLIENT_NAME, DEFAULT_SIDEBAR_WIDTH};
use gpui::{
div, px, AppContext, Axis, Context, Entity, InteractiveElement, IntoElement, ParentElement,
Render, Styled, Subscription, Window,
Render, Styled, Subscription, Task, Window,
};
use gpui_component::dock::{DockArea, DockItem};
use gpui_component::{v_flex, Root, Theme};
use nostr_sdk::prelude::*;
use smallvec::{smallvec, SmallVec};
use state::{client, StateEvent};
use crate::panels::startup;
use crate::sidebar;
@@ -24,6 +27,9 @@ pub struct Workspace {
/// Event subscriptions
_subscriptions: SmallVec<[Subscription; 1]>,
/// Background tasks
_tasks: SmallVec<[Task<Result<(), Error>>; 2]>,
}
impl Workspace {
@@ -34,15 +40,13 @@ impl Workspace {
let mut subscriptions = smallvec![];
subscriptions.push(
// Automatically sync theme with system appearance
window.observe_window_appearance(|window, cx| {
Theme::sync_system_appearance(Some(window), cx);
}),
);
// Automatically sync theme with system appearance
subscriptions.push(window.observe_window_appearance(|window, cx| {
Theme::sync_system_appearance(Some(window), cx);
}));
// Observe account entity changes
subscriptions.push(
// Observe account entity changes
cx.observe_in(&account, window, move |this, state, window, cx| {
if state.read(cx).has_account() {
this.init_app_layout(window, cx);
@@ -50,10 +54,51 @@ impl Workspace {
}),
);
let mut tasks = smallvec![];
let (tx, rx) = flume::bounded::<StateEvent>(2048);
// Handle nostr notifications
tasks.push(cx.background_spawn(async move {
let client = client();
let mut notifications = client.notifications();
while let Ok(notification) = notifications.recv().await {
let RelayPoolNotification::Message { message, relay_url } = notification else {
continue;
};
match message {
RelayMessage::Event { event, .. } => {
// TODO
}
RelayMessage::EndOfStoredEvents(subscription_id) => {
// TODO
}
_ => {}
}
}
Ok(())
}));
// Handle state events
tasks.push(cx.spawn_in(window, async move |this, cx| {
while let Ok(event) = rx.recv_async().await {
cx.update(|window, cx| {
// TODO
})
// Entity has been released, ignore any errors
.ok();
}
Ok(())
}));
Self {
dock,
title_bar,
_subscriptions: subscriptions,
_tasks: tasks,
}
}

View File

@@ -0,0 +1,4 @@
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum StateEvent {
//
}

View File

@@ -1,43 +1,18 @@
use std::sync::OnceLock;
use std::time::Duration;
use common::{config_dir, BOOTSTRAP_RELAYS, SEARCH_RELAYS};
use gpui::{App, AppContext, Context, Entity, Global, Task};
use common::config_dir;
pub use event::*;
use nostr_gossip_memory::prelude::*;
use nostr_lmdb::NostrLmdb;
use nostr_sdk::prelude::*;
use smallvec::{smallvec, SmallVec};
pub fn init(cx: &mut App) {
NostrRegistry::set_global(cx.new(NostrRegistry::new), cx);
}
mod event;
struct GlobalNostrRegistry(Entity<NostrRegistry>);
static NOSTR_CLIENT: OnceLock<Client> = OnceLock::new();
impl Global for GlobalNostrRegistry {}
/// Nostr Registry
#[derive(Debug)]
pub struct NostrRegistry {
/// Nostr Client
client: Client,
/// Tasks for asynchronous operations
_tasks: SmallVec<[Task<()>; 1]>,
}
impl NostrRegistry {
/// Retrieve the global nostr state
pub fn global(cx: &App) -> Entity<Self> {
cx.global::<GlobalNostrRegistry>().0.clone()
}
/// Set the global nostr instance
fn set_global(state: Entity<Self>, cx: &mut App) {
cx.set_global(GlobalNostrRegistry(state));
}
/// Create a new nostr instance
fn new(cx: &mut Context<Self>) -> Self {
pub fn client() -> &'static Client {
NOSTR_CLIENT.get_or_init(|| {
// rustls uses the `aws_lc_rs` provider by default
// This only errors if the default provider has already
// been installed. We can ignore this `Result`.
@@ -54,7 +29,7 @@ impl NostrRegistry {
});
// Construct the lmdb
let lmdb = cx.background_executor().block(async move {
let lmdb = smol::block_on(async move {
let path = config_dir().join("nostr");
NostrLmdb::open(path)
.await
@@ -62,55 +37,10 @@ impl NostrRegistry {
});
// Construct the nostr client
let client = ClientBuilder::default()
ClientBuilder::default()
.database(lmdb)
.gossip(NostrGossipMemory::unbounded())
.opts(opts)
.build();
let mut tasks = smallvec![];
tasks.push(
// Establish connection to the bootstrap relays
//
// And handle notifications from the nostr relay pool channel
cx.background_spawn({
let client = client.clone();
async move {
// Connect to the bootstrap relays
Self::connect(&client).await;
// Handle notifications from the relay pool
// Self::handle_notifications(&client, &gossip, &tracker).await;
}
}),
);
Self {
client,
_tasks: tasks,
}
}
/// Get the nostr client instance
pub fn client(&self) -> Client {
self.client.clone()
}
/// Establish connection to the bootstrap relays
async fn connect(client: &Client) {
// Get all bootstrapping relays
let mut urls = vec![];
urls.extend(BOOTSTRAP_RELAYS);
urls.extend(SEARCH_RELAYS);
// Add relay to the relay pool
for url in urls.into_iter() {
client.add_relay(url).await.ok();
}
// Connect to all added relays
client.connect().await;
}
.build()
})
}