From 55baede2fc0978c1a9c0ba55e6e955709c39dd79 Mon Sep 17 00:00:00 2001 From: Mark Qvist Date: Tue, 10 Dec 2024 20:24:09 +0100 Subject: [PATCH] Enabled Repository server on desktop. Added RNode Flasher to utilities. Added RNode firmware downloads to repository update action. --- sbapp/Makefile | 5 +- sbapp/main.py | 157 +++++++++++++++++++++++++-------------- sbapp/share/flasher.html | 33 ++++++++ sbapp/share/guides.html | 3 +- sbapp/share/index.html | 2 +- sbapp/share/pkgs.html | 4 +- sbapp/sideband/core.py | 11 ++- sbapp/ui/utilities.py | 40 ++++++++++ 8 files changed, 191 insertions(+), 64 deletions(-) create mode 100644 sbapp/share/flasher.html diff --git a/sbapp/Makefile b/sbapp/Makefile index a8c75b5..b6b55dc 100644 --- a/sbapp/Makefile +++ b/sbapp/Makefile @@ -7,7 +7,7 @@ clean: -(rm ./__pycache__ -r) -(rm ./app_storage -r) -(rm ./share/pkg/* -r) - -(rm ./share/mirrors/* -r) + -(rm ./share/mirrors/* -rf) -(rm ./bin -r) cleanlibs: @@ -64,13 +64,14 @@ fetchshare: cp ../../dist_archive/lxmf-*-py3-none-any.whl ./share/pkg/ cp ../../dist_archive/nomadnet-*-py3-none-any.whl ./share/pkg/ cp ../../dist_archive/rnsh-*-py3-none-any.whl ./share/pkg/ -# cp ../../dist_archive/sbapp-*-py3-none-any.whl ./share/pkg/ cp ../../dist_archive/RNode_Firmware_*_Source.zip ./share/pkg/ zip --junk-paths ./share/pkg/example_plugins.zip ../docs/example_plugins/*.py cp -r ../../dist_archive/reticulum.network ./share/mirrors/ cp -r ../../dist_archive/unsigned.io ./share/mirrors/ cp ../../dist_archive/Reticulum\ Manual.pdf ./share/mirrors/Reticulum_Manual.pdf cp ../../dist_archive/Reticulum\ Manual.epub ./share/mirrors/Reticulum_Manual.epub + cp -r ../../rnode-flasher ./share/mirrors/ + -(rm ./share/mirrors/rnode-flasher/.git -rf) release: buildozer android release diff --git a/sbapp/main.py b/sbapp/main.py index 1a54f4c..22623b8 100644 --- a/sbapp/main.py +++ b/sbapp/main.py @@ -3678,6 +3678,7 @@ class SidebandApp(MDApp): ###################################### def repository_action(self, sender=None, direction="left"): if self.repository_ready: + self.repository_update_info() self.repository_open(direction=direction) else: self.loader_action(direction=direction) @@ -3714,9 +3715,9 @@ class SidebandApp(MDApp): info += "If you want to share the Sideband application itself via the repository server, you must first download it into the local repository, using the \"Update Content\" button below.\n\n" info += "To make the repository available on your local network, simply start it below, and it will become browsable on a local IP address for anyone connected to the same WiFi or wired network.\n\n" if self.sideband.webshare_server != None: - if RNS.vendor.platformutils.is_android(): - def getIP(): - adrs = [] + def getIP(): + adrs = [] + if RNS.vendor.platformutils.is_android(): try: from jnius import autoclass import ipaddress @@ -3739,24 +3740,30 @@ class SidebandApp(MDApp): RNS.log("Error while getting repository IP address: "+str(e), RNS.LOG_ERROR) return None - return adrs - - ips = getIP() - if ips == None or len(ips) == 0: - info += "The repository server is running, but the local device IP address could not be determined.\n\nYou can access the repository by pointing a browser to: http://DEVICE_IP:4444/" - self.reposository_url = None else: - ipstr = "" - for ip in ips: - ipstr += "http://"+str(ip)+":4444/\n" - self.reposository_url = ipstr + import socket + adrs.append(socket.gethostbyname(socket.gethostname())) - ms = "" if len(ips) == 1 else "es" - info += "The repository server is running at the following address"+ms+":\n [u][ref=link]"+ipstr+"[/ref][u]" - self.repository_screen.ids.repository_info.bind(on_ref_press=self.repository_link_action) + return adrs - self.repository_screen.ids.repository_enable_button.disabled = True - self.repository_screen.ids.repository_disable_button.disabled = False + ips = getIP() + if ips == None or len(ips) == 0: + info += "The repository server is running, but the local device IP address could not be determined.\n\nYou can access the repository by pointing a browser to: http://DEVICE_IP:4444/" + self.reposository_url = None + else: + ipstr = "" + for ip in ips: + ipstr += "http://"+str(ip)+":4444/\n" + self.reposository_url = ipstr + + ms = "" if len(ips) == 1 else "es" + info += "The repository server is running at the following address"+ms+":\n [u][ref=link]"+ipstr+"[/ref][u]" + self.repository_screen.ids.repository_info.bind(on_ref_press=self.repository_link_action) + + def cb(dt): + self.repository_screen.ids.repository_enable_button.disabled = True + self.repository_screen.ids.repository_disable_button.disabled = False + Clock.schedule_once(cb, 0.1) else: self.repository_screen.ids.repository_enable_button.disabled = False @@ -3778,39 +3785,85 @@ class SidebandApp(MDApp): def update_job(sender=None): try: import requests + ### RNode Firmwares ########### + if True: + downloads = [] + try: + release_url = "https://api.github.com/repos/markqvist/rnode_firmware/releases" + with requests.get(release_url) as response: + releases = response.json() + release = releases[0] + assets = release["assets"] + for asset in assets: + if asset["name"].lower().startswith("rnode_firmware"): + fw_url = asset["browser_download_url"] + pkgname = asset["name"] + fw_version = release["tag_name"] + RNS.log(f"Found version {fw_version} artefact {pkgname} at {fw_url}", RNS.LOG_DEBUG) + downloads.append([fw_url, pkgname, fw_version]) - # Get release info - apk_version = None - apk_url = None - pkgname = None - try: - release_url = "https://api.github.com/repos/markqvist/sideband/releases" - with requests.get(release_url) as response: - releases = response.json() - release = releases[0] - assets = release["assets"] - for asset in assets: - if asset["name"].lower().endswith(".apk"): - apk_url = asset["browser_download_url"] - pkgname = asset["name"] - apk_version = release["tag_name"] - RNS.log(f"Found version {apk_version} artefact {pkgname} at {apk_url}") - except Exception as e: - self.repository_screen.ids.repository_update.text = f"Downloading release info failed with the error:\n"+str(e) - return + except Exception as e: + self.repository_screen.ids.repository_update.text = f"Downloading RNode firmware release info failed with the error:\n"+str(e) + return - self.repository_screen.ids.repository_update.text = "Downloading: "+str(apk_url) - with requests.get(apk_url, stream=True) as response: - with open("./dl_tmp", "wb") as tmp_file: - cs = 32*1024 - tds = 0 - for chunk in response.iter_content(chunk_size=cs): - tmp_file.write(chunk) - tds += cs - self.repository_screen.ids.repository_update.text = "Downloaded "+RNS.prettysize(tds)+" of "+str(pkgname) + try: + for download in downloads: + fw_url = download[0] + pkgname = download[1] + self.repository_screen.ids.repository_update.text = "Downloading: "+str(pkgname) + with requests.get(fw_url, stream=True) as response: + with open("./dl_tmp", "wb") as tmp_file: + cs = 32*1024 + tds = 0 + for chunk in response.iter_content(chunk_size=cs): + tmp_file.write(chunk) + tds += cs + self.repository_screen.ids.repository_update.text = "Downloaded "+RNS.prettysize(tds)+" of "+str(pkgname) + + os.rename("./dl_tmp", f"{self.sideband.webshare_dir}/pkg/{pkgname}") + self.repository_screen.ids.repository_update.text = f"Added {pkgname} to the repository!" + + except Exception as e: + self.repository_screen.ids.repository_update.text = f"Downloading RNode firmware failed with the error:\n"+str(e) + return + + ### Sideband APK File ######### + if True: + # Get release info + apk_version = None + apk_url = None + pkgname = None + try: + release_url = "https://api.github.com/repos/markqvist/sideband/releases" + with requests.get(release_url) as response: + releases = response.json() + release = releases[0] + assets = release["assets"] + for asset in assets: + if asset["name"].lower().endswith(".apk"): + apk_url = asset["browser_download_url"] + pkgname = asset["name"] + apk_version = release["tag_name"] + RNS.log(f"Found version {apk_version} artefact {pkgname} at {apk_url}", RNS.LOG_DEBUG) + except Exception as e: + self.repository_screen.ids.repository_update.text = f"Downloading Sideband APK release info failed with the error:\n"+str(e) + return + + self.repository_screen.ids.repository_update.text = "Downloading: "+str(pkgname) + with requests.get(apk_url, stream=True) as response: + with open("./dl_tmp", "wb") as tmp_file: + cs = 32*1024 + tds = 0 + for chunk in response.iter_content(chunk_size=cs): + tmp_file.write(chunk) + tds += cs + self.repository_screen.ids.repository_update.text = "Downloaded "+RNS.prettysize(tds)+" of "+str(pkgname) + + os.rename("./dl_tmp", f"{self.sideband.webshare_dir}/pkg/{pkgname}") + self.repository_screen.ids.repository_update.text = f"Added {pkgname} to the repository!" + + self.repository_screen.ids.repository_update.text = f"Repository contents updated successfully!" - os.rename("./dl_tmp", f"./share/pkg/{pkgname}") - self.repository_screen.ids.repository_update.text = f"Added {pkgname} to the repository!" except Exception as e: self.repository_screen.ids.repository_update.text = f"Downloading contents failed with the error:\n"+str(e) @@ -3827,15 +3880,7 @@ class SidebandApp(MDApp): self.root.ids.screen_manager.add_widget(self.repository_screen) self.repository_screen.ids.repository_scrollview.effect_cls = ScrollEffect - self.repository_update_info() - - if not RNS.vendor.platformutils.is_android(): - self.widget_hide(self.repository_screen.ids.repository_enable_button) - self.widget_hide(self.repository_screen.ids.repository_disable_button) - self.widget_hide(self.repository_screen.ids.repository_download_button) - self.repository_screen.ids.repository_info.text = "\nThe [b]Repository Webserver[/b] feature is currently only available on mobile devices." - self.repository_ready = True def close_repository_action(self, sender=None): diff --git a/sbapp/share/flasher.html b/sbapp/share/flasher.html new file mode 100644 index 0000000..14bb9d3 --- /dev/null +++ b/sbapp/share/flasher.html @@ -0,0 +1,33 @@ + + + + + + +Sideband Repository + + + + +

Start | RNode Flasher | Software | Guides


+
Sideband includes a copy of the web-based RNode Flasher developed by Liam Cottle. You can use this flasher to install and provision the RNode firmware on any compatible boards.
+
+Please note! Your browser must support Web-USB for this to work.
+
+To use the flasher, you will need firmware packages for the boards you want use. You can obtain these in different ways: + +
+
+
+
+

+ diff --git a/sbapp/share/guides.html b/sbapp/share/guides.html index 143b70c..15d09ed 100644 --- a/sbapp/share/guides.html +++ b/sbapp/share/guides.html @@ -9,7 +9,7 @@ -

Start | Software | Guides


+

Start | RNode Flasher | Software | Guides



Welcome to the Guide Section!

From here, you can browse or download various included manuals, documentation, references and guides. +

\ No newline at end of file diff --git a/sbapp/share/index.html b/sbapp/share/index.html index 7143405..bc6c85d 100644 --- a/sbapp/share/index.html +++ b/sbapp/share/index.html @@ -10,7 +10,7 @@ -

Start | Software | Guides


Hello!

+

Start | RNode Flasher | Software | Guides


Hello!

diff --git a/sbapp/share/pkgs.html b/sbapp/share/pkgs.html index 0ed8470..5e86dd0 100644 --- a/sbapp/share/pkgs.html +++ b/sbapp/share/pkgs.html @@ -9,10 +9,10 @@ -

Start | Software | Guides


+

Start | RNode Flasher | Software | Guides



Welcome to the Software Library!

From here, you can download installable Python Wheel packages of Reticulum and various other auxillary programs and utilities.
    -
+

diff --git a/sbapp/sideband/core.py b/sbapp/sideband/core.py index 927fc82..70f0be3 100644 --- a/sbapp/sideband/core.py +++ b/sbapp/sideband/core.py @@ -233,7 +233,11 @@ class SidebandCore(): self.log_dir = self.app_dir+"/app_storage/" self.tmp_dir = self.app_dir+"/app_storage/tmp" self.exports_dir = self.app_dir+"/exports" - self.webshare_dir = "./share/" + if RNS.vendor.platformutils.is_android(): + self.webshare_dir = "./share/" + else: + sideband_dir = os.path.dirname(os.path.abspath(__file__)) + self.webshare_dir = os.path.abspath(os.path.join(sideband_dir, "..", "share")) self.first_run = True self.saving_configuration = False @@ -4653,7 +4657,7 @@ class SidebandCore(): self.send_response(200) self.send_header("Content-type", "text/json") self.end_headers() - json_result = json.dumps(os.listdir(serve_root+"/pkg")) + json_result = json.dumps(sorted(os.listdir(serve_root+"/pkg"))) self.wfile.write(json_result.encode("utf-8")) except Exception as e: self.send_response(500) @@ -4668,6 +4672,8 @@ class SidebandCore(): self.send_response(200) if path.lower().endswith(".apk"): self.send_header("Content-type", "application/vnd.android.package-archive") + elif path.lower().endswith(".js"): + self.send_header("Content-type", "text/javascript") self.end_headers() self.wfile.write(data) except Exception as e: @@ -4677,6 +4683,7 @@ class SidebandCore(): es = "Error" self.wfile.write(es.encode("utf-8")) + socketserver.TCPServer.allow_reuse_address = True with socketserver.TCPServer(("", port), RequestHandler) as webserver: self.webshare_server = webserver webserver.serve_forever() diff --git a/sbapp/ui/utilities.py b/sbapp/ui/utilities.py index 83907cb..66a6559 100644 --- a/sbapp/ui/utilities.py +++ b/sbapp/ui/utilities.py @@ -9,6 +9,8 @@ from kivy.utils import escape_markup from kivymd.uix.recycleview import MDRecycleView from kivymd.uix.list import OneLineIconListItem from kivymd.uix.pickers import MDColorPicker +from kivymd.uix.button import MDRectangleFlatButton +from kivymd.uix.dialog import MDDialog from kivymd.icon_definitions import md_icons from kivymd.toast import toast from kivy.properties import StringProperty, BooleanProperty @@ -48,6 +50,33 @@ class Utilities(): self.screen.ids.utilities_info.text = info + ### RNode Flasher + ###################################### + + def flasher_action(self, sender=None): + yes_button = MDRectangleFlatButton(text="Launch",font_size=dp(18), theme_text_color="Custom", line_color=self.app.color_accept, text_color=self.app.color_accept) + no_button = MDRectangleFlatButton(text="Back",font_size=dp(18)) + dialog = MDDialog( + title="RNode Flasher", + text="You can use the included web-based RNode flasher, by starting Sideband's built-in repository server, and accessing the RNode Flasher page.", + buttons=[ no_button, yes_button ], + # elevation=0, + ) + def dl_yes(s): + dialog.dismiss() + self.app.sideband.start_webshare() + def cb(dt): + self.app.repository_action() + Clock.schedule_once(cb, 0.6) + + def dl_no(s): + dialog.dismiss() + + yes_button.bind(on_release=dl_yes) + no_button.bind(on_release=dl_no) + dialog.open() + + ### rnstatus screen ###################################### @@ -194,6 +223,17 @@ MDScreen: on_release: root.delegate.logviewer_action(self) disabled: False + MDRectangleFlatIconButton: + id: flasher_button + icon: "radio-handheld" + text: "RNode Flasher" + padding: [dp(0), dp(14), dp(0), dp(14)] + icon_size: dp(24) + font_size: dp(16) + size_hint: [1.0, None] + on_release: root.delegate.flasher_action(self) + disabled: False + MDRectangleFlatIconButton: id: advanced_button icon: "network-pos"