Refactor IPC exceptions handling.

Also fixes an IPC error when qutebrowser was started twice without delay
between the invocations.
This commit is contained in:
Florian Bruhin 2015-04-17 19:22:56 +02:00
parent 38d34e1dea
commit 43df32949d
2 changed files with 60 additions and 15 deletions

View File

@ -31,6 +31,7 @@ import functools
import traceback import traceback
import faulthandler import faulthandler
import json import json
import time
from PyQt5.QtWidgets import QApplication, QDialog, QMessageBox from PyQt5.QtWidgets import QApplication, QDialog, QMessageBox
from PyQt5.QtGui import QDesktopServices, QPixmap, QIcon, QCursor, QWindow from PyQt5.QtGui import QDesktopServices, QPixmap, QIcon, QCursor, QWindow
@ -115,12 +116,18 @@ class Application(QApplication):
sys.exit(0) sys.exit(0)
log.init.debug("Starting IPC server...") log.init.debug("Starting IPC server...")
ipc.init() ipc.init()
except ipc.IPCError as e: except ipc.AddressInUseError as e:
text = ('{}\n\nMaybe another instance is running but ' # This could be a race condition...
'frozen?'.format(e)) log.init.debug("Got AddressInUseError, trying again.")
msgbox = QMessageBox(QMessageBox.Critical, "Error while " time.sleep(500)
"connecting to running instance!", text) sent = ipc.send_to_running_instance(self._args.command)
msgbox.exec_() if sent:
sys.exit(0)
else:
ipc.display_error(e)
sys.exit(1)
except ipc.Error as e:
ipc.display_error(e)
# We didn't really initialize much so far, so we just quit hard. # We didn't really initialize much so far, so we just quit hard.
sys.exit(1) sys.exit(1)

View File

@ -25,7 +25,8 @@ import getpass
import binascii import binascii
from PyQt5.QtCore import pyqtSlot, QObject from PyQt5.QtCore import pyqtSlot, QObject
from PyQt5.QtNetwork import QLocalSocket, QLocalServer from PyQt5.QtNetwork import QLocalSocket, QLocalServer, QAbstractSocket
from PyQt5.QtWidgets import QMessageBox
from qutebrowser.utils import log, objreg, usertypes from qutebrowser.utils import log, objreg, usertypes
@ -36,11 +37,40 @@ WRITE_TIMEOUT = 1000
READ_TIMEOUT = 5000 READ_TIMEOUT = 5000
class IPCError(Exception): class Error(Exception):
"""Exception raised when there was a problem with IPC.""" """Exception raised when there was a problem with IPC."""
class ListenError(Error):
"""Exception raised when there was a problem with listening to IPC.
Args:
code: The error code.
message: The error message.
"""
def __init__(self, server):
"""Constructor.
Args:
server: The QLocalServer which has the error set.
"""
super().__init__()
self.code = server.serverError()
self.message = server.errorString()
def __str__(self):
return "Error while listening to IPC server: {} (error {})".format(
self.message, self.code)
class AddressInUseError(ListenError):
"""Emitted when the server address is already in use."""
class IPCServer(QObject): class IPCServer(QObject):
"""IPC server to which clients connect to. """IPC server to which clients connect to.
@ -63,9 +93,10 @@ class IPCServer(QObject):
self._server = QLocalServer(self) self._server = QLocalServer(self)
ok = self._server.listen(SOCKETNAME) ok = self._server.listen(SOCKETNAME)
if not ok: if not ok:
raise IPCError("Error while listening to IPC server: {} " if self._server.serverError() == QAbstractSocket.AddressInUseError:
"(error {})".format(self._server.errorString(), raise AddressInUseError(self._server)
self._server.serverError())) else:
raise ListenError(self._server)
self._server.newConnection.connect(self.handle_connection) self._server.newConnection.connect(self.handle_connection)
self._socket = None self._socket = None
@ -73,8 +104,7 @@ class IPCServer(QObject):
"""Remove an existing server.""" """Remove an existing server."""
ok = QLocalServer.removeServer(SOCKETNAME) ok = QLocalServer.removeServer(SOCKETNAME)
if not ok: if not ok:
raise IPCError("Error while removing server {}!".format( raise Error("Error while removing server {}!".format(SOCKETNAME))
SOCKETNAME))
@pyqtSlot(int) @pyqtSlot(int)
def on_error(self, error): def on_error(self, error):
@ -185,13 +215,13 @@ def init():
def _socket_error(action, socket): def _socket_error(action, socket):
"""Raise an IPCError based on an action and a QLocalSocket. """Raise an Error based on an action and a QLocalSocket.
Args: Args:
action: A string like "writing to running instance". action: A string like "writing to running instance".
socket: A QLocalSocket. socket: A QLocalSocket.
""" """
raise IPCError("Error while {}: {} (error {})".format( raise Error("Error while {}: {} (error {})".format(
action, socket.errorString(), socket.error())) action, socket.errorString(), socket.error()))
@ -235,3 +265,11 @@ def send_to_running_instance(cmdlist):
log.ipc.debug("No existing instance present (error {})".format( log.ipc.debug("No existing instance present (error {})".format(
socket.error())) socket.error()))
return False return False
def display_error(exc):
"""Display a message box with an IPC error."""
text = '{}\n\nMaybe another instance is running but frozen?'.format(exc)
msgbox = QMessageBox(QMessageBox.Critical, "Error while connecting to "
"running instance!", text)
msgbox.exec_()