chore: release 0.1.4
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -1174,7 +1174,7 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "coop"
|
name = "coop"
|
||||||
version = "0.1.3"
|
version = "0.1.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"chats",
|
"chats",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "coop"
|
name = "coop"
|
||||||
version = "0.1.3"
|
version = "0.1.4"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
publish = false
|
publish = false
|
||||||
|
|
||||||
|
|||||||
@@ -211,6 +211,10 @@ impl Device {
|
|||||||
cx.set_global(GlobalDevice(device));
|
cx.set_global(GlobalDevice(device));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn client_keys(&self) -> Arc<Keys> {
|
||||||
|
self.client_keys.clone()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn profile(&self) -> Option<&NostrProfile> {
|
pub fn profile(&self) -> Option<&NostrProfile> {
|
||||||
self.profile.as_ref()
|
self.profile.as_ref()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -141,19 +141,15 @@ fn main() {
|
|||||||
pubkeys.push(event.pubkey);
|
pubkeys.push(event.pubkey);
|
||||||
|
|
||||||
// Save the event to the database, use for query directly.
|
// Save the event to the database, use for query directly.
|
||||||
if let Err(e) =
|
_ = client.database().save_event(&event).await;
|
||||||
client.database().save_event(&event).await
|
|
||||||
{
|
|
||||||
log::error!("Failed to save event: {}", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send all pubkeys to the batch
|
|
||||||
_ = batch_tx.send(pubkeys).await;
|
|
||||||
|
|
||||||
// Send this event to the GPUI
|
// Send this event to the GPUI
|
||||||
if new_id == *subscription_id {
|
if new_id == *subscription_id {
|
||||||
_ = event_tx.send(Signal::Event(event)).await;
|
_ = event_tx.send(Signal::Event(event)).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Send all pubkeys to the batch
|
||||||
|
_ = batch_tx.send(pubkeys).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -180,6 +176,9 @@ fn main() {
|
|||||||
Kind::Custom(DEVICE_ANNOUNCEMENT_KIND) => {
|
Kind::Custom(DEVICE_ANNOUNCEMENT_KIND) => {
|
||||||
log::info!("Device Announcement received");
|
log::info!("Device Announcement received");
|
||||||
|
|
||||||
|
if let Ok(signer) = client.signer().await {
|
||||||
|
if let Ok(public_key) = signer.get_public_key().await {
|
||||||
|
if event.pubkey == public_key {
|
||||||
if let Some(tag) = event
|
if let Some(tag) = event
|
||||||
.tags
|
.tags
|
||||||
.find(TagKind::custom("client"))
|
.find(TagKind::custom("client"))
|
||||||
@@ -188,6 +187,9 @@ fn main() {
|
|||||||
set_device_name(tag).await;
|
set_device_name(tag).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ pub struct Chat {
|
|||||||
// Chat Room
|
// Chat Room
|
||||||
room: WeakEntity<Room>,
|
room: WeakEntity<Room>,
|
||||||
messages: Entity<Vec<Message>>,
|
messages: Entity<Vec<Message>>,
|
||||||
|
seens: Entity<Vec<EventId>>,
|
||||||
list_state: ListState,
|
list_state: ListState,
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
subscriptions: Vec<Subscription>,
|
subscriptions: Vec<Subscription>,
|
||||||
@@ -116,6 +117,7 @@ impl Chat {
|
|||||||
cx: &mut App,
|
cx: &mut App,
|
||||||
) -> Entity<Self> {
|
) -> Entity<Self> {
|
||||||
let messages = cx.new(|_| vec![Message::placeholder()]);
|
let messages = cx.new(|_| vec![Message::placeholder()]);
|
||||||
|
let seens = cx.new(|_| vec![]);
|
||||||
let attaches = cx.new(|_| None);
|
let attaches = cx.new(|_| None);
|
||||||
let input = cx.new(|cx| {
|
let input = cx.new(|cx| {
|
||||||
TextInput::new(window, cx)
|
TextInput::new(window, cx)
|
||||||
@@ -165,6 +167,7 @@ impl Chat {
|
|||||||
id: id.to_string().into(),
|
id: id.to_string().into(),
|
||||||
room,
|
room,
|
||||||
messages,
|
messages,
|
||||||
|
seens,
|
||||||
list_state,
|
list_state,
|
||||||
input,
|
input,
|
||||||
attaches,
|
attaches,
|
||||||
@@ -244,11 +247,18 @@ impl Chat {
|
|||||||
self.list_state.splice(old_len..old_len, 1);
|
self.list_state.splice(old_len..old_len, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_message(&self, event: &Event, _window: &mut Window, cx: &mut Context<Self>) {
|
fn push_message(&mut self, event: &Event, _window: &mut Window, cx: &mut Context<Self>) {
|
||||||
let Some(model) = self.room.upgrade() else {
|
let Some(model) = self.room.upgrade() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Prevent duplicate messages
|
||||||
|
if self.seens.read(cx).iter().any(|id| id == &event.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Add ID to seen list
|
||||||
|
self.seen(event.id, cx);
|
||||||
|
|
||||||
let old_len = self.messages.read(cx).len();
|
let old_len = self.messages.read(cx).len();
|
||||||
let room = model.read(cx);
|
let room = model.read(cx);
|
||||||
|
|
||||||
@@ -450,6 +460,13 @@ impl Chat {
|
|||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn seen(&mut self, id: EventId, cx: &mut Context<Self>) {
|
||||||
|
self.seens.update(cx, |this, cx| {
|
||||||
|
this.push(id);
|
||||||
|
cx.notify();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fn render_message(
|
fn render_message(
|
||||||
&self,
|
&self,
|
||||||
ix: usize,
|
ix: usize,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use gpui::{
|
|||||||
};
|
};
|
||||||
use nostr_connect::prelude::*;
|
use nostr_connect::prelude::*;
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
use std::{path::PathBuf, time::Duration};
|
use std::{path::PathBuf, sync::Arc, time::Duration};
|
||||||
use ui::{
|
use ui::{
|
||||||
button::{Button, ButtonCustomVariant, ButtonVariants},
|
button::{Button, ButtonCustomVariant, ButtonVariants},
|
||||||
input::{InputEvent, TextInput},
|
input::{InputEvent, TextInput},
|
||||||
@@ -104,8 +104,12 @@ impl Onboarding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn connect(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
fn connect(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||||
|
let Some(model) = Device::global(cx) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
let text = self.bunker_input.read(cx).text().to_string();
|
let text = self.bunker_input.read(cx).text().to_string();
|
||||||
let keys = Keys::generate();
|
let keys = Arc::unwrap_or_clone(model.read(cx).client_keys());
|
||||||
|
|
||||||
self.set_loading(true, cx);
|
self.set_loading(true, cx);
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use anyhow::{anyhow, Context, Error};
|
use anyhow::{anyhow, Error};
|
||||||
use common::{last_seen::LastSeen, profile::NostrProfile, utils::room_hash};
|
use common::{
|
||||||
|
last_seen::LastSeen,
|
||||||
|
profile::NostrProfile,
|
||||||
|
utils::{device_pubkey, room_hash},
|
||||||
|
};
|
||||||
use global::{constants::DEVICE_ANNOUNCEMENT_KIND, get_client, get_device_keys};
|
use global::{constants::DEVICE_ANNOUNCEMENT_KIND, get_client, get_device_keys};
|
||||||
use gpui::{App, AppContext, Entity, EventEmitter, SharedString, Task};
|
use gpui::{App, AppContext, Entity, EventEmitter, SharedString, Task};
|
||||||
use nostr_sdk::prelude::*;
|
use nostr_sdk::prelude::*;
|
||||||
@@ -194,43 +198,37 @@ impl Room {
|
|||||||
|
|
||||||
// Check if the pubkey has a device announcement,
|
// Check if the pubkey has a device announcement,
|
||||||
// then choose the appropriate signer based on device presence
|
// then choose the appropriate signer based on device presence
|
||||||
if let Some(event) = client.database().query(filter).await?.first_owned() {
|
let event = match client.database().query(filter).await?.first() {
|
||||||
|
Some(event) => {
|
||||||
log::info!("Use device signer to send message");
|
log::info!("Use device signer to send message");
|
||||||
let signer = &device;
|
let signer = &device;
|
||||||
|
|
||||||
// Get the device's public key of other user
|
// Get the device's public key of other user
|
||||||
let n_tag = event.tags.find(TagKind::custom("n")).context("Not found")?;
|
let device_pubkey = device_pubkey(event)?;
|
||||||
let hex = n_tag.content().context("Not found")?;
|
|
||||||
let target_pubkey = PublicKey::parse(hex)?;
|
|
||||||
|
|
||||||
let rumor = EventBuilder::private_msg_rumor(*pubkey, &content)
|
let rumor = EventBuilder::private_msg_rumor(*pubkey, &content)
|
||||||
.tags(tags.clone())
|
.tags(tags.clone())
|
||||||
.build(user_pubkey);
|
.build(user_pubkey);
|
||||||
|
|
||||||
let event = EventBuilder::gift_wrap(
|
EventBuilder::gift_wrap(
|
||||||
signer,
|
signer,
|
||||||
&target_pubkey,
|
&device_pubkey,
|
||||||
rumor,
|
rumor,
|
||||||
vec![Tag::public_key(*pubkey)],
|
vec![Tag::public_key(*pubkey)],
|
||||||
)
|
)
|
||||||
.await?;
|
.await?
|
||||||
|
|
||||||
if let Err(e) = client.send_event(&event).await {
|
|
||||||
// Convert error into string, then push it to the report
|
|
||||||
report.push(e.to_string());
|
|
||||||
}
|
}
|
||||||
} else {
|
None => {
|
||||||
log::info!("Use user signer to send message");
|
log::info!("Use user signer to send message");
|
||||||
let signer = &client.signer().await?;
|
let signer = client.signer().await?;
|
||||||
|
|
||||||
let event =
|
EventBuilder::private_msg(&signer, *pubkey, &content, tags.clone()).await?
|
||||||
EventBuilder::private_msg(signer, *pubkey, &content, tags.clone()).await?;
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if let Err(e) = client.send_event(&event).await {
|
if let Err(e) = client.send_event(&event).await {
|
||||||
report.push(e.to_string());
|
report.push(e.to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Ok(report)
|
Ok(report)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use anyhow::Context;
|
||||||
use global::constants::NIP96_SERVER;
|
use global::constants::NIP96_SERVER;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use nostr_sdk::prelude::*;
|
use nostr_sdk::prelude::*;
|
||||||
@@ -43,6 +44,14 @@ pub fn room_hash(event: &Event) -> u64 {
|
|||||||
hasher.finish()
|
hasher.finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn device_pubkey(event: &Event) -> Result<PublicKey, anyhow::Error> {
|
||||||
|
let n_tag = event.tags.find(TagKind::custom("n")).context("Invalid")?;
|
||||||
|
let hex = n_tag.content().context("Invalid")?;
|
||||||
|
let pubkey = PublicKey::parse(hex)?;
|
||||||
|
|
||||||
|
Ok(pubkey)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn random_name(length: usize) -> String {
|
pub fn random_name(length: usize) -> String {
|
||||||
let rng = RNG::from(&Language::Roman);
|
let rng = RNG::from(&Language::Roman);
|
||||||
rng.generate_names(length, true).join("-").to_lowercase()
|
rng.generate_names(length, true).join("-").to_lowercase()
|
||||||
|
|||||||
Reference in New Issue
Block a user