mirror of
https://github.com/onionshare/onionshare.git
synced 2025-03-05 12:45:54 -05:00
Add docstrings to all classes and methods (fix #198)
This commit is contained in:
parent
a5aff46050
commit
dc58921187
@ -120,6 +120,9 @@ def is_root():
|
||||
|
||||
|
||||
def dir_size(start_path):
|
||||
"""
|
||||
Calculates the total size, in bytes, of all of the files in a directory.
|
||||
"""
|
||||
total_size = 0
|
||||
for dirpath, dirnames, filenames in os.walk(start_path):
|
||||
for f in filenames:
|
||||
@ -130,6 +133,11 @@ def dir_size(start_path):
|
||||
|
||||
|
||||
class ZipWriter(object):
|
||||
"""
|
||||
ZipWriter accepts files and directories and compresses them into a zip file
|
||||
with. If a zip_filename is not passed in, it will use the default onionshare
|
||||
filename.
|
||||
"""
|
||||
def __init__(self, zip_filename=None):
|
||||
if zip_filename:
|
||||
self.zip_filename = zip_filename
|
||||
@ -139,9 +147,15 @@ class ZipWriter(object):
|
||||
self.z = zipfile.ZipFile(self.zip_filename, 'w', allowZip64=True)
|
||||
|
||||
def add_file(self, filename):
|
||||
"""
|
||||
Add a file to the zip archive.
|
||||
"""
|
||||
self.z.write(filename, os.path.basename(filename), zipfile.ZIP_DEFLATED)
|
||||
|
||||
def add_dir(self, filename):
|
||||
"""
|
||||
Add a directory, and all of its children, to the zip archive.
|
||||
"""
|
||||
dir_to_strip = os.path.dirname(filename.rstrip('/'))+'/'
|
||||
for dirpath, dirnames, filenames in os.walk(filename):
|
||||
for f in filenames:
|
||||
@ -151,4 +165,7 @@ class ZipWriter(object):
|
||||
self.z.write(full_filename, arc_filename, zipfile.ZIP_DEFLATED)
|
||||
|
||||
def close(self):
|
||||
"""
|
||||
Close the zip archive.
|
||||
"""
|
||||
self.z.close()
|
||||
|
@ -25,12 +25,35 @@ import socks
|
||||
import helpers, strings
|
||||
|
||||
class NoTor(Exception):
|
||||
"""
|
||||
This exception is raised if onionshare can't find a Tor control port
|
||||
to connect to, or if it can't find a Tor socks5 proxy to proxy though.
|
||||
"""
|
||||
pass
|
||||
|
||||
class HSDirError(Exception):
|
||||
"""
|
||||
This exception is raised when onionshare tries create a non-ephemeral
|
||||
hidden service and does not have permission to create or write to
|
||||
the hidden service directory.
|
||||
"""
|
||||
pass
|
||||
|
||||
class HS(object):
|
||||
"""
|
||||
HS is an abstraction layer for connecting to the Tor control port and
|
||||
creating hidden services. Onionshare supports creating hidden services
|
||||
using two methods:
|
||||
|
||||
- Modifying the Tor configuration through the control port is the old
|
||||
method, and will be deprecated in favor of ephemeral hidden services.
|
||||
- Using the control port to create ephemeral hidden servers is the
|
||||
preferred method.
|
||||
|
||||
This class detects the versions of Tor and stem to determine if ephemeral
|
||||
hidden services are supported. If not, it falls back to modifying the
|
||||
Tor configuration.
|
||||
"""
|
||||
def __init__(self, transparent_torification=False):
|
||||
self.transparent_torification = transparent_torification
|
||||
|
||||
@ -57,6 +80,10 @@ class HS(object):
|
||||
self.supports_ephemeral = callable(list_ephemeral_hidden_services) and tor_version >= '0.2.7.1'
|
||||
|
||||
def start(self, port):
|
||||
"""
|
||||
Start a hidden service on port 80, pointing to the given port, and
|
||||
return the onion hostname.
|
||||
"""
|
||||
print strings._("connecting_ctrlport").format(int(port))
|
||||
if self.supports_ephemeral:
|
||||
print strings._('using_ephemeral')
|
||||
@ -104,6 +131,11 @@ class HS(object):
|
||||
return onion_host
|
||||
|
||||
def wait_for_hs(self, onion_host):
|
||||
"""
|
||||
This function is only required when using non-ephemeral hidden services. After
|
||||
creating a hidden service, continually attempt to connect to it until it
|
||||
successfully connects..
|
||||
"""
|
||||
# legacy only, this function is no longer required with ephemeral hidden services
|
||||
print strings._('wait_for_hs')
|
||||
|
||||
@ -148,6 +180,10 @@ class HS(object):
|
||||
return True
|
||||
|
||||
def cleanup(self):
|
||||
"""
|
||||
Stop hidden services that were created earlier, and delete any temporary
|
||||
files that were created.
|
||||
"""
|
||||
if self.supports_ephemeral:
|
||||
# cleanup the ephemeral hidden service
|
||||
if self.service_id:
|
||||
|
@ -22,6 +22,10 @@ import os, sys, subprocess, time, argparse, inspect, shutil, socket, threading
|
||||
import strings, helpers, web, hs
|
||||
|
||||
class OnionShare(object):
|
||||
"""
|
||||
OnionShare is the main application class. Pass in options and run
|
||||
start_hidden_service and it will do the magic.
|
||||
"""
|
||||
def __init__(self, debug=False, local_only=False, stay_open=False, transparent_torification=False):
|
||||
self.port = None
|
||||
self.hs = None
|
||||
@ -45,6 +49,9 @@ class OnionShare(object):
|
||||
self.transparent_torification = transparent_torification
|
||||
|
||||
def choose_port(self):
|
||||
"""
|
||||
Pick an un-used port to bind to.
|
||||
"""
|
||||
# let the OS choose a port
|
||||
tmpsock = socket.socket()
|
||||
tmpsock.bind(("127.0.0.1", 0))
|
||||
@ -52,6 +59,9 @@ class OnionShare(object):
|
||||
tmpsock.close()
|
||||
|
||||
def start_hidden_service(self, gui=False):
|
||||
"""
|
||||
Start the onionshare hidden service.
|
||||
"""
|
||||
if not self.port:
|
||||
self.choose_port()
|
||||
|
||||
@ -65,6 +75,9 @@ class OnionShare(object):
|
||||
self.onion_host = self.hs.start(self.port)
|
||||
|
||||
def cleanup(self):
|
||||
"""
|
||||
Shut everything down and clean up temporary files, etc.
|
||||
"""
|
||||
# cleanup files
|
||||
for filename in self.cleanup_filenames:
|
||||
if os.path.isfile(filename):
|
||||
@ -79,6 +92,10 @@ class OnionShare(object):
|
||||
|
||||
|
||||
def main(cwd=None):
|
||||
"""
|
||||
The main() function implements all of the logic that the command-line version of
|
||||
onionshare uses.
|
||||
"""
|
||||
strings.load_strings()
|
||||
|
||||
# onionshare CLI in OSX needs to change current working directory (#132)
|
||||
|
@ -31,6 +31,11 @@ zip_filesize = None
|
||||
|
||||
|
||||
def set_file_info(filenames):
|
||||
"""
|
||||
Using the list of filenames being shared, fill in details that the web
|
||||
page will need to display. This includes zipping up the file in order to
|
||||
get the zip file's name and size.
|
||||
"""
|
||||
global file_info, zip_filename, zip_filesize
|
||||
|
||||
# build file info list
|
||||
@ -71,6 +76,9 @@ q = Queue.Queue()
|
||||
|
||||
|
||||
def add_request(request_type, path, data=None):
|
||||
"""
|
||||
Add a request to the queue, to communicate with the GUI.
|
||||
"""
|
||||
global q
|
||||
q.put({
|
||||
'type': request_type,
|
||||
@ -84,19 +92,34 @@ download_count = 0
|
||||
|
||||
stay_open = False
|
||||
def set_stay_open(new_stay_open):
|
||||
"""
|
||||
Set stay_open variable.
|
||||
"""
|
||||
global stay_open
|
||||
stay_open = new_stay_open
|
||||
def get_stay_open():
|
||||
"""
|
||||
Get stay_open variable.
|
||||
"""
|
||||
return stay_open
|
||||
|
||||
transparent_torification = False
|
||||
def set_transparent_torification(new_transparent_torification):
|
||||
"""
|
||||
Set transparent_torification variable.
|
||||
"""
|
||||
global transparent_torification
|
||||
stay_open = new_transparent_torification
|
||||
def get_transparent_torification():
|
||||
"""
|
||||
Get transparent_torification variable."
|
||||
"""
|
||||
return transparent_torification
|
||||
|
||||
def debug_mode():
|
||||
"""
|
||||
Turn on debugging mode, which will log flask errors to a debug file.
|
||||
"""
|
||||
import logging
|
||||
|
||||
if platform.system() == 'Windows':
|
||||
@ -111,6 +134,9 @@ def debug_mode():
|
||||
|
||||
@app.route("/<slug_candidate>")
|
||||
def index(slug_candidate):
|
||||
"""
|
||||
Render the template for the onionshare landing page.
|
||||
"""
|
||||
if not helpers.constant_time_compare(slug.encode('ascii'), slug_candidate.encode('ascii')):
|
||||
abort(404)
|
||||
|
||||
@ -128,6 +154,9 @@ def index(slug_candidate):
|
||||
|
||||
@app.route("/<slug_candidate>/download")
|
||||
def download(slug_candidate):
|
||||
"""
|
||||
Download the zip file.
|
||||
"""
|
||||
global download_count
|
||||
if not helpers.constant_time_compare(slug.encode('ascii'), slug_candidate.encode('ascii')):
|
||||
abort(404)
|
||||
@ -205,6 +234,9 @@ def download(slug_candidate):
|
||||
|
||||
@app.errorhandler(404)
|
||||
def page_not_found(e):
|
||||
"""
|
||||
404 error page.
|
||||
"""
|
||||
add_request(REQUEST_OTHER, request.path)
|
||||
return render_template_string(open(helpers.get_html_path('404.html')).read())
|
||||
|
||||
@ -214,6 +246,9 @@ shutdown_slug = helpers.random_string(16)
|
||||
|
||||
@app.route("/<shutdown_slug_candidate>/shutdown")
|
||||
def shutdown(shutdown_slug_candidate):
|
||||
"""
|
||||
Stop the flask web server.
|
||||
"""
|
||||
if not helpers.constant_time_compare(shutdown_slug.encode('ascii'), shutdown_slug_candidate.encode('ascii')):
|
||||
abort(404)
|
||||
|
||||
@ -227,12 +262,18 @@ def shutdown(shutdown_slug_candidate):
|
||||
|
||||
|
||||
def start(port, stay_open=False, transparent_torification=False):
|
||||
"""
|
||||
Start the flask web server.
|
||||
"""
|
||||
set_stay_open(stay_open)
|
||||
set_transparent_torification(transparent_torification)
|
||||
app.run(port=port, threaded=True)
|
||||
|
||||
|
||||
def stop(port):
|
||||
"""
|
||||
Stop the flask web server by loading /shutdown.
|
||||
"""
|
||||
# to stop flask, load http://127.0.0.1:<port>/<shutdown_slug>/shutdown
|
||||
if transparent_torification:
|
||||
import socket
|
||||
|
@ -24,6 +24,10 @@ from onionshare import strings, helpers
|
||||
|
||||
|
||||
class Downloads(QtGui.QVBoxLayout):
|
||||
"""
|
||||
The downloads chunk of the GUI. This lists all of the active download
|
||||
progress bars.
|
||||
"""
|
||||
def __init__(self):
|
||||
super(Downloads, self).__init__()
|
||||
|
||||
@ -37,6 +41,9 @@ class Downloads(QtGui.QVBoxLayout):
|
||||
self.addWidget(self.downloads_label)
|
||||
|
||||
def add_download(self, download_id, total_bytes):
|
||||
"""
|
||||
Add a new download progress bar.
|
||||
"""
|
||||
self.downloads_label.show()
|
||||
|
||||
# make a new progress bar
|
||||
@ -57,6 +64,9 @@ class Downloads(QtGui.QVBoxLayout):
|
||||
self.update_download(download_id, total_bytes, 0)
|
||||
|
||||
def update_download(self, download_id, total_bytes, downloaded_bytes):
|
||||
"""
|
||||
Update the progress of a download progress bar.
|
||||
"""
|
||||
if download_id not in self.progress_bars:
|
||||
self.add_download(download_id, total_bytes)
|
||||
|
||||
@ -68,5 +78,8 @@ class Downloads(QtGui.QVBoxLayout):
|
||||
pb.setFormat("{0:s}, %p%".format(helpers.human_readable_filesize(downloaded_bytes)))
|
||||
|
||||
def cancel_download(self, download_id):
|
||||
"""
|
||||
Update a download progress bar to show that it has been canceled.
|
||||
"""
|
||||
pb = self.progress_bars[download_id]
|
||||
pb.setFormat(strings._('gui_canceled'))
|
||||
|
@ -25,6 +25,9 @@ from onionshare import strings, helpers
|
||||
|
||||
|
||||
class FileList(QtGui.QListWidget):
|
||||
"""
|
||||
The list of files and folders in the GUI.
|
||||
"""
|
||||
files_dropped = QtCore.pyqtSignal()
|
||||
files_updated = QtCore.pyqtSignal()
|
||||
|
||||
@ -35,6 +38,10 @@ class FileList(QtGui.QListWidget):
|
||||
self.setSortingEnabled(True)
|
||||
|
||||
class DropHereLabel(QtGui.QLabel):
|
||||
"""
|
||||
When there are no files or folders in the FileList yet, display the
|
||||
'drop files here' message and graphic.
|
||||
"""
|
||||
def __init__(self, parent, image=False):
|
||||
self.parent = parent
|
||||
super(DropHereLabel, self).__init__(parent=parent)
|
||||
@ -61,6 +68,9 @@ class FileList(QtGui.QListWidget):
|
||||
self.update()
|
||||
|
||||
def update(self):
|
||||
"""
|
||||
Update the GUI elements based on the current state.
|
||||
"""
|
||||
# file list should have a background image if empty
|
||||
if len(self.filenames) == 0:
|
||||
self.drop_here_image.show()
|
||||
@ -70,20 +80,32 @@ class FileList(QtGui.QListWidget):
|
||||
self.drop_here_text.hide()
|
||||
|
||||
def resizeEvent(self, event):
|
||||
"""
|
||||
When the widget is resized, resize the drop files image and text.
|
||||
"""
|
||||
self.drop_here_image.setGeometry(0, 0, self.width(), self.height())
|
||||
self.drop_here_text.setGeometry(0, 0, self.width(), self.height())
|
||||
|
||||
def dragEnterEvent(self, event):
|
||||
"""
|
||||
dragEnterEvent for dragging files and directories into the widget.
|
||||
"""
|
||||
if event.mimeData().hasUrls:
|
||||
event.accept()
|
||||
else:
|
||||
event.ignore()
|
||||
|
||||
def dragLeaveEvent(self, event):
|
||||
"""
|
||||
dragLeaveEvent for dragging files and directories into the widget.
|
||||
"""
|
||||
event.accept()
|
||||
self.update()
|
||||
|
||||
def dragMoveEvent(self, event):
|
||||
"""
|
||||
dragMoveEvent for dragging files and directories into the widget.
|
||||
"""
|
||||
if event.mimeData().hasUrls:
|
||||
event.setDropAction(QtCore.Qt.CopyAction)
|
||||
event.accept()
|
||||
@ -91,6 +113,9 @@ class FileList(QtGui.QListWidget):
|
||||
event.ignore()
|
||||
|
||||
def dropEvent(self, event):
|
||||
"""
|
||||
dropEvent for dragging files and directories into the widget.
|
||||
"""
|
||||
if event.mimeData().hasUrls:
|
||||
event.setDropAction(QtCore.Qt.CopyAction)
|
||||
event.accept()
|
||||
@ -102,6 +127,9 @@ class FileList(QtGui.QListWidget):
|
||||
self.files_dropped.emit()
|
||||
|
||||
def add_file(self, filename):
|
||||
"""
|
||||
Add a file or directory to this widget.
|
||||
"""
|
||||
if filename not in self.filenames:
|
||||
# make filenames unicode-safe for Qt (#141)
|
||||
filename = filename.encode('utf-8').decode('utf-8', 'replace')
|
||||
@ -128,6 +156,10 @@ class FileList(QtGui.QListWidget):
|
||||
|
||||
|
||||
class FileSelection(QtGui.QVBoxLayout):
|
||||
"""
|
||||
The list of files and folders in the GUI, as well as buttons to add and
|
||||
delete the files and folders.
|
||||
"""
|
||||
def __init__(self):
|
||||
super(FileSelection, self).__init__()
|
||||
self.server_on = False
|
||||
@ -156,6 +188,9 @@ class FileSelection(QtGui.QVBoxLayout):
|
||||
self.update()
|
||||
|
||||
def update(self):
|
||||
"""
|
||||
Update the GUI elements based on the current state.
|
||||
"""
|
||||
# all buttons should be disabled if the server is on
|
||||
if self.server_on:
|
||||
self.add_files_button.setEnabled(False)
|
||||
@ -176,6 +211,9 @@ class FileSelection(QtGui.QVBoxLayout):
|
||||
self.file_list.update()
|
||||
|
||||
def add_files(self):
|
||||
"""
|
||||
Add files button clicked.
|
||||
"""
|
||||
filenames = QtGui.QFileDialog.getOpenFileNames(
|
||||
caption=strings._('gui_choose_files', True), options=QtGui.QFileDialog.ReadOnly)
|
||||
if filenames:
|
||||
@ -184,6 +222,9 @@ class FileSelection(QtGui.QVBoxLayout):
|
||||
self.update()
|
||||
|
||||
def add_dir(self):
|
||||
"""
|
||||
Add folder button clicked.
|
||||
"""
|
||||
filename = QtGui.QFileDialog.getExistingDirectory(
|
||||
caption=strings._('gui_choose_folder', True), options=QtGui.QFileDialog.ReadOnly)
|
||||
if filename:
|
||||
@ -191,20 +232,32 @@ class FileSelection(QtGui.QVBoxLayout):
|
||||
self.update()
|
||||
|
||||
def delete_file(self):
|
||||
"""
|
||||
Delete button clicked
|
||||
"""
|
||||
current_row = self.file_list.currentRow()
|
||||
self.file_list.filenames.pop(current_row)
|
||||
self.file_list.takeItem(current_row)
|
||||
self.update()
|
||||
|
||||
def server_started(self):
|
||||
"""
|
||||
Gets called when the server starts.
|
||||
"""
|
||||
self.server_on = True
|
||||
self.file_list.setAcceptDrops(False)
|
||||
self.update()
|
||||
|
||||
def server_stopped(self):
|
||||
"""
|
||||
Gets called when the server stops.
|
||||
"""
|
||||
self.server_on = False
|
||||
self.file_list.setAcceptDrops(True)
|
||||
self.update()
|
||||
|
||||
def get_num_files(self):
|
||||
"""
|
||||
Returns the total number of files and folders in the list.
|
||||
"""
|
||||
return len(self.file_list.filenames)
|
||||
|
@ -37,6 +37,10 @@ from options import Options
|
||||
|
||||
|
||||
class Application(QtGui.QApplication):
|
||||
"""
|
||||
This is Qt's QApplication class. It has been overridden to support threads
|
||||
and the quick keyboard shortcut.
|
||||
"""
|
||||
def __init__(self):
|
||||
platform = helpers.get_platform()
|
||||
if platform == 'Linux':
|
||||
@ -53,6 +57,10 @@ class Application(QtGui.QApplication):
|
||||
|
||||
|
||||
class OnionShareGui(QtGui.QWidget):
|
||||
"""
|
||||
OnionShareGui is the main window for the GUI that contains all of the
|
||||
GUI elements.
|
||||
"""
|
||||
start_server_finished = QtCore.pyqtSignal()
|
||||
stop_server_finished = QtCore.pyqtSignal()
|
||||
starting_server_step2 = QtCore.pyqtSignal()
|
||||
@ -66,6 +74,10 @@ class OnionShareGui(QtGui.QWidget):
|
||||
self.setWindowIcon(window_icon)
|
||||
|
||||
def send_files(self, filenames=None):
|
||||
"""
|
||||
Build the GUI in send files mode.
|
||||
Note that this is the only mode currently implemented.
|
||||
"""
|
||||
# file selection
|
||||
self.file_selection = FileSelection()
|
||||
if filenames:
|
||||
@ -117,12 +129,20 @@ class OnionShareGui(QtGui.QWidget):
|
||||
self.timer.start(500)
|
||||
|
||||
def start_server_step2(self):
|
||||
"""
|
||||
Step 2 in starting the onionshare server. This displays the large filesize
|
||||
warning, if applicable.
|
||||
"""
|
||||
# warn about sending large files over Tor
|
||||
if web.zip_filesize >= 157286400: # 150mb
|
||||
self.filesize_warning.setText(strings._("large_filesize", True))
|
||||
self.filesize_warning.show()
|
||||
|
||||
def start_server(self):
|
||||
"""
|
||||
Start the onionshare server. This uses multiple threads to start the Tor hidden
|
||||
server and the web app.
|
||||
"""
|
||||
# start the hidden service
|
||||
self.status_bar.showMessage(strings._('gui_starting_server1', True))
|
||||
self.app.choose_port()
|
||||
@ -162,6 +182,9 @@ class OnionShareGui(QtGui.QWidget):
|
||||
t.start()
|
||||
|
||||
def stop_server(self):
|
||||
"""
|
||||
Stop the onionshare server.
|
||||
"""
|
||||
if self.server_status.status == self.server_status.STATUS_STARTED:
|
||||
web.stop(self.app.port)
|
||||
self.app.cleanup()
|
||||
@ -169,6 +192,9 @@ class OnionShareGui(QtGui.QWidget):
|
||||
self.stop_server_finished.emit()
|
||||
|
||||
def check_for_requests(self):
|
||||
"""
|
||||
Check for messages communicated from the web app, and update the GUI accordingly.
|
||||
"""
|
||||
self.update()
|
||||
# only check for requests if the server is running
|
||||
if self.server_status.status != self.server_status.STATUS_STARTED:
|
||||
@ -207,13 +233,22 @@ class OnionShareGui(QtGui.QWidget):
|
||||
self.status_bar.showMessage('{0:s}: {1:s}'.format(strings._('other_page_loaded', True), event["path"]))
|
||||
|
||||
def copy_url(self):
|
||||
"""
|
||||
When the URL gets copied to the clipboard, display this in the status bar.
|
||||
"""
|
||||
self.status_bar.showMessage(strings._('gui_copied_url', True), 2000)
|
||||
|
||||
def clear_message(self):
|
||||
"""
|
||||
Clear messages from the status bar.
|
||||
"""
|
||||
self.status_bar.clearMessage()
|
||||
|
||||
|
||||
def alert(msg, icon=QtGui.QMessageBox.NoIcon):
|
||||
"""
|
||||
Pop up a message in a dialog window.
|
||||
"""
|
||||
dialog = QtGui.QMessageBox()
|
||||
dialog.setWindowTitle("OnionShare")
|
||||
dialog.setWindowIcon(window_icon)
|
||||
@ -223,6 +258,9 @@ def alert(msg, icon=QtGui.QMessageBox.NoIcon):
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
The main() function implements all of the logic that the GUI version of onionshare uses.
|
||||
"""
|
||||
strings.load_strings()
|
||||
|
||||
# start the Qt app
|
||||
|
@ -24,6 +24,9 @@ from onionshare import strings, helpers
|
||||
|
||||
|
||||
class Options(QtGui.QHBoxLayout):
|
||||
"""
|
||||
The extra onionshare options in the GUI.
|
||||
"""
|
||||
def __init__(self, web):
|
||||
super(Options, self).__init__()
|
||||
|
||||
@ -42,6 +45,9 @@ class Options(QtGui.QHBoxLayout):
|
||||
self.addWidget(self.close_automatically)
|
||||
|
||||
def stay_open_changed(self, state):
|
||||
"""
|
||||
When the 'close automatically' checkbox is toggled, let the web app know.
|
||||
"""
|
||||
if state > 0:
|
||||
self.web.set_stay_open(False)
|
||||
else:
|
||||
|
@ -25,6 +25,9 @@ from onionshare import strings, helpers
|
||||
|
||||
|
||||
class ServerStatus(QtGui.QVBoxLayout):
|
||||
"""
|
||||
The server status chunk of the GUI.
|
||||
"""
|
||||
server_started = QtCore.pyqtSignal()
|
||||
server_stopped = QtCore.pyqtSignal()
|
||||
url_copied = QtCore.pyqtSignal()
|
||||
@ -73,6 +76,9 @@ class ServerStatus(QtGui.QVBoxLayout):
|
||||
self.update()
|
||||
|
||||
def update(self):
|
||||
"""
|
||||
Update the GUI elements based on the current state.
|
||||
"""
|
||||
# set the status image
|
||||
if self.status == self.STATUS_STOPPED:
|
||||
self.status_image_label.setPixmap(QtGui.QPixmap.fromImage(self.status_image_stopped))
|
||||
@ -110,31 +116,49 @@ class ServerStatus(QtGui.QVBoxLayout):
|
||||
self.server_button.setText(strings._('gui_please_wait'))
|
||||
|
||||
def server_button_clicked(self):
|
||||
"""
|
||||
Toggle starting or stopping the server.
|
||||
"""
|
||||
if self.status == self.STATUS_STOPPED:
|
||||
self.start_server()
|
||||
elif self.status == self.STATUS_STARTED:
|
||||
self.stop_server()
|
||||
|
||||
def start_server(self):
|
||||
"""
|
||||
Start the server.
|
||||
"""
|
||||
self.status = self.STATUS_WORKING
|
||||
self.update()
|
||||
self.server_started.emit()
|
||||
|
||||
def start_server_finished(self):
|
||||
"""
|
||||
The server has finished starting.
|
||||
"""
|
||||
self.status = self.STATUS_STARTED
|
||||
self.copy_url()
|
||||
self.update()
|
||||
|
||||
def stop_server(self):
|
||||
"""
|
||||
Stop the server.
|
||||
"""
|
||||
self.status = self.STATUS_WORKING
|
||||
self.update()
|
||||
self.server_stopped.emit()
|
||||
|
||||
def stop_server_finished(self):
|
||||
"""
|
||||
The server has finished stopping.
|
||||
"""
|
||||
self.status = self.STATUS_STOPPED
|
||||
self.update()
|
||||
|
||||
def copy_url(self):
|
||||
"""
|
||||
Copy the onionshare URL to the clipboard.
|
||||
"""
|
||||
url = 'http://{0:s}/{1:s}'.format(self.app.onion_host, self.web.slug)
|
||||
|
||||
if platform.system() == 'Windows':
|
||||
|
Loading…
x
Reference in New Issue
Block a user