Split out customization of Mode into _custom() functions, and implement those customizations in ShareMode

This commit is contained in:
Micah Lee 2018-04-25 22:59:26 -07:00
parent f59fc79939
commit a24bb75b66
5 changed files with 254 additions and 161 deletions

View file

@ -17,13 +17,12 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
""" """
import threading
import time import time
import os import threading
from PyQt5 import QtCore, QtWidgets, QtGui from PyQt5 import QtCore, QtWidgets, QtGui
from onionshare import strings from onionshare import strings
from onionshare.common import Common, ShutdownTimer from onionshare.common import ShutdownTimer
from .server_status import ServerStatus from .server_status import ServerStatus
from .onion_thread import OnionThread from .onion_thread import OnionThread
@ -38,9 +37,9 @@ class Mode(QtWidgets.QWidget):
starting_server_step2 = QtCore.pyqtSignal() starting_server_step2 = QtCore.pyqtSignal()
starting_server_step3 = QtCore.pyqtSignal() starting_server_step3 = QtCore.pyqtSignal()
starting_server_error = QtCore.pyqtSignal(str) starting_server_error = QtCore.pyqtSignal(str)
set_share_server_active = QtCore.pyqtSignal(bool) set_server_active = QtCore.pyqtSignal(bool)
def __init__(self, common, qtapp, app, web, status_bar, server_share_status_label, system_tray, filenames=None): def __init__(self, common, qtapp, app, web, status_bar, server_status_label, system_tray, filenames=None):
super(Mode, self).__init__() super(Mode, self).__init__()
self.common = common self.common = common
self.qtapp = qtapp self.qtapp = qtapp
@ -48,13 +47,13 @@ class Mode(QtWidgets.QWidget):
self.web = web self.web = web
self.status_bar = status_bar self.status_bar = status_bar
self.server_share_status_label = server_share_status_label self.server_status_label = server_status_label
self.system_tray = system_tray self.system_tray = system_tray
self.filenames = filenames self.filenames = filenames
# Server status # Server status
self.server_status = ServerStatus(self.common, self.qtapp, self.app, self.web, False) self.server_status = ServerStatus(self.common, self.qtapp, self.app, self.web)
self.server_status.server_started.connect(self.start_server) self.server_status.server_started.connect(self.start_server)
self.server_status.server_stopped.connect(self.stop_server) self.server_status.server_stopped.connect(self.stop_server)
self.server_status.server_canceled.connect(self.cancel_server) self.server_status.server_canceled.connect(self.cancel_server)
@ -77,7 +76,7 @@ class Mode(QtWidgets.QWidget):
def init(self): def init(self):
""" """
Add custom initialization of the mode here. Add custom initialization here.
""" """
pass pass
@ -92,17 +91,16 @@ class Mode(QtWidgets.QWidget):
Start the onionshare server. This uses multiple threads to start the Tor onion Start the onionshare server. This uses multiple threads to start the Tor onion
server and the web app. server and the web app.
""" """
self.common.log('ShareMode', 'start_server') self.common.log('Mode', 'start_server')
self.set_share_server_active.emit(True) self.start_server_custom()
self.set_server_active.emit(True)
self.app.set_stealth(self.common.settings.get('use_stealth')) self.app.set_stealth(self.common.settings.get('use_stealth'))
# Hide and reset the downloads if we have previously shared # Clear the status bar
self.downloads.reset_downloads()
self.reset_info_counters()
self.status_bar.clearMessage() self.status_bar.clearMessage()
self.server_share_status_label.setText('') self.server_status_label.setText('')
# Reset web counters # Reset web counters
self.web.download_count = 0 self.web.download_count = 0
@ -128,64 +126,44 @@ class Mode(QtWidgets.QWidget):
# wait for modules in thread to load, preventing a thread-related cx_Freeze crash # wait for modules in thread to load, preventing a thread-related cx_Freeze crash
time.sleep(0.2) time.sleep(0.2)
self.common.log('OnionshareGui', 'start_server', 'Starting an onion thread') self.common.log('Mode', 'start_server', 'Starting an onion thread')
self.t = OnionThread(self.common, function=start_onion_service, kwargs={'self': self}) self.t = OnionThread(self.common, function=start_onion_service, kwargs={'self': self})
self.t.daemon = True self.t.daemon = True
self.t.start() self.t.start()
def start_server_custom(self):
"""
Add custom initialization here.
"""
pass
def start_server_step2(self): def start_server_step2(self):
""" """
Step 2 in starting the onionshare server. Zipping up files. Step 2 in starting the onionshare server.
""" """
self.common.log('ShareMode', 'start_server_step2') self.common.log('Mode', 'start_server_step2')
# add progress bar to the status bar, indicating the compressing of files. self.start_server_step2_custom()
self._zip_progress_bar = ZipProgressBar(0)
self.filenames = []
for index in range(self.file_selection.file_list.count()):
self.filenames.append(self.file_selection.file_list.item(index).filename)
self._zip_progress_bar.total_files_size = Mode._compute_total_size(self.filenames) # Nothing to do here.
self.status_bar.insertWidget(0, self._zip_progress_bar)
# prepare the files for sending in a new thread # start_server_step2_custom has call these to move on:
def finish_starting_server(self): # self.starting_server_step3.emit()
# prepare files to share # self.start_server_finished.emit()
def _set_processed_size(x):
if self._zip_progress_bar != None:
self._zip_progress_bar.update_processed_size_signal.emit(x)
try:
self.web.set_file_info(self.filenames, processed_size_callback=_set_processed_size)
self.app.cleanup_filenames.append(self.web.zip_filename)
# Only continue if the server hasn't been canceled def start_server_step2_custom(self):
if self.server_status.status != self.server_status.STATUS_STOPPED: """
self.starting_server_step3.emit() Add custom initialization here.
self.start_server_finished.emit() """
except OSError as e: pass
self.starting_server_error.emit(e.strerror)
return
t = threading.Thread(target=finish_starting_server, kwargs={'self': self})
t.daemon = True
t.start()
def start_server_step3(self): def start_server_step3(self):
""" """
Step 3 in starting the onionshare server. This displays the large filesize Step 3 in starting the onionshare server.
warning, if applicable.
""" """
self.common.log('ShareMode', 'start_server_step3') self.common.log('Mode', 'start_server_step3')
# Remove zip progress bar self.start_server_step3_custom()
if self._zip_progress_bar is not None:
self.status_bar.removeWidget(self._zip_progress_bar)
self._zip_progress_bar = None
# warn about sending large files over Tor
if self.web.zip_filesize >= 157286400: # 150mb
self.filesize_warning.setText(strings._("large_filesize", True))
self.filesize_warning.show()
if self.common.settings.get('shutdown_timeout'): if self.common.settings.get('shutdown_timeout'):
# Convert the date value to seconds between now and then # Convert the date value to seconds between now and then
@ -200,21 +178,31 @@ class Mode(QtWidgets.QWidget):
self.stop_server() self.stop_server()
self.start_server_error(strings._('gui_server_started_after_timeout')) self.start_server_error(strings._('gui_server_started_after_timeout'))
def start_server_step3_custom(self):
"""
Add custom initialization here.
"""
pass
def start_server_error(self, error): def start_server_error(self, error):
""" """
If there's an error when trying to start the onion service If there's an error when trying to start the onion service
""" """
self.common.log('ShareMode', 'start_server_error') self.common.log('Mode', 'start_server_error')
self.set_share_server_active.emit(False)
Alert(self.common, error, QtWidgets.QMessageBox.Warning) Alert(self.common, error, QtWidgets.QMessageBox.Warning)
self.set_server_active.emit(False)
self.server_status.stop_server() self.server_status.stop_server()
if self._zip_progress_bar is not None:
self.status_bar.removeWidget(self._zip_progress_bar)
self._zip_progress_bar = None
self.status_bar.clearMessage() self.status_bar.clearMessage()
self.start_server_error_custom()
def start_server_error_custom(self):
"""
Add custom initialization here.
"""
pass
def cancel_server(self): def cancel_server(self):
""" """
Cancel the server while it is preparing to start Cancel the server while it is preparing to start
@ -227,7 +215,7 @@ class Mode(QtWidgets.QWidget):
""" """
Stop the onionshare server. Stop the onionshare server.
""" """
self.common.log('ShareMode', 'stop_server') self.common.log('Mode', 'stop_server')
if self.server_status.status != self.server_status.STATUS_STOPPED: if self.server_status.status != self.server_status.STATUS_STOPPED:
try: try:
@ -237,81 +225,27 @@ class Mode(QtWidgets.QWidget):
pass pass
self.app.cleanup() self.app.cleanup()
# Remove the progress bar self.stop_server_custom()
if self._zip_progress_bar is not None:
self.status_bar.removeWidget(self._zip_progress_bar)
self._zip_progress_bar = None
self.filesize_warning.hide() self.set_server_active.emit(False)
self.downloads_in_progress = 0
self.downloads_completed = 0
self.update_downloads_in_progress(0)
self.file_selection.file_list.adjustSize()
self.set_share_server_active.emit(False)
self.stop_server_finished.emit() self.stop_server_finished.emit()
@staticmethod def stop_server_custom(self):
def _compute_total_size(filenames): """
total_size = 0 Add custom initialization here.
for filename in filenames: """
if os.path.isfile(filename): pass
total_size += os.path.getsize(filename)
if os.path.isdir(filename):
total_size += Common.dir_size(filename)
return total_size
def handle_tor_broke(self):
"""
Handle connection from Tor breaking.
"""
if self.server_status.status != self.server_status.STATUS_STOPPED:
self.server_status.stop_server()
self.handle_tor_broke_custom()
class ZipProgressBar(QtWidgets.QProgressBar): def handle_tor_broke_custom(self):
update_processed_size_signal = QtCore.pyqtSignal(int) """
Add custom initialization here.
def __init__(self, total_files_size): """
super(ZipProgressBar, self).__init__() pass
self.setMaximumHeight(20)
self.setMinimumWidth(200)
self.setValue(0)
self.setFormat(strings._('zip_progress_bar_format'))
cssStyleData ="""
QProgressBar {
border: 1px solid #4e064f;
background-color: #ffffff !important;
text-align: center;
color: #9b9b9b;
}
QProgressBar::chunk {
border: 0px;
background-color: #4e064f;
width: 10px;
}"""
self.setStyleSheet(cssStyleData)
self._total_files_size = total_files_size
self._processed_size = 0
self.update_processed_size_signal.connect(self.update_processed_size)
@property
def total_files_size(self):
return self._total_files_size
@total_files_size.setter
def total_files_size(self, val):
self._total_files_size = val
@property
def processed_size(self):
return self._processed_size
@processed_size.setter
def processed_size(self, val):
self.update_processed_size(val)
def update_processed_size(self, val):
self._processed_size = val
if self.processed_size < self.total_files_size:
self.setValue(int((self.processed_size * 100) / self.total_files_size))
elif self.total_files_size != 0:
self.setValue(100)
else:
self.setValue(0)

