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

dnet: fix bug in data structures that propagated notes with duplicate node info

also clean up a bit
lunar-mining 2 лет назад
Родитель
Сommit
e211406b59
3 измененных файлов с 105 добавлено и 137 удалено
  1. 2 2
      bin/dnet/main.py
  2. 41 80
      bin/dnet/model.py
  3. 62 55
      bin/dnet/view.py

+ 2 - 2
bin/dnet/main.py

@@ -82,9 +82,9 @@ class Dnetview:
             method = values.get("method")
 
             if method == "dnet.subscribe_events":
-                self.model.handle_event(info)
+                self.model.add_event(info)
             else:
-                self.model.handle_nodes(info)
+                self.model.add_node(info)
 
             self.queue.task_done()
 

+ 41 - 80
bin/dnet/model.py

@@ -17,69 +17,63 @@
 
 import logging, time 
 import datetime as dt
+from collections import defaultdict as dd
 
 
-# -------------------------------------------------------------------
-# TODO:
-#   * on first get_info call, initialize data structure
-#   * use channel id as key
-#   * e.g. outbound[id] = [info1, info2, ...]
-#   * create unique null id if not connected
-# -------------------------------------------------------------------
-
 class Model:
 
     def __init__(self):
-        self.info = Info()
         self.nodes = {}
-        self.channel_lookup = {}
-
-    def update_node(self, key, value):
-        self.nodes[key] = value
 
-    def handle_nodes(self, node):
-        #logging.debug(f"p2p_get_info(): {node}")
+    def add_node(self, node):
+        channel_lookup = {}
         name = list(node.keys())[0]
         values = list(node.values())[0]
         info = values["result"]
         channels = info["channels"]
+        
+        self.nodes[name] = {}
+        self.nodes[name]['outbound'] = {}
+        self.nodes[name]['inbound'] = {}
+        self.nodes[name]['manual'] = {}
+        self.nodes[name]['event'] = {}
+        self.nodes[name]['seed'] = {}
+        self.nodes[name]['msgs'] = dd(list)
 
         for channel in channels:
             id = channel["id"]
-            self.channel_lookup[id] = channel
+            channel_lookup[id] = channel
 
         for channel in channels:
             if channel["session"] != "inbound":
                 continue
-
             id = channel["id"]
-            url = self.channel_lookup[id]["url"]
-            self.info.update_inbound(f"{id}", url)
+            url = channel_lookup[id]["url"]
+            self.nodes[name]['inbound'][f"{id}"] = url
 
         for i, id in enumerate(info["outbound_slots"]):
             if id == 0:
-                self.info.update_outbound(f"{i}", "none")
+                outbounds = self.nodes[name]['outbound'][f"{i}"] = "none"
                 continue
-
-            assert id in self.channel_lookup
-            url = self.channel_lookup[id]["url"]
-            self.info.update_outbound(f"{i}", url)
+            assert id in channel_lookup
+            url = channel_lookup[id]["url"]
+            outbounds = self.nodes[name]['outbound'][f"{i}"] = url
 
         for channel in channels:
             if channel["session"] != "seed":
                 continue
+            id = channel["id"]
             url = channel["url"]
-            self.info.update_seed("seed", url)
+            self.nodes[name]['seed'][f"{id}"] = url
 
         for channel in channels:
             if channel["session"] != "manual":
                 continue
+            id = channel["id"]
             url = channel["url"]
-            self.info.update_manual("manual", url)
-
-        self.update_node(name, self.info)
+            self.nodes[name]['manual'][f"{id}"] = url
 
-    def handle_event(self, event):
+    def add_event(self, event):
         name = list(event.keys())[0]
         values = list(event.values())[0]
         params = values.get("params")
@@ -98,7 +92,8 @@ class Model:
                 t = (dt.datetime
                         .fromtimestamp(int(nano)/1000000000)
                         .strftime('%H:%M:%S'))
-                self.info.update_msg(addr, (t, event, cmd))
+                msgs = self.nodes[name]['msgs']
+                msgs[addr].append((t, event, cmd))
             case "recv":
                 nano = info.get("time")
                 cmd = info.get("cmd")
@@ -107,84 +102,50 @@ class Model:
                 t = (dt.datetime
                         .fromtimestamp(int(nano)/1000000000)
                         .strftime('%H:%M:%S'))
-                self.info.update_msg(addr, (t, event, cmd))
+                msgs = self.nodes[name]['msgs']
+                msgs[addr].append((t, event, cmd))
             case "inbound_connected":
                 addr = info["addr"]
                 id = info.get("channel_id")
-                self.info.update_inbound(f"{id}", addr)
+                self.nodes[name]['inbound'][f"{id}"] = addr
                 logging.debug(f"{current_time}  inbound (connect):    {addr}")
             case "inbound_disconnected":
                 addr = info["addr"]
                 id = info.get("channel_id")
