Compare commits

...

43 Commits

Author SHA1 Message Date
Mark Qvist
aa4feeb29c Updated version
Some checks failed
Create and publish a Docker image / build-and-push-image (push) Has been cancelled
2025-04-15 20:24:48 +02:00
Mark Qvist
ad985a2552 Updated dependencies 2025-04-15 20:23:24 +02:00
Mark Qvist
42fdc30cf8 Cleanup configobj
Some checks failed
Create and publish a Docker image / build-and-push-image (push) Has been cancelled
2025-04-08 02:05:02 +02:00
Mark Qvist
e79689010e Fixed directory sorting bug 2025-04-08 02:03:34 +02:00
Mark Qvist
e4f57d6260 Updated dependencies 2025-03-31 15:03:44 +02:00
Mark Qvist
03d1b22b8f Updated dependencies
Some checks failed
Create and publish a Docker image / build-and-push-image (push) Has been cancelled
2025-02-18 21:20:50 +01:00
Mark Qvist
f8775adbab Increased announce stream length 2025-02-18 20:27:33 +01:00
markqvist
c0dac0eadb
Merge pull request #68 from byte-diver/network_tabs
Add network tabs
2025-02-18 20:10:40 +01:00
byte-diver
c198d516da cleaning and sort 2025-02-07 00:23:43 +01:00
byte-diver
d9886980fa fix docker, add tabs 2025-02-07 00:10:44 +01:00
Mark Qvist
7ced4c3659 Fixed missing attribute check
Some checks failed
Create and publish a Docker image / build-and-push-image (push) Has been cancelled
2025-01-29 14:45:19 +01:00
Mark Qvist
c3c8f99131 Updated logging
Some checks are pending
Create and publish a Docker image / build-and-push-image (push) Waiting to run
2025-01-29 01:41:25 +01:00
Mark Qvist
9f00ffbae6 Updated version 2025-01-29 01:25:33 +01:00
Mark Qvist
a26edd21db Added acceptance rate to PN peer stats 2025-01-29 01:24:29 +01:00
Mark Qvist
46f3a4127c Updated dependencies 2025-01-29 01:24:08 +01:00
Mark Qvist
eeb15dcb43 Use lock on announce stream updates 2025-01-28 23:04:22 +01:00
Mark Qvist
9ef34fc774 Maintain PN list position 2025-01-28 22:45:32 +01:00
Mark Qvist
704a4ea828 Updated issue template
Some checks failed
Create and publish a Docker image / build-and-push-image (push) Has been cancelled
2025-01-27 10:26:55 +01:00
Mark Qvist
5f31aeb3c1 Fixed missing none check 2025-01-27 10:26:39 +01:00
Mark Qvist
f000073594 Updated versions
Some checks failed
Create and publish a Docker image / build-and-push-image (push) Has been cancelled
2025-01-22 12:06:05 +01:00
Mark Qvist
e332be6211 Added ability configure max_peers and static_peers 2025-01-22 12:05:08 +01:00
Mark Qvist
9ee052a122 Sort PNs according to STR 2025-01-22 12:04:34 +01:00
Mark Qvist
11fda51017 Updated guide 2025-01-22 12:03:49 +01:00
Mark Qvist
d5cf34f9d9 Get PN message counts faster
Some checks are pending
Create and publish a Docker image / build-and-push-image (push) Waiting to run
2025-01-21 17:01:06 +01:00
Mark Qvist
d13c8af88e Updated dependencies
Some checks failed
Create and publish a Docker image / build-and-push-image (push) Has been cancelled
2025-01-19 21:47:22 +01:00
Mark Qvist
7cd025e236 Updated dependencies
Some checks are pending
Create and publish a Docker image / build-and-push-image (push) Waiting to run
2025-01-18 17:20:29 +01:00
Mark Qvist
c48a8d2a09 Updated version
Some checks failed
Create and publish a Docker image / build-and-push-image (push) Has been cancelled
2025-01-13 15:25:12 +01:00
Mark Qvist
4fb97eecc5 Updated dependencies 2025-01-13 15:24:23 +01:00
Mark Qvist
74e7e4e806 Updated default config 2025-01-13 15:22:13 +01:00
Mark Qvist
01a5c21016 Revert NF glyphs 2025-01-13 15:17:03 +01:00
Mark Qvist
5e8a14d7a6 Merge branch 'master' of github.com:markqvist/NomadNet 2025-01-13 15:10:06 +01:00
markqvist
6edf531fbf
Merge pull request #64 from kc1awv/patch-1
Update TextUI.py
2025-01-13 15:09:53 +01:00
Mark Qvist
eb3ff558c0 Use built-in platform check 2025-01-13 15:09:39 +01:00
markqvist
b5bf730e07
Merge pull request #65 from liamcottle/master
Fix serving NomadNet pages from Windows
2025-01-13 15:06:33 +01:00
markqvist
c52c49371b
Merge pull request #66 from penguinolog/urwid_deprecations
Handle urwid API deprecations
2025-01-13 15:04:46 +01:00
Mark Qvist
46eee79da2 Added sync transfer rate to PN list display 2025-01-13 14:40:45 +01:00
Mark Qvist
bd909c9f58 Updated version 2025-01-13 14:40:31 +01:00
Aleksei Stepanov
c95fd83400 Handle urwid API deprecations
* `_get_base_widget` method is going to be removed
2025-01-01 13:37:16 +01:00
liamcottle
7d18a103cf don't try to execute nomadnet pages when running on windows 2024-12-20 23:03:31 +13:00
Steve Miller
00855c32a7
Update TextUI.py
Replace some missing or deprecated NF icons with new / updated icons.
2024-12-17 09:07:14 -05:00
Mark Qvist
d8cfc69ac6 Updated dependencies
Some checks failed
Create and publish a Docker image / build-and-push-image (push) Has been cancelled
2024-12-12 08:54:59 +01:00
Mark Qvist
ccc41a5789 Updated version 2024-12-12 08:54:05 +01:00
Mark Qvist
7b38d4f80e Fix multiline prop 2024-12-12 08:53:20 +01:00
11 changed files with 235 additions and 2614 deletions

