progress in toy-chat

This commit is contained in:
Ivan Folgueira Bande 2024-12-01 20:58:33 +01:00
parent be987f858d
commit 3f72fc7a2d
No known key found for this signature in database
GPG Key ID: 3C117481F89E24A7
5 changed files with 129 additions and 167 deletions

View File

@ -8,10 +8,10 @@ use crossterm::{
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
}; };
use prost::Message; use prost::Message;
use std::str::from_utf8;
use std::io::Write; use std::io::Write;
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
use std::{error::Error, io}; use std::{error::Error, io};
use std::time::Duration;
use tui::{ use tui::{
backend::{Backend, CrosstermBackend}, backend::{Backend, CrosstermBackend},
layout::{Constraint, Direction, Layout}, layout::{Constraint, Direction, Layout},
@ -85,63 +85,30 @@ impl App<Initialized> {
let shared_messages = Arc::clone(&self.messages); let shared_messages = Arc::clone(&self.messages);
self.waku.set_event_callback(move|response| { self.waku.set_event_callback(move|response| {
// if let LibwakuResponse::Success(v) = response {
// let event: WakuEvent =
// serde_json::from_str(v.unwrap().as_str()).expect("Parsing event to succeed");
// match event {
// WakuEvent::WakuMessage(evt) => {
// // println!("WakuMessage event received: {:?}", evt.waku_message);
// let message = evt.waku_message;
// let payload = message.payload.to_vec();
// match from_utf8(&payload) {
// Ok(msg) => {
// // Lock succeeded, proceed to send the message
// // if tx_clone.blocking_send(msg.to_string()).is_err() {
// // eprintln!("Failed to send message to async task");
// // }
// }
// Err(e) => {
// eprintln!("Failed to decode payload as UTF-8: {}", e);
// // Handle the error as needed, or just log and skip
// }
// }
// }
// WakuEvent::Unrecognized(err) => eprintln!("Unrecognized waku event: {:?}", err),
// _ => eprintln!("event case not expected"),
// };
// }
if let LibwakuResponse::Success(v) = response { if let LibwakuResponse::Success(v) = response {
if let Some(msg_str) = v { let event: WakuEvent =
serde_json::from_str(v.unwrap().as_str()).expect("Parsing event to succeed");
match serde_json::from_str::<WakuEvent>(msg_str.as_str()) {
Ok(waku_event) => {
println!("AAAAAA jamon {:?}", waku_event);
// // match waku_event {
// // WakuEvent::WakuMessage(evt) => {
// // // println!("WakuMessage event received: {:?}", evt.waku_message);
// // // match <Chat2Message as Message>::decode(evt.waku_message.payload()) {
// // // Ok(chat_message) => {
// // // shared_messages.write().unwrap().push(chat_message);
// // // }
// // // Err(_e) => {
// // // // let mut out = std::io::stderr();
// // // // write!(out, "{e:?}").unwrap();
// // // }
// // // }
// // },
// // WakuEvent::Unrecognized(err) => println!("Unrecognized waku event: {:?}", err),
// // }
},
Err(_e) => {}, //eprintln!("Error reading file: {}", e), match event {
WakuEvent::WakuMessage(evt) => {
if evt.waku_message.content_topic != TOY_CHAT_CONTENT_TOPIC {
return; // skip the messages that don't belong to the toy chat
}
match <Chat2Message as Message>::decode(evt.waku_message.payload()) {
Ok(chat_message) => {
shared_messages.write().unwrap().push(chat_message);
}
Err(e) => {
let mut out = std::io::stderr();
write!(out, "{e:?}").unwrap();
}
}
} }
} WakuEvent::Unrecognized(err) => eprintln!("Unrecognized waku event: {:?}", err),
_ => eprintln!("event case not expected"),
};
} }
})?; })?;
@ -161,77 +128,84 @@ impl App<Initialized> {
} }
impl App<Running> { impl App<Running> {
fn retrieve_history(&mut self) {
let history = self.waku.store_query(None, vec![TOY_CHAT_CONTENT_TOPIC.clone()], STORE_NODE);
let history = history.unwrap();
let messages = history.messages
.iter()
.map(|store_resp_msg| {
<Chat2Message as Message>::decode(store_resp_msg.message.payload())
.expect("Toy chat messages should be decodeable")
})
.collect();
if history.messages.len() > 0 {
*self.messages.write().unwrap() = messages;
}
}
fn run_main_loop<B: Backend>( fn run_main_loop<B: Backend>(
&mut self, &mut self,
terminal: &mut Terminal<B>, terminal: &mut Terminal<B>,
) -> std::result::Result<(), Box<dyn Error>> { ) -> std::result::Result<(), Box<dyn Error>> {
// let history = self.waku.store_query(None, vec![TOY_CHAT_CONTENT_TOPIC.clone()], STORE_NODE); self.retrieve_history();
// let history = history.unwrap();
// let messages = history.messages
// .iter()
// .map(|store_resp_msg| {
// <Chat2Message as Message>::decode(store_resp_msg.message.payload())
// .expect("Toy chat messages should be decodeable")
// })
// .collect();
// if history.messages.len() > 0 {
// *self.messages.write().unwrap() = messages;
// }
loop { loop {
terminal.draw(|f| ui(f, self))?; terminal.draw(|f| ui(f, self))?;
if let Event::Key(key) = event::read()? { if event::poll(Duration::from_millis(500)).unwrap() {
match self.input_mode { if let Event::Key(key) = event::read()? {
InputMode::Normal => match key.code { match self.input_mode {
KeyCode::Char('e') => { InputMode::Normal => match key.code {
self.input_mode = InputMode::Editing; KeyCode::Char('e') => {
} self.input_mode = InputMode::Editing;
KeyCode::Char('q') => {
return Ok(());
}
_ => {}
},
InputMode::Editing => match key.code {
KeyCode::Enter => {
let message_content: String = self.input.drain(..).collect();
let message = Chat2Message::new(&self.nick, &message_content);
let mut buff = Vec::new();
let meta = Vec::new();
Message::encode(&message, &mut buff)?;
let waku_message = WakuMessage::new(
buff,
TOY_CHAT_CONTENT_TOPIC.clone(),
1,
Utc::now().timestamp_nanos() as usize,
meta,
false,
);
let pubsub_topic = PubsubTopic::new(DEFAULT_PUBSUB_TOPIC);
if let Err(e) = self.waku.relay_publish_message(
&waku_message,
&pubsub_topic,
None,
) {
let mut out = std::io::stderr();
write!(out, "{e:?}").unwrap();
} }
} KeyCode::Char('q') => {
KeyCode::Char(c) => { return Ok(());
self.input.push(c); }
} _ => {}
KeyCode::Backspace => { },
self.input.pop(); InputMode::Editing => match key.code {
} KeyCode::Enter => {
KeyCode::Esc => { let message_content: String = self.input.drain(..).collect();
self.input_mode = InputMode::Normal; let message = Chat2Message::new(&self.nick, &message_content);
} let mut buff = Vec::new();
_ => {} let meta = Vec::new();
}, Message::encode(&message, &mut buff)?;
let waku_message = WakuMessage::new(
buff,
TOY_CHAT_CONTENT_TOPIC.clone(),
1,
Utc::now().timestamp_nanos() as usize,
meta,
false,
);
let pubsub_topic = PubsubTopic::new(DEFAULT_PUBSUB_TOPIC);
if let Err(e) = self.waku.relay_publish_message(
&waku_message,
&pubsub_topic,
None,
) {
let mut out = std::io::stderr();
write!(out, "{e:?}").unwrap();
}
}
KeyCode::Char(c) => {
self.input.push(c);
}
KeyCode::Backspace => {
self.input.pop();
}
KeyCode::Esc => {
self.input_mode = InputMode::Normal;
}
_ => {}
},
}
} }
} }
} }
@ -242,47 +216,6 @@ impl App<Running> {
} }
} }
// fn retrieve_history(
// waku: &WakuNodeHandle<Running>,
// ) -> waku_bindings::Result<Vec<Chat2Message>> {
// let self_id = waku.peer_id().unwrap();
// let peer = waku
// .peers()?
// .iter()
// .find(|&peer| peer.peer_id() != &self_id)
// .cloned()
// .unwrap();
// let result = waku.store_query(
// &StoreQuery {
// pubsub_topic: None,
// content_topics: vec![TOY_CHAT_CONTENT_TOPIC.clone()],
// start_time: Some(
// (Duration::from_secs(Utc::now().timestamp() as u64)
// - Duration::from_secs(60 * 60 * 24))
// .as_nanos() as usize,
// ),
// end_time: None,
// paging_options: Some(PagingOptions {
// page_size: 25,
// cursor: None,
// forward: true,
// }),
// },
// peer.peer_id(),
// Some(Duration::from_secs(10)),
// )?;
// Ok(result
// .messages()
// .iter()
// .map(|waku_message| {
// <Chat2Message as Message>::decode(waku_message.payload())
// .expect("Toy chat messages should be decodeable")
// })
// .collect())
// }
fn main() -> std::result::Result<(), Box<dyn Error>> { fn main() -> std::result::Result<(), Box<dyn Error>> {
let nick = std::env::args().nth(1).expect("Nick to be set"); let nick = std::env::args().nth(1).expect("Nick to be set");

View File

@ -26,22 +26,42 @@ pub struct WakuMessage {
#[serde(with = "base64_serde", default = "Vec::new")] #[serde(with = "base64_serde", default = "Vec::new")]
pub payload: Vec<u8>, pub payload: Vec<u8>,
/// The content topic to be set on the message /// The content topic to be set on the message
content_topic: WakuContentTopic, pub content_topic: WakuContentTopic,
// TODO: check if missing default should be 0
/// The Waku Message version number /// The Waku Message version number
#[serde(default)] #[serde(default)]
version: WakuMessageVersion, pub version: WakuMessageVersion,
/// Unix timestamp in nanoseconds /// Unix timestamp in nanoseconds
#[serde(deserialize_with = "deserialize_number_from_string")] #[serde(deserialize_with = "deserialize_number_from_string")]
timestamp: usize, pub timestamp: usize,
meta: Vec<u8>, #[serde(with = "base64_serde", default = "Vec::new")]
pub meta: Vec<u8>,
#[serde(default)] #[serde(default)]
ephemeral: bool, pub ephemeral: bool,
// TODO: implement RLN fields // TODO: implement RLN fields
#[serde(flatten)] #[serde(flatten)]
_extras: serde_json::Value, _extras: serde_json::Value,
} }
#[derive(Clone, Serialize, Deserialize, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct WakuStoreRespMessage {
// #[serde(with = "base64_serde", default = "Vec::new")]
pub payload: Vec<u8>,
/// The content topic to be set on the message
// #[serde(rename = "contentTopic")]
pub content_topic: String,
// #[serde(with = "base64_serde", default = "Vec::new")]
pub meta: Vec<u8>,
/// The Waku Message version number
#[serde(default)]
pub version: WakuMessageVersion,
/// Unix timestamp in nanoseconds
pub timestamp: usize,
#[serde(default)]
pub ephemeral: bool,
// pub proof: Vec<u8>,
}
impl WakuMessage { impl WakuMessage {
pub fn new<PAYLOAD: AsRef<[u8]>, META: AsRef<[u8]>>( pub fn new<PAYLOAD: AsRef<[u8]>, META: AsRef<[u8]>>(
payload: PAYLOAD, payload: PAYLOAD,
@ -70,6 +90,12 @@ impl WakuMessage {
} }
} }
impl WakuStoreRespMessage {
pub fn payload(&self) -> &[u8] {
&self.payload
}
}
mod base64_serde { mod base64_serde {
use base64::Engine; use base64::Engine;
use serde::de::Error; use serde::de::Error;

View File

@ -33,6 +33,10 @@ pub struct WakuNodeConfig {
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub max_message_size: Option<String>, pub max_message_size: Option<String>,
/// Store protocol
#[serde(skip_serializing_if = "Option::is_none")]
pub storenode: Option<&'static str>,
/// RLN configuration /// RLN configuration
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub rln_relay: Option<RLNConfig>, pub rln_relay: Option<RLNConfig>,

View File

@ -25,7 +25,6 @@ use crate::general::{MessageHash, Result, WakuMessage};
use crate::utils::LibwakuResponse; use crate::utils::LibwakuResponse;
use crate::node::context::WakuNodeContext; use crate::node::context::WakuNodeContext;
use crate::node::store::PagingOptions;
pub use config::RLNConfig; pub use config::RLNConfig;
pub use config::WakuNodeConfig; pub use config::WakuNodeConfig;
pub use events::{WakuEvent, WakuMessageEvent}; pub use events::{WakuEvent, WakuMessageEvent};

View File

@ -7,10 +7,10 @@ use libc::*;
// internal // internal
use crate::general::{ use crate::general::{
contenttopic::WakuContentTopic, pubsubtopic::PubsubTopic, MessageHash, Result, contenttopic::WakuContentTopic, pubsubtopic::PubsubTopic, MessageHash, Result,
WakuStoreRespMessage,
}; };
use crate::node::context::WakuNodeContext; use crate::node::context::WakuNodeContext;
use crate::utils::{get_trampoline, handle_json_response, LibwakuResponse, WakuDecode}; use crate::utils::{get_trampoline, handle_json_response, LibwakuResponse, WakuDecode};
use crate::WakuMessage;
use multiaddr::Multiaddr; use multiaddr::Multiaddr;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -49,7 +49,7 @@ struct StoreQueryRequest {
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct StoreWakuMessageResponse { pub struct StoreWakuMessageResponse {
pub message_hash: [u8; 32], pub message_hash: [u8; 32],
pub message: WakuMessage, pub message: WakuStoreRespMessage,
pub pubsub_topic: String, pub pubsub_topic: String,
} }
@ -72,7 +72,7 @@ pub struct StoreResponse {
// Implement WakuDecode for Vec<Multiaddr> // Implement WakuDecode for Vec<Multiaddr>
impl WakuDecode for StoreResponse { impl WakuDecode for StoreResponse {
fn decode(input: &str) -> Result<Self> { fn decode(input: &str) -> Result<Self> {
let ret: StoreResponse = serde_json::from_str(input).expect("parse store resp correctly"); let ret: StoreResponse = serde_json::from_str(input).expect("could not parse store resp");
Ok(ret) Ok(ret)
} }
} }