mirror of
https://github.com/markqvist/NomadNet.git
synced 2025-12-17 06:44:21 +01:00
Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
24d850107d | ||
|
|
9943cad15f | ||
|
|
dcd5f7df95 | ||
|
|
d840ca32ae | ||
|
|
37063932bb | ||
|
|
0ed4e09b82 | ||
|
|
910e527cc7 | ||
|
|
4eef326d6b | ||
|
|
691f4df098 | ||
|
|
407cc8fb5f | ||
|
|
1f7302903a | ||
|
|
5736012f2c | ||
|
|
bb98a512f3 | ||
|
|
ae0d4c6e0c | ||
|
|
2449b39f77 | ||
|
|
e022d469f8 | ||
|
|
a4f665e650 | ||
|
|
19d1d8504f | ||
|
|
276a5f56e1 | ||
|
|
89dd17ece5 | ||
|
|
82bb479957 | ||
|
|
082026ca1b | ||
|
|
df9fccf199 | ||
|
|
efd1d08399 |
19
README.md
19
README.md
@@ -22,9 +22,6 @@ If you'd rather want to use an LXMF client with a graphical user interface, you
|
||||
- An easy to use and bandwidth efficient markup language for writing pages
|
||||
- Page caching in browser
|
||||
|
||||
## Current Status
|
||||
The current version of the program should be considered a beta release. The program works well, but there will most probably be bugs and possibly sub-optimal performance in some scenarios. On the other hand, this is the ideal time to have an influence on the direction of the development of Nomad Network. To do so, join the discussion, report bugs and request features here on the GitHub project.
|
||||
|
||||
## How do I get started?
|
||||
The easiest way to install Nomad Network is via pip:
|
||||
|
||||
@@ -121,6 +118,22 @@ $ docker run -d \
|
||||
$ docker run -i ghcr.io/markqvist/nomadnet:master --daemon --console
|
||||
```
|
||||
|
||||
## Tools & Extensions
|
||||
|
||||
Nomad Network is a very flexible and extensible platform, and a variety of community-provided tools, utilities and node-side extensions exist:
|
||||
|
||||
- [NomadForum](https://codeberg.org/AutumnSpark1226/nomadForum) ([GitHub mirror](https://github.com/AutumnSpark1226/nomadForum))
|
||||
- [NomadForecast](https://github.com/faragher/NomadForecast)
|
||||
- [micron-blog](https://github.com/randogoth/micron-blog)
|
||||
- [md2mu](https://github.com/randogoth/md2mu)
|
||||
- [Any2MicronConverter](https://github.com/SebastianObi/Any2MicronConverter)
|
||||
- [Some nomadnet page examples](https://github.com/SebastianObi/NomadNet-Pages)
|
||||
- [More nomadnet page examples](https://github.com/epenguins/NomadNet_pages)
|
||||
- [LXMF-Bot](https://github.com/randogoth/lxmf-bot)
|
||||
- [LXMF Messageboard](https://github.com/chengtripp/lxmf_messageboard)
|
||||
- [LXMEvent](https://github.com/faragher/LXMEvent)
|
||||
- [LXMF Tools](https://github.com/SebastianObi/LXMF-Tools)
|
||||
|
||||
## Help & Discussion
|
||||
|
||||
For help requests, discussion, sharing ideas or anything else related to Nomad Network, please have a look at the [Nomad Network discussions pages](https://github.com/markqvist/Reticulum/discussions/categories/nomad-network).
|
||||
|
||||
@@ -142,7 +142,7 @@ class Conversation:
|
||||
|
||||
self.__changed_callback = None
|
||||
|
||||
if not RNS.Transport.has_path(bytes.fromhex(source_hash)):
|
||||
if not RNS.Identity.recall(bytes.fromhex(self.source_hash)):
|
||||
RNS.Transport.request_path(bytes.fromhex(source_hash))
|
||||
|
||||
self.source_identity = RNS.Identity.recall(bytes.fromhex(self.source_hash))
|
||||
|
||||
@@ -90,7 +90,10 @@ class Directory:
|
||||
|
||||
entries = {}
|
||||
for e in unpacked_list:
|
||||
|
||||
|
||||
if e[1] == None:
|
||||
e[1] = "Undefined"
|
||||
|
||||
if len(e) > 3:
|
||||
hosts_node = e[3]
|
||||
else:
|
||||
@@ -375,4 +378,4 @@ class DirectoryEntry:
|
||||
self.hosts_node = hosts_node
|
||||
self.identify = identify_on_connect
|
||||
else:
|
||||
raise TypeError("Attempt to add invalid source hash to directory")
|
||||
raise TypeError("Attempt to add invalid source hash to directory")
|
||||
|
||||
@@ -15,7 +15,11 @@ class Node:
|
||||
self.identity = self.app.identity
|
||||
self.destination = RNS.Destination(self.identity, RNS.Destination.IN, RNS.Destination.SINGLE, "nomadnetwork", "node")
|
||||
self.last_announce = time.time()
|
||||
self.last_file_refresh = time.time()
|
||||
self.last_page_refresh = time.time()
|
||||
self.announce_interval = self.app.node_announce_interval
|
||||
self.page_refresh_interval = self.app.page_refresh_interval
|
||||
self.file_refresh_interval = self.app.file_refresh_interval
|
||||
self.job_interval = Node.JOB_INTERVAL
|
||||
self.should_run_jobs = True
|
||||
self.app_data = None
|
||||
@@ -46,6 +50,8 @@ class Node:
|
||||
|
||||
|
||||
def register_pages(self):
|
||||
# TODO: Deregister previously registered pages
|
||||
# that no longer exist.
|
||||
self.servedpages = []
|
||||
self.scan_pages(self.app.pagespath)
|
||||
|
||||
@@ -65,6 +71,8 @@ class Node:
|
||||
)
|
||||
|
||||
def register_files(self):
|
||||
# TODO: Deregister previously registered files
|
||||
# that no longer exist.
|
||||
self.servedfiles = []
|
||||
self.scan_files(self.app.filespath)
|
||||
|
||||
@@ -222,6 +230,16 @@ class Node:
|
||||
|
||||
if now > self.last_announce + self.announce_interval*60:
|
||||
self.announce()
|
||||
|
||||
if self.page_refresh_interval > 0:
|
||||
if now > self.last_page_refresh + self.page_refresh_interval*60:
|
||||
self.register_pages()
|
||||
self.last_page_refresh = time.time()
|
||||
|
||||
if self.file_refresh_interval > 0:
|
||||
if now > self.last_file_refresh + self.file_refresh_interval*60:
|
||||
self.register_files()
|
||||
self.last_file_refresh = time.time()
|
||||
|
||||
time.sleep(self.job_interval)
|
||||
|
||||
|
||||
@@ -115,10 +115,12 @@ class NomadNetworkApp:
|
||||
|
||||
self.downloads_path = os.path.expanduser("~/Downloads")
|
||||
|
||||
self.firstrun = False
|
||||
self.should_run_jobs = True
|
||||
self.job_interval = 5
|
||||
self.defer_jobs = 90
|
||||
self.firstrun = False
|
||||
self.should_run_jobs = True
|
||||
self.job_interval = 5
|
||||
self.defer_jobs = 90
|
||||
self.page_refresh_interval = 0
|
||||
self.file_refresh_interval = 0
|
||||
|
||||
self.peer_announce_at_start = True
|
||||
self.try_propagation_on_fail = True
|
||||
@@ -427,16 +429,24 @@ class NomadNetworkApp:
|
||||
return "Receiving messages"
|
||||
elif self.message_router.propagation_transfer_state == LXMF.LXMRouter.PR_RESPONSE_RECEIVED:
|
||||
return "Messages received"
|
||||
elif self.message_router.propagation_transfer_state == LXMF.LXMRouter.PR_NO_PATH:
|
||||
return "No path to node"
|
||||
elif self.message_router.propagation_transfer_state == LXMF.LXMRouter.PR_LINK_FAILED:
|
||||
return "Link establisment failed"
|
||||
elif self.message_router.propagation_transfer_state == LXMF.LXMRouter.PR_TRANSFER_FAILED:
|
||||
return "Sync request failed"
|
||||
elif self.message_router.propagation_transfer_state == LXMF.LXMRouter.PR_NO_IDENTITY_RCVD:
|
||||
return "Remote got no identity"
|
||||
elif self.message_router.propagation_transfer_state == LXMF.LXMRouter.PR_NO_ACCESS:
|
||||
return "Node rejected request"
|
||||
elif self.message_router.propagation_transfer_state == LXMF.LXMRouter.PR_FAILED:
|
||||
return "Sync failed"
|
||||
elif self.message_router.propagation_transfer_state == LXMF.LXMRouter.PR_COMPLETE:
|
||||
new_msgs = self.message_router.propagation_transfer_last_result
|
||||
if new_msgs == 0:
|
||||
return "Done, no new messages"
|
||||
else:
|
||||
return "Downloaded "+str(new_msgs)+" new messages"
|
||||
elif self.message_router.propagation_transfer_state == LXMF.LXMRouter.PR_NO_IDENTITY_RCVD:
|
||||
return "Node did not receive identification"
|
||||
elif self.message_router.propagation_transfer_state == LXMF.LXMRouter.PR_NO_ACCESS:
|
||||
return "Node did not allow request"
|
||||
else:
|
||||
return "Unknown"
|
||||
|
||||
@@ -819,12 +829,30 @@ class NomadNetworkApp:
|
||||
if value < 1:
|
||||
value = 1
|
||||
self.node_announce_interval = value
|
||||
|
||||
|
||||
if "pages_path" in self.config["node"]:
|
||||
self.pagespath = self.config["node"]["pages_path"]
|
||||
|
||||
if not "page_refresh_interval" in self.config["node"]:
|
||||
self.page_refresh_interval = 0
|
||||
else:
|
||||
value = self.config["node"].as_int("page_refresh_interval")
|
||||
if value < 0:
|
||||
value = 0
|
||||
self.page_refresh_interval = value
|
||||
|
||||
|
||||
if "files_path" in self.config["node"]:
|
||||
self.filespath = self.config["node"]["files_path"]
|
||||
|
||||
if not "file_refresh_interval" in self.config["node"]:
|
||||
self.file_refresh_interval = 0
|
||||
else:
|
||||
value = self.config["node"].as_int("file_refresh_interval")
|
||||
if value < 0:
|
||||
value = 0
|
||||
self.file_refresh_interval = value
|
||||
|
||||
|
||||
if "prioritise_destinations" in self.config["node"]:
|
||||
self.prioritised_lxmf_destinations = self.config["node"].as_list("prioritise_destinations")
|
||||
@@ -1049,6 +1077,22 @@ announce_at_start = Yes
|
||||
# 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 specify the interval in minutes for
|
||||
# rescanning the hosted pages path. By default,
|
||||
# this option is disabled, and the pages path
|
||||
# will only be scanned on startup.
|
||||
# page_refresh_interval = 0
|
||||
|
||||
# You can specify the interval in minutes for
|
||||
# rescanning the hosted files path. By default,
|
||||
# this option is disabled, and the files path
|
||||
# will only be scanned on startup.
|
||||
# file_refresh_interval = 0
|
||||
|
||||
[printing]
|
||||
|
||||
# You can configure Nomad Network to print
|
||||
|
||||
@@ -1 +1 @@
|
||||
__version__ = "0.4.0"
|
||||
__version__ = "0.4.5"
|
||||
|
||||
@@ -517,7 +517,7 @@ class Browser:
|
||||
self.status = Browser.PATH_REQUESTED
|
||||
self.update_display()
|
||||
|
||||
pr_time = time.time()
|
||||
pr_time = time.time()+RNS.Transport.first_hop_timeout(self.destination_hash)
|
||||
while not RNS.Transport.has_path(self.destination_hash):
|
||||
now = time.time()
|
||||
if now > pr_time+self.timeout:
|
||||
@@ -770,7 +770,7 @@ class Browser:
|
||||
self.status = Browser.PATH_REQUESTED
|
||||
self.update_display()
|
||||
|
||||
pr_time = time.time()
|
||||
pr_time = time.time()+RNS.Transport.first_hop_timeout(self.destination_hash)
|
||||
while not RNS.Transport.has_path(self.destination_hash):
|
||||
now = time.time()
|
||||
if now > pr_time+self.timeout:
|
||||
@@ -976,7 +976,10 @@ class Browser:
|
||||
try:
|
||||
file_name = request_receipt.response[0]
|
||||
file_data = request_receipt.response[1]
|
||||
file_destination = self.app.downloads_path+"/"+file_name
|
||||
file_destination_name = file_name.split("/")
|
||||
file_destination_name = file_destination_name[len(file_destination_name)-1]
|
||||
file_destination = self.app.downloads_path+"/"+file_destination_name
|
||||
|
||||
|
||||
counter = 0
|
||||
while os.path.isfile(file_destination):
|
||||
|
||||
@@ -894,7 +894,7 @@ class ConversationWidget(urwid.WidgetWrap):
|
||||
if allowed:
|
||||
self.frame.contents["footer"] = (self.minimal_editor, None)
|
||||
else:
|
||||
warning = urwid.AttrMap(urwid.Padding(urwid.Text("\n"+g["info"]+"\n\nYou cannot currently message this peer, since it's identity keys are not known.\n\nWait for an announce to arrive from the peer, or query the network for it.\n\nTo query the network, select this conversation in the conversation list, press Ctrl-E, and use the query button.\n", align="center")), "msg_header_caution")
|
||||
warning = urwid.AttrMap(urwid.Padding(urwid.Text("\n"+g["info"]+"\n\nYou cannot currently message this peer, since it's identity keys are not known. The keys have been requested from the network and should arrive shortly, if available. Close this conversation and reopen it to try again.\n\nTo query the network manually, select this conversation in the conversation list, press Ctrl-E, and use the query button.\n", align="center")), "msg_header_caution")
|
||||
self.frame.contents["footer"] = (warning, None)
|
||||
|
||||
def toggle_focus_area(self):
|
||||
|
||||
@@ -163,9 +163,8 @@ class GuideDisplay():
|
||||
entry.display_topic(entry.display_topic, entry.topic_name)
|
||||
|
||||
def set_content_widgets(self, new_content):
|
||||
options = self.columns.options(width_type="weight", width_amount=1-GuideDisplay.list_width)
|
||||
options = self.columns.options(width_type="weight", width_amount=1-GuideDisplay.list_width, box_widget=True)
|
||||
pile = urwid.Pile(new_content)
|
||||
#content = urwid.LineBox(urwid.Filler(pile, "top"))
|
||||
content = urwid.LineBox(urwid.AttrMap(ScrollBar(Scrollable(pile), thumb_char="\u2503", trough_char=" "), "scrollbar"))
|
||||
|
||||
self.columns.contents[1] = (content, options)
|
||||
@@ -398,7 +397,7 @@ You're currently located in the guide section of the program. I'm sorry I had to
|
||||
|
||||
To get the most out of Nomad Network, you will need a terminal that supports UTF-8 and at least 256 colors, ideally true-color. If your terminal supports true-color, you can go to the `![ Config ]`! menu item, launch the editor and change the configuration.
|
||||
|
||||
It is recommended to use a terminal size of at least 122x32. Nomad Network will work with smaller terminal sizes, but the interface might feel a bit cramped.
|
||||
It is recommended to use a terminal size of at least 135x32. Nomad Network will work with smaller terminal sizes, but the interface might feel a bit cramped.
|
||||
|
||||
If you don't already have a Nerd Font installed (see https://www.nerdfonts.com/), I also highly recommend to do so, since it will greatly expand the amount of glyphs, icons and graphics that Nomad Network can use. Once you have your terminal set up with a Nerd Font, go to the `![ Config ]`! menu item and enable Nerd Fonts in the configuration instead of normal unicode glyphs.
|
||||
|
||||
@@ -621,12 +620,24 @@ Determines how often, in minutes, your node is announced on the network. Default
|
||||
Determines where the node server will look for hosted pages. Must be a readable filesystem path.
|
||||
<
|
||||
|
||||
>>>
|
||||
`!page_refresh_interval = 0`!
|
||||
>>>>
|
||||
Determines the interval in minutes for rescanning the hosted pages path. By default, this option is disabled, and the pages path will only be scanned on startup.
|
||||
<
|
||||
|
||||
>>>
|
||||
`!files_path = ~/.nomadnetwork/storage/files`!
|
||||
>>>>
|
||||
Determines where the node server will look for downloadable files. Must be a readable filesystem path.
|
||||
<
|
||||
|
||||
>>>
|
||||
`!file_refresh_interval = 0`!
|
||||
>>>>
|
||||
Determines the interval in minutes for rescanning the hosted files path. By default, this option is disabled, and the files path will only be scanned on startup.
|
||||
<
|
||||
|
||||
>>>
|
||||
`!disable_propagation = no`!
|
||||
>>>>
|
||||
@@ -1144,7 +1155,7 @@ To display literal content, for example source-code, or blocks of text that shou
|
||||
`=
|
||||
'''
|
||||
TOPIC_MARKUP += TOPIC_MARKUP.replace("`=", "\\`=") + "[ micron source for document goes here, we don't want infinite recursion now, do we? ]\n\\`="
|
||||
TOPIC_MARKUP += "\n`=\n\n>Closing Remarks\n\nIf you made it all the way here, you should be well equipped to write documents, pages and applications using micron and Nomad Network. Thank you for staying with me.\n\n`c\U0001F332\n"
|
||||
TOPIC_MARKUP += "\n`=\n\n>Closing Remarks\n\nIf you made it all the way here, you should be well equipped to write documents, pages and applications using micron and Nomad Network. Thank you for staying with me.\n"
|
||||
|
||||
|
||||
TOPICS = {
|
||||
|
||||
@@ -12,10 +12,21 @@ class LogDisplay():
|
||||
def __init__(self, app):
|
||||
import urwid
|
||||
self.app = app
|
||||
self.log_term = LogTerminal(self.app)
|
||||
self.log_term = None
|
||||
|
||||
self.shortcuts_display = LogDisplayShortcuts(self.app)
|
||||
self.widget = urwid.LineBox(self.log_term)
|
||||
self.widget = None
|
||||
|
||||
def show(self):
|
||||
if self.log_term == None:
|
||||
self.log_term = LogTerminal(self.app)
|
||||
self.widget = urwid.LineBox(self.log_term)
|
||||
|
||||
def kill(self):
|
||||
if self.log_term != None:
|
||||
self.log_term.terminate()
|
||||
self.log_term = None
|
||||
self.widget = None
|
||||
|
||||
def shortcuts(self):
|
||||
return self.shortcuts_display
|
||||
@@ -26,10 +37,14 @@ class LogTerminal(urwid.WidgetWrap):
|
||||
self.log_term = urwid.Terminal(
|
||||
("tail", "-fn50", self.app.logfilepath),
|
||||
encoding='utf-8',
|
||||
escape_sequence="up"
|
||||
escape_sequence="up",
|
||||
main_loop=self.app.ui.loop,
|
||||
)
|
||||
urwid.WidgetWrap.__init__(self, self.log_term)
|
||||
|
||||
def terminate(self):
|
||||
self.log_term.terminate()
|
||||
|
||||
|
||||
def keypress(self, size, key):
|
||||
if key == "up":
|
||||
|
||||
@@ -116,6 +116,7 @@ class MainDisplay():
|
||||
|
||||
def show_log(self, user_data):
|
||||
self.sub_displays.active_display = self.sub_displays.log_display
|
||||
self.sub_displays.log_display.show()
|
||||
self.update_active_sub_display()
|
||||
|
||||
def show_guide(self, user_data):
|
||||
@@ -125,6 +126,8 @@ class MainDisplay():
|
||||
def update_active_sub_display(self):
|
||||
self.frame.contents["body"] = (self.sub_displays.active().widget, None)
|
||||
self.update_active_shortcuts()
|
||||
if self.sub_displays.active_display != self.sub_displays.log_display:
|
||||
self.sub_displays.log_display.kill()
|
||||
|
||||
def update_active_shortcuts(self):
|
||||
self.frame.contents["footer"] = (self.sub_displays.active().shortcuts().widget, None)
|
||||
|
||||
6
nomadnet/vendor/Scrollable.py
vendored
6
nomadnet/vendor/Scrollable.py
vendored
@@ -268,10 +268,10 @@ class Scrollable(urwid.WidgetDecoration):
|
||||
def _get_original_widget_size(self, size):
|
||||
ow = self._original_widget
|
||||
sizing = ow.sizing()
|
||||
if FIXED in sizing:
|
||||
return ()
|
||||
elif FLOW in sizing:
|
||||
if FLOW in sizing:
|
||||
return (size[0],)
|
||||
elif FIXED in sizing:
|
||||
return ()
|
||||
|
||||
def get_scrollpos(self, size=None, focus=False):
|
||||
"""Current scrolling position
|
||||
|
||||
2
setup.py
2
setup.py
@@ -30,6 +30,6 @@ setuptools.setup(
|
||||
entry_points= {
|
||||
'console_scripts': ['nomadnet=nomadnet.nomadnet:main']
|
||||
},
|
||||
install_requires=["rns>=0.6.2", "lxmf>=0.3.6", "urwid==2.1.2", "qrcode"],
|
||||
install_requires=["rns>=0.7.0", "lxmf>=0.3.9", "urwid>=2.4.2", "qrcode"],
|
||||
python_requires=">=3.6",
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user