View File

@ -12,7 +12,7 @@ Before creating a bug report on this issue tracker, you **must** read the [Contr
- The issue tracker is used by developers of this project. **Do not use it to ask general questions, or for support requests**.
- Ideas and feature requests can be made on the [Discussions](https://github.com/markqvist/Reticulum/discussions). **Only** feature requests accepted by maintainers and developers are tracked and included on the issue tracker. **Do not post feature requests here**.
- After reading the [Contribution Guidelines](https://github.com/markqvist/Reticulum/blob/master/Contributing.md), delete this section from your bug report.
- After reading the [Contribution Guidelines](https://github.com/markqvist/Reticulum/blob/master/Contributing.md), **delete this section only** (*"Read the Contribution Guidelines"*) from your bug report, **and fill in all the other sections**.
**Describe the Bug**
A clear and concise description of what the bug is.

View File

@ -16,10 +16,6 @@ ENV PATH="/home/myuser/.local/bin:${PATH}"
################### BEGIN NomadNet ###########################################
COPY --chown=myuser:myuser requirements.txt requirements.txt
RUN pip install --user -r requirements.txt
COPY --chown=myuser:myuser . .

View File

@ -3,6 +3,7 @@ import RNS
import LXMF
import time
import nomadnet
import threading
import RNS.vendor.umsgpack as msgpack
class PNAnnounceHandler:
@ -29,7 +30,7 @@ class PNAnnounceHandler:
RNS.log("The contained exception was: "+str(e), RNS.LOG_DEBUG)
class Directory:
ANNOUNCE_STREAM_MAXLENGTH = 64
ANNOUNCE_STREAM_MAXLENGTH = 256
aspect_filter = "nomadnetwork.node"
@staticmethod
@ -55,6 +56,7 @@ class Directory:
self.directory_entries = {}
self.announce_stream = []
self.app = app
self.announce_lock = threading.Lock()
self.load_from_disk()
self.pn_announce_handler = PNAnnounceHandler(self)
@ -124,90 +126,94 @@ class Directory:
RNS.log("Could not load directory from disk. The contained exception was: "+str(e), RNS.LOG_ERROR)
def lxmf_announce_received(self, source_hash, app_data):
if app_data != None:
if self.app.compact_stream:
try:
remove_announces = []
for announce in self.announce_stream:
if announce[1] == source_hash:
remove_announces.append(announce)
with self.announce_lock:
if app_data != None:
if self.app.compact_stream:
try:
remove_announces = []
for announce in self.announce_stream:
if announce[1] == source_hash:
remove_announces.append(announce)
for a in remove_announces:
self.announce_stream.remove(a)
except Exception as e:
RNS.log("An error occurred while compacting the announce stream. The contained exception was:"+str(e), RNS.LOG_ERROR)
for a in remove_announces:
self.announce_stream.remove(a)
except Exception as e:
RNS.log("An error occurred while compacting the announce stream. The contained exception was:"+str(e), RNS.LOG_ERROR)
timestamp = time.time()
self.announce_stream.insert(0, (timestamp, source_hash, app_data, "peer"))
while len(self.announce_stream) > Directory.ANNOUNCE_STREAM_MAXLENGTH:
self.announce_stream.pop()
timestamp = time.time()
self.announce_stream.insert(0, (timestamp, source_hash, app_data, "peer"))
while len(self.announce_stream) > Directory.ANNOUNCE_STREAM_MAXLENGTH:
self.announce_stream.pop()
if hasattr(self.app.ui, "main_display"):
self.app.ui.main_display.sub_displays.network_display.directory_change_callback()
if hasattr(self.app, "ui") and self.app.ui != None:
if hasattr(self.app.ui, "main_display"):
self.app.ui.main_display.sub_displays.network_display.directory_change_callback()
def node_announce_received(self, source_hash, app_data, associated_peer):
if app_data != None:
if self.app.compact_stream:
try:
remove_announces = []
for announce in self.announce_stream:
if announce[1] == source_hash:
remove_announces.append(announce)
with self.announce_lock:
if app_data != None:
if self.app.compact_stream:
try:
remove_announces = []
for announce in self.announce_stream:
if announce[1] == source_hash:
remove_announces.append(announce)
for a in remove_announces:
self.announce_stream.remove(a)
for a in remove_announces:
self.announce_stream.remove(a)
except Exception as e:
RNS.log("An error occurred while compacting the announce stream. The contained exception was:"+str(e), RNS.LOG_ERROR)
timestamp = time.time()
self.announce_stream.insert(0, (timestamp, source_hash, app_data, "node"))
while len(self.announce_stream) > Directory.ANNOUNCE_STREAM_MAXLENGTH:
self.announce_stream.pop()
if self.trust_level(associated_peer) == DirectoryEntry.TRUSTED:
existing_entry = self.find(source_hash)
if not existing_entry:
node_entry = DirectoryEntry(source_hash, display_name=app_data.decode("utf-8"), trust_level=DirectoryEntry.TRUSTED, hosts_node=True)
self.remember(node_entry)
except Exception as e:
RNS.log("An error occurred while compacting the announce stream. The contained exception was:"+str(e), RNS.LOG_ERROR)
timestamp = time.time()
self.announce_stream.insert(0, (timestamp, source_hash, app_data, "node"))
while len(self.announce_stream) > Directory.ANNOUNCE_STREAM_MAXLENGTH:
self.announce_stream.pop()
if self.trust_level(associated_peer) == DirectoryEntry.TRUSTED:
existing_entry = self.find(source_hash)
if not existing_entry:
node_entry = DirectoryEntry(source_hash, display_name=app_data.decode("utf-8"), trust_level=DirectoryEntry.TRUSTED, hosts_node=True)
self.remember(node_entry)
if hasattr(self.app.ui, "main_display"):
self.app.ui.main_display.sub_displays.network_display.directory_change_callback()
if hasattr(self.app.ui, "main_display"):
self.app.ui.main_display.sub_displays.network_display.directory_change_callback()
def pn_announce_received(self, source_hash, app_data, associated_peer, associated_node):
found_node = None
for sh in self.directory_entries:
if sh == associated_node:
found_node = True
break
with self.announce_lock:
found_node = None
for sh in self.directory_entries:
if sh == associated_node:
found_node = True
break
for e in self.announce_stream:
if e[1] == associated_node:
found_node = True
break
for e in self.announce_stream:
if e[1] == associated_node:
found_node = True
break
if not found_node:
if self.app.compact_stream:
try:
remove_announces = []
for announce in self.announce_stream:
if announce[1] == source_hash:
remove_announces.append(announce)
if not found_node:
if self.app.compact_stream:
try:
remove_announces = []
for announce in self.announce_stream:
if announce[1] == source_hash:
remove_announces.append(announce)
for a in remove_announces:
self.announce_stream.remove(a)
for a in remove_announces:
self.announce_stream.remove(a)
except Exception as e:
RNS.log("An error occurred while compacting the announce stream. The contained exception was:"+str(e), RNS.LOG_ERROR)
timestamp = time.time()
self.announce_stream.insert(0, (timestamp, source_hash, app_data, "pn"))
while len(self.announce_stream) > Directory.ANNOUNCE_STREAM_MAXLENGTH:
self.announce_stream.pop()
except Exception as e:
RNS.log("An error occurred while compacting the announce stream. The contained exception was:"+str(e), RNS.LOG_ERROR)
timestamp = time.time()
self.announce_stream.insert(0, (timestamp, source_hash, app_data, "pn"))
while len(self.announce_stream) > Directory.ANNOUNCE_STREAM_MAXLENGTH:
self.announce_stream.pop()
if hasattr(self.app.ui, "main_display"):
self.app.ui.main_display.sub_displays.network_display.directory_change_callback()
if hasattr(self.app, "ui") and hasattr(self.app.ui, "main_display"):
self.app.ui.main_display.sub_displays.network_display.directory_change_callback()
def remove_announce_with_timestamp(self, timestamp):
selected_announce = None
@ -339,7 +345,7 @@ class Directory:
if e.hosts_node:
node_list.append(e)
node_list.sort(key = lambda e: (e.sort_rank if e.sort_rank != None else 2^32, DirectoryEntry.TRUSTED-e.trust_level, e.display_name))
node_list.sort(key = lambda e: (e.sort_rank if e.sort_rank != None else 2^32, DirectoryEntry.TRUSTED-e.trust_level, e.display_name if e.display_name != None else "_"))
return node_list
def number_of_known_nodes(self):

View File

@ -1,4 +1,6 @@
import os
import sys
import RNS
import time
import threading
@ -159,7 +161,7 @@ class Node:
try:
if request_allowed:
RNS.log("Serving page: "+file_path, RNS.LOG_VERBOSE)
if os.access(file_path, os.X_OK):
if not RNS.vendor.platformutils.is_windows() and os.access(file_path, os.X_OK):
env_map = {}
if "PATH" in os.environ:
env_map["PATH"] = os.environ["PATH"]

View File

@ -19,7 +19,7 @@ from datetime import datetime
import RNS.vendor.umsgpack as msgpack
from ._version import __version__
from .vendor.configobj import ConfigObj
from RNS.vendor.configobj import ConfigObj
class NomadNetworkApp:
time_format = "%Y-%m-%d %H:%M:%S"
@ -290,9 +290,20 @@ class NomadNetworkApp:
self.directory = nomadnet.Directory(self)
static_peers = []
for static_peer in self.static_peers:
try:
dh = bytes.fromhex(static_peer)
if len(dh) != RNS.Reticulum.TRUNCATED_HASHLENGTH//8:
raise ValueError("Invalid destination length")
static_peers.append(dh)
except Exception as e:
RNS.log(f"Could not decode static peer destination hash {static_peer}: {e}", RNS.LOG_ERROR)
self.message_router = LXMF.LXMRouter(
identity = self.identity, storagepath = self.storagepath, autopeer = True,
propagation_limit = self.lxmf_max_propagation_size, delivery_limit = self.lxmf_max_incoming_size,
max_peers = self.max_peers, static_peers = static_peers,
)
self.message_router.register_delivery_callback(self.lxmf_delivery)
@ -526,7 +537,7 @@ class NomadNetworkApp:
RNS.log("Could not autoselect a propagation node! LXMF propagation will not be available until a trusted node announces on the network, or a propagation node is manually selected.", RNS.LOG_WARNING)
else:
pn_name_str = ""
RNS.log("Selecting "+RNS.prettyhexrep(selected_node)+pn_name_str+" as default LXMF propagation node", RNS.LOG_INFO)
RNS.log("Selecting "+RNS.prettyhexrep(selected_node)+pn_name_str+" as default LXMF propagation node", RNS.LOG_DEBUG)
self.message_router.set_outbound_propagation_node(selected_node)
def get_user_selected_propagation_node(self):
@ -920,6 +931,19 @@ class NomadNetworkApp:
else:
self.prioritised_lxmf_destinations = []
if "static_peers" in self.config["node"]:
self.static_peers = self.config["node"].as_list("static_peers")
else:
self.static_peers = []
if not "max_peers" in self.config["node"]:
self.max_peers = None
else:
value = self.config["node"].as_int("max_peers")
if value < 0:
value = 0
self.max_peers = value
if not "message_storage_limit" in self.config["node"]:
self.message_storage_limit = 2000
else:
@ -1136,13 +1160,15 @@ announce_interval = 360
# Whether to announce when the node starts.
announce_at_start = Yes
# By default, when Nomad Network is hosting a
# node, it will also act as an LXMF propagation
# When Nomad Network is hosting a page-serving
# node, it can also act as an LXMF propagation
# node. If there is already a large amount of
# propagation nodes on the network, or you
# simply want to run a pageserving-only node,
# you can disable running a propagation node.
# disable_propagation = False
# Due to lots of propagation nodes being
# available, this is currently the default.
disable_propagation = Yes
# The maximum amount of storage to use for
# the LXMF Propagation Node message store,
@ -1176,9 +1202,16 @@ max_transfer_size = 256
# and generally you do not need to use it.
# prioritise_destinations = 41d20c727598a3fbbdf9106133a3a0ed, d924b81822ca24e68e2effea99bcb8cf
# Automatic rescan interval of the pages directory in minutes.
# Default: int = 0 (no rescan)
page_refresh_interval = 0
# You can configure the maximum number of other
# propagation nodes that this node will peer
# with automatically. The default is 50.
# max_peers = 25
# You can configure a list of static propagation
# node peers, that this node will always be
# peered with, by specifying a list of
# destination hashes.
# static_peers = e17f833c4ddf8890dd3a79a6fea8161d, 5a2d0029b6e5ec87020abaea0d746da4
# You can specify the interval in minutes for
# rescanning the hosted pages path. By default,

View File

@ -1 +1 @@
__version__ = "0.5.5"
__version__ = "0.6.2"

View File

@ -666,9 +666,9 @@ Determines the interval in minutes for rescanning the hosted files path. By defa
<
>>>
`!disable_propagation = no`!
`!disable_propagation = yes`!
>>>>
By default, when Nomad Network is hosting a node, it will also run an LXMF propagation node. If there is already a large amount of propagation nodes on the network, or you simply want to run a pageserving-only node, you can disable running a propagation node.
When Nomad Network is hosting a node, it can also run an LXMF propagation node. If there is already a large amount of propagation nodes on the network, or you simply want to run a pageserving-only node, you can disable running a propagation node.
<
>>>
@ -689,6 +689,18 @@ The maximum accepted transfer size per incoming propagation transfer, in kilobyt
Configures the LXMF Propagation Node to prioritise storing messages for certain destinations. If the message store reaches the specified limit, LXMF will prioritise keeping messages for destinations specified with this option. This setting is optional, and generally you do not need to use it.
<
>>>
`!max_peers = 25`!
>>>>
Configures the maximum number of other nodes the LXMF Propagation Node will automatically peer with. The default is 50, but can be lowered or increased according to available resources.
<
>>>
`!static_peers = e17f833c4ddf8890dd3a79a6fea8161d, 5a2d0029b6e5ec87020abaea0d746da4`!
>>>>
Configures the LXMF Propagation Node to always maintain propagation node peering with the specified list of destination hashes.
<
>> Printing Section
This section holds configuration directives related to printing. It is delimited by the `![printing]`! header in the configuration file. Available directives, along with example values, are as follows:

View File

@ -168,7 +168,7 @@ def parse_line(line, state, url_delegate):
fn = o["name"]
fs = o["style"]
fmask = "*" if o["masked"] else None
f = urwid.Edit(caption="", edit_text=fd, align=state["align"], multiline=False, mask=fmask)
f = urwid.Edit(caption="", edit_text=fd, align=state["align"], multiline=True, mask=fmask)
f.field_name = fn
fa = urwid.AttrMap(f, fs)
widgets.append((fw, fa))

View File

@ -141,7 +141,7 @@ class AnnounceInfo(urwid.WidgetWrap):
if is_node:
try:
existing_conversations = nomadnet.Conversation.conversation_list(self.app)
source_hash_text = RNS.hexrep(op_hash, delimit=False)
display_name = op_str
@ -162,7 +162,7 @@ class AnnounceInfo(urwid.WidgetWrap):
show_announce_stream(None)
try:
existing_conversations = nomadnet.Conversation.conversation_list(self.app)
source_hash_text = RNS.hexrep(source_hash, delimit=False)
display_name = data_str
@ -316,7 +316,7 @@ class AnnounceStreamEntry(urwid.WidgetWrap):
info_widget = AnnounceInfo(announce, parent, self.app)
options = parent.left_pile.options(height_type=urwid.WEIGHT, height_amount=1)
parent.left_pile.contents[0] = (info_widget, options)
except KeyError as e:
def dismiss_dialog(sender):
self.delegate.parent.close_list_dialogs()
@ -368,6 +368,10 @@ class AnnounceStreamEntry(urwid.WidgetWrap):
def timestamp(self):
return self.timestamp
class TabButton(urwid.Button):
button_left = urwid.Text("[")
button_right = urwid.Text("]")
class AnnounceStream(urwid.WidgetWrap):
def __init__(self, app, parent):
self.app = app
@ -376,11 +380,24 @@ class AnnounceStream(urwid.WidgetWrap):
self.timeout = self.app.config["textui"]["animation_interval"]*2
self.ilb = None
self.no_content = True
self.current_tab = "nodes"
self.added_entries = []
self.widget_list = []
self.update_widget_list()
# Create tab buttons
self.tab_nodes = TabButton("Nodes", on_press=self.show_nodes_tab)
self.tab_peers = TabButton("Peers", on_press=self.show_peers_tab)
self.tab_pn = TabButton("Propagation Nodes", on_press=self.show_pn_tab)
# Create tab bar with proportional widths
self.tab_bar = urwid.Columns([
('weight', 1, self.tab_nodes),
('weight', 1, self.tab_peers),
('weight', 3, self.tab_pn),
], dividechars=1) # Add 1 character spacing between tabs
self.ilb = ExceptionHandlingListBox(
self.widget_list,
on_selection_change=self.list_selection,
@ -389,7 +406,13 @@ class AnnounceStream(urwid.WidgetWrap):
#highlight_offFocus="list_off_focus"
)
self.display_widget = self.ilb
# Combine tab bar and list box
self.pile = urwid.Pile([
('pack', self.tab_bar),
('weight', 1, self.ilb),
])
self.display_widget = self.pile
super().__init__(urwid.LineBox(self.display_widget, title="Announce Stream"))
def keypress(self, size, key):
@ -397,7 +420,7 @@ class AnnounceStream(urwid.WidgetWrap):
nomadnet.NomadNetworkApp.get_shared_instance().ui.main_display.frame.focus_position = "header"
elif key == "ctrl x":
self.delete_selected_entry()
return super(AnnounceStream, self).keypress(size, key)
def delete_selected_entry(self):
@ -412,28 +435,45 @@ class AnnounceStream(urwid.WidgetWrap):
self.update_widget_list()
def update_widget_list(self):
self.widget_list = []
new_entries = []
for e in self.app.directory.announce_stream:
if not e[0] in self.added_entries:
self.added_entries.insert(0, e[0])
new_entries.insert(0, e)
announce_type = e[3]
# Filter based on current tab
if self.current_tab == "nodes" and (announce_type == "node" or announce_type == True):
new_entries.append(e)
elif self.current_tab == "peers" and (announce_type == "peer" or announce_type == False):
new_entries.append(e)
elif self.current_tab == "pn" and announce_type == "pn":
new_entries.append(e)
for e in new_entries:
nw = AnnounceStreamEntry(self.app, e, self)
nw.timestamp = e[0]
self.widget_list.insert(0, nw)
self.widget_list.append(nw)
if len(new_entries) > 0:
self.no_content = False
if self.ilb != None:
self.ilb.set_body(self.widget_list)
else:
if len(self.widget_list) == 0:
self.no_content = True
if self.ilb != None:
self.ilb.set_body(self.widget_list)
self.no_content = True
self.widget_list = [urwid.Text(f"No {self.current_tab} announces", align='center')]
if self.ilb:
self.ilb.set_body(self.widget_list)
def show_nodes_tab(self, button):
self.current_tab = "nodes"
self.update_widget_list()
def show_peers_tab(self, button):
self.current_tab = "peers"
self.update_widget_list()
def show_pn_tab(self, button):
self.current_tab = "pn"
self.update_widget_list()
def list_selection(self, arg1, arg2):
pass
@ -596,7 +636,7 @@ class KnownNodeInfo(urwid.WidgetWrap):
if node_ident != None:
try:
existing_conversations = nomadnet.Conversation.conversation_list(self.app)
source_hash_text = RNS.hexrep(op_hash, delimit=False)
display_name = op_str
@ -632,7 +672,7 @@ class KnownNodeInfo(urwid.WidgetWrap):
trust_level = DirectoryEntry.UNTRUSTED
if r_unknown.get_state() == True:
trust_level = DirectoryEntry.UNKNOWN
if r_trusted.get_state() == True:
trust_level = DirectoryEntry.TRUSTED
@ -699,7 +739,7 @@ class KnownNodeInfo(urwid.WidgetWrap):
pile_widgets.insert(4, operator_entry)
pile = urwid.Pile(pile_widgets)
pile.focus_position = len(pile.contents)-1
button_columns.focus_position = 0
@ -733,7 +773,7 @@ class KnownNodes(urwid.WidgetWrap):
g = self.app.ui.glyphs
self.widget_list = self.make_node_widgets()
self.ilb = ExceptionHandlingListBox(
self.widget_list,
on_selection_change=self.node_list_selection,
@ -767,7 +807,7 @@ class KnownNodes(urwid.WidgetWrap):
nomadnet.NomadNetworkApp.get_shared_instance().ui.main_display.frame.focus_position = "header"
elif key == "ctrl x":
self.delete_selected_entry()
return super(KnownNodes, self).keypress(size, key)
@ -910,7 +950,7 @@ class NodeEntry(urwid.WidgetWrap):
focus_style = "list_focus_untrusted"
type_symbol = g["node"]
widget = ListEntry(type_symbol+" "+display_str)
urwid.connect_signal(widget, "click", delegate.connect_node, node)
@ -1209,7 +1249,7 @@ class LocalPeer(urwid.WidgetWrap):
#overlay = urwid.Overlay(dialog, bottom, align=urwid.CENTER, width=urwid.RELATIVE_100, valign=urwid.MIDDLE, height=urwid.PACK, left=4, right=4)
overlay = dialog
self.dialog_open = True
options = self.parent.left_pile.options(height_type=urwid.PACK, height_amount=None)
self.parent.left_pile.contents[1] = (overlay, options)
@ -1226,7 +1266,7 @@ class LocalPeer(urwid.WidgetWrap):
self.t_last_announce.update_time()
announce_button = urwid.Button("Announce Now", on_press=announce_query)
self.display_widget = urwid.Pile(
[
t_id,
@ -1270,13 +1310,13 @@ class NodeInfo(urwid.WidgetWrap):
def show_peer_info(sender):
options = self.parent.left_pile.options(height_type=urwid.PACK, height_amount=None)
self.parent.left_pile.contents[1] = (LocalPeer(self.app, self.parent), options)
if self.app.enable_node:
if self.app.node != None:
display_name = self.app.node.name
else:
display_name = None
if display_name == None:
display_name = ""
@ -1308,7 +1348,7 @@ class NodeInfo(urwid.WidgetWrap):
#overlay = urwid.Overlay(dialog, bottom, align=urwid.CENTER, width=urwid.RELATIVE_100, valign=urwid.MIDDLE, height=urwid.PACK, left=4, right=4)
overlay = dialog
self.dialog_open = True
options = self.parent.left_pile.options(height_type=urwid.PACK, height_amount=None)
self.parent.left_pile.contents[1] = (overlay, options)
@ -1594,14 +1634,14 @@ class NetworkDisplay():
if self.list_display == 1:
parent = self.app.ui.main_display.sub_displays.network_display
selected_node_entry = parent.known_nodes_display.ilb.get_selected_item()
if selected_node_entry != None:
selected_node_hash = selected_node_entry._get_base_widget().display_widget.source_hash
if selected_node_hash != None:
if selected_node_entry is not None:
selected_node_hash = selected_node_entry.base_widget.display_widget.source_hash
if selected_node_hash is not None:
info_widget = KnownNodeInfo(selected_node_hash)
options = parent.left_pile.options(height_type=urwid.WEIGHT, height_amount=1)
parent.left_pile.contents[0] = (info_widget, options)
def focus_lists(self):
self.columns.focus_position = 0
@ -1612,9 +1652,15 @@ class NetworkDisplay():
self.announce_stream_display.rebuild_widget_list()
def reinit_lxmf_peers(self):
if self.lxmf_peers_display:
si = self.lxmf_peers_display.ilb.get_selected_position()
else:
si = None
self.lxmf_peers_display = LXMFPeers(self.app)
self.lxmf_peers_display.delegate = self
self.close_list_dialogs()
if si != None:
self.lxmf_peers_display.ilb.select_item(si)
def close_list_dialogs(self):
if self.list_display == 0:
@ -1683,7 +1729,7 @@ class LXMFPeers(urwid.WidgetWrap):
self.delete_selected_entry()
elif key == "ctrl r":
self.sync_selected_entry()
return super(LXMFPeers, self).keypress(size, key)
@ -1707,7 +1753,7 @@ class LXMFPeers(urwid.WidgetWrap):
peer = self.app.message_router.peers[destination_hash]
if time.time() > peer.last_sync_attempt+sync_grace:
peer.next_sync_attempt = time.time()-1
def job():
peer.sync()
threading.Thread(target=job, daemon=True).start()
@ -1753,7 +1799,7 @@ class LXMFPeers(urwid.WidgetWrap):
def make_peer_widgets(self):
widget_list = []
sorted_peers = sorted(self.peer_list, key=lambda pid: (self.app.directory.pn_trust_level(pid), self.peer_list[pid].link_establishment_rate), reverse=True)
sorted_peers = sorted(self.peer_list, key=lambda pid: (self.app.directory.pn_trust_level(pid), self.peer_list[pid].sync_transfer_rate), reverse=True)
for peer_id in sorted_peers:
peer = self.peer_list[peer_id]
trust_level = self.app.directory.pn_trust_level(peer_id)
@ -1772,7 +1818,7 @@ class LXMFPeerEntry(urwid.WidgetWrap):
node_identity = RNS.Identity.recall(destination_hash)
display_str = RNS.prettyhexrep(destination_hash)
if node_identity != None:
if node_identity != None:
node_hash = RNS.Destination.hash_from_name_and_identity("nomadnetwork.node", node_identity)
display_name = self.app.directory.alleged_display_str(node_hash)
if display_name != None:
@ -1797,7 +1843,16 @@ class LXMFPeerEntry(urwid.WidgetWrap):
style = "list_unresponsive"
focus_style = "list_focus_unresponsive"
widget = ListEntry(sym+" "+display_str+"\n "+alive_string+", last heard "+pretty_date(int(peer.last_heard))+"\n "+str(len(peer.unhandled_messages))+" unhandled LXMs, "+RNS.prettysize(peer.link_establishment_rate/8, "b")+"/s LER")
if peer.propagation_transfer_limit:
txfer_limit = RNS.prettysize(peer.propagation_transfer_limit*1000)
else:
txfer_limit = "No"
ar = round(peer.acceptance_rate*100, 2)
peer_info_str = sym+" "+display_str+"\n "+alive_string+", last heard "+pretty_date(int(peer.last_heard))
peer_info_str += "\n "+str(peer.unhandled_message_count)+f" unhandled LXMs, {txfer_limit} sync limit\n"
peer_info_str += f" {RNS.prettyspeed(peer.sync_transfer_rate)} STR, "
peer_info_str += f"{RNS.prettyspeed(peer.link_establishment_rate)} LER, {ar}% AR\n"
widget = ListEntry(peer_info_str)
self.display_widget = urwid.AttrMap(widget, style, focus_style)
self.display_widget.destination_hash = destination_hash
super().__init__(self.display_widget)

File diff suppressed because it is too large Load Diff

View File

@ -30,6 +30,6 @@ setuptools.setup(
entry_points= {
'console_scripts': ['nomadnet=nomadnet.nomadnet:main']
},
install_requires=["rns>=0.8.7", "lxmf>=0.5.8", "urwid>=2.4.4", "qrcode"],
python_requires=">=3.6",
install_requires=["rns>=0.9.4", "lxmf>=0.6.3", "urwid>=2.6.16", "qrcode"],
python_requires=">=3.7",
)