View file

@ -152,12 +152,12 @@ class OnionShareGui(QtWidgets.QMainWindow):
self.setStatusBar(self.status_bar) self.setStatusBar(self.status_bar)
# Status bar, sharing messages # Status bar, sharing messages
self.server_share_status_label = QtWidgets.QLabel('') self.server_status_label = QtWidgets.QLabel('')
self.server_share_status_label.setStyleSheet('QLabel { font-style: italic; color: #666666; padding: 2px; }') self.server_status_label.setStyleSheet('QLabel { font-style: italic; color: #666666; padding: 2px; }')
self.status_bar.insertWidget(0, self.server_share_status_label) self.status_bar.insertWidget(0, self.server_status_label)
# Share and receive mode widgets # Share and receive mode widgets
self.share_mode = ShareMode(self.common, qtapp, app, web, self.status_bar, self.server_share_status_label, self.system_tray, filenames) self.share_mode = ShareMode(self.common, qtapp, app, web, self.status_bar, self.server_status_label, self.system_tray, filenames)
self.share_mode.init() self.share_mode.init()
self.share_mode.server_status.server_started.connect(self.update_server_status_indicator) self.share_mode.server_status.server_started.connect(self.update_server_status_indicator)
self.share_mode.server_status.server_stopped.connect(self.update_server_status_indicator) self.share_mode.server_status.server_stopped.connect(self.update_server_status_indicator)
@ -168,8 +168,8 @@ class OnionShareGui(QtWidgets.QMainWindow):
self.share_mode.server_status.button_clicked.connect(self.clear_message) self.share_mode.server_status.button_clicked.connect(self.clear_message)
self.share_mode.server_status.url_copied.connect(self.copy_url) self.share_mode.server_status.url_copied.connect(self.copy_url)
self.share_mode.server_status.hidservauth_copied.connect(self.copy_hidservauth) self.share_mode.server_status.hidservauth_copied.connect(self.copy_hidservauth)
self.share_mode.set_share_server_active.connect(self.set_share_server_active) self.share_mode.set_server_active.connect(self.set_share_server_active)
self.receive_mode = ReceiveMode(self.common, qtapp, app, web, self.status_bar, self.server_share_status_label, self.system_tray) self.receive_mode = ReceiveMode(self.common, qtapp, app, web, self.status_bar, self.server_status_label, self.system_tray)
self.receive_mode.init() self.receive_mode.init()
self.update_mode_switcher() self.update_mode_switcher()