-                self.info.remove_inbound(f"{id}")
+                inbound = self.nodes[name]['inbound']
+                del inbound[f"{id}"]
                 logging.debug(f"{current_time}  inbound (disconnect): {addr}")
             case "outbound_slot_sleeping":
                 slot = info["slot"]
-                self.info.update_event((f"{name}", f"{slot}"), "sleeping")
                 logging.debug(f"{current_time}  slot {slot}: sleeping")
+                self.nodes[name]['event'][(f"{name}", f"{slot}")] = "sleeping"
             case "outbound_slot_connecting":
                 slot = info["slot"]
                 addr = info["addr"]
-                self.info.update_event((f"{name}", f"{slot}"), f"connecting: addr={addr}")
+                event = self.nodes[name]['event']
+                event[(f"{name}", f"{slot}")] = f"connecting: addr={addr}"
                 logging.debug(f"{current_time}  slot {slot}: connecting   addr={addr}")
             case "outbound_slot_connected":
                 slot = info["slot"]
                 addr = info["addr"]
                 channel_id = info["channel_id"]
-                self.info.update_event((f"{name}", f"{slot}"), f"connected: addr={addr}")
+                event = self.nodes[name]['event']
+                event[(f"{name}", f"{slot}")] = f"connected: addr={addr}"
                 logging.debug(f"{current_time}  slot {slot}: connected    addr={addr}")
             case "outbound_slot_disconnected":
                 slot = info["slot"]
                 err = info["err"]
-                self.info.update_event((f"{name}", f"{slot}"), f"disconnected: {err}")
+                event = self.nodes[name]['event']
+                event[(f"{name}", f"{slot}")] = f"disconnected: {err}"
                 logging.debug(f"{current_time}  slot {slot}: disconnected err='{err}'")
             case "outbound_peer_discovery":
                 attempt = info["attempt"]
                 state = info["state"]
-                self.info.update_event((f"{name}", "outbound"), f"peer discovery: {state} (attempt {attempt})")
+                event = self.nodes[name]['event']
+                key = (f"{name}", "outbound")
+                event[key] = f"peer discovery: {state} (attempt {attempt})"
                 logging.debug(f"{current_time}  peer_discovery: {state} (attempt {attempt})")
 
-    def __repr__(self):
-        return f"{self.nodes}"
-    
-
-class Info:
-
-    def __init__(self):
-        self.outbound = {}
-        self.inbound = {}
-        self.manual = {}
-        self.event = {}
-        self.seed = {}
-        self.msgs = {}
-    
-    def update_outbound(self, key, value):
-        self.outbound[key] = value
-
-    def update_inbound(self, key, value):
-        self.inbound[key] = value
-
-    def remove_inbound(self, key):
-        del self.inbound[key]
-
-    def update_manual(self, key, value):
-        self.manual[key] = value
-
-    def update_seed(self, key, value):
-        self.seed[key] = value
-
-    def update_event(self, key, value):
-        self.event[key] = value
-
-    def update_msg(self, key, value):
-        if key in self.msgs:
-            self.msgs[key] += [value]
-        else:
-            self.msgs[key] = [value]
 
     def __repr__(self):
-        return (f"outbound: {self.outbound}"
-            f"inbound: {self.inbound}"
-            f"manual: {self.manual}"
-            f"seed: {self.seed}"
-            f"msg: {self.msgs}")
+        return f"{self.nodes}"

+ 62 - 55
bin/dnet/view.py

@@ -23,14 +23,6 @@ import datetime as dt
 from scroll import ScrollBar, Scrollable
 from model import Model
 
-#----------------------------------------------------------------------
-# TODO: 
-#   * create a dictionary that stores:
-#   * channel[id] = index
-#   * index = listwalker.contents[i]
-#   * sort data by ID, constantly update listwalker_contents[i]
-#   * if it's a null id, render empty info
-# -------------------------------------------------------------------
 
 event_loop = asyncio.get_event_loop()
 
@@ -171,7 +163,7 @@ class View():
         known_nodes = []
         known_inbound = []
         while True:
-            await asyncio.sleep(0.01)
+            await asyncio.sleep(0.1)
             for index, item in enumerate(self.listwalker.contents):
                 known_nodes.append(item.get_name())
 
@@ -182,39 +174,43 @@ class View():
                 else:
                     widget = NodeView(node)
                     self.listwalker.contents.append(widget)
-                    outbounds = values.outbound
-                    inbound = values.inbound
-                    manual = values.manual
-                    seed = values.seed
-                    if len(outbounds) != 0:
+
+                    if values['outbound']:
                         widget = ConnectView(node, "outbound")
                         self.listwalker.contents.append(widget)
-                        for i, info in outbounds.items():
+                        for i, info in values['outbound'].items():
                             widget = SlotView(node, "outbound", i, info)
                             self.listwalker.contents.append(widget)
