Convert IPCServer to a class and handle connections async.
This commit is contained in:
parent
a3ee504c59
commit
6dc0bfa2d2
@ -127,7 +127,7 @@ class Application(QApplication):
|
|||||||
self._python_hacks()
|
self._python_hacks()
|
||||||
|
|
||||||
log.init.debug("Starting IPC server...")
|
log.init.debug("Starting IPC server...")
|
||||||
ipc.init_server()
|
ipc.init()
|
||||||
|
|
||||||
log.init.debug("Init done!")
|
log.init.debug("Init done!")
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
import json
|
import json
|
||||||
import getpass
|
import getpass
|
||||||
|
|
||||||
|
from PyQt5.QtCore import pyqtSlot, QObject
|
||||||
from PyQt5.QtNetwork import QLocalSocket, QLocalServer
|
from PyQt5.QtNetwork import QLocalSocket, QLocalServer
|
||||||
|
|
||||||
from qutebrowser.utils import log, objreg
|
from qutebrowser.utils import log, objreg
|
||||||
@ -31,14 +32,71 @@ SOCKETNAME = 'qutebrowser-{}'.format(getpass.getuser())
|
|||||||
CONNECT_TIMEOUT = 100
|
CONNECT_TIMEOUT = 100
|
||||||
WRITE_TIMEOUT = 1000
|
WRITE_TIMEOUT = 1000
|
||||||
|
|
||||||
server = None
|
|
||||||
|
|
||||||
|
|
||||||
class IPCError(Exception):
|
class IPCError(Exception):
|
||||||
|
|
||||||
"""Exception raised when there was a problem with IPC."""
|
"""Exception raised when there was a problem with IPC."""
|
||||||
|
|
||||||
|
|
||||||
|
class IPCServer(QObject):
|
||||||
|
|
||||||
|
"""IPC server to which clients connect to."""
|
||||||
|
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
"""Start the IPC server and listen to commands."""
|
||||||
|
super().__init__(parent)
|
||||||
|
ok = QLocalServer.removeServer(SOCKETNAME)
|
||||||
|
if not ok:
|
||||||
|
raise IPCError("Error while removing server {}!".format(
|
||||||
|
SOCKETNAME))
|
||||||
|
self._server = QLocalServer(self)
|
||||||
|
ok = self._server.listen(SOCKETNAME)
|
||||||
|
if not ok:
|
||||||
|
_socket_error("listening to local server", self._server)
|
||||||
|
self._server.newConnection.connect(self.on_connection)
|
||||||
|
self._socket = None
|
||||||
|
|
||||||
|
@pyqtSlot(int)
|
||||||
|
def on_error(self, error):
|
||||||
|
"""Convenience method which calls _socket_error on an error."""
|
||||||
|
if error != QLocalSocket.PeerClosedError:
|
||||||
|
_socket_error("handling IPC connection", self._socket)
|
||||||
|
|
||||||
|
@pyqtSlot()
|
||||||
|
def on_connection(self):
|
||||||
|
"""Slot for a new connection for the local socket."""
|
||||||
|
socket = self._server.nextPendingConnection()
|
||||||
|
if self._socket is not None:
|
||||||
|
# We already have a connection running, so we refuse this one.
|
||||||
|
socket.close()
|
||||||
|
socket.deleteLater()
|
||||||
|
else:
|
||||||
|
socket.readyRead.connect(self.on_ready_read)
|
||||||
|
socket.disconnected.connect(self.on_disconnected)
|
||||||
|
socket.error.connect(self.on_error)
|
||||||
|
self._socket = socket
|
||||||
|
|
||||||
|
def on_disconnected(self):
|
||||||
|
"""Clean up socket when the client disconnected."""
|
||||||
|
self._socket.deleteLater()
|
||||||
|
self._socket = None
|
||||||
|
|
||||||
|
def on_ready_read(self):
|
||||||
|
"""Read json data from the client."""
|
||||||
|
while self._socket.canReadLine():
|
||||||
|
data = bytes(self._socket.readLine())
|
||||||
|
args = json.loads(data.decode('utf-8'))
|
||||||
|
app = objreg.get('app')
|
||||||
|
app.process_args(args)
|
||||||
|
|
||||||
|
|
||||||
|
def init():
|
||||||
|
"""Initialize the global IPC server."""
|
||||||
|
app = objreg.get('app')
|
||||||
|
server = IPCServer(app)
|
||||||
|
objreg.register('ipc-server', server)
|
||||||
|
|
||||||
|
|
||||||
def _socket_error(action, socket):
|
def _socket_error(action, socket):
|
||||||
"""Raise an IPCError based on an action and a QLocal{Socket,Server}.
|
"""Raise an IPCError based on an action and a QLocal{Socket,Server}.
|
||||||
|
|
||||||
@ -79,30 +137,3 @@ def send_to_running_instance(cmdlist):
|
|||||||
_socket_error("connecting to running instance", socket)
|
_socket_error("connecting to running instance", socket)
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def init_server():
|
|
||||||
"""Start the IPC server and listen to commands."""
|
|
||||||
ok = QLocalServer.removeServer(SOCKETNAME)
|
|
||||||
if not ok:
|
|
||||||
raise IPCError("Error while removing server {}!".format(SOCKETNAME))
|
|
||||||
server = QLocalServer()
|
|
||||||
ok = server.listen(SOCKETNAME)
|
|
||||||
if not ok:
|
|
||||||
_socket_error("listening to local server", server)
|
|
||||||
server.newConnection.connect(on_localsocket_connection)
|
|
||||||
|
|
||||||
|
|
||||||
def on_localsocket_connection():
|
|
||||||
"""Slot for a new connection for the local socket.
|
|
||||||
|
|
||||||
FIXME this should be async.
|
|
||||||
"""
|
|
||||||
socket = server.nextPendingConnection()
|
|
||||||
while not socket.canReadLine():
|
|
||||||
socket.waitForReadyRead()
|
|
||||||
data = bytes(socket.readLine())
|
|
||||||
args = json.loads(data.decode('utf-8'))
|
|
||||||
app = objreg.get('app')
|
|
||||||
app.process_args(args)
|
|
||||||
socket.deleteLater()
|
|
||||||
|
Loading…
Reference in New Issue
Block a user