Skip to content

Commit

Permalink
feat(chat): display names with /name
Browse files Browse the repository at this point in the history
  • Loading branch information
smallbraingames committed Oct 21, 2024
1 parent f3a47be commit 911cef4
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 38 deletions.
24 changes: 18 additions & 6 deletions chat/src/chat.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod input;
mod loader;
mod name;

use crate::logic::{get_current_version, Logic};
use gpui::{
Expand All @@ -9,6 +10,7 @@ use gpui::{
use gpui::{View, VisualContext};
use input::TextInput;
use loader::Loader;
use name::Name;
use std::sync::Arc;

actions!(chat, [Enter]);
Expand All @@ -30,7 +32,7 @@ impl Chat {
.detach();

let mut message_watch = logic.get_message_watch();
let mut initial_sync_watch = logic.get_initial_sync_wach();
let mut initial_sync_watch = logic.get_initial_sync_watch();

let logic_quit = logic.clone();
cx.on_app_quit(move |_| {
Expand Down Expand Up @@ -108,6 +110,13 @@ impl Render for Chat {
let view = cx.view().clone();
let messages = self.logic.get_messages();
let initial_sync = self.logic.get_initial_sync();
let logic = self.logic.clone();

let name_views: Vec<View<Name>> = messages
.iter()
.map(|(pubkey, _)| cx.new_view(|cx| Name::new(cx, *pubkey, logic.clone())))
.collect();

if initial_sync {
div()
.child(
Expand Down Expand Up @@ -170,15 +179,18 @@ impl Render for Chat {
.bg(gpui::white())
.child(
uniform_list(view, "messages-list", messages.len(), {
let name_views = name_views.clone();
move |_, visible_range, _| {
visible_range
.map(|ix| {
let (_, message) = messages.get(ix).unwrap();
let name_view = &name_views[ix];
div()
.child(format!(
"{}: {}",
messages.get(ix).unwrap().clone().0,
messages.get(ix).unwrap().clone().1,
))
.flex()
.flex_row()
.gap_1()
.child(name_view.clone())
.child(message.clone())
.into_any_element()
})
.collect::<Vec<_>>()
Expand Down
23 changes: 23 additions & 0 deletions chat/src/chat/name.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use gpui::{div, rgba, IntoElement, ParentElement, Render, Styled, ViewContext};
use iroh::net::key::PublicKey;
use std::sync::Arc;

use crate::logic::Logic;

pub struct Name {
pubkey: PublicKey,
logic: Arc<Logic>,
}

impl Name {
pub fn new(_cx: &mut ViewContext<Self>, pubkey: PublicKey, logic: Arc<Logic>) -> Self {
Name { pubkey, logic }
}
}

impl Render for Name {
fn render(&mut self, _cx: &mut ViewContext<Self>) -> impl IntoElement {
let name = self.logic.get_name(&self.pubkey);
div().text_color(rgba(0x00000050)).child(name)
}
}
87 changes: 56 additions & 31 deletions chat/src/logic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ use iroh::net::discovery::pkarr::dht::DhtDiscovery;
use iroh::net::endpoint::{TransportConfig, VarInt};
use iroh::net::key::{PublicKey, SecretKey};
use iroh::{client::docs::LiveEvent, node::DiscoveryConfig};
use message::{Message, SignedMessage};
use message::SignedMessage;
use name::Names;
use persistence::get_or_create_secret_key;
use std::sync::Mutex;
use std::time::Duration;
use std::{
str::FromStr,
Expand All @@ -21,13 +23,16 @@ use std::{
use tokio::sync::watch;
use tracing::info;

pub use message::Message;

type IrohNode = iroh::node::Node<iroh::blobs::store::fs::Store>;

pub struct Logic {
iroh: Arc<tokio::sync::RwLock<Option<IrohNode>>>,
secret_key: SecretKey,
doc0: Arc<tokio::sync::RwLock<Option<Doc>>>,
messages: RwLock<Vec<(PublicKey, Message)>>,
names: Mutex<Names>,
message_watch: (watch::Sender<()>, watch::Receiver<()>),
initial_sync: RwLock<bool>,
initial_sync_watch: (watch::Sender<()>, watch::Receiver<()>),
Expand All @@ -37,8 +42,7 @@ pub struct Logic {
const _DOC0: &str = "6noafdqcxno4xv4ejf5xpma6gcl4gaw4w2gxsyvlp6kfwq3t6i2q";
const DOC0_TICKET: &str = "docaaacaxeh5eddy2cni7cuu5gail5gaxqqy2loiv6cghg5u45akcplu4skahswyqlad2rachperq7aesmyhoxycbsn7djsqwrn4m7yd7pkr3rxwaaa";

const _DOC1: &str = "6noafdqcxno4xv4ejf5xpma6gcl4gaw4w2gxsyvlp6kfwq3t6i2q";
const DOC1_TICKET: &str = "docaaacaxeh5eddy2cni7cuu5gail5gaxqqy2loiv6cghg5u45akcplu4skahswyqlad2rachperq7aesmyhoxycbsn7djsqwrn4m7yd7pkr3rxwaaa";
mod name;

impl Logic {
pub fn new() -> Self {
Expand All @@ -52,6 +56,7 @@ impl Logic {
secret_key,
doc0: Arc::new(tokio::sync::RwLock::new(None)),
messages: RwLock::new(Vec::new()),
names: Mutex::new(Names::new()),
message_watch,
initial_sync: RwLock::new(true),
initial_sync_watch,
Expand Down Expand Up @@ -111,9 +116,9 @@ impl Logic {
}
}

initial_messages.sort_by_key(|m| *m.1.timestamp());
*self.messages.write().unwrap() = initial_messages;
self.message_watch.0.send(()).unwrap();
for (pubkey, message) in &initial_messages {
self.add_message(*pubkey, message);
}
}
info!("initial messages loaded");
Ok(())
Expand All @@ -133,12 +138,7 @@ impl Logic {
if let Ok(content) = iroh.blobs().read_to_bytes(hash).await {
if let Ok(m) = SignedMessage::verify_and_decode(&content) {
info!("inserting message");
self.messages.write().unwrap().push(m);
self.messages
.write()
.unwrap()
.sort_by_key(|m| *m.1.timestamp());
self.message_watch.0.send(()).unwrap();
self.add_message(m.0, &m.1);
}
}
}
Expand All @@ -154,24 +154,16 @@ impl Logic {
Ok(())
}

pub async fn send_message(&self, message: &Message) -> anyhow::Result<()> {
info!("sending message: {}", message);

let message = Message::Chat {
timestamp: chrono::Utc::now(),
text: message.to_string(),
};
pub async fn send_message(&self, input: &str) -> anyhow::Result<()> {
let message = parse_message_input(input);

let content = SignedMessage::sign_and_encode(&self.secret_key, &message)?;
let timestamp = message.timestamp().clone();
let timestamp = *message.timestamp();

let iroh = Arc::clone(&self.iroh);
let doc0 = Arc::clone(&self.doc0);

self.messages
.write()
.unwrap()
.push((self.secret_key.public(), message));
self.add_message(self.secret_key.public(), &message);

tokio::spawn(async move {
let iroh = iroh.read().await;
Expand All @@ -189,22 +181,28 @@ impl Logic {
Ok(())
}

pub fn get_name(&self, pubkey: &PublicKey) -> String {
self.names
.lock()
.unwrap()
.get_name(pubkey)
.cloned()
.unwrap_or_else(|| pubkey.to_string().chars().take(6).collect::<String>())
}

pub fn get_initial_sync(&self) -> bool {
*self.initial_sync.read().unwrap()
}

pub fn get_messages(&self) -> Vec<(String, String)> {
let m: Vec<(String, String)> = self
pub fn get_messages(&self) -> Vec<(PublicKey, String)> {
let m: Vec<(PublicKey, String)> = self
.messages
.read()
.map(|msg| msg.clone())
.unwrap()
.into_iter()
.filter_map(|m| match m {
(public_key, Message::Chat { timestamp: _, text }) => {
let shortened_pkey: String = public_key.to_string().chars().take(4).collect();
Some((shortened_pkey, text))
}
(public_key, Message::Chat { timestamp: _, text }) => Some((public_key, text)),
_ => None,
})
.collect();
Expand All @@ -215,7 +213,7 @@ impl Logic {
self.message_watch.1.clone()
}

pub fn get_initial_sync_wach(&self) -> watch::Receiver<()> {
pub fn get_initial_sync_watch(&self) -> watch::Receiver<()> {
self.initial_sync_watch.1.clone()
}

Expand All @@ -230,4 +228,31 @@ impl Logic {
.await?;
Ok(())
}

fn add_message(&self, pubkey: PublicKey, message: &Message) {
self.messages
.write()
.unwrap()
.push((pubkey, message.clone()));
self.names
.lock()
.unwrap()
.apply_about_message(pubkey, message);
self.messages
.write()
.unwrap()
.sort_by_key(|m| *m.1.timestamp());
self.message_watch.0.send(()).unwrap();
}
}

pub fn parse_message_input(input: &str) -> Message {
input
.strip_prefix('/')
.and_then(|cmd| cmd.strip_prefix("name"))
.filter(|name| !name.trim().is_empty())
.map_or_else(
|| Message::new_chat(input.to_string()),
|name| Message::new_about_me(name.trim().to_string()),
)
}
15 changes: 15 additions & 0 deletions chat/src/logic/message.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::fmt::Display;

use bytes::Bytes;
use chrono::{DateTime, Utc};
use ed25519_dalek::Signature;
Expand Down Expand Up @@ -67,3 +69,16 @@ impl Message {
}
}
}

impl Display for Message {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Message::AboutMe { name, timestamp } => {
write!(f, "AboutMe: {} at {}", name, timestamp)
}
Message::Chat { text, timestamp } => {
write!(f, "Chat: {} at {}", text, timestamp)
}
}
}
}
26 changes: 26 additions & 0 deletions chat/src/logic/name.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use iroh::net::key::PublicKey;
use std::collections::HashMap;

use super::Message;

pub struct Names {
names: HashMap<PublicKey, String>,
}

impl Names {
pub fn new() -> Self {
Self {
names: HashMap::new(),
}
}

pub fn apply_about_message(&mut self, pubkey: PublicKey, message: &Message) {
if let Message::AboutMe { name, timestamp: _ } = message {
self.names.insert(pubkey, name.clone());
}
}

pub fn get_name(&self, pubkey: &PublicKey) -> Option<&String> {
self.names.get(pubkey)
}
}
2 changes: 1 addition & 1 deletion chat/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ async fn main() {
},
|cx| cx.new_view(Chat::new),
);
});
})
}

fn quit(_: &Quit, cx: &mut gpui::AppContext) {
Expand Down

0 comments on commit 911cef4

Please sign in to comment.