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 faulthandler
import json
import time
from PyQt5.QtWidgets import QApplication, QDialog, QMessageBox
from PyQt5.QtGui import QDesktopServices, QPixmap, QIcon, QCursor, QWindow
@ -115,12 +116,18 @@ class Application(QApplication):
sys.exit(0)
log.init.debug("Starting IPC server...")
ipc.init()
except ipc.IPCError as e:
text = ('{}\n\nMaybe another instance is running but '
'frozen?'.format(e))
msgbox = QMessageBox(QMessageBox.Critical, "Error while "
"connecting to running instance!", text)
msgbox.exec_()
except ipc.AddressInUseError as e:
# This could be a race condition...
log.init.debug("Got AddressInUseError, trying again.")
time.sleep(500)
sent = ipc.send_to_running_instance(self._args.command)
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.
sys.exit(1)

View File

@ -25,7 +25,8 @@ import getpass
import binascii
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
@ -36,11 +37,40 @@ WRITE_TIMEOUT = 1000
READ_TIMEOUT = 5000
class IPCError(Exception):
class Error(Exception):
"""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):
"""IPC server to which clients connect to.
@ -63,9 +93,10 @@ class IPCServer(QObject):
self._server = QLocalServer(self)
ok = self._server.listen(SOCKETNAME)
if not ok:
raise IPCError("Error while listening to IPC server: {} "
"(error {})".format(self._server.errorString(),
self._server.serverError()))
if self._server.serverError() == QAbstractSocket.AddressInUseError:
raise AddressInUseError(self._server)
else:
raise ListenError(self._server)
self._server.newConnection.connect(self.handle_connection)
self._socket = None
@ -73,8 +104,7 @@ class IPCServer(QObject):
"""Remove an existing server."""
ok = QLocalServer.removeServer(SOCKETNAME)
if not ok:
raise IPCError("Error while removing server {}!".format(
SOCKETNAME))
raise Error("Error while removing server {}!".format(SOCKETNAME))
@pyqtSlot(int)
def on_error(self, error):
@ -185,13 +215,13 @@ def init():
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:
action: A string like "writing to running instance".
socket: A QLocalSocket.
"""
raise IPCError("Error while {}: {} (error {})".format(
raise Error("Error while {}: {} (error {})".format(
action, socket.errorString(), socket.error()))
@ -235,3 +265,11 @@ def send_to_running_instance(cmdlist):
log.ipc.debug("No existing instance present (error {})".format(
socket.error()))
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_()