mirror of
https://github.com/onionshare/onionshare.git
synced 2025-01-12 15:59:30 -05:00
Support handling events by monitoring an events folder for changes
This commit is contained in:
parent
d78d67adf6
commit
e7c683528d
4
BUILD.md
4
BUILD.md
@ -14,13 +14,13 @@ Install the needed dependencies:
|
||||
For Debian-like distros:
|
||||
|
||||
```
|
||||
apt install -y python3-flask python3-stem python3-pyqt5 python3-crypto python3-socks python-nautilus tor obfs4proxy python3-pytest build-essential fakeroot python3-all python3-stdeb dh-python python3-flask-httpauth python3-distutils python3-psutil
|
||||
apt install -y python3-flask python3-stem python3-pyqt5 python3-crypto python3-socks python-nautilus tor obfs4proxy python3-pytest build-essential fakeroot python3-all python3-stdeb dh-python python3-flask-httpauth python3-distutils python3-psutil python3-watchdog
|
||||
```
|
||||
|
||||
For Fedora-like distros:
|
||||
|
||||
```
|
||||
dnf install -y python3-flask python3-flask-httpauth python3-stem python3-qt5 python3-crypto python3-pysocks nautilus-python tor obfs4 python3-pytest rpm-build python3-psutil
|
||||
dnf install -y python3-flask python3-flask-httpauth python3-stem python3-qt5 python3-crypto python3-pysocks nautilus-python tor obfs4 python3-pytest rpm-build python3-psutil python3-watchdog
|
||||
```
|
||||
|
||||
After that you can try both the CLI and the GUI version of OnionShare:
|
||||
|
@ -21,3 +21,4 @@ requests==2.22.0
|
||||
stem==1.7.1
|
||||
urllib3==1.25.3
|
||||
Werkzeug==0.15.6
|
||||
watchdog==0.9.0
|
@ -23,9 +23,11 @@ import sys
|
||||
import platform
|
||||
import argparse
|
||||
import signal
|
||||
import psutil
|
||||
from PyQt5 import QtCore, QtWidgets
|
||||
|
||||
if platform.system() == "Linux":
|
||||
import psutil
|
||||
|
||||
from onionshare.common import Common
|
||||
|
||||
from .gui_common import GuiCommon
|
||||
@ -122,28 +124,30 @@ def main():
|
||||
sys.exit()
|
||||
|
||||
# Is there another onionshare-gui running?
|
||||
existing_pid = None
|
||||
for proc in psutil.process_iter(attrs=["pid", "name", "cmdline"]):
|
||||
if proc.info["pid"] == os.getpid():
|
||||
continue
|
||||
if common.platform == "Linux":
|
||||
existing_pid = None
|
||||
for proc in psutil.process_iter(attrs=["pid", "name", "cmdline"]):
|
||||
if proc.info["pid"] == os.getpid():
|
||||
continue
|
||||
|
||||
if proc.info["name"] == "onionshare-gui":
|
||||
existing_pid = proc.info["pid"]
|
||||
break
|
||||
else:
|
||||
# Dev mode onionshare?
|
||||
if proc.info["cmdline"] and len(proc.info["cmdline"]) >= 2:
|
||||
if (
|
||||
os.path.basename(proc.info["cmdline"][0]).lower() == "python"
|
||||
and os.path.basename(proc.info["cmdline"][1]) == "onionshare-gui"
|
||||
):
|
||||
existing_pid = proc.info["pid"]
|
||||
break
|
||||
if proc.info["name"] == "onionshare-gui":
|
||||
existing_pid = proc.info["pid"]
|
||||
break
|
||||
else:
|
||||
# Dev mode onionshare?
|
||||
if proc.info["cmdline"] and len(proc.info["cmdline"]) >= 2:
|
||||
if (
|
||||
os.path.basename(proc.info["cmdline"][0]).lower() == "python"
|
||||
and os.path.basename(proc.info["cmdline"][1])
|
||||
== "onionshare-gui"
|
||||
):
|
||||
existing_pid = proc.info["pid"]
|
||||
break
|
||||
|
||||
if existing_pid:
|
||||
print(f"Opening tab in existing OnionShare window (pid {proc.info['pid']})")
|
||||
# TODO: open tab
|
||||
return
|
||||
if existing_pid:
|
||||
print(f"Opening tab in existing OnionShare window (pid {proc.info['pid']})")
|
||||
# TODO: open tab
|
||||
return
|
||||
|
||||
# Attach the GUI common parts to the common object
|
||||
common.gui = GuiCommon(common, qtapp, local_only)
|
||||
|
89
onionshare_gui/event_handler.py
Normal file
89
onionshare_gui/event_handler.py
Normal file
@ -0,0 +1,89 @@
|
||||
# -*- 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}"
|
||||
)
|
||||
|
@ -17,6 +17,8 @@ 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 os
|
||||
|
||||
from onionshare import strings
|
||||
from onionshare.onion import Onion
|
||||
|
||||
@ -44,6 +46,12 @@ class GuiCommon:
|
||||
# Start the Onion
|
||||
self.onion = Onion(common)
|
||||
|
||||
# Directory to watch for events
|
||||
self.events_dir = os.path.join(self.common.build_data_dir(), "events")
|
||||
if not os.path.exists(self.events_dir):
|
||||
os.makedirs(self.events_dir, 0o700, True)
|
||||
self.events_filename = os.path.join(self.events_dir, "events")
|
||||
|
||||
self.css = {
|
||||
# OnionShareGui styles
|
||||
"tab_widget_new_tab_button": """
|
||||
|
@ -119,6 +119,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||
|
||||
# Tabs
|
||||
self.tabs = TabWidget(self.common, self.system_tray, self.status_bar)
|
||||
self.tabs.bring_to_front.connect(self.bring_to_front)
|
||||
|
||||
# If we have saved persistent tabs, try opening those
|
||||
if len(self.common.settings.get("persistent_tabs")) > 0:
|
||||
@ -281,6 +282,11 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||
self.update_thread.update_available.connect(update_available)
|
||||
self.update_thread.start()
|
||||
|
||||
def bring_to_front(self):
|
||||
self.common.log("MainWindow", "bring_to_front")
|
||||
self.raise_()
|
||||
self.activateWindow()
|
||||
|
||||
def closeEvent(self, e):
|
||||
self.common.log("MainWindow", "closeEvent")
|
||||
|
||||
|
@ -18,11 +18,13 @@ 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
|
||||
|
||||
|
||||
class TabWidget(QtWidgets.QTabWidget):
|
||||
@ -30,6 +32,8 @@ class TabWidget(QtWidgets.QTabWidget):
|
||||
A custom tab widget, that has a "+" button for adding new tabs
|
||||
"""
|
||||
|
||||
bring_to_front = QtCore.pyqtSignal()
|
||||
|
||||
def __init__(self, common, system_tray, status_bar):
|
||||
super(TabWidget, self).__init__()
|
||||
self.common = common
|
||||
@ -67,6 +71,14 @@ 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()
|
||||
|
||||
def move_new_tab_button(self):
|
||||
# Find the width of all tabs
|
||||
tabs_width = sum(
|
||||
@ -95,6 +107,12 @@ class TabWidget(QtWidgets.QTabWidget):
|
||||
mode_settings = ModeSettings(self.common, id=mode_settings_id)
|
||||
self.add_tab(mode_settings)
|
||||
|
||||
def new_share_tab(self, filenames):
|
||||
mode_settings = ModeSettings(self.common)
|
||||
mode_settings.set("persistent", "mode", "share")
|
||||
mode_settings.set("share", "filenames", filenames)
|
||||
self.add_tab(mode_settings)
|
||||
|
||||
def add_tab(self, mode_settings=None):
|
||||
tab = Tab(self.common, self.current_tab_id, self.system_tray, self.status_bar)
|
||||
tab.change_title.connect(self.change_title)
|
||||
@ -111,6 +129,9 @@ class TabWidget(QtWidgets.QTabWidget):
|
||||
# If it's persistent, set the persistent image in the tab
|
||||
self.change_persistent(tab.tab_id, tab.settings.get("persistent", "enabled"))
|
||||
|
||||
# Bring the window to front, in case this is being added by an event
|
||||
self.bring_to_front.emit()
|
||||
|
||||
def change_title(self, tab_id, title):
|
||||
index = self.indexOf(self.tabs[tab_id])
|
||||
self.setTabText(index, title)
|
||||
|
Loading…
Reference in New Issue
Block a user