فهرست منبع

wallet: call method insert_line through scene graph

darkfi 2 سال پیش
والد
کامیت
1796ba2f2c

+ 11 - 0
bin/darkwallet/insert_line.py

@@ -0,0 +1,11 @@
+from gui import *
+
+node_id = api.lookup_node_id("/window/view/chatty")
+
+arg_data = bytearray()
+serial.write_u32(arg_data, 110)
+serial.encode_str(arg_data, "nick")
+serial.encode_str(arg_data, "hello1234")
+
+api.call_method(node_id, "insert_line", arg_data)
+

+ 6 - 1
bin/darkwallet/pydrk/api.py

@@ -152,6 +152,7 @@ class ErrorCode:
     PY_EVAL_ERR = 30
     SEXPR_EMPTY = 31
     SEXPR_GLOBAL_NOT_FOUND = 32
+    CHANNEL_CLOSED = 36
 
     @staticmethod
     def to_str(errc):
@@ -218,6 +219,8 @@ class ErrorCode:
                 return "sexpr_empty"
             case ErrorCode.SEXPR_GLOBAL_NOT_FOUND:
                 return "sexpr_global_not_found"
+            case ErrorCode.CHANNEL_CLOSED:
+                return "channel_closed"
 
 def vertex(x, y, r, g, b, a, u, v):
     buf = bytearray()
@@ -319,6 +322,8 @@ class Api:
                 raise exc.SExprEmpty
             case 32:
                 raise exc.SExprGlobalNotFound
+            case 36:
+                raise exc.ChannelClosed
         return cursor
 
     def hello(self):
@@ -475,7 +480,7 @@ class Api:
         serial.encode_str(req, node_path)
         try:
             cur = self._make_request(Command.LOOKUP_NODE_ID, req)
-        except exc.RequestNodeNotFound:
+        except exc.NodeNotFound:
             return None
         return serial.read_u32(cur)
 

+ 29 - 4
bin/darkwallet/src/app.rs

@@ -22,10 +22,11 @@ use futures::{stream::FuturesUnordered, StreamExt};
 use std::{sync::Arc, thread};
 
 use crate::{
+    error::Error,
     expr::Op,
     gfx2::{GraphicsEventPublisherPtr, RenderApiPtr, Vertex},
     prop::{Property, PropertySubType, PropertyType},
-    scene::{Pimpl, SceneGraph, SceneGraphPtr2, SceneNodeId, SceneNodeType},
+    scene::{MethodResponseFn, Pimpl, SceneGraph, SceneGraphPtr2, SceneNodeId, SceneNodeType},
     text2::TextShaperPtr,
     ui::{chatview, Button, ChatView, EditBox, Image, Mesh, RenderLayer, Stoppable, Text, Window},
 };
