Remove watchdog, replace with a simple background thread

This commit is contained in:
Micah Lee 2020-04-06 19:26:45 -07:00
parent e84ca43da8
commit a9d55e9169
No known key found for this signature in database
GPG Key ID: 403C2657CD994F73
5 changed files with 90 additions and 129 deletions

View File

@ -1,89 +0,0 @@
# -*- coding: utf-8 -*-
"""
OnionShare | https://onionshare.org/
Copyright (C) 2014-2018 Micah Lee <micah@micahflee.com>
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 <http://www.gnu.org/licenses/>.
"""
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}"
)

View File

@ -18,13 +18,12 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
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()):

View File

@ -18,6 +18,8 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
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)

30
poetry.lock generated
View File

@ -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"},

View File

@ -28,7 +28,6 @@ requests = "*"
stem = "*"
urllib3 = "*"
Werkzeug = "*"
watchdog = "*"
psutil = "*"
[tool.poetry.dev-dependencies]