Просмотр исходного кода

wallet: migrate to using async slots/signals and zmq debug backend

darkfi 2 лет назад
Родитель
Сommit
6d295ab1ca

+ 5 - 1
bin/darkwallet/Cargo.toml

@@ -21,7 +21,9 @@ freetype-sys = "0.20.1"
 image = "0.25.1"
 log = "0.4.21"
 glam = "0.27.0"
-zmq = "0.10.0"
+#zmq = "0.10.0"
+#async_zmq = "0.4.0"
+zeromq = { version = "*", default-features = false, features = ["async-std-runtime", "all-transport"] }
 #darkfi-serial = { path = "../../src/serial" }
 darkfi-serial = { git = "https://codeberg.org/darkrenaissance/darkfi.git" }
 thiserror = "1.0.61"
@@ -31,6 +33,8 @@ atomic_float = "1.0.0"
 async-channel = "2.3.1"
 easy-parallel = "3.3.1"
 rand = "0.8.5"
+async-lock = "3.4.0"
+futures = "0.3.30"
 
 #rustpython-vm = "0.3.1"
 

+ 20 - 0
bin/darkwallet/echo.py

@@ -0,0 +1,20 @@
+#!/usr/bin/python
+import zmq
+from pydrk import serial
+
+context = zmq.Context()
+socket = context.socket(zmq.REQ)
+#self.socket.setsockopt(zmq.IPV6, True)
+socket.connect(f"tcp://127.0.0.1:9484")
+
+req_cmd = bytearray()
+serial.write_u8(req_cmd, 0)
+payload = bytearray()
+socket.send_multipart([req_cmd, payload])
+
+errc, reply = socket.recv_multipart()
+errc = int.from_bytes(errc, "little")
+cursor = serial.Cursor(reply)
+response = serial.decode_str(cursor)
+print(errc, response)
+

+ 1 - 1
bin/darkwallet/gui/api.py

@@ -2,7 +2,7 @@ from collections import namedtuple
 from pydrk import Api, HostApi, PropertyType, PropertySubType, Property, serial
 import zmq
 
-api = Api(addr="[2a02:aa13:8342:1400:81b3:9662:6650:690d]")
+api = Api()
 host = HostApi(api)
 print("Node status:", api.hello())
 

+ 2 - 2
bin/darkwallet/pydrk/api.py

@@ -239,10 +239,10 @@ def face(idx1, idx2, idx3):
 
 class Api:
 
-    def __init__(self, addr="[::1]", port=9484):
+    def __init__(self, addr="127.0.0.1", port=9484):
         context = zmq.Context()
         self.socket = context.socket(zmq.REQ)
-        self.socket.setsockopt(zmq.IPV6, True)
+        #self.socket.setsockopt(zmq.IPV6, True)
         self.socket.connect(f"tcp://{addr}:{port}")
 
     def _make_request(self, cmd, payload):

+ 4 - 2
bin/darkwallet/src/chatview.rs

@@ -63,6 +63,7 @@ impl ChatView {
             atlas: Mutex::new(HashMap::new()),
         });
 
+        /*
         let weak_self = Arc::downgrade(&self_);
         let slot_move = Slot {
             name: format!("{}::mouse_move", node_name),
@@ -94,13 +95,14 @@ impl ChatView {
                 }
             }),
         };
+        */
 
         let mouse_node = 
             scene_graph
             .lookup_node_mut("/window/input/mouse")
             .expect("no mouse attached!");
-        mouse_node.register("wheel", slot_wheel);
-        mouse_node.register("move", slot_move);
+        //mouse_node.register("wheel", slot_wheel);
+        //mouse_node.register("move", slot_move);
 
         // Save any properties we use
         Ok(Pimpl::ChatView(self_))

+ 3 - 1
bin/darkwallet/src/editbox.rs

@@ -154,6 +154,7 @@ impl EditBox {
         });
         self_.regen_glyphs().unwrap();
 
+        /*
         let weak_self = Arc::downgrade(&self_);
         let slot_key_down = Slot {
             name: format!("{}::key_down", node_name),
@@ -270,12 +271,13 @@ impl EditBox {
                 }
             }),
         };
+        */
 
         let window_node = 
             scene_graph
             .lookup_node_mut("/window")
             .expect("no window attached!");
-        window_node.register("resize", slot_resize).unwrap();
+        //window_node.register("resize", slot_resize).unwrap();
 
         // Save any properties we use
         Ok(Pimpl::EditBox(self_))