View file

@ -44,3 +44,10 @@ class ReceiveMode(Mode):
This method is called regularly on a timer while receive mode is active. This method is called regularly on a timer while receive mode is active.
""" """
pass pass
def start_server_step2_custom(self):
"""
Step 2 in starting the server. Nothing to do here but move on to step 3.
"""
self.starting_server_step3.emit()
self.start_server_finished.emit()

View file

@ -39,22 +39,18 @@ class ServerStatus(QtWidgets.QWidget):
STATUS_WORKING = 1 STATUS_WORKING = 1
STATUS_STARTED = 2 STATUS_STARTED = 2
def __init__(self, common, qtapp, app, web, share_mode, file_selection=None): def __init__(self, common, qtapp, app, web, file_selection=None):
super(ServerStatus, self).__init__() super(ServerStatus, self).__init__()
self.common = common self.common = common
self.status = self.STATUS_STOPPED self.status = self.STATUS_STOPPED
self.share_mode = False # Gets changed in in self.set_share_mode
self.qtapp = qtapp self.qtapp = qtapp
self.app = app self.app = app
self.web = web self.web = web
# Only used in share mode
self.share_mode = share_mode
if self.share_mode:
self.file_selection = file_selection
# Shutdown timeout layout # Shutdown timeout layout
self.shutdown_timeout_label = QtWidgets.QLabel(strings._('gui_settings_shutdown_timeout', True)) self.shutdown_timeout_label = QtWidgets.QLabel(strings._('gui_settings_shutdown_timeout', True))
self.shutdown_timeout = QtWidgets.QDateTimeEdit() self.shutdown_timeout = QtWidgets.QDateTimeEdit()
@ -119,6 +115,13 @@ class ServerStatus(QtWidgets.QWidget):
self.update() self.update()
def set_share_mode(self, file_selection):
"""
The server status is in share mode.
"""
self.share_mode = True
self.file_selection = file_selection
def shutdown_timeout_reset(self): def shutdown_timeout_reset(self):
""" """
Reset the timeout in the UI after stopping a share Reset the timeout in the UI after stopping a share