-                    if len(inbound) != 0:
+
+                    if values['inbound']:
                         widget = ConnectView(node, "inbound")
                         self.listwalker.contents.append(widget)
-                        for i, info in inbound.items():
+                        for i, info in values['inbound'].items():
                             widget = SlotView(node, "inbound", i, info)
                             self.listwalker.contents.append(widget)
-                    if len(seed) != 0:
-                        widget = ConnectView(node, "seed")
-                        self.listwalker.contents.append(widget)
-                    if len(manual) != 0:
+
+                    if values['manual']:
                         widget = ConnectView(node, "manual")
                         self.listwalker.contents.append(widget)
-                        for i, info in manual.items():
+                        for i, info in values['manual'].items():
                             widget = SlotView(node, "manual", i, info)
                             self.listwalker.contents.append(widget)
 
+                    if values['seed']:
+                        widget = ConnectView(node, "seed")
+                        self.listwalker.contents.append(widget)
+                        for i, info in values['seed'].items():
+                            widget = SlotView(node, "seed", i, info)
+                            self.listwalker.contents.append(widget)
+
+
             # Update outbound slot info
             for index, item in enumerate(self.listwalker.contents):
                 if item.get_type() == "outbound":
                     name = item.get_name()
-                    if name in self.model.info.event.keys():
-                        value = self.model.info.event.get(name)
-                        logging.debug(value)
+                    node = name[0]
+                    if name in self.model.nodes[node]['event']:
+                        value = self.model.nodes[node]['event'].get(name)
                         widget = SlotView(node, "outbound", name[1], value)
                         self.listwalker.contents[index] = widget
 
@@ -222,56 +218,67 @@ class View():
             for index, item in enumerate(self.listwalker.contents):
                 if item.get_type() == "inbound":
                     name = item.get_name()
-                    known_inbound.append(name[1])
-            for id, addr in self.model.info.inbound.items():
-                if id in known_inbound:
-                    continue
-                else:
-                    widget = SlotView(node, "inbound", id, addr)
-                    self.listwalker.contents.append(widget)
-
-            # Remove disconnected inbounds 
-            for id in known_inbound:
-                if id in self.model.info.inbound.keys():
-                    continue
-                for index, item in enumerate(self.listwalker.contents):
-                    name = item.get_name()
-                    if name[1] == id:
-                        del self.listwalker.contents[index]
+                    if name[1] not in known_inbound:
+                        known_inbound.append(name[1])
+            for node, value in self.model.nodes.items():
+                for id, addr in value['inbound'].items():
+                   if id in known_inbound:
+                       continue
+                   else:
+                       widget = SlotView(node, "inbound", id, addr)
+                       self.listwalker.contents.append(widget)
+
+            # Remove disconnected inbounds
+            for inbound in known_inbound:
+                for value in self.model.nodes.values():
+                    if inbound in value['inbound']:
+                        continue
+                    for index, item in enumerate(self.listwalker.contents):
+                        name = item.get_name()
+                        if name[1] == id:
+                            del self.listwalker.contents[index]
             
+
     # Render subscribe_events() (right menu)
     async def render_info(self):
         while True:
-            await asyncio.sleep(0.1)
+            await asyncio.sleep(0.01)
             self.pile.contents.clear()
+            logging.debug(self.pile.contents)
             focus_w = self.list.get_focus()
             if focus_w[0] is None:
                 continue
             else:
                 match focus_w[0].get_widget():
                     case "NodeView":
+                        logging.debug("node selected")
+                        # TODO: We will display additional node info here.
                         self.pile.contents.append((
-                            urwid.Text(f"Node selected"),
+                            urwid.Text(f""),
                             self.pile.options()))
                     case "ConnectView":
+                        logging.debug("connection selected")
                         name = focus_w[0].get_name()
-                        
-                        if name in self.model.info.event.keys():
-                            values = self.model.info.event.get(name)
+                        info = self.model.nodes.get(name[0])
+                        if name in info['event']:
+                            ev = info['event'].get(name)
+                            logging.debug(f"{ev}")
 
                             self.pile.contents.append((
-                                urwid.Text(f" {values}"),
+                                urwid.Text(f" {ev}"),
                                 self.pile.options()))
                     case "SlotView":
+                        logging.debug("slot selected")
                         addr = focus_w[0].get_addr()
-
-                        if addr in self.model.info.msgs.keys():
-                            values = self.model.info.msgs.get(addr)
-
-                            for value in values:
-                                time = value[0]
-                                event = value[1]
-                                msg = value[2]
+                        name = focus_w[0].get_name()
+                        info = self.model.nodes.get(name[0])
+                        if addr in info['msgs']:
+                            msg = info['msgs'].get(addr)
+
+                            for m in msg:
+                                time = m[0]
+                                event = m[1]
+                                msg = m[2]
 
                                 self.pile.contents.append((urwid.Text(
                                         f"{time}: {event}: {msg}"),