summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--changes/feature_use-qtreactor1
-rw-r--r--pkg/requirements-dev.pip3
-rw-r--r--pkg/requirements.pip4
-rw-r--r--src/leap/app.py27
-rw-r--r--src/leap/gui/mainwindow.py76
-rw-r--r--src/leap/gui/twisted_main.py49
-rw-r--r--src/leap/platform_init/initializers.py3
-rw-r--r--src/leap/services/tx.py46
8 files changed, 168 insertions, 41 deletions
diff --git a/changes/feature_use-qtreactor b/changes/feature_use-qtreactor
new file mode 100644
index 00000000..154a99e5
--- /dev/null
+++ b/changes/feature_use-qtreactor
@@ -0,0 +1 @@
+ o Use a qt4 reactor for twisted, for launching leap twisted services.
diff --git a/pkg/requirements-dev.pip b/pkg/requirements-dev.pip
index 23d50ceb..e241474a 100644
--- a/pkg/requirements-dev.pip
+++ b/pkg/requirements-dev.pip
@@ -11,5 +11,6 @@
# to install it. (do it after python setup.py develop and it
# will only install this)
--e git+git://github.com/leapcode/leap_pycommon.git@develop#egg=leap.common
sphinx
+
+-e git+git://github.com/leapcode/leap_pycommon.git@develop#egg=leap.common
diff --git a/pkg/requirements.pip b/pkg/requirements.pip
index a225d0de..3c5bfad0 100644
--- a/pkg/requirements.pip
+++ b/pkg/requirements.pip
@@ -13,5 +13,7 @@ keyring
python-dateutil
psutil
ipaddr
+twisted
+qt4reactor
-leap.common>=0.2.1-dev
+leap.common>=0.2.3-dev
diff --git a/src/leap/app.py b/src/leap/app.py
index bb8add0d..797cea8a 100644
--- a/src/leap/app.py
+++ b/src/leap/app.py
@@ -17,7 +17,6 @@
import logging
import signal
-import socket
import sys
from functools import partial
@@ -28,14 +27,19 @@ from leap.common.events import server as event_server
from leap.util import __version__ as VERSION
from leap.util import leap_argparse
from leap.gui import locale_rc
+from leap.gui import twisted_main
from leap.gui.mainwindow import MainWindow
from leap.platform_init import IS_MAC
from leap.platform_init.locks import we_are_the_one_and_only
+from leap.services.tx import leap_services
import codecs
codecs.register(lambda name: codecs.lookup('utf-8')
if name == 'cp65001' else None)
+# pylint: avoid unused import
+assert(locale_rc)
+
def sigint_handler(*args, **kwargs):
"""
@@ -48,9 +52,15 @@ def sigint_handler(*args, **kwargs):
mainwindow.quit()
+def install_qtreactor(logger):
+ import qt4reactor
+ qt4reactor.install()
+ logger.debug("Qt4 reactor installed")
+
+
def main():
"""
- Launches the main event loop
+ Starts the main event loop and launches the main window.
"""
event_server.ensure_server(event_server.SERVER_PORT)
@@ -96,6 +106,9 @@ def main():
logger.info('Starting app')
app = QtGui.QApplication(sys.argv)
+ # install the qt4reactor.
+ install_qtreactor(logger)
+
# To test:
# $ LANG=es ./app.py
locale = QtCore.QLocale.system().name()
@@ -119,7 +132,10 @@ def main():
timer.start(500)
timer.timeout.connect(lambda: None)
- window = MainWindow(standalone, bypass_checks)
+ window = MainWindow(
+ lambda: twisted_main.quit(app),
+ standalone=standalone,
+ bypass_checks=bypass_checks)
window.show()
sigint_window = partial(sigint_handler, window, logger=logger)
@@ -128,8 +144,11 @@ def main():
if IS_MAC:
window.raise_()
+ tx_app = leap_services()
+ assert(tx_app)
+
# Run main loop
- sys.exit(app.exec_())
+ twisted_main.start(app)
if __name__ == "__main__":
main()
diff --git a/src/leap/gui/mainwindow.py b/src/leap/gui/mainwindow.py
index b3ab56d3..fdf84766 100644
--- a/src/leap/gui/mainwindow.py
+++ b/src/leap/gui/mainwindow.py
@@ -71,15 +71,22 @@ class MainWindow(QtGui.QMainWindow):
new_updates = QtCore.Signal(object)
raise_window = QtCore.Signal([])
- def __init__(self, standalone=False, bypass_checks=False):
+ def __init__(self, quit_callback,
+ standalone=False, bypass_checks=False):
"""
Constructor for the client main window
+ :param quit_callback: Function to be called when closing
+ the application.
+ :type quit_callback: callable
+
:param standalone: Set to true if the app should use configs
- inside its pwd
+ inside its pwd
:type standalone: bool
+
:param bypass_checks: Set to true if the app should bypass
- first round of checks for CA certificates at bootstrap
+ first round of checks for CA
+ certificates at bootstrap
:type bypass_checks: bool
"""
QtGui.QMainWindow.__init__(self)
@@ -89,6 +96,7 @@ class MainWindow(QtGui.QMainWindow):
callback=self._new_updates_available)
register(signal=proto.RAISE_WINDOW,
callback=self._on_raise_window_event)
+ self._quit_callback = quit_callback
self._updates_content = ""
@@ -173,27 +181,6 @@ class MainWindow(QtGui.QMainWindow):
self._vpn.process_finished.connect(
self._eip_finished)
- QtCore.QCoreApplication.instance().connect(
- QtCore.QCoreApplication.instance(),
- QtCore.SIGNAL("aboutToQuit()"),
- self._vpn.set_should_quit)
- QtCore.QCoreApplication.instance().connect(
- QtCore.QCoreApplication.instance(),
- QtCore.SIGNAL("aboutToQuit()"),
- self._vpn.wait)
- QtCore.QCoreApplication.instance().connect(
- QtCore.QCoreApplication.instance(),
- QtCore.SIGNAL("aboutToQuit()"),
- self._checker_thread.set_should_quit)
- QtCore.QCoreApplication.instance().connect(
- QtCore.QCoreApplication.instance(),
- QtCore.SIGNAL("aboutToQuit()"),
- self._checker_thread.wait)
- QtCore.QCoreApplication.instance().connect(
- QtCore.QCoreApplication.instance(),
- QtCore.SIGNAL("aboutToQuit()"),
- self._cleanup_pidfiles)
-
self.ui.chkRemember.stateChanged.connect(
self._remember_state_changed)
self.ui.chkRemember.setEnabled(keyring.get_keyring() is not None)
@@ -447,12 +434,6 @@ class MainWindow(QtGui.QMainWindow):
"<a href=\"https://leap.se\">More about LEAP"
"</a>") % (VERSION,))
- def quit(self):
- self._really_quit = True
- if self._wizard:
- self._wizard.close()
- self.close()
-
def changeEvent(self, e):
"""
Reimplements the changeEvent method to minimize to tray
@@ -976,17 +957,42 @@ class MainWindow(QtGui.QMainWindow):
def _cleanup_pidfiles(self):
"""
- SLOT
- TRIGGERS:
- self.aboutToQuit
+ Removes lockfiles on a clean shutdown.
- Triggered on about to quit signal, removes lockfiles on a clean
- shutdown
+ Triggered after aboutToQuit signal.
"""
if IS_WIN:
lockfile = WindowsLock()
lockfile.release_lock()
+ def _cleanup_and_quit(self):
+ """
+ Call all the cleanup actions in a serialized way.
+ Should be called from the quit function.
+ """
+ logger.debug('About to quit, doing cleanup...')
+ self._vpn.set_should_quit()
+ self._vpn.wait()
+ self._checker_thread.set_should_quit()
+ self._checker_thread.wait()
+ self._cleanup_pidfiles()
+
+ def quit(self):
+ """
+ Cleanup and tidely close the main window before quitting.
+ """
+ self._cleanup_and_quit()
+
+ self._really_quit = True
+ if self._wizard:
+ self._wizard.close()
+ self.close()
+
+ if self._quit_callback:
+ self._quit_callback()
+ logger.debug('Bye.')
+
+
if __name__ == "__main__":
import signal
diff --git a/src/leap/gui/twisted_main.py b/src/leap/gui/twisted_main.py
new file mode 100644
index 00000000..44f532a4
--- /dev/null
+++ b/src/leap/gui/twisted_main.py
@@ -0,0 +1,49 @@
+# -*- coding: utf-8 -*-
+# twisted_main.py
+# Copyright (C) 2013 LEAP
+#
+# 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/>.
+"""
+Main functions for integration of twisted reactor
+"""
+import logging
+
+# Resist the temptation of putting the import reactor here,
+# it will raise an "reactor already imported" error.
+
+logger = logging.getLogger(__name__)
+
+
+def start(app):
+ """
+ Start the mainloop.
+
+ :param app: the main qt QApplication instance.
+ :type app: QtCore.QApplication
+ """
+ from twisted.internet import reactor
+ logger.debug('starting twisted reactor')
+ reactor.run()
+
+
+def quit(app):
+ """
+ Stop the mainloop.
+
+ :param app: the main qt QApplication instance.
+ :type app: QtCore.QApplication
+ """
+ from twisted.internet import reactor
+ logger.debug('stopping twisted reactor')
+ reactor.stop()
diff --git a/src/leap/platform_init/initializers.py b/src/leap/platform_init/initializers.py
index 91c7086b..2e8cbe95 100644
--- a/src/leap/platform_init/initializers.py
+++ b/src/leap/platform_init/initializers.py
@@ -28,6 +28,9 @@ from PySide import QtGui
logger = logging.getLogger(__name__)
+# NOTE we could use a deferToThread here, but should
+# be aware of this bug: http://www.themacaque.com/?p=1067
+
def init_platform():
"""
diff --git a/src/leap/services/tx.py b/src/leap/services/tx.py
new file mode 100644
index 00000000..ef08fcc6
--- /dev/null
+++ b/src/leap/services/tx.py
@@ -0,0 +1,46 @@
+# -*- coding: utf-8 -*-
+# twisted.py
+# Copyright (C) 2013 LEAP
+#
+# 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/>.
+"""
+Twisted services launched by the client
+"""
+import logging
+
+from twisted.application.service import Application
+from twisted.internet.task import LoopingCall
+
+logger = logging.getLogger(__name__)
+
+
+def task():
+ """
+ stub periodic task, mainly for tests.
+ DELETE-ME when there's real meat here :)
+ """
+ from datetime import datetime
+ logger.debug("hi there %s", datetime.now())
+
+
+def leap_services():
+ """
+ Check which twisted services are enabled and
+ register them.
+ """
+ logger.debug('starting leap services')
+ application = Application("LEAP Client Local Services")
+ #lc = LoopingCall(task)
+ #lc.start(5)
+ return application