@@ -635,7 +636,7 @@ impl App {
         sg.link(node_id, layer_node_id).unwrap();
 
         // ChatView
-        let node_id = create_chatview(&mut sg, "chatty");
+        let (node_id, recvr) = create_chatview(&mut sg, "chatty");
         let node = sg.get_node(node_id).unwrap();
         let prop = node.get_property("rect").unwrap();
         prop.set_f32(0, 0.).unwrap();
@@ -708,6 +709,7 @@ impl App {
             self.event_pub.clone(),
             self.text_shaper.clone(),
             chat_tree,
+            recvr,
         )
         .await;
         let mut sg = self.sg.lock().await;
@@ -916,7 +918,10 @@ fn create_editbox(sg: &mut SceneGraph, name: &str) -> SceneNodeId {
     node.id
 }
 
-fn create_chatview(sg: &mut SceneGraph, name: &str) -> SceneNodeId {
+fn create_chatview(
+    sg: &mut SceneGraph,
+    name: &str,
+) -> (SceneNodeId, async_channel::Receiver<Vec<u8>>) {
     debug!(target: "app", "create_chatview({name})");
     let node = sg.add_node(name, SceneNodeType::ChatView);
 
@@ -959,5 +964,25 @@ fn create_chatview(sg: &mut SceneGraph, name: &str) -> SceneNodeId {
     let mut prop = Property::new("debug", PropertyType::Bool, PropertySubType::Null);
     node.add_property(prop).unwrap();
 
-    node.id
+    let (sender, recvr) = async_channel::unbounded::<Vec<u8>>();
+    let method = move |data: Vec<u8>, response_fn: MethodResponseFn| {
+        if sender.try_send(data).is_err() {
+            response_fn(Err(Error::ChannelClosed));
+        } else {
+            response_fn(Ok(vec![]));
+        }
+    };
+    node.add_method(
+        "insert_line",
+        vec![
+            ("timestamp", "Timestamp", PropertyType::Uint32),
+            ("nick", "Nickname", PropertyType::Str),
+            ("text", "Text", PropertyType::Str),
+        ],
+        vec![],
+        Box::new(method),
+    )
+    .unwrap();
+
+    (node.id, recvr)
 }

+ 3 - 0
bin/darkwallet/src/error.rs

@@ -125,4 +125,7 @@ pub enum Error {
 
     #[error("Empty atlas")]
     AtlasIsEmpty = 35,
+
+    #[error("Channel closed")]
+    ChannelClosed = 36,
 }

+ 1 - 1
bin/darkwallet/src/net.rs

@@ -526,7 +526,7 @@ impl ZeroMQAdapter {
                 let node = scene_graph.get_node_mut(node_id).ok_or(Error::NodeNotFound)?;
 
                 let method_name2 = method_name.clone();
-                let (tx, rx) = mpsc::sync_channel::<Result<Vec<u8>>>(0);
+                let (tx, rx) = mpsc::sync_channel::<Result<Vec<u8>>>(1);
                 let response_fn = Box::new(move |result| {
                     debug!(target: "req", "processing callmethod for {}:'{}'", node_id, method_name2);
                     tx.send(result).unwrap();

+ 24 - 24
bin/darkwallet/src/ui/button.rs

@@ -66,27 +66,18 @@ impl Button {
         let self_ = Arc::new_cyclic(|me: &Weak<Self>| {
             let ev_sub = event_pub.subscribe_mouse_btn_down();
             let me2 = me.clone();
-            let mouse_btn_down_task = ex.spawn(async move {
-                loop {
-                    Self::process_mouse_btn_down(&me2, &ev_sub).await;
-                }
-            });
+            let mouse_btn_down_task =
+                ex.spawn(async move { while Self::process_mouse_btn_down(&me2, &ev_sub).await {} });
 
             let ev_sub = event_pub.subscribe_mouse_btn_up();
             let me2 = me.clone();
-            let mouse_btn_up_task = ex.spawn(async move {
-                loop {
-                    Self::process_mouse_btn_up(&me2, &ev_sub).await;
-                }
-            });
+            let mouse_btn_up_task =
+                ex.spawn(async move { while Self::process_mouse_btn_up(&me2, &ev_sub).await {} });
 
             let ev_sub = event_pub.subscribe_touch();
             let me2 = me.clone();
-            let touch_task = ex.spawn(async move {
-                loop {
-                    Self::process_touch(&me2, &ev_sub).await;
-                }
-            });
+            let touch_task =
+                ex.spawn(async move { while Self::process_touch(&me2, &ev_sub).await {} });
 
             let tasks = vec![mouse_btn_down_task, mouse_btn_up_task, touch_task];
 
@@ -99,10 +90,10 @@ impl Button {
     async fn process_mouse_btn_down(
         me: &Weak<Self>,
         ev_sub: &Subscription<(MouseButton, f32, f32)>,
-    ) {
+    ) -> bool {
         let Ok((btn, mouse_x, mouse_y)) = ev_sub.receive().await else {
             debug!(target: "ui::button", "Event relayer closed");
-            return
+            return false
         };
 
         let Some(self_) = me.upgrade() else {
@@ -111,16 +102,20 @@ impl Button {
         };
 
         if !self_.is_active.get() {
-            return
+            return true
         }
 
         self_.handle_mouse_btn_down(btn, mouse_x, mouse_y);
+        true
     }
 
-    async fn process_mouse_btn_up(me: &Weak<Self>, ev_sub: &Subscription<(MouseButton, f32, f32)>) {
+    async fn process_mouse_btn_up(
+        me: &Weak<Self>,
+        ev_sub: &Subscription<(MouseButton, f32, f32)>,
+    ) -> bool {
         let Ok((btn, mouse_x, mouse_y)) = ev_sub.receive().await else {
             debug!(target: "ui::button", "Event relayer closed");
-            return
+            return false
         };
 
         let Some(self_) = me.upgrade() else {
@@ -129,16 +124,20 @@ impl Button {
         };
 
         if !self_.is_active.get() {
-            return
+            return true
         }
 
         self_.handle_mouse_btn_up(btn, mouse_x, mouse_y).await;
+        true
     }
 
-    async fn process_touch(me: &Weak<Self>, ev_sub: &Subscription<(TouchPhase, u64, f32, f32)>) {
+    async fn process_touch(
+        me: &Weak<Self>,
+        ev_sub: &Subscription<(TouchPhase, u64, f32, f32)>,
+    ) -> bool {
         let Ok((phase, id, touch_x, touch_y)) = ev_sub.receive().await else {
             debug!(target: "ui::button", "Event relayer closed");
-            return
+            return false
         };
 
         let Some(self_) = me.upgrade() else {
@@ -147,10 +146,11 @@ impl Button {
         };
 
         if !self_.is_active.get() {
-            return
+            return true
         }
 
         self_.handle_touch(phase, id, touch_x, touch_y).await;
+        true
     }
 
     fn handle_mouse_btn_down(&self, btn: MouseButton, mouse_x: f32, mouse_y: f32) {

+ 101 - 22
bin/darkwallet/src/ui/chatview.rs

@@ -22,6 +22,7 @@ use rand::{rngs::OsRng, Rng};
 use std::{
     collections::BTreeMap,
     hash::{DefaultHasher, Hash, Hasher},
+    io::Cursor,
     sync::{Arc, Mutex as SyncMutex, Weak},
 };
 
@@ -244,6 +245,7 @@ impl ChatView {
         event_pub: GraphicsEventPublisherPtr,
         text_shaper: TextShaperPtr,
         tree: sled::Tree,
+        recvr: async_channel::Receiver<Vec<u8>>,
     ) -> Pimpl {
         debug!(target: "ui::chatview", "ChatView::new()");
         let scene_graph = sg.lock().await;
@@ -265,27 +267,24 @@ impl ChatView {
         let self_ = Arc::new_cyclic(|me: &Weak<Self>| {
             let ev_sub = event_pub.subscribe_mouse_wheel();
             let me2 = me.clone();
-            let mouse_wheel_task = ex.spawn(async move {
-                loop {
-                    Self::process_mouse_wheel(&me2, &ev_sub).await;
-                }
-            });
+            let mouse_wheel_task =
+                ex.spawn(async move { while Self::process_mouse_wheel(&me2, &ev_sub).await {} });
 
             let ev_sub = event_pub.subscribe_mouse_move();
             let me2 = me.clone();
-            let mouse_move_task = ex.spawn(async move {
-                loop {
-                    Self::process_mouse_move(&me2, &ev_sub).await;
-                }
-            });
+            let mouse_move_task =
+                ex.spawn(async move { while Self::process_mouse_move(&me2, &ev_sub).await {} });
 
             let ev_sub = event_pub.subscribe_touch();
             let me2 = me.clone();
-            let touch_task = ex.spawn(async move {
-                loop {
-                    Self::process_touch(&me2, &ev_sub).await;
-                }
-            });
+            let touch_task =
+                ex.spawn(async move { while Self::process_touch(&me2, &ev_sub).await {} });
+
+            let me2 = me.clone();
+            let insert_line_method_task =
+                ex.spawn(
+                    async move { while Self::process_insert_line_method(&me2, &recvr).await {} },
+                );
 
             let mut on_modify = OnModify::new(ex, node_name, node_id, me.clone());
 
@@ -296,7 +295,8 @@ impl ChatView {
             }
             on_modify.when_change(rect.clone(), redraw);
 
-            let mut tasks = vec![mouse_wheel_task, mouse_move_task, touch_task];
+            let mut tasks =
+                vec![mouse_wheel_task, mouse_move_task, touch_task, insert_line_method_task];
             tasks.append(&mut on_modify.tasks);
 
             Self {
@@ -334,10 +334,10 @@ impl ChatView {
         Pimpl::ChatView(self_)
     }
 
-    async fn process_mouse_wheel(me: &Weak<Self>, ev_sub: &Subscription<(f32, f32)>) {
+    async fn process_mouse_wheel(me: &Weak<Self>, ev_sub: &Subscription<(f32, f32)>) -> bool {
         let Ok((wheel_x, wheel_y)) = ev_sub.receive().await else {
             debug!(target: "ui::chatview", "Event relayer closed");
-            return
+            return false
         };
 
         let Some(self_) = me.upgrade() else {
@@ -346,12 +346,13 @@ impl ChatView {
         };
 
         self_.handle_mouse_wheel(wheel_x, wheel_y).await;
+        true
     }
 
-    async fn process_mouse_move(me: &Weak<Self>, ev_sub: &Subscription<(f32, f32)>) {
+    async fn process_mouse_move(me: &Weak<Self>, ev_sub: &Subscription<(f32, f32)>) -> bool {
         let Ok((mouse_x, mouse_y)) = ev_sub.receive().await else {
             debug!(target: "ui::chatview", "Event relayer closed");
-            return
+            return false
         };
 
         let Some(self_) = me.upgrade() else {
@@ -360,12 +361,16 @@ impl ChatView {
         };
 
         self_.handle_mouse_move(mouse_x, mouse_y).await;
+        true
     }
 
-    async fn process_touch(me: &Weak<Self>, ev_sub: &Subscription<(TouchPhase, u64, f32, f32)>) {
+    async fn process_touch(
+        me: &Weak<Self>,
+        ev_sub: &Subscription<(TouchPhase, u64, f32, f32)>,
+    ) -> bool {
         let Ok((phase, id, touch_x, touch_y)) = ev_sub.receive().await else {
             debug!(target: "ui::chatview", "Event relayer closed");
-            return
+            return false
         };
 
         let Some(self_) = me.upgrade() else {
@@ -374,6 +379,38 @@ impl ChatView {
         };
 
         self_.handle_touch(phase, id, touch_x, touch_y).await;
+        true
+    }
+
+    async fn process_insert_line_method(
+        me: &Weak<Self>,
+        recvr: &async_channel::Receiver<Vec<u8>>,
+    ) -> bool {
+        let Ok(data) = recvr.recv().await else {
+            debug!(target: "ui::chatview", "Event relayer closed");
+            return false
+        };
+
+        fn decode_data(data: &[u8]) -> std::io::Result<(u32, String, String)> {
+            let mut cur = Cursor::new(&data);
+            let timestamp = u32::decode(&mut cur)?;
+            let nick = String::decode(&mut cur)?;
+            let text = String::decode(&mut cur)?;
+            Ok((timestamp, nick, text))
+        }
+
+        let Ok((timestamp, nick, text)) = decode_data(&data) else {
+            error!(target: "ui::chatview", "insert_line() method invalid arg data");
+            return true
+        };
+
+        let Some(self_) = me.upgrade() else {
+            // Should not happen
+            panic!("self destroyed before touch_task was stopped!");
+        };
+
+        self_.handle_insert_line(timestamp, nick, text).await;
+        true
     }
 
     async fn handle_mouse_wheel(&self, wheel_x: f32, wheel_y: f32) {
@@ -435,6 +472,48 @@ impl ChatView {
         }
     }
 
+    async fn handle_insert_line(&self, timest: u32, nick: String, text: String) {
+        debug!(target: "ui::chatview", "handle_insert_line({timest}, {nick}, {text})");
+
+        /*
+        let chatmsg = ChatMsg { nick, text };
+
+        let timestr = timest.to_string();
+        // left pad with zeros
+        let mut timestr = format!("{:0>4}", timestr);
+        timestr.insert(2, ':');
+
+        let text = format!("{} {} {}", timestr, chatmsg.nick, chatmsg.text);
+        let glyphs = self.text_shaper.shape(text, self.font_size.get()).await;
+
+        // Now add message to page
+
+        let mut pages = self.pages2.lock().unwrap();
+        let mut idx = None;
+        for (i, page) in pages.iter_mut().enumerate() {
+            let first_timest = page.msgs.first().unwrap().timest;
+            let last_timest = page.msgs.last().unwrap().timest;
+
+            if first_timest <= timest && timest <= last_timest {
+                idx = Some(i);
+            }
+        }
+        if idx.is_none() {
+            idx = Some(pages.len() - 1);
+        }
+        let idx = idx.unwrap();
+
+        let mut msgs = pages[idx].msgs.clone();
+
+        msgs.push(Message { timest, chatmsg, glyphs });
+        msgs.sort_unstable_by_key(|msg| msg.timest);
+
+        let new_page = Page2::new(msgs, &self.render_api).await;
+        let _ = std::mem::replace(&mut pages[idx], new_page);
+        drop(pages);
+        */
+    }
+
     /// Descent = line height - baseline
     fn descent(&self) -> f32 {
         self.line_height.get() - self.baseline.get()

+ 49 - 52
bin/darkwallet/src/ui/editbox.rs

@@ -204,19 +204,13 @@ impl EditBox {
             // Start a task monitoring for key down events
             let ev_sub = event_pub.subscribe_char();
             let me2 = me.clone();
-            let char_task = ex.spawn(async move {
-                loop {
-                    Self::process_char(&me2, &ev_sub).await;
-                }
-            });
+            let char_task =
+                ex.spawn(async move { while Self::process_char(&me2, &ev_sub).await {} });
 
             let ev_sub = event_pub.subscribe_key_down();
             let me2 = me.clone();
-            let key_down_task = ex.spawn(async move {
-                loop {
-                    Self::process_key_down(&me2, &ev_sub).await;
-                }
-            });
+            let key_down_task =
+                ex.spawn(async move { while Self::process_key_down(&me2, &ev_sub).await {} });
 
             /*
             let ev_sub = event_pub.subscribe_key_up();
@@ -242,35 +236,23 @@ impl EditBox {
 
             let ev_sub = event_pub.subscribe_mouse_btn_down();
             let me2 = me.clone();
-            let mouse_btn_down_task = ex.spawn(async move {
-                loop {
-                    Self::process_mouse_btn_down(&me2, &ev_sub).await;
-                }
-            });
+            let mouse_btn_down_task =
+                ex.spawn(async move { while Self::process_mouse_btn_down(&me2, &ev_sub).await {} });
 
             let ev_sub = event_pub.subscribe_mouse_btn_up();
             let me2 = me.clone();
-            let mouse_btn_up_task = ex.spawn(async move {
-                loop {
-                    Self::process_mouse_btn_up(&me2, &ev_sub).await;
-                }
-            });
+            let mouse_btn_up_task =
+                ex.spawn(async move { while Self::process_mouse_btn_up(&me2, &ev_sub).await {} });
 
             let ev_sub = event_pub.subscribe_mouse_move();
             let me2 = me.clone();
-            let mouse_move_task = ex.spawn(async move {
-                loop {
-                    Self::process_mouse_move(&me2, &ev_sub).await;
-                }
-            });
+            let mouse_move_task =
+                ex.spawn(async move { while Self::process_mouse_move(&me2, &ev_sub).await {} });
 
             let ev_sub = event_pub.subscribe_touch();
             let me2 = me.clone();
-            let touch_task = ex.spawn(async move {
-                loop {
-                    Self::process_touch(&me2, &ev_sub).await;
-                }
-            });
+            let touch_task =
+                ex.spawn(async move { while Self::process_touch(&me2, &ev_sub).await {} });
 
             let mut on_modify = OnModify::new(ex, node_name, node_id, me.clone());
             on_modify.when_change(is_focused.prop(), Self::change_focus);
@@ -479,15 +461,15 @@ impl EditBox {
         }
     }
 
-    async fn process_char(me: &Weak<Self>, ev_sub: &Subscription<(char, KeyMods, bool)>) {
+    async fn process_char(me: &Weak<Self>, ev_sub: &Subscription<(char, KeyMods, bool)>) -> bool {
         let Ok((key, mods, repeat)) = ev_sub.receive().await else {
             debug!(target: "ui::editbox", "Event relayer closed");
-            return
+            return false
         };
 
         // First filter for only single digit keys
         if DISALLOWED_CHARS.contains(&key) {
-            return
+            return true
         }
 
         let Some(self_) = me.upgrade() else {
@@ -496,15 +478,15 @@ impl EditBox {
         };
 
         if !self_.is_focused.get() {
-            return
+            return true
         }
 
         if mods.ctrl || mods.alt {
             if repeat {
-                return
+                return true
             }
             self_.handle_shortcut(key, &mods).await;
-            return
+            return true
         }
 
         let actions = {
@@ -515,18 +497,22 @@ impl EditBox {
         for _ in 0..actions {
             self_.insert_char(key).await;
         }
+        true
     }
 
-    async fn process_key_down(me: &Weak<Self>, ev_sub: &Subscription<(KeyCode, KeyMods, bool)>) {
+    async fn process_key_down(
+        me: &Weak<Self>,
+        ev_sub: &Subscription<(KeyCode, KeyMods, bool)>,
+    ) -> bool {
         let Ok((key, mods, repeat)) = ev_sub.receive().await else {
             debug!(target: "ui::editbox", "Event relayer closed");
-            return
+            return false
         };
 
         // First filter for only single digit keys
         // Avoid processing events handled by insert_char()
         if !ALLOWED_KEYCODES.contains(&key) {
-            return
+            return true
         }
 
         let Some(self_) = me.upgrade() else {
@@ -535,7 +521,7 @@ impl EditBox {
         };
 
         if !self_.is_focused.get() {
-            return
+            return true
         }
 
         let actions = {
@@ -549,15 +535,16 @@ impl EditBox {
         for _ in 0..actions {
             self_.handle_key(&key, &mods).await;
         }
+        true
     }
 
     async fn process_mouse_btn_down(
         me: &Weak<Self>,
         ev_sub: &Subscription<(MouseButton, f32, f32)>,
-    ) {
+    ) -> bool {
         let Ok((btn, mouse_x, mouse_y)) = ev_sub.receive().await else {
             debug!(target: "ui::editbox", "Event relayer closed");
-            return
+            return false
         };
 
         let Some(self_) = me.upgrade() else {
@@ -566,16 +553,20 @@ impl EditBox {
         };
 
         if !self_.is_active.get() {
-            return
+            return true
         }
 
         self_.handle_mouse_btn_down(btn, mouse_x, mouse_y).await;
+        true
     }
 
-    async fn process_mouse_btn_up(me: &Weak<Self>, ev_sub: &Subscription<(MouseButton, f32, f32)>) {
+    async fn process_mouse_btn_up(
+        me: &Weak<Self>,
+        ev_sub: &Subscription<(MouseButton, f32, f32)>,
+    ) -> bool {
         let Ok((btn, mouse_x, mouse_y)) = ev_sub.receive().await else {
             debug!(target: "ui::editbox", "Event relayer closed");
-            return
+            return false
         };
 
         let Some(self_) = me.upgrade() else {
@@ -584,16 +575,17 @@ impl EditBox {
         };
 
         if !self_.is_active.get() {
-            return
+            return true
         }
 
         self_.handle_mouse_btn_up(btn, mouse_x, mouse_y);
+        true
     }
 
-    async fn process_mouse_move(me: &Weak<Self>, ev_sub: &Subscription<(f32, f32)>) {
+    async fn process_mouse_move(me: &Weak<Self>, ev_sub: &Subscription<(f32, f32)>) -> bool {
         let Ok((mouse_x, mouse_y)) = ev_sub.receive().await else {
             debug!(target: "ui::editbox", "Event relayer closed");
-            return
+            return false
         };
 
         let Some(self_) = me.upgrade() else {
@@ -602,16 +594,20 @@ impl EditBox {
         };
 
         if !self_.is_active.get() {
-            return
+            return true
         }
 
         self_.handle_mouse_move(mouse_x, mouse_y).await;
+        true
     }
 
-    async fn process_touch(me: &Weak<Self>, ev_sub: &Subscription<(TouchPhase, u64, f32, f32)>) {
+    async fn process_touch(
+        me: &Weak<Self>,
+        ev_sub: &Subscription<(TouchPhase, u64, f32, f32)>,
+    ) -> bool {
         let Ok((phase, id, touch_x, touch_y)) = ev_sub.receive().await else {
             debug!(target: "ui::editbox", "Event relayer closed");
-            return
+            return false
         };
 
         let Some(self_) = me.upgrade() else {
@@ -620,10 +616,11 @@ impl EditBox {
         };
 
         if !self_.is_active.get() {
-            return
+            return true
         }
 
         self_.handle_touch(phase, id, touch_x, touch_y).await;
+        true
     }
 
     async fn change_focus(self: Arc<Self>) {