diff --git a/onionshare_gui/event_handler.py b/onionshare_gui/event_handler.py deleted file mode 100644 index f4d10c24..00000000 --- a/onionshare_gui/event_handler.py +++ /dev/null @@ -1,89 +0,0 @@ -# -*- coding: utf-8 -*- -""" -OnionShare | https://onionshare.org/ - -Copyright (C) 2014-2018 Micah Lee - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -""" -import json -import os -from watchdog.observers import Observer -from watchdog.events import FileSystemEventHandler, FileModifiedEvent -from PyQt5 import QtCore - - -class EventHandler(FileSystemEventHandler, QtCore.QObject): - """ - To trigger an event, write a JSON line to the events file. When that file changes, - each line will be handled as an event. Valid events are: - {"type": "new_tab"} - {"type": "new_share_tab", "filenames": ["file1", "file2"]} - """ - - new_tab = QtCore.pyqtSignal() - new_share_tab = QtCore.pyqtSignal(list) - - def __init__(self, common): - super(EventHandler, self).__init__() - self.common = common - - def on_modified(self, event): - if ( - type(event) == FileModifiedEvent - and event.src_path == self.common.gui.events_filename - ): - # Read all the lines in the events, then delete it - with open(self.common.gui.events_filename, "r") as f: - lines = f.readlines() - os.remove(self.common.gui.events_filename) - - self.common.log( - "EventHandler", "on_modified", f"processing {len(lines)} lines" - ) - for line in lines: - try: - obj = json.loads(line) - if "type" not in obj: - self.common.log( - "EventHandler", - "on_modified", - f"event does not have a type: {obj}", - ) - continue - except json.decoder.JSONDecodeError: - self.common.log( - "EventHandler", "on_modified", f"ignoring invalid line: {line}" - ) - continue - - if obj["type"] == "new_tab": - self.common.log("EventHandler", "on_modified", "new_tab event") - self.new_tab.emit() - - elif obj["type"] == "new_share_tab": - if "filenames" in obj and type(obj["filenames"]) is list: - self.new_share_tab.emit(obj["filenames"]) - else: - self.common.log( - "EventHandler", - "on_modified", - f"invalid new_share_tab event: {obj}", - ) - - else: - self.common.log( - "EventHandler", "on_modified", f"invalid event type: {obj}" - ) - diff --git a/onionshare_gui/tab_widget.py b/onionshare_gui/tab_widget.py index d69931c0..7d8283fc 100644 --- a/onionshare_gui/tab_widget.py +++ b/onionshare_gui/tab_widget.py @@ -18,13 +18,12 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ from PyQt5 import QtCore, QtWidgets, QtGui -from watchdog.observers import Observer from onionshare import strings from onionshare.mode_settings import ModeSettings from .tab import Tab -from .event_handler import EventHandler +from .threads import EventHandlerThread class TabWidget(QtWidgets.QTabWidget): @@ -72,17 +71,15 @@ class TabWidget(QtWidgets.QTabWidget): self.move_new_tab_button() # Watch the events file for changes - self.event_handler = EventHandler(common) - self.event_handler.new_tab.connect(self.add_tab) - self.event_handler.new_share_tab.connect(self.new_share_tab) - self.observer = Observer() - self.observer.schedule(self.event_handler, self.common.gui.events_dir) - self.observer.start() + self.event_handler_t = EventHandlerThread(common) + self.event_handler_t.new_tab.connect(self.add_tab) + self.event_handler_t.new_share_tab.connect(self.new_share_tab) + self.event_handler_t.start() def cleanup(self): # Stop the event thread - self.observer.stop() - self.observer.join() + self.event_handler_t.stop() + self.event_handler_t.join() # Clean up each tab for index in range(self.count()): diff --git a/onionshare_gui/threads.py b/onionshare_gui/threads.py index 785e6ece..f3e01c12 100644 --- a/onionshare_gui/threads.py +++ b/onionshare_gui/threads.py @@ -18,6 +18,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ import time +import json +import os from PyQt5 import QtCore from onionshare import strings @@ -166,3 +168,83 @@ class AutoStartTimer(QtCore.QThread): except ValueError as e: self.error.emit(e.args[0]) return + + +class EventHandlerThread(QtCore.QThread): + """ + To trigger an event, write a JSON line to the events file. When that file changes, + each line will be handled as an event. Valid events are: + {"type": "new_tab"} + {"type": "new_share_tab", "filenames": ["file1", "file2"]} + """ + + new_tab = QtCore.pyqtSignal() + new_share_tab = QtCore.pyqtSignal(list) + + def __init__(self, common): + super(EventHandler, self).__init__() + self.common = common + self.common.log("EventHandlerThread", "__init__") + + def run(self): + self.common.log("EventHandlerThread", "run") + + mtime = os.stat(self.common.gui.events_filename).st_mtime + + while True: + if os.path.exist(self.common.gui.events_filename): + # Events file exists + if os.stat(self.common.gui.events_filename).st_mtime != mtime: + # Events file has been modified, load events + try: + with open(self.common.gui.events_filename, "r") as f: + lines = f.readlines() + os.remove(self.common.gui.events_filename) + + self.common.log( + "EventHandler", "run", f"processing {len(lines)} lines" + ) + for line in lines: + try: + obj = json.loads(line) + if "type" not in obj: + self.common.log( + "EventHandler", + "run", + f"event does not have a type: {obj}", + ) + continue + except json.decoder.JSONDecodeError: + self.common.log( + "EventHandler", + "run", + f"ignoring invalid line: {line}", + ) + continue + + if obj["type"] == "new_tab": + self.common.log("EventHandler", "run", "new_tab event") + self.new_tab.emit() + + elif obj["type"] == "new_share_tab": + if ( + "filenames" in obj + and type(obj["filenames"]) is list + ): + self.new_share_tab.emit(obj["filenames"]) + else: + self.common.log( + "EventHandler", + "run", + f"invalid new_share_tab event: {obj}", + ) + + else: + self.common.log( + "EventHandler", "run", f"invalid event type: {obj}" + ) + + except: + pass + + time.sleep(0.2) diff --git a/poetry.lock b/poetry.lock index 400669a2..cc053fa4 100644 --- a/poetry.lock +++ b/poetry.lock @@ -193,14 +193,6 @@ version = "20.3" pyparsing = ">=2.0.2" six = "*" -[[package]] -category = "main" -description = "File system general utilities" -name = "pathtools" -optional = false -python-versions = "*" -version = "0.1.2" - [[package]] category = "main" description = "Python PE parsing module" @@ -403,20 +395,6 @@ brotli = ["brotlipy (>=0.6.0)"] secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"] -[[package]] -category = "main" -description = "Filesystem events monitoring" -name = "watchdog" -optional = false -python-versions = "*" -version = "0.10.2" - -[package.dependencies] -pathtools = ">=0.1.1" - -[package.extras] -watchmedo = ["PyYAML (>=3.10)", "argh (>=0.24.1)"] - [[package]] category = "dev" description = "Measures number of Terminal column cells of wide-character codes" @@ -451,7 +429,7 @@ docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] testing = ["jaraco.itertools", "func-timeout"] [metadata] -content-hash = "41d68ea93701fdaa1aa56159195db7a65863e3b34cc7305ef4a3f5d02f2bdf13" +content-hash = "7a4a60fcd1c6d6345fec30e7fbe87681288929468d069896acad0f23b9e90f5a" python-versions = "^3.7" [metadata.files] @@ -562,9 +540,6 @@ packaging = [ {file = "packaging-20.3-py2.py3-none-any.whl", hash = "sha256:82f77b9bee21c1bafbf35a84905d604d5d1223801d639cf3ed140bd651c08752"}, {file = "packaging-20.3.tar.gz", hash = "sha256:3c292b474fda1671ec57d46d739d072bfd495a4f51ad01a055121d81e952b7a3"}, ] -pathtools = [ - {file = "pathtools-0.1.2.tar.gz", hash = "sha256:7c35c5421a39bb82e58018febd90e3b6e5db34c5443aaaf742b3f33d4655f1c0"}, -] pefile = [ {file = "pefile-2019.4.18.tar.gz", hash = "sha256:a5d6e8305c6b210849b47a6174ddf9c452b2888340b8177874b862ba6c207645"}, ] @@ -686,9 +661,6 @@ urllib3 = [ {file = "urllib3-1.25.8-py2.py3-none-any.whl", hash = "sha256:2f3db8b19923a873b3e5256dc9c2dedfa883e33d87c690d9c7913e1f40673cdc"}, {file = "urllib3-1.25.8.tar.gz", hash = "sha256:87716c2d2a7121198ebcb7ce7cccf6ce5e9ba539041cfbaeecfb641dc0bf6acc"}, ] -watchdog = [ - {file = "watchdog-0.10.2.tar.gz", hash = "sha256:c560efb643faed5ef28784b2245cf8874f939569717a4a12826a173ac644456b"}, -] wcwidth = [ {file = "wcwidth-0.1.9-py2.py3-none-any.whl", hash = "sha256:cafe2186b3c009a04067022ce1dcd79cb38d8d65ee4f4791b8888d6599d1bbe1"}, {file = "wcwidth-0.1.9.tar.gz", hash = "sha256:ee73862862a156bf77ff92b09034fc4825dd3af9cf81bc5b360668d425f3c5f1"}, diff --git a/pyproject.toml b/pyproject.toml index 53ce5858..a5bcf469 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,7 +28,6 @@ requests = "*" stem = "*" urllib3 = "*" Werkzeug = "*" -watchdog = "*" psutil = "*" [tool.poetry.dev-dependencies]