From 140aff0c0c3d55d8c5a958cd6bed0d17f8f516ad Mon Sep 17 00:00:00 2001 From: totaam Date: Sat, 2 Sep 2023 22:41:25 +0700 Subject: [PATCH] #3930 rename for consistency with prefix --- docs/Subsystems/Logging.md | 10 +- docs/Subsystems/Notifications.md | 6 +- docs/Subsystems/README.md | 14 +- .../unit/client/mixins/notifications_test.py | 2 +- .../unit/client/mixins/remotelogging_test.py | 2 +- xpra/client/gtk3/gtk_client_base.py | 2 +- xpra/client/gui/ui_client_base.py | 4 +- xpra/client/mixins/notifications.py | 184 ------------------ xpra/client/mixins/remote_logging.py | 170 ---------------- 9 files changed, 20 insertions(+), 374 deletions(-) delete mode 100644 xpra/client/mixins/notifications.py delete mode 100644 xpra/client/mixins/remote_logging.py diff --git a/docs/Subsystems/Logging.md b/docs/Subsystems/Logging.md index c5dfd86669..22fadde40c 100644 --- a/docs/Subsystems/Logging.md +++ b/docs/Subsystems/Logging.md @@ -9,11 +9,11 @@ but it can also be used in the opposite direction. ## Implementations -| Component | Link | -|-------------------|---------------------------------------------------------------------------------| -| client | [xpra.client.mixins.remote_logging](../../xpra/client/mixins/remote_logging.py) | -| client connection | none | -| server | [xpra.server.mixins.logging](../../xpra/server/mixins/logging.py) | +| Component | Link | +|-------------------|---------------------------------------------------------------------| +| client | [xpra.client.mixins.logging](../../xpra/client/mixins/logging.py) | +| client connection | none | +| server | [xpra.server.mixins.logging](../../xpra/server/mixins/logging.py) | ## Capabilities diff --git a/docs/Subsystems/Notifications.md b/docs/Subsystems/Notifications.md index c9323a0dbe..847b9df608 100644 --- a/docs/Subsystems/Notifications.md +++ b/docs/Subsystems/Notifications.md @@ -7,7 +7,7 @@ For usage related information, see [notitications feature](../Features/Notificat | Component | Link | |-------------------|-------------------------------------------------------------------------------| -| client | [xpra.client.mixins.notifications](../../xpra/client/mixins/notifications.py) | +| client | [xpra.client.mixins.notification](../../xpra/client/mixins/notification.py) | | client connection | [xpra.server.source.notification](../../xpra/server/source/notification.py) | | server | [xpra.server.mixins.notification](../../xpra/server/mixins/notification.py) | @@ -33,7 +33,7 @@ The server exposes a single `enabled` flag using the `notifications` capability | Argument | Type | Notes | |-----------------------------|-------------------------|----------------------------------| | `dbus_id` | `integer` | 0 if unused | -| `notification id` | `integer` | should be unique | +| `notification id` | `integer` | should be unique | | `applciation name` | `string` | | | `replaced notification id` | `integer` | 0 if unused | | `application icon` | `string` | the name of the icon to show | @@ -54,6 +54,6 @@ The icon data is a list or tuple with 4 elements: | `width` | `integer` | | `height` | `integer` | | `data` | `bytes` | - + The only format which is guaranteed to be supported is `png`. Other formats should not be used. diff --git a/docs/Subsystems/README.md b/docs/Subsystems/README.md index dcf32ee26c..40963e155b 100644 --- a/docs/Subsystems/README.md +++ b/docs/Subsystems/README.md @@ -12,10 +12,10 @@ Most modules are optional, see [security considerations](../Usage/Security.md). * Server Module: feature implemented by the server, it may interact with multiple "Client Connection Modules" -| Subsystem | [Client Module](../../xpra/client/mixins/) | [Server Module](../../xpra/server/mixins) | [Client Connection Module](../../xpra/server/source/) | User Documentation | -|-------------------------------------|--------------------------------------------------------------|----------------------------------------------------|----------------------------------------------------------|---------------------------------------------------------| -| [Audio](./Audio.md) | [audio](../../xpra/client/mixins/audio.py) | [audio](../../xpra/server/mixins/audio.py) | [audio](../../xpra/server/source/audio.py) | [audio feature](../Features/Audio.md) | -| [Clipboard](./Clipboard.md) | [clipboard](../../xpra/client/mixins/clipboard.py) | [clipboard](../../xpra/server/mixins/clipboard.py) | [clipboard](../../xpra/server/source/clipboard.py) | [clipboard feature](../Features/Clipboard.md) | -| [MMAP](./MMAP.md) | [mmap](../../xpra/client/mixins/mmap.py) | [mmap](../../xpra/server/mixins/mmap.py) | [mmap](../../xpra/server/source/mmap.py) | enabled automatically | -| [Logging](./Logging.md) | [remote-logging](../../xpra/client/mixins/remote_logging.py) | [logging](../../xpra/server/mixins/logging.py) | none | [logging usage](../Usage/Logging.md) | -| [Notifications](./Notifications.md) | [notifications](../../xpra/client/mixins/notifications.py) | [logging](../../xpra/server/mixins/notification.py) | [notification](../../xpra/server/source/notification.py) | [notifications feature](../Features/Notifications.md) | +| Subsystem | [Client Module](../../xpra/client/mixins/) | [Server Module](../../xpra/server/mixins) | [Client Connection Module](../../xpra/server/source/) | User Documentation | +|-------------------------------------|--------------------------------------------------------------|-----------------------------------------------------|------------------------------------------------------------|----------------------------------------------------------| +| [Audio](./Audio.md) | [audio](../../xpra/client/mixins/audio.py) | [audio](../../xpra/server/mixins/audio.py) | [audio](../../xpra/server/source/audio.py) | [audio feature](../Features/Audio.md) | +| [Clipboard](./Clipboard.md) | [clipboard](../../xpra/client/mixins/clipboard.py) | [clipboard](../../xpra/server/mixins/clipboard.py) | [clipboard](../../xpra/server/source/clipboard.py) | [clipboard feature](../Features/Clipboard.md) | +| [MMAP](./MMAP.md) | [mmap](../../xpra/client/mixins/mmap.py) | [mmap](../../xpra/server/mixins/mmap.py) | [mmap](../../xpra/server/source/mmap.py) | enabled automatically | +| [Logging](./Logging.md) | [remote-logging](../../xpra/client/mixins/logging.py) | [logging](../../xpra/server/mixins/logging.py) | none | [logging usage](../Usage/Logging.md) | +| [Notifications](./Notifications.md) | [notifications](../../xpra/client/mixins/notification.py) | [logging](../../xpra/server/mixins/notification.py) | [notification](../../xpra/server/source/notification.py) | [notifications feature](../Features/Notifications.md) | diff --git a/tests/unittests/unit/client/mixins/notifications_test.py b/tests/unittests/unit/client/mixins/notifications_test.py index 4afdcb7d42..a1855a3774 100755 --- a/tests/unittests/unit/client/mixins/notifications_test.py +++ b/tests/unittests/unit/client/mixins/notifications_test.py @@ -7,7 +7,7 @@ import unittest from xpra.util import AdHocStruct -from xpra.client.mixins.notifications import NotificationClient +from xpra.client.mixins.notification import NotificationClient from unit.client.mixins.clientmixintest_util import ClientMixinTest diff --git a/tests/unittests/unit/client/mixins/remotelogging_test.py b/tests/unittests/unit/client/mixins/remotelogging_test.py index c3174af472..f4122ae2d5 100755 --- a/tests/unittests/unit/client/mixins/remotelogging_test.py +++ b/tests/unittests/unit/client/mixins/remotelogging_test.py @@ -7,7 +7,7 @@ import unittest from xpra.util import AdHocStruct -from xpra.client.mixins import remote_logging +from xpra.client.mixins import logging from unit.test_util import silence_info from unit.client.mixins.clientmixintest_util import ClientMixinTest diff --git a/xpra/client/gtk3/gtk_client_base.py b/xpra/client/gtk3/gtk_client_base.py index 8dbfc694f2..8e0a41945c 100644 --- a/xpra/client/gtk3/gtk_client_base.py +++ b/xpra/client/gtk3/gtk_client_base.py @@ -260,7 +260,7 @@ def get_notifier_classes(self) -> list[type]: #use the native ones first: from xpra.client.gui import mixin_features assert mixin_features.notifications - from xpra.client.mixins.notifications import NotificationClient + from xpra.client.mixins.notification import NotificationClient assert isinstance(self, NotificationClient) ncs = NotificationClient.get_notifier_classes(self) try: diff --git a/xpra/client/gui/ui_client_base.py b/xpra/client/gui/ui_client_base.py index cf005ddde2..e4537f2bd5 100644 --- a/xpra/client/gui/ui_client_base.py +++ b/xpra/client/gui/ui_client_base.py @@ -54,13 +54,13 @@ from xpra.client.mixins.clipboard import ClipboardClient CLIENT_BASES.append(ClipboardClient) if mixin_features.notifications: - from xpra.client.mixins.notifications import NotificationClient + from xpra.client.mixins.notification import NotificationClient CLIENT_BASES.append(NotificationClient) if mixin_features.mmap: from xpra.client.mixins.mmap import MmapClient CLIENT_BASES.append(MmapClient) if mixin_features.logging: - from xpra.client.mixins.remote_logging import RemoteLogging + from xpra.client.mixins.logging import RemoteLogging CLIENT_BASES.append(RemoteLogging) if mixin_features.network_state: from xpra.client.mixins.network_state import NetworkState diff --git a/xpra/client/mixins/notifications.py b/xpra/client/mixins/notifications.py deleted file mode 100644 index 30cbbace71..0000000000 --- a/xpra/client/mixins/notifications.py +++ /dev/null @@ -1,184 +0,0 @@ -# This file is part of Xpra. -# Copyright (C) 2010-2023 Antoine Martin -# Xpra is released under the terms of the GNU GPL v2, or, at your option, any -# later version. See the file COPYING for details. -#pylint: disable-msg=E1101 - -from typing import Any - -from xpra.platform.paths import get_icon_filename -from xpra.platform.gui import get_native_notifier_classes -from xpra.net.common import PacketType -from xpra.util import envbool, repr_ellipsized, make_instance, typedict -from xpra.client.base.stub_client_mixin import StubClientMixin -from xpra.log import Logger - -log = Logger("notify") - -NATIVE_NOTIFIER = envbool("XPRA_NATIVE_NOTIFIER", True) -THREADED_NOTIFICATIONS = envbool("XPRA_THREADED_NOTIFICATIONS", True) - - -class NotificationClient(StubClientMixin): - """ - Mixin for clients that handle notifications - """ - - def __init__(self): - super().__init__() - self.client_supports_notifications = False - self.server_notifications = False - self.notifications_enabled = False - self.notifier = None - self.tray = None - self.callbacks = {} - #override the default handler in client base: - self.may_notify = self.do_notify - - def init(self, opts): - if opts.notifications: - try: - from xpra import notifications - assert notifications - except ImportError: - log.warn("Warning: notifications module not found") - else: - self.client_supports_notifications = True - self.notifier = self.make_notifier() - log("using notifier=%s", self.notifier) - self.client_supports_notifications = self.notifier is not None - - - def cleanup(self): - n = self.notifier - log("NotificationClient.cleanup() notifier=%s", n) - if n: - self.notifier = None - with log.trap_error(f"Error on notifier {n!r} cleanup"): - n.cleanup() - - - def parse_server_capabilities(self, c : typedict) -> bool: - self.server_notifications = "notifications" in c - self.notifications_enabled = self.client_supports_notifications - return True - - - def get_caps(self) -> dict[str,Any]: - enabled = self.client_supports_notifications - return { - "notifications" : { - "enabled" : enabled, - }, - } - - - def init_authenticated_packet_handlers(self): - self.add_packet_handler("notify_show", self._process_notify_show) - self.add_packet_handler("notify_close", self._process_notify_close) - - def make_notifier(self): - nc = self.get_notifier_classes() - log("make_notifier() notifier classes: %s", nc) - return make_instance(nc, self.notification_closed, self.notification_action) - - def notification_closed(self, nid, reason=3, text=""): - log("notification_closed(%i, %i, %s) server notification.close=%s", - nid, reason, text, self.server_notifications_close) - callback = self.callbacks.pop(nid, None) - if callback: - callback("notification-close", nid, reason, text) - elif self.server_notifications_close: - self.send("notification-close", nid, reason, text) - - def notification_action(self, nid, action_id): - log("notification_action(%i, %s)", nid, action_id) - callback = self.callbacks.get(nid, None) - if callback: - callback("notification-action", nid, action_id) - else: - self.send("notification-action", nid, action_id) - - def get_notifier_classes(self): - #subclasses will generally add their toolkit specific variants - #by overriding this method - #use the native ones first: - if not NATIVE_NOTIFIER: - return [] - return get_native_notifier_classes() - - def do_notify(self, nid, summary, body, actions=(), - hints=None, expire_timeout=10*1000, icon_name=None, callback=None): - log("do_notify%s client_supports_notifications=%s, notifier=%s", - (nid, summary, body, actions, hints, expire_timeout, icon_name), - self.client_supports_notifications, self.notifier) - if callback: - self.callbacks[nid] = callback - n = self.notifier - if not self.client_supports_notifications or not n: - #just log it instead: - log.info("%s", summary) - if body: - for x in body.splitlines(): - log.info(" %s", x) - return - def show_notification(): - try: - from xpra.notifications.common import parse_image_path - icon_filename = get_icon_filename(icon_name) - icon = parse_image_path(icon_filename) - n.show_notify("", self.tray, nid, "Xpra", nid, "", - summary, body, actions, hints or {}, expire_timeout, icon) - except Exception as e: - log("failed to show notification", exc_info=True) - log.error("Error: cannot show notification") - log.error(" '%s'", summary) - log.estr(e) - if THREADED_NOTIFICATIONS: - show_notification() - else: - self.idle_add(show_notification) - - def _process_notify_show(self, packet : PacketType): - if not self.notifications_enabled: - log("process_notify_show: ignoring packet, notifications are disabled") - return - self._ui_event() - dbus_id = packet[1] - nid = int(packet[2]) - app_name = str(packet[3]) - replaces_nid = int(packet[4]) - app_icon = packet[5] - summary = str(packet[6]) - body = str(packet[7]) - expire_timeout = int(packet[8]) - icon = None - actions, hints = [], {} - if len(packet)>=10: - icon = packet[9] - if len(packet)>=12: - actions, hints = packet[10], packet[11] - #note: if the server doesn't support notification forwarding, - #it can still send us the messages (via xpra control or the dbus interface) - log("_process_notify_show(%s) notifier=%s, server_notifications=%s", - repr_ellipsized(packet), self.notifier, self.server_notifications) - log("notification actions=%s, hints=%s", actions, hints) - assert self.notifier - #this one of the few places where we actually do care about character encoding: - tray = self.get_tray_window(app_name, hints) - log("get_tray_window(%s)=%s", app_name, tray) - self.notifier.show_notify(dbus_id, tray, nid, - app_name, replaces_nid, app_icon, - summary, body, actions, hints, expire_timeout, icon) - - def _process_notify_close(self, packet : PacketType): - if not self.notifications_enabled: - return - assert self.notifier - nid = packet[1] - log("_process_notify_close(%s)", nid) - self.notifier.close_notify(nid) - - def get_tray_window(self, _app_name, _hints): - #overridden in subclass to use the correct window if we can find it - return self.tray diff --git a/xpra/client/mixins/remote_logging.py b/xpra/client/mixins/remote_logging.py deleted file mode 100644 index 9c8cea5d67..0000000000 --- a/xpra/client/mixins/remote_logging.py +++ /dev/null @@ -1,170 +0,0 @@ -# This file is part of Xpra. -# Copyright (C) 2010-2023 Antoine Martin -# Xpra is released under the terms of the GNU GPL v2, or, at your option, any -# later version. See the file COPYING for details. - -import sys -import logging -import traceback -from time import monotonic -from threading import Lock - -from xpra.util import csv, typedict, repr_ellipsized -from xpra.client.base.stub_client_mixin import StubClientMixin -from xpra.log import Logger, set_global_logging_handler -from xpra.net.common import PacketType - -log = Logger("client") - - -class RemoteLogging(StubClientMixin): - """ - Mixin for remote logging support, - either sending local logging events to the server, - or receiving logging events from the server. - """ - - def __init__(self): - super().__init__() - self.remote_logging = "no" - self.in_remote_logging = False - self.local_logging = None - self.logging_lock = Lock() - self.log_both = False - self.request_server_log = False - self.monotonic_start_time = monotonic() - - def init(self, opts): - self.remote_logging = opts.remote_logging - self.log_both = (opts.remote_logging or "").lower()=="both" - - - def cleanup(self): - ll = self.local_logging - log("cleanup() local_logging=%s", ll) - if ll: - self.local_logging = None - set_global_logging_handler(ll) - - - def parse_server_capabilities(self, c : typedict) -> bool: - receive = c.boolget("remote-logging.receive") - send = c.boolget("remote-logging.send") - v = c.get("remote-logging") - if isinstance(v, dict): - c = typedict(v) - receive = c.boolget("receive") - send = c.boolget("send") - if self.remote_logging.lower() in ("send", "both", "yes", "true", "on") and receive: - #check for debug: - from xpra.log import is_debug_enabled - conflict = tuple(v for v in ("network", "crypto", "websocket", "quic") if is_debug_enabled(v)) - if conflict: - log.warn("Warning: cannot enable remote logging") - log.warn(" because debug logging is enabled for: %s", csv(conflict)) - return True - log.info("enabled remote logging") - if not self.log_both: - log.info(" see server log file for further output") - self.local_logging = set_global_logging_handler(self.remote_logging_handler) - elif self.remote_logging.lower()=="receive": - self.request_server_log = send - if not self.request_server_log: - log.warn("Warning: cannot receive log output from the server") - log.warn(" the feature is not enabled or not supported by the server") - else: - self.after_handshake(self.start_receiving_logging) #pylint: disable=no-member - return True - - def start_receiving_logging(self) -> None: - self.add_packet_handler("logging", self._process_logging, False) - self.send("logging-control", "start") - - #def stop_receiving_logging(self): - # self.send("logging-control", "stop") - - def _process_logging(self, packet : PacketType) -> None: - assert not self.local_logging, "cannot receive logging packets when forwarding logging!" - level = int(packet[1]) - msg = packet[2] - prefix = "server: " - if len(packet)>=4: - dtime = packet[3] - prefix += "@%02i.%03i " % ((dtime//1000)%60, dtime%1000) - try: - if isinstance(msg, (tuple, list)): - dmsg = " ".join(str(x) for x in msg) - else: - dmsg = str(msg) - for l in dmsg.splitlines(): - self.do_log(level, prefix+l) - except Exception as e: - log("log message decoding error", exc_info=True) - log.error("Error: failed to parse logging message:") - log.error(" %s", repr_ellipsized(msg)) - log.estr(e) - - def do_log(self, level:int, line) -> None: - with self.logging_lock: - log.log(level, line) - - - def remote_logging_handler(self, logger_log, level:int, msg:str, *args, **kwargs) -> None: - #prevent loops (if our send call ends up firing another logging call): - if self.in_remote_logging: - return - self.in_remote_logging = True - ll = self.local_logging - def local_warn(*args): - if ll: - ll(logger_log, logging.WARNING, *args) - try: - dtime = int(1000*(monotonic() - self.monotonic_start_time)) - if args: - data = msg % args - else: - data = msg - if len(data)>=32: - try: - data = self.compressed_wrapper("text", data.encode("utf8"), level=1) - except Exception: - pass - self.send("logging", level, data, dtime) - exc_info = kwargs.get("exc_info") - if exc_info is True: - exc_info = sys.exc_info() - if exc_info and exc_info[0]: - for x in traceback.format_tb(exc_info[2]): - self.send("logging", level, x, dtime) - try: - etypeinfo = exc_info[0].__name__ - except AttributeError: - etypeinfo = str(exc_info[0]) - self.send("logging", level, f"{etypeinfo}: {exc_info[1]}", dtime) - if self.log_both and ll: - ll(logger_log, level, msg, *args, **kwargs) - except Exception as e: - if self.exit_code is not None: - #errors can happen during exit, don't care - return - local_warn("Warning: failed to send logging packet:") - local_warn(f" {e}") - local_warn(f" original unformatted message: {msg}") - if args: - local_warn(f" {len(args)} arguments: {args}") - else: - local_warn(" (no arguments)") - if ll: - try: - ll(logger_log, level, msg, *args, **kwargs) - except Exception: - pass - try: - exc_info = sys.exc_info() - for x in traceback.format_tb(exc_info[2]): - for v in x.splitlines(): - local_warn(v) - except Exception: - pass - finally: - self.in_remote_logging = False