mirror of
https://github.com/markqvist/NomadNet.git
synced 2025-12-17 23:04:24 +01:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6c16e810e5 | ||
|
|
6d4ac49264 | ||
|
|
939bc37f86 | ||
|
|
14eb35f7de | ||
|
|
19fb70fb3f | ||
|
|
9f9f10d54e | ||
|
|
863a6cd2cd | ||
|
|
2ec95df3ec | ||
|
|
313cc108de | ||
|
|
33ccab0907 | ||
|
|
71125252ee | ||
|
|
2ec674fbf3 |
@@ -49,6 +49,13 @@ The first time the program is running, you will be presented with the guide sect
|
|||||||
|
|
||||||
To use Nomad Network on packet radio or LoRa, you will need to configure your Reticulum installation to use any relevant packet radio TNCs or LoRa devices on your system. See the [Reticulum documentation](https://markqvist.github.io/Reticulum/manual/interfaces.html) for info.
|
To use Nomad Network on packet radio or LoRa, you will need to configure your Reticulum installation to use any relevant packet radio TNCs or LoRa devices on your system. See the [Reticulum documentation](https://markqvist.github.io/Reticulum/manual/interfaces.html) for info.
|
||||||
|
|
||||||
|
## Support Nomad Network
|
||||||
|
You can help support the continued development of open, free and private communications systems by donating via one of the following channels:
|
||||||
|
|
||||||
|
- Ethereum: 0x81F7B979fEa6134bA9FD5c701b3501A2e61E897a
|
||||||
|
- Bitcoin: 3CPmacGm34qYvR6XWLVEJmi2aNe3PZqUuq
|
||||||
|
- Ko-Fi: https://ko-fi.com/markqvist
|
||||||
|
|
||||||
## Caveat Emptor
|
## Caveat Emptor
|
||||||
Nomad Network is beta software, and should be considered as such. While it has been built with cryptography best-practices very foremost in mind, it _has not_ been externally security audited, and there could very well be privacy-breaking bugs. If you want to help out, or help sponsor an audit, please do get in touch.
|
Nomad Network is beta software, and should be considered as such. While it has been built with cryptography best-practices very foremost in mind, it _has not_ been externally security audited, and there could very well be privacy-breaking bugs. If you want to help out, or help sponsor an audit, please do get in touch.
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,10 @@ class Node:
|
|||||||
if self.app.node_announce_at_start:
|
if self.app.node_announce_at_start:
|
||||||
self.announce()
|
self.announce()
|
||||||
|
|
||||||
|
job_thread = threading.Thread(target=self.__jobs)
|
||||||
|
job_thread.setDaemon(True)
|
||||||
|
job_thread.start()
|
||||||
|
|
||||||
|
|
||||||
def register_pages(self):
|
def register_pages(self):
|
||||||
self.servedpages = []
|
self.servedpages = []
|
||||||
@@ -134,7 +138,7 @@ class Node:
|
|||||||
while self.should_run_jobs:
|
while self.should_run_jobs:
|
||||||
now = time.time()
|
now = time.time()
|
||||||
|
|
||||||
if now > self.last_announce + self.announce_interval:
|
if now > self.last_announce + self.announce_interval*60:
|
||||||
self.announce()
|
self.announce()
|
||||||
|
|
||||||
time.sleep(self.job_interval)
|
time.sleep(self.job_interval)
|
||||||
|
|||||||
@@ -218,6 +218,8 @@ class NomadNetworkApp:
|
|||||||
elif self.message_router.propagation_transfer_state == LXMF.LXMRouter.PR_LINK_ESTABLISHED:
|
elif self.message_router.propagation_transfer_state == LXMF.LXMRouter.PR_LINK_ESTABLISHED:
|
||||||
return "Link established"
|
return "Link established"
|
||||||
elif self.message_router.propagation_transfer_state == LXMF.LXMRouter.PR_REQUEST_SENT:
|
elif self.message_router.propagation_transfer_state == LXMF.LXMRouter.PR_REQUEST_SENT:
|
||||||
|
return "Sync request sent"
|
||||||
|
elif self.message_router.propagation_transfer_state == LXMF.LXMRouter.PR_RECEIVING:
|
||||||
return "Receiving messages"
|
return "Receiving messages"
|
||||||
elif self.message_router.propagation_transfer_state == LXMF.LXMRouter.PR_RESPONSE_RECEIVED:
|
elif self.message_router.propagation_transfer_state == LXMF.LXMRouter.PR_RESPONSE_RECEIVED:
|
||||||
return "Messages received"
|
return "Messages received"
|
||||||
@@ -241,6 +243,8 @@ class NomadNetworkApp:
|
|||||||
return True
|
return True
|
||||||
elif self.message_router.propagation_transfer_state == LXMF.LXMRouter.PR_REQUEST_SENT:
|
elif self.message_router.propagation_transfer_state == LXMF.LXMRouter.PR_REQUEST_SENT:
|
||||||
return True
|
return True
|
||||||
|
elif self.message_router.propagation_transfer_state == LXMF.LXMRouter.PR_RECEIVING:
|
||||||
|
return True
|
||||||
elif self.message_router.propagation_transfer_state == LXMF.LXMRouter.PR_RESPONSE_RECEIVED:
|
elif self.message_router.propagation_transfer_state == LXMF.LXMRouter.PR_RESPONSE_RECEIVED:
|
||||||
return True
|
return True
|
||||||
elif self.message_router.propagation_transfer_state == LXMF.LXMRouter.PR_COMPLETE:
|
elif self.message_router.propagation_transfer_state == LXMF.LXMRouter.PR_COMPLETE:
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
__version__ = "0.1.2"
|
__version__ = "0.1.4"
|
||||||
@@ -20,7 +20,7 @@ class ConversationDisplayShortcuts():
|
|||||||
def __init__(self, app):
|
def __init__(self, app):
|
||||||
self.app = app
|
self.app = app
|
||||||
|
|
||||||
self.widget = urwid.AttrMap(urwid.Text("[C-d] Send [C-k] Clear Editor [C-w] Close [C-t] Editor Type [C-p] Purge [C-x] Clear History [C-o] Sort"), "shortcutbar")
|
self.widget = urwid.AttrMap(urwid.Text("[C-d] Send [C-k] Clear [C-w] Close [C-t] Title [C-p] Purge [C-x] Clear History [C-o] Sort"), "shortcutbar")
|
||||||
|
|
||||||
class ConversationsArea(urwid.LineBox):
|
class ConversationsArea(urwid.LineBox):
|
||||||
def keypress(self, size, key):
|
def keypress(self, size, key):
|
||||||
@@ -352,6 +352,7 @@ class ConversationsDisplay():
|
|||||||
|
|
||||||
def cancel_sync(sender):
|
def cancel_sync(sender):
|
||||||
self.app.cancel_lxmf_sync()
|
self.app.cancel_lxmf_sync()
|
||||||
|
self.update_sync_dialog()
|
||||||
|
|
||||||
cancel_button = urwid.Button("Close", on_press=dismiss_dialog)
|
cancel_button = urwid.Button("Close", on_press=dismiss_dialog)
|
||||||
sync_progress = SyncProgressBar("progress_empty" , "progress_full", current=self.app.get_sync_progress(), done=1.0, satt=None)
|
sync_progress = SyncProgressBar("progress_empty" , "progress_full", current=self.app.get_sync_progress(), done=1.0, satt=None)
|
||||||
|
|||||||
@@ -129,11 +129,12 @@ class MainDisplay():
|
|||||||
def update_active_shortcuts(self):
|
def update_active_shortcuts(self):
|
||||||
self.frame.contents["footer"] = (self.sub_displays.active().shortcuts().widget, None)
|
self.frame.contents["footer"] = (self.sub_displays.active().shortcuts().widget, None)
|
||||||
|
|
||||||
def request_redraw(self):
|
def request_redraw(self, extra_delay=0.0):
|
||||||
self.app.ui.loop.set_alarm_in(0.25, self.redraw_now)
|
self.app.ui.loop.set_alarm_in(0.25+extra_delay, self.redraw_now)
|
||||||
|
|
||||||
def redraw_now(self, sender=None, data=None):
|
def redraw_now(self, sender=None, data=None):
|
||||||
self.app.ui.loop.draw_screen()
|
self.app.ui.loop.screen.clear()
|
||||||
|
#self.app.ui.loop.draw_screen()
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
self.menu_display.start()
|
self.menu_display.start()
|
||||||
|
|||||||
@@ -107,6 +107,7 @@ class AnnounceInfo(urwid.WidgetWrap):
|
|||||||
self.parent.left_pile.contents[0] = (self.parent.announce_stream_display, options)
|
self.parent.left_pile.contents[0] = (self.parent.announce_stream_display, options)
|
||||||
|
|
||||||
def connect(sender):
|
def connect(sender):
|
||||||
|
self.app.ui.main_display.request_redraw(extra_delay=0.75)
|
||||||
self.parent.browser.retrieve_url(RNS.hexrep(source_hash, delimit=False))
|
self.parent.browser.retrieve_url(RNS.hexrep(source_hash, delimit=False))
|
||||||
show_announce_stream(None)
|
show_announce_stream(None)
|
||||||
|
|
||||||
@@ -433,6 +434,7 @@ class KnownNodeInfo(urwid.WidgetWrap):
|
|||||||
self.parent.left_pile.contents[0] = (self.parent.known_nodes_display, options)
|
self.parent.left_pile.contents[0] = (self.parent.known_nodes_display, options)
|
||||||
|
|
||||||
def connect(sender):
|
def connect(sender):
|
||||||
|
self.app.ui.main_display.request_redraw(extra_delay=0.75)
|
||||||
self.parent.browser.retrieve_url(RNS.hexrep(source_hash, delimit=False))
|
self.parent.browser.retrieve_url(RNS.hexrep(source_hash, delimit=False))
|
||||||
show_known_nodes(None)
|
show_known_nodes(None)
|
||||||
|
|
||||||
@@ -576,7 +578,9 @@ class KnownNodes(urwid.WidgetWrap):
|
|||||||
self.delegate.left_pile.contents[0] = (overlay, options)
|
self.delegate.left_pile.contents[0] = (overlay, options)
|
||||||
|
|
||||||
def delete_selected_entry(self):
|
def delete_selected_entry(self):
|
||||||
source_hash = self.ilb.get_selected_item().original_widget.source_hash
|
si = self.ilb.get_selected_item()
|
||||||
|
if si != None:
|
||||||
|
source_hash = si.original_widget.source_hash
|
||||||
|
|
||||||
def dismiss_dialog(sender):
|
def dismiss_dialog(sender):
|
||||||
self.delegate.close_list_dialogs()
|
self.delegate.close_list_dialogs()
|
||||||
@@ -1022,6 +1026,9 @@ class NetworkLeftPile(urwid.Pile):
|
|||||||
def keypress(self, size, key):
|
def keypress(self, size, key):
|
||||||
if key == "ctrl l":
|
if key == "ctrl l":
|
||||||
self.parent.toggle_list()
|
self.parent.toggle_list()
|
||||||
|
elif key == "ctrl p":
|
||||||
|
self.parent.reinit_lxmf_peers()
|
||||||
|
self.parent.show_peers()
|
||||||
elif key == "ctrl w":
|
elif key == "ctrl w":
|
||||||
self.parent.browser.disconnect()
|
self.parent.browser.disconnect()
|
||||||
elif key == "ctrl u":
|
elif key == "ctrl u":
|
||||||
@@ -1043,6 +1050,7 @@ class NetworkDisplay():
|
|||||||
self.browser.loopback = self.app.node.destination.hash
|
self.browser.loopback = self.app.node.destination.hash
|
||||||
|
|
||||||
self.known_nodes_display = KnownNodes(self.app)
|
self.known_nodes_display = KnownNodes(self.app)
|
||||||
|
self.lxmf_peers_display = LXMFPeers(self.app)
|
||||||
self.network_stats_display = NetworkStats(self.app, self)
|
self.network_stats_display = NetworkStats(self.app, self)
|
||||||
self.announce_stream_display = AnnounceStream(self.app, self)
|
self.announce_stream_display = AnnounceStream(self.app, self)
|
||||||
self.local_peer_display = LocalPeer(self.app, self)
|
self.local_peer_display = LocalPeer(self.app, self)
|
||||||
@@ -1084,6 +1092,15 @@ class NetworkDisplay():
|
|||||||
self.left_pile.contents[0] = (self.known_nodes_display, options)
|
self.left_pile.contents[0] = (self.known_nodes_display, options)
|
||||||
self.list_display = 1
|
self.list_display = 1
|
||||||
|
|
||||||
|
def show_peers(self):
|
||||||
|
options = self.left_pile.options(height_type="weight", height_amount=1)
|
||||||
|
self.left_pile.contents[0] = (self.lxmf_peers_display, options)
|
||||||
|
|
||||||
|
if self.list_display != 0:
|
||||||
|
self.list_display = 0
|
||||||
|
else:
|
||||||
|
self.list_display = 1
|
||||||
|
|
||||||
def focus_lists(self):
|
def focus_lists(self):
|
||||||
self.columns.focus_position = 0
|
self.columns.focus_position = 0
|
||||||
|
|
||||||
@@ -1093,6 +1110,11 @@ class NetworkDisplay():
|
|||||||
self.close_list_dialogs()
|
self.close_list_dialogs()
|
||||||
self.announce_stream_display.rebuild_widget_list()
|
self.announce_stream_display.rebuild_widget_list()
|
||||||
|
|
||||||
|
def reinit_lxmf_peers(self):
|
||||||
|
self.lxmf_peers_display = LXMFPeers(self.app)
|
||||||
|
self.lxmf_peers_display.delegate = self
|
||||||
|
self.close_list_dialogs()
|
||||||
|
|
||||||
def close_list_dialogs(self):
|
def close_list_dialogs(self):
|
||||||
if self.list_display == 0:
|
if self.list_display == 0:
|
||||||
options = self.left_pile.options(height_type="weight", height_amount=1)
|
options = self.left_pile.options(height_type="weight", height_amount=1)
|
||||||
@@ -1121,6 +1143,97 @@ class NetworkDisplay():
|
|||||||
self.known_nodes_display.rebuild_widget_list()
|
self.known_nodes_display.rebuild_widget_list()
|
||||||
|
|
||||||
|
|
||||||
|
class LXMFPeers(urwid.WidgetWrap):
|
||||||
|
def __init__(self, app):
|
||||||
|
self.app = app
|
||||||
|
self.peer_list = app.message_router.peers
|
||||||
|
# self.peer_list = {}
|
||||||
|
|
||||||
|
g = self.app.ui.glyphs
|
||||||
|
|
||||||
|
self.widget_list = self.make_peer_widgets()
|
||||||
|
|
||||||
|
self.ilb = IndicativeListBox(
|
||||||
|
self.widget_list,
|
||||||
|
on_selection_change=self.node_list_selection,
|
||||||
|
initialization_is_selection_change=False,
|
||||||
|
highlight_offFocus="list_off_focus"
|
||||||
|
)
|
||||||
|
|
||||||
|
if len(self.peer_list) > 0:
|
||||||
|
self.display_widget = self.ilb
|
||||||
|
widget_style = None
|
||||||
|
self.no_content = False
|
||||||
|
else:
|
||||||
|
self.no_content = True
|
||||||
|
widget_style = "inactive_text"
|
||||||
|
self.pile = urwid.Pile([urwid.Text(("warning_text", g["info"]+"\n"), align="center"), SelectText(("warning_text", "Currently, no LXMF nodes are peered\n\n"), align="center")])
|
||||||
|
self.display_widget = urwid.Filler(self.pile, valign="top", height="pack")
|
||||||
|
|
||||||
|
urwid.WidgetWrap.__init__(self, urwid.AttrMap(urwid.LineBox(self.display_widget, title="LXMF Peers"), widget_style))
|
||||||
|
|
||||||
|
def keypress(self, size, key):
|
||||||
|
if key == "up" and (self.no_content or self.ilb.first_item_is_selected()):
|
||||||
|
nomadnet.NomadNetworkApp.get_shared_instance().ui.main_display.frame.set_focus("header")
|
||||||
|
elif key == "ctrl x":
|
||||||
|
self.delete_selected_entry()
|
||||||
|
|
||||||
|
return super(LXMFPeers, self).keypress(size, key)
|
||||||
|
|
||||||
|
|
||||||
|
def node_list_selection(self, arg1, arg2):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def delete_selected_entry(self):
|
||||||
|
si = self.ilb.get_selected_item()
|
||||||
|
if si != None:
|
||||||
|
destination_hash = si.original_widget.destination_hash
|
||||||
|
self.app.message_router.unpeer(destination_hash)
|
||||||
|
self.delegate.reinit_lxmf_peers()
|
||||||
|
self.delegate.show_peers()
|
||||||
|
|
||||||
|
|
||||||
|
def rebuild_widget_list(self):
|
||||||
|
self.peer_list = self.app.message_router.peers
|
||||||
|
self.widget_list = self.make_peer_widgets()
|
||||||
|
self.ilb.set_body(self.widget_list)
|
||||||
|
if len(self.widget_list) > 0:
|
||||||
|
self.no_content = False
|
||||||
|
else:
|
||||||
|
self.no_content = True
|
||||||
|
self.delegate.reinit_lxmf_peers()
|
||||||
|
|
||||||
|
def make_peer_widgets(self):
|
||||||
|
widget_list = []
|
||||||
|
for peer_id in self.peer_list:
|
||||||
|
peer = self.peer_list[peer_id]
|
||||||
|
pe = LXMFPeerEntry(self.app, peer, self)
|
||||||
|
pe.destination_hash = peer.destination_hash
|
||||||
|
widget_list.append(pe)
|
||||||
|
|
||||||
|
# TODO: Sort list
|
||||||
|
return widget_list
|
||||||
|
|
||||||
|
class LXMFPeerEntry(urwid.WidgetWrap):
|
||||||
|
def __init__(self, app, peer, delegate):
|
||||||
|
destination_hash = peer.destination_hash
|
||||||
|
|
||||||
|
self.app = app
|
||||||
|
g = self.app.ui.glyphs
|
||||||
|
|
||||||
|
display_str = RNS.prettyhexrep(destination_hash)
|
||||||
|
|
||||||
|
sym = g["sent"]
|
||||||
|
style = "list_unknown"
|
||||||
|
focus_style = "list_focus"
|
||||||
|
|
||||||
|
widget = ListEntry(sym+" "+display_str+"\n Last heard "+pretty_date(int(peer.last_heard))+"\n "+str(len(peer.unhandled_messages))+" unhandled")
|
||||||
|
# urwid.connect_signal(widget, "click", delegate.connect_node, node)
|
||||||
|
|
||||||
|
self.display_widget = urwid.AttrMap(widget, style, focus_style)
|
||||||
|
self.display_widget.destination_hash = destination_hash
|
||||||
|
urwid.WidgetWrap.__init__(self, self.display_widget)
|
||||||
|
|
||||||
|
|
||||||
def pretty_date(time=False):
|
def pretty_date(time=False):
|
||||||
"""
|
"""
|
||||||
|
|||||||
2
setup.py
2
setup.py
@@ -23,6 +23,6 @@ setuptools.setup(
|
|||||||
entry_points= {
|
entry_points= {
|
||||||
'console_scripts': ['nomadnet=nomadnet.nomadnet:main']
|
'console_scripts': ['nomadnet=nomadnet.nomadnet:main']
|
||||||
},
|
},
|
||||||
install_requires=['rns>=0.2.7', 'lxmf>=0.1.0', 'urwid>=2.1.2'],
|
install_requires=['rns>=0.2.9', 'lxmf>=0.1.2', 'urwid>=2.1.2'],
|
||||||
python_requires='>=3.6',
|
python_requires='>=3.6',
|
||||||
)
|
)
|
||||||
Reference in New Issue
Block a user