chore: improve data requests (#81)

* refactor

* refactor

* add documents

* clean up

* refactor

* clean up

* refactor identity

* .

* .

* rename
This commit is contained in:
reya
2025-07-08 15:23:35 +07:00
committed by GitHub
parent 122dbaf693
commit 8bfad30a99
32 changed files with 1478 additions and 1594 deletions
+170
View File
@@ -0,0 +1,170 @@
use std::cell::RefCell;
use std::iter::IntoIterator;
use std::rc::Rc;
use chrono::{Local, TimeZone};
use gpui::SharedString;
use nostr_sdk::prelude::*;
use smallvec::{smallvec, SmallVec};
use crate::room::SendError;
/// Represents a message in the chat system.
///
/// Contains information about the message content, author, creation time,
/// mentions, replies, and any errors that occurred during sending.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Message {
/// Unique identifier of the message (EventId from nostr_sdk)
pub id: EventId,
/// Author's public key
pub author: PublicKey,
/// The content/text of the message
pub content: SharedString,
/// When the message was created
pub created_at: Timestamp,
/// List of mentioned public keys in the message
pub mentions: SmallVec<[PublicKey; 2]>,
/// List of EventIds this message is replying to
pub replies_to: Option<SmallVec<[EventId; 1]>>,
/// Any errors that occurred while sending this message
pub errors: Option<SmallVec<[SendError; 1]>>,
}
/// Builder pattern implementation for constructing Message objects.
#[derive(Debug)]
pub struct MessageBuilder {
id: EventId,
author: PublicKey,
content: Option<SharedString>,
created_at: Option<Timestamp>,
mentions: SmallVec<[PublicKey; 2]>,
replies_to: Option<SmallVec<[EventId; 1]>>,
errors: Option<SmallVec<[SendError; 1]>>,
}
impl MessageBuilder {
/// Creates a new MessageBuilder with default values
pub fn new(id: EventId, author: PublicKey) -> Self {
Self {
id,
author,
content: None,
created_at: None,
mentions: smallvec![],
replies_to: None,
errors: None,
}
}
/// Sets the message content
pub fn content(mut self, content: impl Into<SharedString>) -> Self {
self.content = Some(content.into());
self
}
/// Sets the creation timestamp
pub fn created_at(mut self, created_at: Timestamp) -> Self {
self.created_at = Some(created_at);
self
}
/// Adds a single mention to the message
pub fn mention(mut self, mention: PublicKey) -> Self {
self.mentions.push(mention);
self
}
/// Adds multiple mentions to the message
pub fn mentions<I>(mut self, mentions: I) -> Self
where
I: IntoIterator<Item = PublicKey>,
{
self.mentions.extend(mentions);
self
}
/// Sets a single message this is replying to
pub fn reply_to(mut self, reply_to: EventId) -> Self {
self.replies_to = Some(smallvec![reply_to]);
self
}
/// Sets multiple messages this is replying to
pub fn replies_to<I>(mut self, replies_to: I) -> Self
where
I: IntoIterator<Item = EventId>,
{
let replies: SmallVec<[EventId; 1]> = replies_to.into_iter().collect();
if !replies.is_empty() {
self.replies_to = Some(replies);
}
self
}
/// Adds errors that occurred during sending
pub fn errors<I>(mut self, errors: I) -> Self
where
I: IntoIterator<Item = SendError>,
{
self.errors = Some(errors.into_iter().collect());
self
}
/// Builds the message wrapped in an Rc<RefCell<Message>>
pub fn build_rc(self) -> Result<Rc<RefCell<Message>>, String> {
self.build().map(|m| Rc::new(RefCell::new(m)))
}
/// Builds the message
pub fn build(self) -> Result<Message, String> {
Ok(Message {
id: self.id,
author: self.author,
content: self.content.ok_or("Content is required")?,
created_at: self.created_at.unwrap_or_else(Timestamp::now),
mentions: self.mentions,
replies_to: self.replies_to,
errors: self.errors,
})
}
}
impl Message {
/// Creates a new MessageBuilder
pub fn builder(id: EventId, author: PublicKey) -> MessageBuilder {
MessageBuilder::new(id, author)
}
/// Converts the message into an Rc<RefCell<Message>>
pub fn into_rc(self) -> Rc<RefCell<Self>> {
Rc::new(RefCell::new(self))
}
/// Builds a message from a builder and wraps it in Rc<RefCell>
pub fn build_rc(builder: MessageBuilder) -> Result<Rc<RefCell<Self>>, String> {
builder.build().map(|m| Rc::new(RefCell::new(m)))
}
/// Returns a human-readable string representing how long ago the message was created
pub fn ago(&self) -> SharedString {
let input_time = match Local.timestamp_opt(self.created_at.as_u64() as i64, 0) {
chrono::LocalResult::Single(time) => time,
_ => return "Invalid timestamp".into(),
};
let now = Local::now();
let input_date = input_time.date_naive();
let now_date = now.date_naive();
let yesterday_date = (now - chrono::Duration::days(1)).date_naive();
let time_format = input_time.format("%H:%M %p");
match input_date {
date if date == now_date => format!("Today at {time_format}"),
date if date == yesterday_date => format!("Yesterday at {time_format}"),
_ => format!("{}, {time_format}", input_time.format("%d/%m/%y")),
}
.into()
}
}