+ 7 - 7
bin/darkwallet/src/gfx.rs

@@ -1222,7 +1222,7 @@ impl EventHandler for Stage {
         modifiers.logo.encode(&mut data).unwrap();
         repeat.encode(&mut data).unwrap();
         key.encode(&mut data).unwrap();
-        win.trigger("key_down", data).unwrap();
+        //win.trigger("key_down", data).unwrap();
     }
     fn key_up_event(&mut self, keycode: KeyCode, modifiers: KeyMods) {
         let mut scene_graph = self.scene_graph.lock().unwrap();
@@ -1236,7 +1236,7 @@ impl EventHandler for Stage {
         modifiers.alt.encode(&mut data).unwrap();
         modifiers.logo.encode(&mut data).unwrap();
         key.encode(&mut data).unwrap();
-        win.trigger("key_up", data).unwrap();
+        //win.trigger("key_up", data).unwrap();
     }
     fn mouse_motion_event(&mut self, x: f32, y: f32) {
         let mut scene_graph = self.scene_graph.lock().unwrap();
@@ -1244,7 +1244,7 @@ impl EventHandler for Stage {
         x.encode(&mut data).unwrap();
         y.encode(&mut data).unwrap();
         let mouse = scene_graph.lookup_node_mut("/window/input/mouse").unwrap();
-        mouse.trigger("move", data).unwrap();
+        //mouse.trigger("move", data).unwrap();
     }
     fn mouse_wheel_event(&mut self, x: f32, y: f32) {
         let mut scene_graph = self.scene_graph.lock().unwrap();
@@ -1252,7 +1252,7 @@ impl EventHandler for Stage {
         x.encode(&mut data).unwrap();
         y.encode(&mut data).unwrap();
         let mouse = scene_graph.lookup_node_mut("/window/input/mouse").unwrap();
-        mouse.trigger("wheel", data).unwrap();
+        //mouse.trigger("wheel", data).unwrap();
     }
     fn mouse_button_down_event(&mut self, button: MouseButton, x: f32, y: f32) {
         let mut scene_graph = self.scene_graph.lock().unwrap();
@@ -1261,7 +1261,7 @@ impl EventHandler for Stage {
         x.encode(&mut data).unwrap();
         y.encode(&mut data).unwrap();
         let mouse = scene_graph.lookup_node_mut("/window/input/mouse").unwrap();
-        mouse.trigger("button_down", data).unwrap();
+        //mouse.trigger("button_down", data).unwrap();
     }
     fn mouse_button_up_event(&mut self, button: MouseButton, x: f32, y: f32) {
         let mut scene_graph = self.scene_graph.lock().unwrap();
@@ -1270,7 +1270,7 @@ impl EventHandler for Stage {
         x.encode(&mut data).unwrap();
         y.encode(&mut data).unwrap();
         let mouse = scene_graph.lookup_node_mut("/window/input/mouse").unwrap();
-        mouse.trigger("button_up", data).unwrap();
+        //mouse.trigger("button_up", data).unwrap();
     }
 
     fn resize_event(&mut self, width: f32, height: f32) {
@@ -1283,7 +1283,7 @@ impl EventHandler for Stage {
         let prop = win.get_property("screen_size").unwrap();
         prop.set_f32(0, width).unwrap();
         prop.set_f32(1, height).unwrap();
-        win.trigger("resize", data).unwrap();
+        //win.trigger("resize", data).unwrap();
     }
 }
 

+ 38 - 22
bin/darkwallet/src/main.rs

@@ -1,8 +1,9 @@
 #![feature(deadline_api)]
 #![feature(str_split_whitespace_remainder)]
 
+use async_lock::Mutex;
 use std::{
-    sync::{Arc, Mutex, mpsc},
+    sync::{Arc, mpsc},
     thread,
 };
 
@@ -52,10 +53,6 @@ use log::LevelFilter;
 
 fn start_zmq(scene_graph: SceneGraphPtr) {
     // detach thread
-    let _ = thread::spawn(move || {
-        let mut zmq_rpc = ZeroMQAdapter::new(scene_graph);
-        zmq_rpc.run();
-    });
 }
 
 fn start_sentinel(scene_graph: SceneGraphPtr) {
@@ -67,16 +64,8 @@ fn start_sentinel(scene_graph: SceneGraphPtr) {
     });
 }
 
-async fn amain(ex: Arc<smol::Executor<'static>>, render_api: Arc<gfx2::RenderApi>,
-    event_sub: pubsub::Subscription<gfx2::GraphicsEvent>
-    ) {
-    let task = ex.spawn(async move {
-        loop {
-            let ev = event_sub.receive().await;
-            debug!("ev: {:?}", ev);
-        }
-    });
-
+/*
+async fn greensq(render_api: Arc<gfx2::RenderApi>) -> (miniquad::BufferId, miniquad::BufferId) {
     let x1 = 0.1;
     let x2 = 0.6;
     let y1 = 0.1;
@@ -127,6 +116,20 @@ async fn amain(ex: Arc<smol::Executor<'static>>, render_api: Arc<gfx2::RenderApi
         ]
     };
     render_api.replace_draw_call(vec![], dc).await;
+    (vertex_buffer, index_buffer)
+}
+
+async fn amain(ex: Arc<smol::Executor<'static>>, render_api: Arc<gfx2::RenderApi>,
+    event_sub: pubsub::Subscription<gfx2::GraphicsEvent>
+    ) {
+
+    let task = ex.spawn(async move {
+        let (vert_buffer, idx_buffer) = greensq(render_api).await;
+        loop {
+            let ev = event_sub.receive().await;
+            debug!("ev: {:?}", ev);
+        }
+    });
 
     smol::Timer::after(std::time::Duration::from_secs(2)).await;
 
@@ -157,14 +160,23 @@ async fn amain(ex: Arc<smol::Executor<'static>>, render_api: Arc<gfx2::RenderApi
         dcs: vec![]
     };
     render_api.replace_draw_call(vec![0], dc).await;
-    render_api.delete_buffer(vertex_buffer);
+    //render_api.delete_buffer(vertex_buffer);
 
     println!("hello!");
 }
+*/
 
 fn main() {
+    let ex = std::sync::Arc::new(smol::Executor::new());
     let scene_graph = Arc::new(Mutex::new(SceneGraph::new()));
 
+    let scene_graph2 = scene_graph.clone();
+    let ex2 = ex.clone();
+    let zmq_task = ex.spawn(async {
+        let mut zmq_rpc = ZeroMQAdapter::new(scene_graph2, ex2).await;
+        zmq_rpc.run().await;
+    });
+
     let (method_sender, method_recvr) = mpsc::channel();
     let render_api = gfx2::RenderApi::new(method_sender);
 
@@ -176,7 +188,6 @@ fn main() {
     });
 
     let n_threads = std::thread::available_parallelism().unwrap().get();
-    let ex = std::sync::Arc::new(smol::Executor::new());
     let (signal, shutdown) = smol::channel::unbounded::<()>();
     easy_parallel::Parallel::new()
         // Executor threads
@@ -184,17 +195,22 @@ fn main() {
         // Run the main future on this thread
         .finish(|| {
             smol::future::block_on(async {
-                amain(ex.clone(), render_api, event_sub).await;
+                //amain(ex.clone(), render_api, event_sub).await;
+
+                // Need to figure out how closing the window works
+                // Some time to allow processes to clean up
+                // But a time limit whereby we just close
+                loop {
+                    smol::Timer::after(std::time::Duration::from_secs(2)).await;
+                }
                 drop(signal);
+
+                zmq_task.cancel().await;
                 Ok::<(), Error>(())
             });
         });
 
     gfx_handle.join();
-
-    //start_zmq(scene_graph.clone());
-    //start_sentinel(scene_graph.clone());
-    //run_gui(scene_graph);
 }
 
 /*

+ 74 - 61
bin/darkwallet/src/net.rs

@@ -1,15 +1,17 @@
 use darkfi_serial::{deserialize, Decodable, Encodable, SerialDecodable, VarInt};
+use async_lock::Mutex;
 use std::{
     io::Cursor,
-    sync::{atomic::Ordering, mpsc},
+    sync::{Arc, atomic::Ordering, mpsc},
     thread,
 };
+use zeromq::{Socket, SocketSend, SocketRecv};
 
 use crate::{
     error::{Error, Result},
     expr::SExprCode,
     prop::{Property, PropertySubType, PropertyType, PropertyValue},
-    scene::{SceneGraphPtr, SceneNodeId, SceneNodeType, Slot, SlotId},
+    scene::{SceneGraphPtr2, SceneNodeId, SceneNodeType, Slot, SlotId},
 };
 
 #[derive(Debug, SerialDecodable)]
@@ -49,78 +51,75 @@ enum Command {
 // PropertyIsUnset
 
 pub struct ZeroMQAdapter {
+    /*
     // req-reply commands
     req_socket: zmq::Socket,
     // We cannot share zmq sockets across threads, and we cannot quickly spawn
     // pub sockets due to address reuse errors.
     slot_sender: mpsc::SyncSender<(Vec<u8>, Vec<u8>)>,
     slot_recvr: Option<mpsc::Receiver<(Vec<u8>, Vec<u8>)>>,
-    scene_graph: SceneGraphPtr,
+    */
+    scene_graph: SceneGraphPtr2,
+    ex: Arc<smol::Executor<'static>>,
+
+    zmq_rep: Mutex<zeromq::RepSocket>,
+    zmq_pub: Mutex<zeromq::PubSocket>,
 }
 
 impl ZeroMQAdapter {
-    pub fn new(scene_graph: SceneGraphPtr) -> Self {
-        let zmq_ctx = zmq::Context::new();
-        let req_socket = zmq_ctx.socket(zmq::REP).unwrap();
-        req_socket.set_ipv6(true).unwrap();
-        req_socket.bind("tcp://*:9484").unwrap();
-
-        let (slot_sender, slot_recvr) = mpsc::sync_channel(100);
-
-        Self { req_socket, slot_sender, slot_recvr: Some(slot_recvr), scene_graph }
+    pub async fn new(scene_graph: SceneGraphPtr2,
+    ex: Arc<smol::Executor<'static>>,
+        ) -> Arc<Self> {
+        let mut zmq_rep = zeromq::RepSocket::new();
+        zmq_rep.bind("tcp://127.0.0.1:9484").await.unwrap();
+
+        let mut zmq_pub = zeromq::PubSocket::new();
+        zmq_pub.bind("tcp://127.0.0.1:9485").await.unwrap();
+
+        Arc::new(Self {
+            scene_graph,
+            ex,
+            zmq_rep: Mutex::new(zmq_rep),
+            zmq_pub: Mutex::new(zmq_pub),
+        })
     }
 
-    pub fn run(&mut self) {
-        let rx = std::mem::take(&mut self.slot_recvr).unwrap();
-        let _ = thread::spawn(move || {
-            let zmq_ctx = zmq::Context::new();
-            let pub_socket = zmq_ctx.socket(zmq::PUB).unwrap();
-            pub_socket.set_ipv6(true).unwrap();
-            pub_socket.bind("tcp://*:9485").unwrap();
-
-            loop {
-                let (signal_data, user_data) = rx.recv().unwrap();
-                pub_socket.send_multipart(&[signal_data, user_data], zmq::DONTWAIT).unwrap();
-            }
-        });
-
+    pub async fn run(self: Arc<Self>) {
         loop {
-            // https://github.com/johnliu55tw/rust-zmq-poller/blob/master/src/main.rs
-            let mut items = [self.req_socket.as_poll_item(zmq::POLLIN)];
-            // Poll forever
-            let _rc = zmq::poll(&mut items, -1).unwrap();
-
-            // Rust borrow checker things
-            let is_item0_readable = items[0].is_readable();
-            drop(items);
-
-            if is_item0_readable {
-                let req = self.req_socket.recv_multipart(zmq::DONTWAIT).unwrap();
-
-                assert_eq!(req[0].len(), 1);
-                assert_eq!(req.len(), 2);
-                let cmd = deserialize(&req[0]).unwrap();
-                let payload = req[1].clone();
-
-                match self.process_request(cmd, payload) {
-                    Ok(reply) => {
-                        // [errc:1] [reply]
-                        self.req_socket.send_multipart(&[vec![0], reply], zmq::DONTWAIT).unwrap();
-                    }
-                    Err(err) => {
-                        let errc = err as u8;
-                        warn!(target: "req", "errc {}: {}", errc, err);
-                        self.req_socket
-                            .send_multipart(&[vec![errc], vec![]], zmq::DONTWAIT)
-                            .unwrap();
-                    }
+            let req = self.zmq_rep.lock().await.recv().await.unwrap();
+            assert_eq!(req.len(), 2);
+            let cmd = req.get(0).unwrap().to_vec();
+            assert_eq!(cmd.len(), 1);
+            let payload = req.get(1).unwrap().to_vec();
+
+            let cmd = deserialize(&cmd).unwrap();
+            debug!(target: "req", "zmq: {:?} {:?}", cmd, payload);
+
+            let self2 = self.clone();
+            match self2.process_request(cmd, payload).await {
+                Ok(reply) => {
+                    let mut m = zeromq::ZmqMessage::from(vec![0u8]);
+                    m.push_back(reply.into());
+
+                    // [errc:1] [reply]
+                    self.zmq_rep.lock().await.send(m).await.unwrap();
+                }
+                Err(err) => {
+                    let errc = err as u8;
+                    warn!(target: "req", "errc {}: {}", errc, err);
+
+                    let mut m = zeromq::ZmqMessage::from(vec![errc]);
+                    m.push_back(vec![].into());
+
+                    // [errc:1] [reply]
+                    self.zmq_rep.lock().await.send(m).await.unwrap();
                 }
             }
         }
     }
 
-    fn process_request(&self, cmd: Command, payload: Vec<u8>) -> Result<Vec<u8>> {
-        let mut scene_graph = self.scene_graph.lock().unwrap();
+    async fn process_request(self: Arc<Self>, cmd: Command, payload: Vec<u8>) -> Result<Vec<u8>> {
+        let mut scene_graph = self.scene_graph.lock().await;
         let mut cur = Cursor::new(&payload);
         let mut reply = vec![];
         match cmd {
@@ -425,14 +424,28 @@ impl ZeroMQAdapter {
 
                 let node = scene_graph.get_node_mut(node_id).ok_or(Error::NodeNotFound)?;
 
-                let sender = self.slot_sender.clone();
+                let (sendr, recvr) = async_channel::unbounded();
                 let slot = Slot {
                     name: slot_name,
-                    func: Box::new(move |signal_data| {
-                        sender.send((signal_data, user_data.clone())).unwrap();
-                    }),
+                    notify: sendr
                 };
 
+                // This task will auto-die when the slot is unregistered
+                let self2 = self.clone();
+                self.ex.spawn(async move {
+                    loop {
+                        let Ok(signal_data) = recvr.recv().await else {
+                            // Die
+                            break;
+                        };
+
+                        let mut m = zeromq::ZmqMessage::from(signal_data);
+                        m.push_back(user_data.clone().into());
+
+                        self2.zmq_pub.lock().await.send(m).await.unwrap();
+                    }
+                }).detach();
+
                 let slot_id = node.register(&sig_name, slot)?;
                 slot_id.encode(&mut reply).unwrap();
             }

+ 13 - 11
bin/darkwallet/src/scene.rs

@@ -1,11 +1,14 @@
 use atomic_float::AtomicF32;
 use darkfi_serial::{SerialDecodable, SerialEncodable};
+use async_lock::Mutex;
+use async_channel::Sender;
+use futures::{stream::FuturesUnordered, StreamExt};
 use std::{
     fmt,
     str::FromStr,
     sync::{
         atomic::{AtomicBool, AtomicU32, Ordering},
-        Arc, Mutex, MutexGuard,
+        Arc
     },
 };
 
@@ -89,7 +92,8 @@ impl FromStr for ScenePath {
     }
 }
 
-pub type SceneGraphPtr = Arc<Mutex<SceneGraph>>;
+pub type SceneGraphPtr = Arc<std::sync::Mutex<SceneGraph>>;
+pub type SceneGraphPtr2 = Arc<Mutex<SceneGraph>>;
 
 pub struct SceneGraph {
     // Node 0 is always the root
@@ -513,12 +517,16 @@ impl SceneNode {
         sig.freed.push(slot_id);
         Ok(())
     }
-    pub fn trigger(&self, sig_name: &str, data: Vec<u8>) -> Result<()> {
+    pub async fn trigger(&self, sig_name: &str, data: Vec<u8>) -> Result<()> {
         let sig = self.get_signal(sig_name).ok_or(Error::SignalNotFound)?;
+        let mut futures = FuturesUnordered::new();
         for (_, slot) in sig.get_slots() {
             // Trigger the slot
-            slot.call(data.clone());
+            futures.push(async {
+                slot.notify.send(data.clone()).await;
+            });
         }
+        let _: Vec<_> = futures.collect().await;
         Ok(())
     }
 
@@ -576,13 +584,7 @@ pub type SlotId = u32;
 
 pub struct Slot {
     pub name: String,
-    pub func: SlotFn,
-}
-
-impl Slot {
-    fn call(&self, data: Vec<u8>) {
-        (self.func)(data)
-    }
+    pub notify: Sender<Vec<u8>>
 }
 
 pub struct Signal {