| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- #!/usr/bin/python3
- # This file is part of DarkFi (https://dark.fi)
- #
- # Copyright (C) 2020-2024 Dyne.org foundation
- #
- # This program is free software: you can redistribute it and/or modify
- # it under the terms of the GNU Affero General Public License as
- # published by the Free Software Foundation, either version 3 of the
- # License, or (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU Affero General Public License for more details.
- #
- # You should have received a copy of the GNU Affero General Public License
- # along with this program. If not, see <https://www.gnu.org/licenses/>.
- import asyncio, random, re, sys, base58, json
- import base58
- import urwid as u
- import networkx as nx
- # import matplotlib.pyplot as plt
- import src.util
- from os.path import join
- # # Create a directed graph
- # dag = nx.DiGraph()
- # # Add edges to the graph (this also adds nodes)
- # dag.add_edges_from([
- # ("root", "a"),
- # ("a", "b"),
- # ("a", "e"),
- # ("b", "c"),
- # ("b", "d"),
- # ("d", "e")
- # ])
- class JsonRpc:
- async def start(self, server, port):
- reader, writer = await asyncio.open_connection(server, port, limit=1024 * 128)
- self.reader = reader
- self.writer = writer
- async def stop(self):
- self.writer.close()
- await self.writer.wait_closed()
- async def _make_request(self, method, params):
- ident = random.randint(0, 2**16)
- #print(ident)
- request = {
- "jsonrpc": "2.0",
- "method": method,
- "params": params,
- "id": ident,
- }
- message = json.dumps(request) + "\n"
- self.writer.write(message.encode())
- await self.writer.drain()
- data = await self.reader.readline()
- message = data.decode().strip()
- response = json.loads(message)
- #print(response)
- return response
- async def _subscribe(self, method, params):
- ident = random.randint(0, 2**16)
- request = {
- "jsonrpc": "2.0",
- "method": method,
- "params": params,
- "id": ident,
- }
- message = json.dumps(request) + "\n"
- self.writer.write(message.encode())
- await self.writer.drain()
- #print("Subscribed")
- async def ping(self):
- return await self._make_request("ping", [])
- async def dnet_switch(self, state):
- return await self._make_request("dnet.switch", [state])
- async def dnet_subscribe_events(self):
- return await self._subscribe("dnet.subscribe_events", [])
-
- async def deg_switch(self, state):
- return await self._make_request("deg.switch", [state])
- class ListItem(u.WidgetWrap):
-
- def __init__ (self, event):
- self.content = event
- layer_num = int(event["layer"])
- layer = "layer " + str(layer_num) if layer_num != 0 else "genesis"
- t = u.AttrWrap(u.Text(layer), "event", "event_selected")
- u.WidgetWrap.__init__(self, t)
- def selectable (self):
- return True
-
- def keypress(self, size, key):
- return key
- class ListView(u.WidgetWrap):
- def __init__(self):
- u.register_signal(self.__class__, ['show_details'])
- self.walker = u.SimpleFocusListWalker([])
- lb = u.ListBox(self.walker)
- u.WidgetWrap.__init__(self, lb)
- def modified(self):
- focus_w, _ = self.walker.get_focus()
- u.emit_signal(self, 'show_details', focus_w.content)
- def set_data(self, events):
- events_widgets = [ListItem(e) for e in events]
- u.disconnect_signal(self.walker, 'modified', self.modified)
- while len(self.walker) > 0:
- self.walker.pop()
-
- self.walker.extend(events_widgets)
- u.connect_signal(self.walker, "modified", self.modified)
- self.walker.set_focus(0)
- class DetailView(u.WidgetWrap):
-
- def __init__ (self):
- t = u.Text("")
- u.WidgetWrap.__init__(self, t)
-
- def set_event(self, c):
- s = f'Hash: {c["hash"]}\nChildren: {c["children"]}\nContent: {c["content"]}\nLayer: {c["layer"]}'
- self._w.set_text(s)
- class App(object):
-
- def unhandled_input(self, key):
- if key in ('q',):
- raise u.ExitMainLoop()
- def show_details(self, event):
- self.detail_view.set_event(event)
-
- def __init__(self):
- self.palette = {
- ("bg", "white", "black"),
- ("event", "white", "black"),
- ("event_selected", "white", "yellow"),
- ("footer", "white, bold", "dark red")
- }
- self.list_view = ListView()
- self.detail_view = DetailView()
- u.connect_signal(self.list_view, 'show_details', self.show_details)
- footer = u.AttrWrap(u.Text(" Q to exit"), "footer")
- col_rows = u.raw_display.Screen().get_cols_rows()
- h = col_rows[0] - 2
- f1 = u.Filler(self.list_view, valign='top', height=h)
- f2 = u.Filler(self.detail_view, valign='top')
- c_list = u.LineBox(f1, title="Layers")
- c_details = u.LineBox(f2, title="Details")
- columns = u.Columns([('weight', 15, c_list), ('weight', 85, c_details)])
- frame = u.AttrMap(u.Frame(body=columns, footer=footer), 'bg')
- self.loop = u.MainLoop(frame, self.palette, unhandled_input=self.unhandled_input)
- async def update_data(self, config):
- host = config['host']
- port = config['port']
- rpc = JsonRpc()
- while True:
- try:
- await rpc.start(host, port)
- break
- except OSError:
- print("Error: Couldn't connent to rpc")
- exit(-1)
- await rpc.deg_switch(True)
- await rpc.deg_switch(False)
- json_result = await rpc._make_request("eventgraph.get_info", [])
-
- if json_result['result']['eventgraph_info']:
- dag_dict = json_result['result']['eventgraph_info']['dag']
- dag_list = list(dag_dict.items())
- # sorted_dag = sorted(dag_list, key=lambda x:x[1]['layer'])
- # genesis_hash = sorted_dag[0][0]
- parent_child_pairs = []
- for item in dag_list:
- parents = item[1]['parents']
- child = item[0]
- for parent in parents:
- if parent == '0' * 64:
- continue
- parent_child_pairs.append((parent, child))
-
- # Create a directed graph
- dag = nx.DiGraph()
- # Add edges to the graph (this also adds nodes)
- dag.add_edges_from(parent_child_pairs)
- l = []
- topological_order = list(nx.topological_sort(dag))
- for node in topological_order:
- event_details = dag_dict.get(node) # details
- layer = int(event_details['layer'])
- content = event_details['content'] # event content
- # print(content)
- pattern = r'\\x[0-9A-Fa-f]{2}'
- decoded_str = str(base58.b58decode(content))
- matches = re.split(pattern, decoded_str)
- children = dag.successors(node)
- l.append({"layer":f"{layer}", "hash":f"{node}", "children":f"{list(children)}", "content":f"{matches[1:]}"})
-
- self.list_view.set_data(l)
- async def start(self, config):
- await self.update_data(config)
- self.loop.run()
- async def main(argv):
- os = src.util.get_os()
- config_path = src.util.user_config_dir('darkfi', os)
- suffix = '.toml'
- filename = 'deg_config'
- path = join(config_path, filename + suffix)
- config = src.util.spawn_config(path)
- config = config['nodes'][0]
- if len(argv) > 1:
- if argv[1] in ['darkirc', 'irc']:
- config['port'] = 26660
- elif argv[1] in ['taud', 'tau']:
- config['port'] = 23330
- app = App()
- await app.start(config)
-
- asyncio.run(main(sys.argv))
|