View file

@ -17,10 +17,13 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
""" """
import threading
import os
from PyQt5 import QtCore, QtWidgets, QtGui from PyQt5 import QtCore, QtWidgets, QtGui
from onionshare import strings from onionshare import strings
from onionshare.onion import * from onionshare.onion import *
from onionshare.common import Common
from .file_selection import FileSelection from .file_selection import FileSelection
from .downloads import Downloads from .downloads import Downloads
@ -43,6 +46,7 @@ class ShareMode(Mode):
self.file_selection.file_list.add_file(filename) self.file_selection.file_list.add_file(filename)
# Server status # Server status
self.server_status.set_share_mode(self.file_selection)
self.server_status.server_started.connect(self.file_selection.server_started) self.server_status.server_started.connect(self.file_selection.server_started)
self.server_status.server_stopped.connect(self.file_selection.server_stopped) self.server_status.server_stopped.connect(self.file_selection.server_stopped)
self.server_status.server_stopped.connect(self.update_primary_action) self.server_status.server_stopped.connect(self.update_primary_action)
@ -102,8 +106,8 @@ class ShareMode(Mode):
self._zip_progress_bar = None self._zip_progress_bar = None
# Layout # Layout
self.layout.insertWidget(1, self.info_widget)
self.layout.insertLayout(0, self.file_selection) self.layout.insertLayout(0, self.file_selection)
self.layout.insertWidget(0, self.info_widget)
# Always start with focus on file selection # Always start with focus on file selection
self.file_selection.setFocus() self.file_selection.setFocus()
@ -129,18 +133,98 @@ class ShareMode(Mode):
if self.web.download_count == 0 or self.web.done: if self.web.download_count == 0 or self.web.done:
self.server_status.stop_server() self.server_status.stop_server()
self.status_bar.clearMessage() self.status_bar.clearMessage()
self.server_share_status_label.setText(strings._('close_on_timeout', True)) self.server_status_label.setText(strings._('close_on_timeout', True))
# A download is probably still running - hold off on stopping the share # A download is probably still running - hold off on stopping the share
else: else:
self.status_bar.clearMessage() self.status_bar.clearMessage()
self.server_share_status_label.setText(strings._('timeout_download_still_running', True)) self.server_status_label.setText(strings._('timeout_download_still_running', True))
def handle_tor_broke(self): def start_server_custom(self):
""" """
Handle connection from Tor breaking. Starting the server.
""" """
# Hide and reset the downloads if we have previously shared
self.downloads.reset_downloads()
self.reset_info_counters()
def start_server_step2_custom(self):
"""
Step 2 in starting the server. Zipping up files.
"""
# Add progress bar to the status bar, indicating the compressing of files.
self._zip_progress_bar = ZipProgressBar(0)
self.filenames = []
for index in range(self.file_selection.file_list.count()):
self.filenames.append(self.file_selection.file_list.item(index).filename)
self._zip_progress_bar.total_files_size = ShareMode._compute_total_size(self.filenames)
self.status_bar.insertWidget(0, self._zip_progress_bar)
# Prepare the files for sending in a new thread
def finish_starting_server(self):
# Prepare files to share
def _set_processed_size(x):
if self._zip_progress_bar != None:
self._zip_progress_bar.update_processed_size_signal.emit(x)
try:
self.web.set_file_info(self.filenames, processed_size_callback=_set_processed_size)
self.app.cleanup_filenames.append(self.web.zip_filename)
# Only continue if the server hasn't been canceled
if self.server_status.status != self.server_status.STATUS_STOPPED: if self.server_status.status != self.server_status.STATUS_STOPPED:
self.server_status.stop_server() self.starting_server_step3.emit()
self.start_server_finished.emit()
except OSError as e:
self.starting_server_error.emit(e.strerror)
return
t = threading.Thread(target=finish_starting_server, kwargs={'self': self})
t.daemon = True
t.start()
def start_server_step3_custom(self):
"""
Step 3 in starting the server. Remove zip progess bar, and display large filesize
warning, if applicable.
"""
# Remove zip progress bar
if self._zip_progress_bar is not None:
self.status_bar.removeWidget(self._zip_progress_bar)
self._zip_progress_bar = None
# Warn about sending large files over Tor
if self.web.zip_filesize >= 157286400: # 150mb
self.filesize_warning.setText(strings._("large_filesize", True))
self.filesize_warning.show()
def start_server_error_custom(self):
"""
Start server error.
"""
if self._zip_progress_bar is not None:
self.status_bar.removeWidget(self._zip_progress_bar)
self._zip_progress_bar = None
def stop_server_custom(self):
"""
Stop server.
"""
# Remove the progress bar
if self._zip_progress_bar is not None:
self.status_bar.removeWidget(self._zip_progress_bar)
self._zip_progress_bar = None
self.filesize_warning.hide()
self.downloads_in_progress = 0
self.downloads_completed = 0
self.update_downloads_in_progress(0)
self.file_selection.file_list.adjustSize()
def handle_tor_broke_custom(self):
"""
Connection to Tor broke.
"""
self.primary_action.hide() self.primary_action.hide()
self.info_widget.hide() self.info_widget.hide()
@ -190,7 +274,7 @@ class ShareMode(Mode):
if not self.web.stay_open: if not self.web.stay_open:
self.server_status.stop_server() self.server_status.stop_server()
self.status_bar.clearMessage() self.status_bar.clearMessage()
self.server_share_status_label.setText(strings._('closing_automatically', True)) self.server_status_label.setText(strings._('closing_automatically', True))
else: else:
if self.server_status.status == self.server_status.STATUS_STOPPED: if self.server_status.status == self.server_status.STATUS_STOPPED:
self.downloads.cancel_download(event["data"]["id"]) self.downloads.cancel_download(event["data"]["id"])
@ -285,3 +369,68 @@ class ShareMode(Mode):
self.info_show_downloads.setIcon(QtGui.QIcon(self.common.get_resource_path('images/download_window_green.png'))) self.info_show_downloads.setIcon(QtGui.QIcon(self.common.get_resource_path('images/download_window_green.png')))
self.info_in_progress_downloads_count.setText('<img src="{0:s}" /> {1:d}'.format(self.info_in_progress_downloads_image, count)) self.info_in_progress_downloads_count.setText('<img src="{0:s}" /> {1:d}'.format(self.info_in_progress_downloads_image, count))
self.info_in_progress_downloads_count.setToolTip(strings._('info_in_progress_downloads_tooltip', True).format(count)) self.info_in_progress_downloads_count.setToolTip(strings._('info_in_progress_downloads_tooltip', True).format(count))
@staticmethod
def _compute_total_size(filenames):
total_size = 0
for filename in filenames:
if os.path.isfile(filename):
total_size += os.path.getsize(filename)
if os.path.isdir(filename):
total_size += Common.dir_size(filename)
return total_size
class ZipProgressBar(QtWidgets.QProgressBar):
update_processed_size_signal = QtCore.pyqtSignal(int)
def __init__(self, total_files_size):
super(ZipProgressBar, self).__init__()
self.setMaximumHeight(20)
self.setMinimumWidth(200)
self.setValue(0)
self.setFormat(strings._('zip_progress_bar_format'))
cssStyleData ="""
QProgressBar {
border: 1px solid #4e064f;
background-color: #ffffff !important;
text-align: center;
color: #9b9b9b;
}
QProgressBar::chunk {
border: 0px;
background-color: #4e064f;
width: 10px;
}"""
self.setStyleSheet(cssStyleData)
self._total_files_size = total_files_size
self._processed_size = 0
self.update_processed_size_signal.connect(self.update_processed_size)
@property
def total_files_size(self):
return self._total_files_size
@total_files_size.setter
def total_files_size(self, val):
self._total_files_size = val
@property
def processed_size(self):
return self._processed_size
@processed_size.setter
def processed_size(self, val):
self.update_processed_size(val)
def update_processed_size(self, val):
self._processed_size = val
if self.processed_size < self.total_files_size:
self.setValue(int((self.processed_size * 100) / self.total_files_size))
elif self.total_files_size != 0:
self.setValue(100)
else:
self.setValue(0)