Explorar o código

dchat: improved UI + cleanup

lunar-mining %!s(int64=4) %!d(string=hai) anos
pai
achega
29feadcf1c
Modificáronse 2 ficheiros con 166 adicións e 97 borrados
  1. 159 74
      example/dchat/src/main.rs
  2. 7 23
      example/dchat/src/protocol_dchat.rs

+ 159 - 74
example/dchat/src/main.rs

@@ -1,13 +1,13 @@
 use async_executor::Executor;
 use async_executor::Executor;
 use async_std::sync::{Arc, Mutex};
 use async_std::sync::{Arc, Mutex};
 use easy_parallel::Parallel;
 use easy_parallel::Parallel;
-use log::{error, info};
+use log::debug;
 use simplelog::WriteLogger;
 use simplelog::WriteLogger;
 use std::{
 use std::{
     fs::File,
     fs::File,
-    io::{self, Read, Write},
+    io::{stdin, stdout, Read, Write},
 };
 };
-use termion::{async_stdin, event::Key, input::TermRead};
+use termion::{event::Key, input::TermRead, raw::IntoRawMode};
 use url::Url;
 use url::Url;
 
 
 use darkfi::{
 use darkfi::{
@@ -27,101 +27,194 @@ pub mod protocol_dchat;
 
 
 struct Dchat {
 struct Dchat {
     p2p: net::P2pPtr,
     p2p: net::P2pPtr,
-    msgs: DchatmsgsBuffer,
+    recv_msgs: DchatmsgsBuffer,
+    input: String,
+    display: DisplayMode,
+}
+
+#[derive(Debug)]
+enum DisplayMode {
+    Normal,
+    Editing,
+    Inbox,
+    MessageSent,
 }
 }
 
 
 impl Dchat {
 impl Dchat {
-    fn new(p2p: net::P2pPtr, msgs: DchatmsgsBuffer) -> Arc<Self> {
-        Arc::new(Self { p2p, msgs })
+    fn new(
+        p2p: net::P2pPtr,
+        recv_msgs: DchatmsgsBuffer,
+        input: String,
+        display: DisplayMode,
+    ) -> Self {
+        Self { p2p, recv_msgs, input, display }
     }
     }
 
 
-    async fn render(&self) -> Result<()> {
-        info!(target: "dchat", "DCHAT::render()::start");
-        let mut stdout = io::stdout().lock();
-        let mut stdin = async_stdin();
-
-        println!(
-            "Welcome to dchat
-                s: send message
-                i. inbox
-                q: quit \n",
-        );
+    async fn menu(&mut self) -> Result<()> {
+        debug!(target: "dchat", "Dchat::menu() [START]");
+        let stdout = stdout();
+        let mut stdout = stdout.lock().into_raw_mode().unwrap();
+        let mut stdin = stdin();
 
 
         loop {
         loop {
+            self.render().await?;
             for k in stdin.by_ref().keys() {
             for k in stdin.by_ref().keys() {
-                match k.unwrap() {
-                    Key::Char('q') => {
-                        info!(target: "dchat", "DCHAT::Q pressed.... exiting");
-                        return Ok(())
-                    }
-                    Key::Char('i') => {
-                        let vec = self.msgs.lock().await;
-                        for i in vec.iter() {
-                            println!("iterated version {:?}", i);
+                match self.display {
+                    DisplayMode::Normal => match k.unwrap() {
+                        Key::Char('q') => return Ok(()),
+                        Key::Char('i') => {
+                            self.display = DisplayMode::Inbox;
+                            break
                         }
                         }
-                        println!("with indexing {:?}", vec[0]);
-                        //for v in vec {
-                        //    //
-                        //}
-                        //for msg in self.msgs.lock().await {
-                        //    //println!("{}", msg);
-                        //}
-                    }
-
-                    Key::Char('s') => {
-                        //stdout.write_all(b"type your message and then press enter\n")?;
-                        //let mut input = String::new();
-                        //stdin.read_line(&mut input)?;
 
 
-                        let msg = self.get_input().await?;
-                        self.send(msg).await?;
+                        Key::Char('s') => {
+                            self.display = DisplayMode::Editing;
+                            break
+                        }
+                        _ => {}
+                    },
+                    DisplayMode::Editing => {
+                        match k.unwrap() {
+                            Key::Char('q') => return Ok(()),
+                            Key::Char('\n') => {
+                                match self.send().await {
+                                    Ok(_) => {
+                                        self.display = DisplayMode::MessageSent;
+                                    }
+                                    // TODO
+                                    Err(_) => {}
+                                }
+                                break
+                            }
+                            Key::Char(c) => {
+                                self.input.push(c);
+                            }
+                            Key::Esc => {
+                                self.display = DisplayMode::Normal;
+                                break
+                            }
+                            _ => {}
+                        }
                     }
                     }
-                    _ => {}
+                    DisplayMode::MessageSent => match k.unwrap() {
+                        Key::Char('q') => return Ok(()),
+                        Key::Esc => {
+                            self.display = DisplayMode::Normal;
+                            break
+                        }
+                        _ => {}
+                    },
+                    DisplayMode::Inbox => match k.unwrap() {
+                        Key::Char('q') => return Ok(()),
+                        _ => {}
+                    },
                 }
                 }
             }
             }
+            stdout.flush()?;
         }
         }
     }
     }
 
 
-    async fn get_input(&self) -> Result<String> {
-        let mut stdout = io::stdout().lock();
-        stdout.write_all(b"type your message and then press enter\n")?;
-        let mut input = String::new();
-        io::stdin().read_line(&mut input)?;
-        stdout.write_all(b"you entered:")?;
-        stdout.write_all(input.as_bytes())?;
-        return Ok(input)
-    }
+    async fn render(&mut self) -> Result<()> {
+        debug!(target: "dchat", "Dchat::render() [START]");
+        let stdout = stdout();
+        let mut stdout = stdout.lock().into_raw_mode().unwrap();
+
+        match self.display {
+            DisplayMode::Normal => {
+                write!(
+                    stdout,
+                    "{}{}{}Welcome to dchat. {} s: send message {} i: inbox {} q: quit {}",
+                    termion::clear::All,
+                    termion::style::Bold,
+                    termion::cursor::Goto(1, 2),
+                    termion::cursor::Goto(1, 3),
+                    termion::cursor::Goto(1, 4),
+                    termion::cursor::Goto(1, 5),
+                    termion::cursor::Goto(1, 6)
+                )?;
+                stdout.flush()?;
+            }
+            DisplayMode::Editing => {
+                write!(
+                    stdout,
+                    "{}{}{}enter your msg.{} esc: stop editing {} enter: send {}",
+                    termion::clear::All,
+                    termion::style::Bold,
+                    termion::cursor::Goto(1, 2),
+                    termion::cursor::Goto(1, 3),
+                    termion::cursor::Goto(1, 4),
+                    termion::cursor::Goto(1, 5)
+                )?;
+                stdout.flush()?;
+            }
+            DisplayMode::Inbox => {
+                let msgs = self.recv_msgs.lock().await;
+                for i in msgs.iter() {
+                    if !i.message.is_empty() {
+                        write!(
+                            stdout,
+                            "{}{}{}received msg: {}",
+                            termion::clear::All,
+                            termion::style::Bold,
+                            termion::cursor::Goto(1, 2),
+                            i.message
+                        )?;
+                    } else {
+                        write!(
+                            stdout,
+                            "{}{}{}inbox is empty",
+                            termion::clear::All,
+                            termion::style::Bold,
+                            termion::cursor::Goto(1, 2),
+                        )?;
+                    }
+                }
+                stdout.flush()?;
+            }
+            DisplayMode::MessageSent => {
+                write!(
+                    stdout,
+                    "{}{}{}message sent! {} esc: return to main menu {}",
+                    termion::clear::All,
+                    termion::style::Bold,
+                    termion::cursor::Goto(1, 2),
+                    termion::cursor::Goto(1, 3),
+                    termion::cursor::Goto(1, 4),
+                )?;
+                stdout.flush()?;
+            }
+        }
 
 
+        Ok(())
+    }
     async fn register_protocol(&self, msgs: DchatmsgsBuffer) -> Result<()> {
     async fn register_protocol(&self, msgs: DchatmsgsBuffer) -> Result<()> {
-        info!(target: "dchat", "dchat::register_protocol()::start");
+        debug!(target: "dchat", "Dchat::register_protocol() [START]");
         let registry = self.p2p.protocol_registry();
         let registry = self.p2p.protocol_registry();
         registry
         registry
-            .register(net::SESSION_ALL, move |channel, p2p| {
+            .register(net::SESSION_ALL, move |channel, _p2p| {
                 let msgs2 = msgs.clone();
                 let msgs2 = msgs.clone();
-                async move { ProtocolDchat::init(channel, p2p, msgs2).await }
+                async move { ProtocolDchat::init(channel, msgs2).await }
             })
             })
             .await;
             .await;
-        info!(target: "dchat", "DCHAT::register_protocol()::stop");
+        debug!(target: "dchat", "Dchat::register_protocol() [STOP]");
         Ok(())
         Ok(())
     }
     }
 
 
     async fn start(&self, ex: Arc<Executor<'_>>) -> Result<()> {
     async fn start(&self, ex: Arc<Executor<'_>>) -> Result<()> {
-        info!(target: "dchat", "DCHAT::start()::start");
+        debug!(target: "dchat", "Dchat::start() [START]");
 
 
         let ex2 = ex.clone();
         let ex2 = ex.clone();
 
 
-        self.register_protocol(self.msgs.clone()).await?;
+        self.register_protocol(self.recv_msgs.clone()).await?;
         self.p2p.clone().start(ex.clone()).await?;
         self.p2p.clone().start(ex.clone()).await?;
         ex2.spawn(self.p2p.clone().run(ex.clone())).detach();
         ex2.spawn(self.p2p.clone().run(ex.clone())).detach();
 
 
-        info!(target: "dchat", "DCHAT::start()::stop");
+        debug!(target: "dchat", "Dchat::start() [STOP]");
         Ok(())
         Ok(())
     }
     }
 
 
-    async fn send(&self, message: String) -> Result<()> {
-        let mut stdout = io::stdout().lock();
-        stdout.write_all(b"sending: ")?;
-        stdout.write_all(message.as_bytes())?;
+    async fn send(&self) -> Result<()> {
+        let message = self.input.clone();
         let dchatmsg = Dchatmsg { message };
         let dchatmsg = Dchatmsg { message };
         self.p2p.broadcast(dchatmsg).await?;
         self.p2p.broadcast(dchatmsg).await?;
         Ok(())
         Ok(())
@@ -187,14 +280,8 @@ async fn main() -> Result<()> {
     // TODO:: proper error handling
     // TODO:: proper error handling
     let settings: Result<Settings> = match std::env::args().nth(1) {
     let settings: Result<Settings> = match std::env::args().nth(1) {
         Some(id) => match id.as_str() {
         Some(id) => match id.as_str() {
-            "a" => {
-                println!("alice selected");
-                alice()
-            }
-            "b" => {
-                println!("bob selected");
-                bob()
-            }
+            "a" => alice(),
+            "b" => bob(),
             _ => {
             _ => {
                 println!("you must specify either a or b");
                 println!("you must specify either a or b");
                 Err(Error::ConfigInvalid)
                 Err(Error::ConfigInvalid)
@@ -208,8 +295,6 @@ async fn main() -> Result<()> {
 
 
     let p2p = net::P2p::new(settings?.into()).await;
     let p2p = net::P2p::new(settings?.into()).await;
 
 
-    //let p2p = p2p.clone();
-
     let nthreads = num_cpus::get();
     let nthreads = num_cpus::get();
     let (signal, shutdown) = async_channel::unbounded::<()>();
     let (signal, shutdown) = async_channel::unbounded::<()>();
 
 
@@ -218,14 +303,14 @@ async fn main() -> Result<()> {
 
 
     let msgs: DchatmsgsBuffer = Arc::new(Mutex::new(vec![Dchatmsg { message: String::new() }]));
     let msgs: DchatmsgsBuffer = Arc::new(Mutex::new(vec![Dchatmsg { message: String::new() }]));
 
 
-    let dchat = Dchat::new(p2p, msgs);
+    let mut dchat = Dchat::new(p2p, msgs, String::new(), DisplayMode::Normal);
 
 
     let (_, result) = Parallel::new()
     let (_, result) = Parallel::new()
         .each(0..nthreads, |_| smol::future::block_on(ex.run(shutdown.recv())))
         .each(0..nthreads, |_| smol::future::block_on(ex.run(shutdown.recv())))
         .finish(|| {
         .finish(|| {
             smol::future::block_on(async move {
             smol::future::block_on(async move {
                 dchat.start(ex2).await?;
                 dchat.start(ex2).await?;
-                dchat.render().await?;
+                dchat.menu().await?;
                 drop(signal);
                 drop(signal);
                 Ok(())
                 Ok(())
             })
             })

+ 7 - 23
example/dchat/src/protocol_dchat.rs

@@ -2,25 +2,19 @@ use async_executor::Executor;
 use async_std::sync::Arc;
 use async_std::sync::Arc;
 use async_trait::async_trait;
 use async_trait::async_trait;
 use darkfi::{net, Result};
 use darkfi::{net, Result};
-use log::info;
+use log::debug;
 
 
 use crate::dchatmsg::{Dchatmsg, DchatmsgsBuffer};
 use crate::dchatmsg::{Dchatmsg, DchatmsgsBuffer};
 
 
 pub struct ProtocolDchat {
 pub struct ProtocolDchat {
     jobsman: net::ProtocolJobsManagerPtr,
     jobsman: net::ProtocolJobsManagerPtr,
     msg_sub: net::MessageSubscription<Dchatmsg>,
     msg_sub: net::MessageSubscription<Dchatmsg>,
-    p2p: net::P2pPtr,
     msgs: DchatmsgsBuffer,
     msgs: DchatmsgsBuffer,
 }
 }
 
 
 impl ProtocolDchat {
 impl ProtocolDchat {
-    pub async fn init(
-        channel: net::ChannelPtr,
-        p2p: net::P2pPtr,
-        msgs: DchatmsgsBuffer,
-    ) -> net::ProtocolBasePtr {
-        info!(target: "dchat", "ProtocolDchat::init() [START]");
-
+    pub async fn init(channel: net::ChannelPtr, msgs: DchatmsgsBuffer) -> net::ProtocolBasePtr {
+        debug!(target: "dchat", "ProtocolDchat::init() [START]");
         let message_subsytem = channel.get_message_subsystem();
         let message_subsytem = channel.get_message_subsystem();
         message_subsytem.add_dispatch::<Dchatmsg>().await;
         message_subsytem.add_dispatch::<Dchatmsg>().await;
 
 
@@ -30,38 +24,28 @@ impl ProtocolDchat {
         Arc::new(Self {
         Arc::new(Self {
             jobsman: net::ProtocolJobsManager::new("ProtocolDchat", channel.clone()),
             jobsman: net::ProtocolJobsManager::new("ProtocolDchat", channel.clone()),
             msg_sub,
             msg_sub,
-            p2p,
             msgs,
             msgs,
         })
         })
     }
     }
 
 
     async fn handle_receive_msg(self: Arc<Self>) -> Result<()> {
     async fn handle_receive_msg(self: Arc<Self>) -> Result<()> {
-        //let mut msg_vec = Vec::new();
-        info!(target: "dchat", "ProtocolDchat::handle_receive_msg() [START]");
+        debug!(target: "dchat", "ProtocolDchat::handle_receive_msg() [START]");
         while let Ok(msg) = self.msg_sub.receive().await {
         while let Ok(msg) = self.msg_sub.receive().await {
             let msg = (*msg).to_owned();
             let msg = (*msg).to_owned();
             self.msgs.lock().await.push(msg);
             self.msgs.lock().await.push(msg);
-            //self.p2p.broadcast(msg).await?;
-            //msg_vec.push(msg);
-            //senders.notify(msg).await;
         }
         }
-        Ok(())
 
 
-        //loop {
-        //    let msg = self.msg_sub.receive().await?;
-        //    let msg = (*msg).to_owned();
-        //    self.p2p.broadcast(msg).await?;
-        //}
+        Ok(())
     }
     }
 }
 }
 
 
 #[async_trait]
 #[async_trait]
 impl net::ProtocolBase for ProtocolDchat {
 impl net::ProtocolBase for ProtocolDchat {
     async fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) -> Result<()> {
     async fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) -> Result<()> {
-        info!(target: "dchat", "ProtocolDchat::ProtocolBase::start() [START]");
+        debug!(target: "dchat", "ProtocolDchat::ProtocolBase::start() [START]");
         self.jobsman.clone().start(executor.clone());
         self.jobsman.clone().start(executor.clone());
         self.jobsman.clone().spawn(self.clone().handle_receive_msg(), executor.clone()).await;
         self.jobsman.clone().spawn(self.clone().handle_receive_msg(), executor.clone()).await;
-        info!(target: "dchat", "ProtocolDchat::ProtocolBase::start() [STOP]");
+        debug!(target: "dchat", "ProtocolDchat::ProtocolBase::start() [STOP]");
         Ok(())
         Ok(())
     }
     }