mirror of
https://github.com/markqvist/NomadNet.git
synced 2025-12-17 14:54:26 +01:00
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2aa5c6f665 | ||
|
|
72a5ed9c8e | ||
|
|
c411ce703f | ||
|
|
c670aa82ad | ||
|
|
c52efbfb75 | ||
|
|
da348c3b42 | ||
|
|
92c3c55e03 | ||
|
|
8d9f4956db | ||
|
|
062e31964a | ||
|
|
f36018632f | ||
|
|
81f65e3453 | ||
|
|
34b3987ded | ||
|
|
22a7acf259 | ||
|
|
919a146da1 | ||
|
|
f0a4efa28b | ||
|
|
3d0043499c | ||
|
|
b6e6c4bd3d | ||
|
|
d06e1d3f1b | ||
|
|
02f9a5a760 | ||
|
|
bf7004fd0f | ||
|
|
8109bce5a3 |
31
README.md
31
README.md
@@ -30,7 +30,36 @@ The easiest way to install Nomad Network is via pip:
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Install Nomad Network and dependencies
|
# Install Nomad Network and dependencies
|
||||||
pip3 install nomadnet
|
pip install nomadnet
|
||||||
|
|
||||||
|
# Run the client
|
||||||
|
nomadnet
|
||||||
|
|
||||||
|
# Or alternatively run as a daemon, with no user interface
|
||||||
|
nomadnet --daemon
|
||||||
|
|
||||||
|
# List options
|
||||||
|
nomadnet --help
|
||||||
|
```
|
||||||
|
|
||||||
|
If you are using an operating system that blocks normal user package installation via `pip`, you can return `pip` to normal behaviour by editing the `~/.config/pip/pip.conf` file, and adding the following directive in the `[global]` section:
|
||||||
|
|
||||||
|
```text
|
||||||
|
[global]
|
||||||
|
break-system-packages = true
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, you can use the `pipx` tool to install Nomad Network in an isolated environment:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install Nomad Network
|
||||||
|
pipx install nomadnet
|
||||||
|
|
||||||
|
# Optionally install Reticulum utilities
|
||||||
|
pipx install rns
|
||||||
|
|
||||||
|
# Optionally install standalone LXMF utilities
|
||||||
|
pipx install lxmf
|
||||||
|
|
||||||
# Run the client
|
# Run the client
|
||||||
nomadnet
|
nomadnet
|
||||||
|
|||||||
@@ -34,16 +34,21 @@ class Directory:
|
|||||||
aspect_filter = "nomadnetwork.node"
|
aspect_filter = "nomadnetwork.node"
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def received_announce(destination_hash, announced_identity, app_data):
|
def received_announce(destination_hash, announced_identity, app_data):
|
||||||
app = nomadnet.NomadNetworkApp.get_shared_instance()
|
try:
|
||||||
|
app = nomadnet.NomadNetworkApp.get_shared_instance()
|
||||||
|
|
||||||
if not destination_hash in app.ignored_list:
|
if not destination_hash in app.ignored_list:
|
||||||
associated_peer = RNS.Destination.hash_from_name_and_identity("lxmf.delivery", announced_identity)
|
associated_peer = RNS.Destination.hash_from_name_and_identity("lxmf.delivery", announced_identity)
|
||||||
|
|
||||||
app.directory.node_announce_received(destination_hash, app_data, associated_peer)
|
app.directory.node_announce_received(destination_hash, app_data, associated_peer)
|
||||||
app.autoselect_propagation_node()
|
app.autoselect_propagation_node()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
RNS.log("Ignored announce from "+RNS.prettyhexrep(destination_hash), RNS.LOG_DEBUG)
|
RNS.log("Ignored announce from "+RNS.prettyhexrep(destination_hash), RNS.LOG_DEBUG)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
RNS.log("Error while evaluating LXMF destination announce, ignoring announce.", RNS.LOG_DEBUG)
|
||||||
|
RNS.log("The contained exception was: "+str(e), RNS.LOG_DEBUG)
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, app):
|
def __init__(self, app):
|
||||||
@@ -113,6 +118,19 @@ class Directory:
|
|||||||
|
|
||||||
def lxmf_announce_received(self, source_hash, app_data):
|
def lxmf_announce_received(self, source_hash, app_data):
|
||||||
if app_data != None:
|
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)
|
||||||
|
|
||||||
timestamp = time.time()
|
timestamp = time.time()
|
||||||
self.announce_stream.insert(0, (timestamp, source_hash, app_data, "peer"))
|
self.announce_stream.insert(0, (timestamp, source_hash, app_data, "peer"))
|
||||||
while len(self.announce_stream) > Directory.ANNOUNCE_STREAM_MAXLENGTH:
|
while len(self.announce_stream) > Directory.ANNOUNCE_STREAM_MAXLENGTH:
|
||||||
@@ -123,6 +141,19 @@ class Directory:
|
|||||||
|
|
||||||
def node_announce_received(self, source_hash, app_data, associated_peer):
|
def node_announce_received(self, source_hash, app_data, associated_peer):
|
||||||
if app_data != None:
|
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)
|
||||||
|
|
||||||
timestamp = time.time()
|
timestamp = time.time()
|
||||||
self.announce_stream.insert(0, (timestamp, source_hash, app_data, "node"))
|
self.announce_stream.insert(0, (timestamp, source_hash, app_data, "node"))
|
||||||
while len(self.announce_stream) > Directory.ANNOUNCE_STREAM_MAXLENGTH:
|
while len(self.announce_stream) > Directory.ANNOUNCE_STREAM_MAXLENGTH:
|
||||||
@@ -150,6 +181,19 @@ class Directory:
|
|||||||
break
|
break
|
||||||
|
|
||||||
if not found_node:
|
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)
|
||||||
|
|
||||||
|
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()
|
timestamp = time.time()
|
||||||
self.announce_stream.insert(0, (timestamp, source_hash, app_data, "pn"))
|
self.announce_stream.insert(0, (timestamp, source_hash, app_data, "pn"))
|
||||||
while len(self.announce_stream) > Directory.ANNOUNCE_STREAM_MAXLENGTH:
|
while len(self.announce_stream) > Directory.ANNOUNCE_STREAM_MAXLENGTH:
|
||||||
|
|||||||
@@ -153,6 +153,8 @@ class Node:
|
|||||||
RNS.log("Serving page: "+file_path, RNS.LOG_VERBOSE)
|
RNS.log("Serving page: "+file_path, RNS.LOG_VERBOSE)
|
||||||
if os.access(file_path, os.X_OK):
|
if os.access(file_path, os.X_OK):
|
||||||
env_map = {}
|
env_map = {}
|
||||||
|
if "PATH" in os.environ:
|
||||||
|
env_map["PATH"] = os.environ["PATH"]
|
||||||
if link_id != None:
|
if link_id != None:
|
||||||
env_map["link_id"] = RNS.hexrep(link_id, delimit=False)
|
env_map["link_id"] = RNS.hexrep(link_id, delimit=False)
|
||||||
if remote_identity != None:
|
if remote_identity != None:
|
||||||
|
|||||||
@@ -126,6 +126,7 @@ class NomadNetworkApp:
|
|||||||
self.periodic_lxmf_sync = True
|
self.periodic_lxmf_sync = True
|
||||||
self.lxmf_sync_interval = 360*60
|
self.lxmf_sync_interval = 360*60
|
||||||
self.lxmf_sync_limit = 8
|
self.lxmf_sync_limit = 8
|
||||||
|
self.compact_stream = False
|
||||||
|
|
||||||
if not os.path.isdir(self.storagepath):
|
if not os.path.isdir(self.storagepath):
|
||||||
os.makedirs(self.storagepath)
|
os.makedirs(self.storagepath)
|
||||||
@@ -698,6 +699,10 @@ class NomadNetworkApp:
|
|||||||
else:
|
else:
|
||||||
self.lxmf_sync_limit = None
|
self.lxmf_sync_limit = None
|
||||||
|
|
||||||
|
if option == "compact_announce_stream":
|
||||||
|
value = self.config["client"].as_bool(option)
|
||||||
|
self.compact_stream = value
|
||||||
|
|
||||||
if option == "user_interface":
|
if option == "user_interface":
|
||||||
value = value.lower()
|
value = value.lower()
|
||||||
if value == "none":
|
if value == "none":
|
||||||
@@ -929,6 +934,12 @@ lxmf_sync_interval = 360
|
|||||||
# the limit, and download everything every time.
|
# the limit, and download everything every time.
|
||||||
lxmf_sync_limit = 8
|
lxmf_sync_limit = 8
|
||||||
|
|
||||||
|
# The announce stream will only show one entry
|
||||||
|
# per destination or node by default. You can
|
||||||
|
# change this to show as many announces as have
|
||||||
|
# been received, for every destination.
|
||||||
|
compact_announce_stream = yes
|
||||||
|
|
||||||
[textui]
|
[textui]
|
||||||
|
|
||||||
# Amount of time to show intro screen
|
# Amount of time to show intro screen
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
__version__ = "0.3.4"
|
__version__ = "0.3.9"
|
||||||
|
|||||||
@@ -45,6 +45,8 @@ THEMES = {
|
|||||||
("list_normal", "dark gray", "default", "default", "#bbb", "default"),
|
("list_normal", "dark gray", "default", "default", "#bbb", "default"),
|
||||||
("list_untrusted", "dark red", "default", "default", "#a22", "default"),
|
("list_untrusted", "dark red", "default", "default", "#a22", "default"),
|
||||||
("list_focus_untrusted", "black", "light gray", "standout", "#810", "#aaa"),
|
("list_focus_untrusted", "black", "light gray", "standout", "#810", "#aaa"),
|
||||||
|
("list_unresponsive", "yellow", "default", "default", "#b92", "default"),
|
||||||
|
("list_focus_unresponsive", "black", "light gray", "standout", "#530", "#aaa"),
|
||||||
("topic_list_normal", "light gray", "default", "default", "#ddd", "default"),
|
("topic_list_normal", "light gray", "default", "default", "#ddd", "default"),
|
||||||
("browser_controls", "light gray", "default", "default", "#bbb", "default"),
|
("browser_controls", "light gray", "default", "default", "#bbb", "default"),
|
||||||
("progress_full", "black", "light gray", "standout", "#111", "#bbb"),
|
("progress_full", "black", "light gray", "standout", "#111", "#bbb"),
|
||||||
@@ -78,6 +80,8 @@ THEMES = {
|
|||||||
("list_normal", "dark gray", "default", "default", "#444", "default"),
|
("list_normal", "dark gray", "default", "default", "#444", "default"),
|
||||||
("list_untrusted", "dark red", "default", "default", "#a22", "default"),
|
("list_untrusted", "dark red", "default", "default", "#a22", "default"),
|
||||||
("list_focus_untrusted", "black", "dark gray", "standout", "#810", "#aaa"),
|
("list_focus_untrusted", "black", "dark gray", "standout", "#810", "#aaa"),
|
||||||
|
("list_unresponsive", "yellow", "default", "default", "#b92", "default"),
|
||||||
|
("list_focus_unresponsive", "black", "light gray", "standout", "#530", "#aaa"),
|
||||||
("topic_list_normal", "dark gray", "default", "default", "#222", "default"),
|
("topic_list_normal", "dark gray", "default", "default", "#222", "default"),
|
||||||
("browser_controls", "dark gray", "default", "default", "#444", "default"),
|
("browser_controls", "dark gray", "default", "default", "#444", "default"),
|
||||||
("progress_full", "black", "dark gray", "standout", "#111", "#bbb"),
|
("progress_full", "black", "dark gray", "standout", "#111", "#bbb"),
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ class BrowserFrame(urwid.Frame):
|
|||||||
self.delegate.url_dialog()
|
self.delegate.url_dialog()
|
||||||
elif key == "ctrl s":
|
elif key == "ctrl s":
|
||||||
self.delegate.save_node_dialog()
|
self.delegate.save_node_dialog()
|
||||||
|
elif key == "ctrl b":
|
||||||
|
self.delegate.save_node_dialog()
|
||||||
elif key == "ctrl g":
|
elif key == "ctrl g":
|
||||||
nomadnet.NomadNetworkApp.get_shared_instance().ui.main_display.sub_displays.network_display.toggle_fullscreen()
|
nomadnet.NomadNetworkApp.get_shared_instance().ui.main_display.sub_displays.network_display.toggle_fullscreen()
|
||||||
elif self.get_focus() == "body":
|
elif self.get_focus() == "body":
|
||||||
@@ -719,6 +721,10 @@ class Browser:
|
|||||||
env_map = self.request_data
|
env_map = self.request_data
|
||||||
else:
|
else:
|
||||||
env_map = {}
|
env_map = {}
|
||||||
|
|
||||||
|
if "PATH" in os.environ:
|
||||||
|
env_map["PATH"] = os.environ["PATH"]
|
||||||
|
|
||||||
generated = subprocess.run([page_path], stdout=subprocess.PIPE, env=env_map)
|
generated = subprocess.run([page_path], stdout=subprocess.PIPE, env=env_map)
|
||||||
page_data = generated.stdout
|
page_data = generated.stdout
|
||||||
else:
|
else:
|
||||||
@@ -750,7 +756,7 @@ class Browser:
|
|||||||
def __load(self):
|
def __load(self):
|
||||||
# If an established link exists, but it doesn't match the target
|
# If an established link exists, but it doesn't match the target
|
||||||
# destination, we close and clear it.
|
# destination, we close and clear it.
|
||||||
if self.link != None and self.link.destination.hash != self.destination_hash:
|
if self.link != None and (self.link.destination.hash != self.destination_hash or self.link.status != RNS.Link.ACTIVE):
|
||||||
self.link.teardown()
|
self.link.teardown()
|
||||||
self.link = None
|
self.link = None
|
||||||
|
|
||||||
@@ -999,6 +1005,11 @@ class Browser:
|
|||||||
self.response_transfer_size = None
|
self.response_transfer_size = None
|
||||||
|
|
||||||
self.update_display()
|
self.update_display()
|
||||||
|
if self.link != None:
|
||||||
|
try:
|
||||||
|
self.link.teardown()
|
||||||
|
except Exception as e:
|
||||||
|
pass
|
||||||
else:
|
else:
|
||||||
self.status = Browser.REQUEST_FAILED
|
self.status = Browser.REQUEST_FAILED
|
||||||
self.response_progress = 0
|
self.response_progress = 0
|
||||||
@@ -1006,6 +1017,11 @@ class Browser:
|
|||||||
self.response_transfer_size = None
|
self.response_transfer_size = None
|
||||||
|
|
||||||
self.update_display()
|
self.update_display()
|
||||||
|
if self.link != None:
|
||||||
|
try:
|
||||||
|
self.link.teardown()
|
||||||
|
except Exception as e:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def request_timeout(self, request_receipt=None):
|
def request_timeout(self, request_receipt=None):
|
||||||
@@ -1015,6 +1031,11 @@ class Browser:
|
|||||||
self.response_transfer_size = None
|
self.response_transfer_size = None
|
||||||
|
|
||||||
self.update_display()
|
self.update_display()
|
||||||
|
if self.link != None:
|
||||||
|
try:
|
||||||
|
self.link.teardown()
|
||||||
|
except Exception as e:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def response_progressed(self, request_receipt):
|
def response_progressed(self, request_receipt):
|
||||||
|
|||||||
@@ -335,7 +335,7 @@ By default, you can find the examples in `!~/.nomadnetwork/examples`!. If you bu
|
|||||||
|
|
||||||
Sometimes, you don't want everyone to be able to view certain pages or execute certain scripts. In such cases, you can use `*authentication`* to control who gets to run certain requests.
|
Sometimes, you don't want everyone to be able to view certain pages or execute certain scripts. In such cases, you can use `*authentication`* to control who gets to run certain requests.
|
||||||
|
|
||||||
To enable authentication for any page, simply add a new file to your pages directory with ".allowed" added to the file-name of the page. If your page is named "secret_page.mu", just add a file named "secret_page.mu.allowed".
|
To enable authentication for any page, simply add a new file to your pages directory with ".allowed" added to the file-name of the page. If your page is named "secret_page.mu", just add a file named "secret_page.allowed".
|
||||||
|
|
||||||
For each user allowed to access the page, add a line to this file, containing the hash of that users primary identity. Users can find their own identity hash in the `![ Network ]`! part of the program, under `!Local Peer Info`!. If you want to allow access for three different users, your file would look like this:
|
For each user allowed to access the page, add a line to this file, containing the hash of that users primary identity. Users can find their own identity hash in the `![ Network ]`! part of the program, under `!Local Peer Info`!. If you want to allow access for three different users, your file would look like this:
|
||||||
|
|
||||||
@@ -506,6 +506,12 @@ The number of minutes between each automatic sync. The default is equal to 6 hou
|
|||||||
On low-bandwidth networks, it can be useful to limit the amount of messages downloaded in each sync. The default is 8. Set to 0 to download all available messages every time a sync occurs.
|
On low-bandwidth networks, it can be useful to limit the amount of messages downloaded in each sync. The default is 8. Set to 0 to download all available messages every time a sync occurs.
|
||||||
<
|
<
|
||||||
|
|
||||||
|
>>>
|
||||||
|
`!compact_announce_stream = yes`!
|
||||||
|
>>>>
|
||||||
|
With this option enabled, Nomad Network will only display one entry in the announce stream per destination. Older announces are culled when a new one arrives.
|
||||||
|
<
|
||||||
|
|
||||||
>> Text UI Section
|
>> Text UI Section
|
||||||
|
|
||||||
This section hold configuration directives related to the look and feel of the text-based user interface of the program. It is delimited by the `![textui]`! header in the configuration file. Available directives, along with their default values, are as follows:
|
This section hold configuration directives related to the look and feel of the text-based user interface of the program. It is delimited by the `![textui]`! header in the configuration file. Available directives, along with their default values, are as follows:
|
||||||
|
|||||||
@@ -751,41 +751,45 @@ class LinkableText(urwid.Text):
|
|||||||
return x, y
|
return x, y
|
||||||
|
|
||||||
def mouse_event(self, size, event, button, x, y, focus):
|
def mouse_event(self, size, event, button, x, y, focus):
|
||||||
if button != 1 or not is_mouse_press(event):
|
try:
|
||||||
return False
|
if button != 1 or not is_mouse_press(event):
|
||||||
else:
|
return False
|
||||||
(maxcol,) = size
|
|
||||||
translation = self.get_line_translation(maxcol)
|
|
||||||
line_offset = 0
|
|
||||||
|
|
||||||
if self.align == "center":
|
|
||||||
line_offset = translation[y][1][1]-translation[y][0][0]
|
|
||||||
if x < translation[y][0][0]:
|
|
||||||
x = translation[y][0][0]
|
|
||||||
|
|
||||||
if x > translation[y][1][0]+translation[y][0][0]:
|
|
||||||
x = translation[y][1][0]+translation[y][0][0]
|
|
||||||
|
|
||||||
elif self.align == "right":
|
|
||||||
line_offset = translation[y][1][1]-translation[y][0][0]
|
|
||||||
if x < translation[y][0][0]:
|
|
||||||
x = translation[y][0][0]
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
line_offset = translation[y][0][1]
|
(maxcol,) = size
|
||||||
if x > translation[y][0][0]:
|
translation = self.get_line_translation(maxcol)
|
||||||
x = translation[y][0][0]
|
line_offset = 0
|
||||||
|
|
||||||
pos = line_offset+x
|
if self.align == "center":
|
||||||
|
line_offset = translation[y][1][1]-translation[y][0][0]
|
||||||
|
if x < translation[y][0][0]:
|
||||||
|
x = translation[y][0][0]
|
||||||
|
|
||||||
self._cursor_position = pos
|
if x > translation[y][1][0]+translation[y][0][0]:
|
||||||
item = self.find_item_at_pos(self._cursor_position)
|
x = translation[y][1][0]+translation[y][0][0]
|
||||||
|
|
||||||
if item != None:
|
elif self.align == "right":
|
||||||
if isinstance(item, LinkSpec):
|
line_offset = translation[y][1][1]-translation[y][0][0]
|
||||||
self.handle_link(item.link_target, item.link_fields)
|
if x < translation[y][0][0]:
|
||||||
|
x = translation[y][0][0]
|
||||||
|
|
||||||
self._invalidate()
|
else:
|
||||||
self._emit("change")
|
line_offset = translation[y][0][1]
|
||||||
|
if x > translation[y][0][0]:
|
||||||
|
x = translation[y][0][0]
|
||||||
|
|
||||||
return True
|
pos = line_offset+x
|
||||||
|
|
||||||
|
self._cursor_position = pos
|
||||||
|
item = self.find_item_at_pos(self._cursor_position)
|
||||||
|
|
||||||
|
if item != None:
|
||||||
|
if isinstance(item, LinkSpec):
|
||||||
|
self.handle_link(item.link_target, item.link_fields)
|
||||||
|
|
||||||
|
self._invalidate()
|
||||||
|
self._emit("change")
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return False
|
||||||
@@ -13,9 +13,7 @@ class NetworkDisplayShortcuts():
|
|||||||
self.app = app
|
self.app = app
|
||||||
g = app.ui.glyphs
|
g = app.ui.glyphs
|
||||||
|
|
||||||
self.widget = urwid.AttrMap(urwid.Text("[C-l] Nodes/Announces [C-x] Remove [C-w] Disconnect [C-d] Back [C-f] Forward [C-r] Reload [C-u] URL [C-g] Fullscreen"), "shortcutbar")
|
self.widget = urwid.AttrMap(urwid.Text("[C-l] Nodes/Announces [C-x] Remove [C-w] Disconnect [C-d] Back [C-f] Forward [C-r] Reload [C-u] URL [C-g] Fullscreen [C-s / C-b] Save Node"), "shortcutbar")
|
||||||
# "[C-"+g["arrow_u"]+g["arrow_d"]+"] Navigate Lists"
|
|
||||||
|
|
||||||
|
|
||||||
class DialogLineBox(urwid.LineBox):
|
class DialogLineBox(urwid.LineBox):
|
||||||
def keypress(self, size, key):
|
def keypress(self, size, key):
|
||||||
@@ -588,7 +586,7 @@ class KnownNodeInfo(urwid.WidgetWrap):
|
|||||||
def ident_change(sender, userdata):
|
def ident_change(sender, userdata):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
propagation_node_checkbox = urwid.CheckBox("Use as default propagation node", state=(self.app.get_user_selected_propagation_node() == source_hash), on_state_change=pn_change)
|
propagation_node_checkbox = urwid.CheckBox("Use as default propagation node", state=(self.app.get_user_selected_propagation_node() == pn_hash), on_state_change=pn_change)
|
||||||
connect_identify_checkbox = urwid.CheckBox("Identify when connecting", state=self.app.directory.should_identify_on_connect(source_hash), on_state_change=ident_change)
|
connect_identify_checkbox = urwid.CheckBox("Identify when connecting", state=self.app.directory.should_identify_on_connect(source_hash), on_state_change=ident_change)
|
||||||
|
|
||||||
def save_node(sender):
|
def save_node(sender):
|
||||||
@@ -1578,7 +1576,11 @@ class LXMFPeers(urwid.WidgetWrap):
|
|||||||
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.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")
|
self.display_widget = urwid.Filler(self.pile, valign="top", height="pack")
|
||||||
|
|
||||||
urwid.WidgetWrap.__init__(self, urwid.AttrMap(urwid.LineBox(self.display_widget, title="LXMF Propagation Peers"), widget_style))
|
if hasattr(self, "peer_list") and self.peer_list:
|
||||||
|
pl = len(self.peer_list)
|
||||||
|
else:
|
||||||
|
pl = 0
|
||||||
|
urwid.WidgetWrap.__init__(self, urwid.AttrMap(urwid.LineBox(self.display_widget, title=f"LXMF Propagation Peers ({pl})"), widget_style))
|
||||||
|
|
||||||
def keypress(self, size, key):
|
def keypress(self, size, key):
|
||||||
if key == "up" and (self.no_content or self.ilb.first_item_is_selected()):
|
if key == "up" and (self.no_content or self.ilb.first_item_is_selected()):
|
||||||
@@ -1613,13 +1615,13 @@ class LXMFPeers(urwid.WidgetWrap):
|
|||||||
|
|
||||||
def make_peer_widgets(self):
|
def make_peer_widgets(self):
|
||||||
widget_list = []
|
widget_list = []
|
||||||
for peer_id in self.peer_list:
|
sorted_peers = sorted(self.peer_list, key=lambda pid: self.peer_list[pid].link_establishment_rate, reverse=True)
|
||||||
|
for peer_id in sorted_peers:
|
||||||
peer = self.peer_list[peer_id]
|
peer = self.peer_list[peer_id]
|
||||||
pe = LXMFPeerEntry(self.app, peer, self)
|
pe = LXMFPeerEntry(self.app, peer, self)
|
||||||
pe.destination_hash = peer.destination_hash
|
pe.destination_hash = peer.destination_hash
|
||||||
widget_list.append(pe)
|
widget_list.append(pe)
|
||||||
|
|
||||||
# TODO: Sort list
|
|
||||||
return widget_list
|
return widget_list
|
||||||
|
|
||||||
class LXMFPeerEntry(urwid.WidgetWrap):
|
class LXMFPeerEntry(urwid.WidgetWrap):
|
||||||
@@ -1635,7 +1637,7 @@ class LXMFPeerEntry(urwid.WidgetWrap):
|
|||||||
node_hash = RNS.Destination.hash_from_name_and_identity("nomadnetwork.node", node_identity)
|
node_hash = RNS.Destination.hash_from_name_and_identity("nomadnetwork.node", node_identity)
|
||||||
display_name = self.app.directory.alleged_display_str(node_hash)
|
display_name = self.app.directory.alleged_display_str(node_hash)
|
||||||
if display_name != None:
|
if display_name != None:
|
||||||
display_str += " "+str(display_name)
|
display_str = str(display_name)+"\n "+display_str
|
||||||
|
|
||||||
sym = g["sent"]
|
sym = g["sent"]
|
||||||
style = "list_unknown"
|
style = "list_unknown"
|
||||||
@@ -1645,8 +1647,12 @@ class LXMFPeerEntry(urwid.WidgetWrap):
|
|||||||
if hasattr(peer, "alive"):
|
if hasattr(peer, "alive"):
|
||||||
if peer.alive:
|
if peer.alive:
|
||||||
alive_string = "Available"
|
alive_string = "Available"
|
||||||
|
style = "list_normal"
|
||||||
|
focus_style = "list_focus"
|
||||||
else:
|
else:
|
||||||
alive_string = "Unresponsive"
|
alive_string = "Unresponsive"
|
||||||
|
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")
|
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")
|
||||||
# urwid.connect_signal(widget, "click", delegate.connect_node, node)
|
# urwid.connect_signal(widget, "click", delegate.connect_node, node)
|
||||||
|
|||||||
2
setup.py
2
setup.py
@@ -30,6 +30,6 @@ setuptools.setup(
|
|||||||
entry_points= {
|
entry_points= {
|
||||||
'console_scripts': ['nomadnet=nomadnet.nomadnet:main']
|
'console_scripts': ['nomadnet=nomadnet.nomadnet:main']
|
||||||
},
|
},
|
||||||
install_requires=["rns>=0.4.9", "lxmf>=0.3.1", "urwid>=2.1.2", "qrcode"],
|
install_requires=["rns>=0.6.2", "lxmf>=0.3.4", "urwid==2.1.2", "qrcode"],
|
||||||
python_requires=">=3.6",
|
python_requires=">=3.6",
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user