From 468d4145b7c745179235895b3986c4aa80bf97e2 Mon Sep 17 00:00:00 2001 From: Mark Qvist Date: Sun, 29 Oct 2023 16:54:12 +0100 Subject: [PATCH] Added daemon mode --- sbapp/main.py | 226 +++++++++++++++++++++++------------------ sbapp/sideband/core.py | 21 ++-- sbapp/ui/layouts.py | 8 +- sbapp/ui/telemetry.py | 19 ++++ 4 files changed, 162 insertions(+), 112 deletions(-) diff --git a/sbapp/main.py b/sbapp/main.py index 97c654b..b346a78 100644 --- a/sbapp/main.py +++ b/sbapp/main.py @@ -1,4 +1,4 @@ -__debug_build__ = False +__debug_build__ = True __disable_shaders__ = False __version__ = "0.7.0" __variant__ = "beta" @@ -7,6 +7,7 @@ import sys import argparse parser = argparse.ArgumentParser(description="Sideband LXMF Client") parser.add_argument("-v", "--verbose", action='store_true', default=False, help="increase logging verbosity") +parser.add_argument("-d", "--daemon", action='store_true', default=False, help="run as a daemon, without user interface") parser.add_argument("--version", action="version", version="sideband {version}".format(version=__version__)) args = parser.parse_args() sys.argv = [sys.argv[0]] @@ -16,103 +17,122 @@ import LXMF import time import os import pathlib -import plyer import base64 import threading import RNS.vendor.umsgpack as msgpack -from kivy.logger import Logger, LOG_LEVELS +if not args.daemon: + import plyer + from kivy.logger import Logger, LOG_LEVELS -# Squelch excessive method signature logging -class redirect_log(): - def isEnabledFor(self, arg): - return False - def debug(self, arg): - pass - def trace(self, arg): - pass - def warning(self, arg): - RNS.log("Kivy error: "+str(arg), RNS.LOG_WARNING) - def critical(self, arg): - RNS.log("Kivy error: "+str(arg), RNS.LOG_ERROR) + # Squelch excessive method signature logging + class redirect_log(): + def isEnabledFor(self, arg): + return False + def debug(self, arg): + pass + def trace(self, arg): + pass + def warning(self, arg): + RNS.log("Kivy error: "+str(arg), RNS.LOG_WARNING) + def critical(self, arg): + RNS.log("Kivy error: "+str(arg), RNS.LOG_ERROR) -if RNS.vendor.platformutils.get_platform() == "android": - import jnius.reflect - def mod(method, name, signature): - pass - jnius.reflect.log_method = mod - jnius.reflect.log = redirect_log() + if RNS.vendor.platformutils.get_platform() == "android": + import jnius.reflect + def mod(method, name, signature): + pass + jnius.reflect.log_method = mod + jnius.reflect.log = redirect_log() -if __debug_build__ or args.verbose: - Logger.setLevel(LOG_LEVELS["debug"]) -else: - Logger.setLevel(LOG_LEVELS["error"]) + if __debug_build__ or args.verbose: + Logger.setLevel(LOG_LEVELS["debug"]) + else: + Logger.setLevel(LOG_LEVELS["error"]) -if RNS.vendor.platformutils.get_platform() != "android": - local = os.path.dirname(__file__) - sys.path.append(local) + if RNS.vendor.platformutils.get_platform() != "android": + local = os.path.dirname(__file__) + sys.path.append(local) -from kivymd.app import MDApp -from kivy.core.window import Window -from kivy.core.clipboard import Clipboard -from kivy.base import EventLoop -from kivy.clock import Clock -from kivy.lang.builder import Builder -from kivy.effects.scroll import ScrollEffect -from kivy.uix.screenmanager import ScreenManager -from kivy.uix.screenmanager import FadeTransition, NoTransition -from kivymd.uix.list import OneLineIconListItem -from kivy.properties import StringProperty -from kivymd.uix.button import BaseButton, MDIconButton -from kivymd.uix.filemanager import MDFileManager -from kivymd.toast import toast -from sideband.sense import Telemeter -from mapview import CustomMapMarker -from mapview.mbtsource import MBTilesMapSource -from mapview.source import MapSource -import webbrowser - -import kivy.core.image -kivy.core.image.Logger = redirect_log() - -if RNS.vendor.platformutils.get_platform() == "android": - from sideband.core import SidebandCore - - from ui.layouts import * - from ui.conversations import Conversations, MsgSync, NewConv - from ui.telemetry import Telemetry - from ui.objectdetails import ObjectDetails - from ui.announces import Announces - from ui.messages import Messages, ts_format, messages_screen_kv - from ui.helpers import ContentNavigationDrawer, DrawerList, IconListItem - - from jnius import cast - from jnius import autoclass - from android import mActivity - from android.permissions import request_permissions, check_permission - from android.storage import primary_external_storage_path, secondary_external_storage_path - - from kivymd.utils.set_bars_colors import set_bars_colors - android_api_version = autoclass('android.os.Build$VERSION').SDK_INT - -else: +if args.daemon: from .sideband.core import SidebandCore + class DaemonElement(): + pass + class DaemonApp(): + pass - from .ui.layouts import * - from .ui.conversations import Conversations, MsgSync, NewConv - from .ui.announces import Announces - from .ui.telemetry import Telemetry - from .ui.objectdetails import ObjectDetails - from .ui.messages import Messages, ts_format, messages_screen_kv - from .ui.helpers import ContentNavigationDrawer, DrawerList, IconListItem + MDApp = DaemonApp; OneLineIconListItem = DaemonElement; Window = DaemonElement; Clipboard = DaemonElement + EventLoop = DaemonElement; Clock = DaemonElement; Builder = DaemonElement; ScrollEffect = DaemonElement; + ScreenManager = DaemonElement; FadeTransition = DaemonElement; NoTransition = DaemonElement; OneLineIconListItem = DaemonElement; + StringProperty = DaemonElement; BaseButton = DaemonElement; MDIconButton = DaemonElement; MDFileManager = DaemonElement; + toast = DaemonElement; dp = DaemonElement; sp = DaemonElement; MDRectangleFlatButton = DaemonElement; MDDialog = DaemonElement; + colors = DaemonElement; Telemeter = DaemonElement; CustomMapMarker = DaemonElement; MBTilesMapSource = DaemonElement; + MapSource = DaemonElement; webbrowser = DaemonElement; Conversations = DaemonElement; MsgSync = DaemonElement; + NewConv = DaemonElement; Telemetry = DaemonElement; ObjectDetails = DaemonElement; Announces = DaemonElement; + Messages = DaemonElement; ts_format = DaemonElement; messages_screen_kv = DaemonElement; plyer = DaemonElement; + ContentNavigationDrawer = DaemonElement; DrawerList = DaemonElement; IconListItem = DaemonElement; - from kivy.config import Config - Config.set('input', 'mouse', 'mouse,disable_multitouch') +else: + from kivymd.app import MDApp + app_superclass = MDApp + from kivy.core.window import Window + from kivy.core.clipboard import Clipboard + from kivy.base import EventLoop + from kivy.clock import Clock + from kivy.lang.builder import Builder + from kivy.effects.scroll import ScrollEffect + from kivy.uix.screenmanager import ScreenManager + from kivy.uix.screenmanager import FadeTransition, NoTransition + from kivymd.uix.list import OneLineIconListItem + from kivy.properties import StringProperty + from kivymd.uix.button import BaseButton, MDIconButton + from kivymd.uix.filemanager import MDFileManager + from kivymd.toast import toast + from kivy.metrics import dp, sp + from kivymd.uix.button import MDRectangleFlatButton + from kivymd.uix.dialog import MDDialog + from kivymd.color_definitions import colors + from sideband.sense import Telemeter + from mapview import CustomMapMarker + from mapview.mbtsource import MBTilesMapSource + from mapview.source import MapSource + import webbrowser + import kivy.core.image + kivy.core.image.Logger = redirect_log() -from kivy.metrics import dp, sp -from kivymd.uix.button import MDRectangleFlatButton -from kivymd.uix.dialog import MDDialog -from kivymd.color_definitions import colors + if RNS.vendor.platformutils.get_platform() == "android": + from sideband.core import SidebandCore + + from ui.layouts import * + from ui.conversations import Conversations, MsgSync, NewConv + from ui.telemetry import Telemetry + from ui.objectdetails import ObjectDetails + from ui.announces import Announces + from ui.messages import Messages, ts_format, messages_screen_kv + from ui.helpers import ContentNavigationDrawer, DrawerList, IconListItem + + from jnius import cast + from jnius import autoclass + from android import mActivity + from android.permissions import request_permissions, check_permission + from android.storage import primary_external_storage_path, secondary_external_storage_path + + from kivymd.utils.set_bars_colors import set_bars_colors + android_api_version = autoclass('android.os.Build$VERSION').SDK_INT + + else: + from .sideband.core import SidebandCore + + from .ui.layouts import * + from .ui.conversations import Conversations, MsgSync, NewConv + from .ui.announces import Announces + from .ui.telemetry import Telemetry + from .ui.objectdetails import ObjectDetails + from .ui.messages import Messages, ts_format, messages_screen_kv + from .ui.helpers import ContentNavigationDrawer, DrawerList, IconListItem + + from kivy.config import Config + Config.set('input', 'mouse', 'mouse,disable_multitouch') dark_theme_text_color = "ddd" @@ -3841,22 +3861,30 @@ class CustomOneLineIconListItem(OneLineIconListItem): class MDMapIconButton(MDIconButton): pass -from kivy.base import ExceptionManager, ExceptionHandler -class SidebandExceptionHandler(ExceptionHandler): - def handle_exception(self, e): - etype = type(e) - if etype != SystemExit: - import traceback - exception_info = "".join(traceback.TracebackException.from_exception(e).format()) - RNS.log(f"An unhandled {str(type(e))} exception occurred: {str(e)}", RNS.LOG_ERROR) - RNS.log(exception_info, RNS.LOG_ERROR) - return ExceptionManager.PASS - else: - return ExceptionManager.RAISE +if not args.daemon: + from kivy.base import ExceptionManager, ExceptionHandler + class SidebandExceptionHandler(ExceptionHandler): + def handle_exception(self, e): + etype = type(e) + if etype != SystemExit: + import traceback + exception_info = "".join(traceback.TracebackException.from_exception(e).format()) + RNS.log(f"An unhandled {str(type(e))} exception occurred: {str(e)}", RNS.LOG_ERROR) + RNS.log(exception_info, RNS.LOG_ERROR) + return ExceptionManager.PASS + else: + return ExceptionManager.RAISE def run(): - ExceptionManager.add_handler(SidebandExceptionHandler()) - SidebandApp().run() + if args.daemon: + RNS.log("Starting Sideband in daemon mode") + sideband = SidebandCore(None, is_client=False, verbose=(args.verbose or __debug_build__)) + sideband.start() + while True: + time.sleep(5) + else: + ExceptionManager.add_handler(SidebandExceptionHandler()) + SidebandApp().run() if __name__ == "__main__": run() diff --git a/sbapp/sideband/core.py b/sbapp/sideband/core.py index e8112f1..805829f 100644 --- a/sbapp/sideband/core.py +++ b/sbapp/sideband/core.py @@ -519,6 +519,8 @@ class SidebandCore(): self.config["telemetry_send_appearance"] = False if not "telemetry_display_trusted_only" in self.config: self.config["telemetry_display_trusted_only"] = False + if not "telemetry_receive_trusted_only" in self.config: + self.config["telemetry_receive_trusted_only"] = False if not "telemetry_s_location" in self.config: self.config["telemetry_s_location"] = False @@ -1824,16 +1826,17 @@ class SidebandCore(): packed_telemetry = None if not originator and lxm.fields != None: - if LXMF.FIELD_ICON_APPEARANCE in lxm.fields: - self._db_update_appearance(context_dest, lxm.timestamp, lxm.fields[LXMF.FIELD_ICON_APPEARANCE]) + if self.config["telemetry_receive_trusted_only"] == False or (self.config["telemetry_receive_trusted_only"] == True and self.is_trusted(context_dest)): + if LXMF.FIELD_ICON_APPEARANCE in lxm.fields: + self._db_update_appearance(context_dest, lxm.timestamp, lxm.fields[LXMF.FIELD_ICON_APPEARANCE]) - if LXMF.FIELD_TELEMETRY in lxm.fields: - physical_link = {} - if lxm.rssi or lxm.snr or lxm.q: - physical_link["rssi"] = lxm.rssi - physical_link["snr"] = lxm.snr - physical_link["q"] = lxm.q - packed_telemetry = self._db_save_telemetry(context_dest, lxm.fields[LXMF.FIELD_TELEMETRY], physical_link=physical_link, source_dest=context_dest) + if LXMF.FIELD_TELEMETRY in lxm.fields: + physical_link = {} + if lxm.rssi or lxm.snr or lxm.q: + physical_link["rssi"] = lxm.rssi + physical_link["snr"] = lxm.snr + physical_link["q"] = lxm.q + packed_telemetry = self._db_save_telemetry(context_dest, lxm.fields[LXMF.FIELD_TELEMETRY], physical_link=physical_link, source_dest=context_dest) db = self.__db_connect() dbc = db.cursor() diff --git a/sbapp/ui/layouts.py b/sbapp/ui/layouts.py index 52835ff..8d55b5f 100644 --- a/sbapp/ui/layouts.py +++ b/sbapp/ui/layouts.py @@ -989,11 +989,11 @@ MDScreen: [['menu', lambda x: root.app.nav_drawer.set_state("open")]] right_action_items: [ - # ['format-list-bulleted-type', lambda x: root.app.map_object_list(self)], # Object List - # ['arrow-down-bold-hexagon-outline', lambda x: root.app.telemetry_request_action(self)], # Download telemetry - # ['upload-lock', lambda x: root.app.telemetry_send_update(self)], # Send telemetry update - ['layers', lambda x: root.app.map_layers_action(self)], + ['format-list-bulleted-type', lambda x: root.app.map_object_list(self)], # Object List + ['arrow-down-bold-hexagon-outline', lambda x: root.app.telemetry_request_action(self)], # Download telemetry + ['upload-lock', lambda x: root.app.telemetry_send_update(self)], # Send telemetry update ['wrench-cog', lambda x: root.app.map_settings_action(self)], + ['layers', lambda x: root.app.map_layers_action(self)], ['close', lambda x: root.app.close_any_action(self)], ] diff --git a/sbapp/ui/telemetry.py b/sbapp/ui/telemetry.py index b93498f..ddf9481 100644 --- a/sbapp/ui/telemetry.py +++ b/sbapp/ui/telemetry.py @@ -58,6 +58,9 @@ class Telemetry(): self.screen.ids.telemetry_display_trusted_only.active = self.app.sideband.config["telemetry_display_trusted_only"] self.screen.ids.telemetry_display_trusted_only.bind(active=self.telemetry_save) + self.screen.ids.telemetry_receive_trusted_only.active = self.app.sideband.config["telemetry_receive_trusted_only"] + self.screen.ids.telemetry_receive_trusted_only.bind(active=self.telemetry_save) + self.screen.ids.telemetry_send_appearance.active = self.app.sideband.config["telemetry_send_appearance"] self.screen.ids.telemetry_send_appearance.bind(active=self.telemetry_save) @@ -212,6 +215,7 @@ class Telemetry(): self.app.sideband.config["telemetry_send_to_trusted"] = self.screen.ids.telemetry_send_to_trusted.active self.app.sideband.config["telemetry_display_trusted_only"] = self.screen.ids.telemetry_display_trusted_only.active self.app.sideband.config["telemetry_send_appearance"] = self.screen.ids.telemetry_send_appearance.active + self.app.sideband.config["telemetry_receive_trusted_only"] = self.screen.ids.telemetry_receive_trusted_only.active self.app.sideband.save_configuration() if run_telemetry_update: @@ -545,6 +549,21 @@ MDScreen: pos_hint: {"center_y": 0.3} active: False + MDBoxLayout: + orientation: "horizontal" + size_hint_y: None + padding: [0,0,dp(24),dp(0)] + height: dp(48) + + MDLabel: + text: "Only receive from trusted" + font_style: "H6" + + MDSwitch: + id: telemetry_receive_trusted_only + pos_hint: {"center_y": 0.3} + active: False + MDBoxLayout: orientation: "horizontal" size_hint_y: None