class SingleApplication(QObject): newInstance = pyqtSignal() urlPost = pyqtSignal(str) def __init__(self): super().__init__() self.mServer = QLocalServer() self.mServer.newConnection.connect(self.newConnection) def listen(self, client): self.mServer.removeServer(client) self.mServer.listen(client) print(self.mServer.errorString()) def hasPrevious(self, name, args): socket = QLocalSocket() socket.connectToServer(name, QLocalSocket.ReadWrite) if socket.waitForConnected(): if len(args) > 1: socket.write(args[1]) socket.flush() return True return False def newConnection(self): self.newInstance.emit() self.mSocket = self.mServer.nextPendingConnection() self.mSocket.readyRead.connect(self.readyRead) def readyRead(self): self.urlPost.emit(str(self.mSocket.readAll())) self.mSocket.close()
class Server(QDialog): def __init__(self, parent=None): super(Server, self).__init__(parent) statusLabel = QLabel() statusLabel.setWordWrap(True) quitButton = QPushButton("Quit") quitButton.setAutoDefault(False) self.fortunes = ( "You've been leading a dog's life. Stay off the furniture.", "You've got to think about tomorrow.", "You will be surprised by a loud noise.", "You will feel hungry again in another hour.", "You might have mail.", "You cannot kill time without injuring eternity.", "Computers are not intelligent. They only think they are.", ) self.server = QLocalServer() if not self.server.listen('fortune'): QMessageBox.critical( self, "Fortune Server", "Unable to start the server: %s." % self.server.errorString()) self.close() return statusLabel.setText("The server is running.\nRun the Fortune Client " "example now.") quitButton.clicked.connect(self.close) self.server.newConnection.connect(self.sendFortune) buttonLayout = QHBoxLayout() buttonLayout.addStretch(1) buttonLayout.addWidget(quitButton) buttonLayout.addStretch(1) mainLayout = QVBoxLayout() mainLayout.addWidget(statusLabel) mainLayout.addLayout(buttonLayout) self.setLayout(mainLayout) self.setWindowTitle("Fortune Server") def sendFortune(self): block = QByteArray() out = QDataStream(block, QIODevice.WriteOnly) out.setVersion(QDataStream.Qt_4_0) out.writeUInt16(0) out.writeQString(random.choice(self.fortunes)) out.device().seek(0) out.writeUInt16(block.size() - 2) clientConnection = self.server.nextPendingConnection() clientConnection.disconnected.connect(clientConnection.deleteLater) clientConnection.write(block) clientConnection.flush() clientConnection.disconnectFromServer()
class Server(QDialog): def __init__(self, parent=None): super(Server, self).__init__(parent) statusLabel = QLabel() statusLabel.setWordWrap(True) quitButton = QPushButton("Quit") quitButton.setAutoDefault(False) self.fortunes = ( "You've been leading a dog's life. Stay off the furniture.", "You've got to think about tomorrow.", "You will be surprised by a loud noise.", "You will feel hungry again in another hour.", "You might have mail.", "You cannot kill time without injuring eternity.", "Computers are not intelligent. They only think they are.", ) self.server = QLocalServer() if not self.server.listen('fortune'): QMessageBox.critical(self, "Fortune Server", "Unable to start the server: %s." % self.server.errorString()) self.close() return statusLabel.setText("The server is running.\nRun the Fortune Client " "example now.") quitButton.clicked.connect(self.close) self.server.newConnection.connect(self.sendFortune) buttonLayout = QHBoxLayout() buttonLayout.addStretch(1) buttonLayout.addWidget(quitButton) buttonLayout.addStretch(1) mainLayout = QVBoxLayout() mainLayout.addWidget(statusLabel) mainLayout.addLayout(buttonLayout) self.setLayout(mainLayout) self.setWindowTitle("Fortune Server") def sendFortune(self): block = QByteArray() out = QDataStream(block, QIODevice.WriteOnly) out.setVersion(QDataStream.Qt_4_0) out.writeUInt16(0) out.writeQString(random.choice(self.fortunes)) out.device().seek(0) out.writeUInt16(block.size() - 2) clientConnection = self.server.nextPendingConnection() clientConnection.disconnected.connect(clientConnection.deleteLater) clientConnection.write(block) clientConnection.flush() clientConnection.disconnectFromServer()
class IpcServer(QObject): @classmethod def get_sock_name(cls, instance): if instance is None: return "webmacs.ipc" return "webmacs.{}.ipc".format(instance) @classmethod def check_server_connection(cls, instance=None): sock = QLocalSocket() sock.connectToServer(cls.get_sock_name(instance)) if sock.waitForConnected(1000): return IPcReader(sock) return None def __init__(self, instance=None): QObject.__init__(self) sock_name = self.get_sock_name(instance) QLocalServer.removeServer(sock_name) self._server = QLocalServer() self._server.newConnection.connect(self._on_new_connection) if not self._server.listen(sock_name): logging.error("Can not start ipc: %s" % self._server.errorString()) self._readers = {} def cleanup(self): try: os.unlink(self._server.fullServerName()) except OSError: pass @Slot() def _on_new_connection(self): conn = self._server.nextPendingConnection() reader = IPcReader(conn) reader.message_received.connect(self.handle_data) conn.readyRead.connect(reader.on_ready_read) conn.disconnected.connect(self.reader_disconnected) self._readers[conn] = reader @Slot(object) def handle_data(self, data): reader = self.sender() try: res = ipc_dispatch(data) except Exception as exc: res = str(exc) if res in (True, None): reader.send_data({"result": True}) else: reader.send_data({"result": False, "message": res}) def reader_disconnected(self): conn = self.sender() reader = self._readers.pop(conn) reader.clear() reader.deleteLater()
def test_socket_options_address_in_use_problem(qlocalserver, short_tmpdir): """Qt seems to ignore AddressInUseError when using socketOptions. With this test we verify this bug still exists. If it fails, we can probably start using setSocketOptions again. """ servername = str(short_tmpdir / 'x') s1 = QLocalServer() ok = s1.listen(servername) assert ok s2 = QLocalServer() s2.setSocketOptions(QLocalServer.UserAccessOption) ok = s2.listen(servername) print(s2.errorString()) # We actually would expect ok == False here - but we want the test to fail # when the Qt bug is fixed. assert ok
class Server(QObject): dataReceived = pyqtSignal(list) quit = pyqtSignal() def __init__(self): super().__init__() self.conn = None self.server = None def create(self, name=piony.G_SOCKET_NAME): QLocalServer.removeServer(name) self.server = QLocalServer() if not self.server.listen(name): print("Error: server -- unable to start: {}." .format(self.server.errorString())) self.quit.emit() self.server.newConnection.connect(self.notify) def close(self): self.server.close() def notify(self): logger.info("1 new conn") # WARNING: when multiple connections, each will overwrite previous! self.conn = self.server.nextPendingConnection() self.conn.readyRead.connect(self.receiveData) self.conn.disconnected.connect(self.conn.deleteLater) def receiveData(self): logger.info("waits for data") ins = QDataStream(self.conn) ins.setVersion(QDataStream.Qt_5_0) if ins.atEnd(): return argv = ins.readQVariant() logger.info("reads '%s'", str(argv)) # Must be setted up on 'show' action. Move from beginning to appropriate. action.search_dst_window() self.dataReceived.emit(argv)
class Server(QObject): dataReceived = pyqtSignal(list) quit = pyqtSignal() def __init__(self): super().__init__() self.conn = None self.server = None def create(self, name=piony.G_SOCKET_NAME): QLocalServer.removeServer(name) self.server = QLocalServer() if not self.server.listen(name): print("Error: server -- unable to start: {}.".format( self.server.errorString())) self.quit.emit() self.server.newConnection.connect(self.notify) def close(self): self.server.close() def notify(self): logger.info("1 new conn") # WARNING: when multiple connections, each will overwrite previous! self.conn = self.server.nextPendingConnection() self.conn.readyRead.connect(self.receiveData) self.conn.disconnected.connect(self.conn.deleteLater) def receiveData(self): logger.info("waits for data") ins = QDataStream(self.conn) ins.setVersion(QDataStream.Qt_5_0) if ins.atEnd(): return argv = ins.readQVariant() logger.info("reads '%s'", str(argv)) # Must be setted up on 'show' action. Move from beginning to appropriate. action.search_dst_window() self.dataReceived.emit(argv)
class IPCServer(QObject): """IPC server to which clients connect to. Attributes: ignored: Whether requests are ignored (in exception hook). _timer: A timer to handle timeouts. _server: A QLocalServer to accept new connections. _socket: The QLocalSocket we're currently connected to. """ def __init__(self, parent=None): """Start the IPC server and listen to commands.""" super().__init__(parent) self.ignored = False self._remove_server() self._timer = usertypes.Timer(self, 'ipc-timeout') self._timer.setInterval(READ_TIMEOUT) self._timer.timeout.connect(self.on_timeout) 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())) self._server.newConnection.connect(self.handle_connection) self._socket = None def _remove_server(self): """Remove an existing server.""" ok = QLocalServer.removeServer(SOCKETNAME) if not ok: raise IPCError( "Error while removing server {}!".format(SOCKETNAME)) @pyqtSlot(int) def on_error(self, error): """Convenience method which calls _socket_error on an error.""" self._timer.stop() log.ipc.debug("Socket error {}: {}".format(self._socket.error(), self._socket.errorString())) if error != QLocalSocket.PeerClosedError: _socket_error("handling IPC connection", self._socket) @pyqtSlot() def handle_connection(self): """Handle a new connection to the server.""" if self.ignored: return if self._socket is not None: log.ipc.debug("Got new connection but ignoring it because we're " "still handling another one.") return socket = self._server.nextPendingConnection() if socket is None: log.ipc.debug("No new connection to handle.") return log.ipc.debug("Client connected.") self._timer.start() self._socket = socket socket.readyRead.connect(self.on_ready_read) if socket.canReadLine(): log.ipc.debug("We can read a line immediately.") self.on_ready_read() socket.error.connect(self.on_error) if socket.error() not in (QLocalSocket.UnknownSocketError, QLocalSocket.PeerClosedError): log.ipc.debug("We got an error immediately.") self.on_error(socket.error()) socket.disconnected.connect(self.on_disconnected) if socket.state() == QLocalSocket.UnconnectedState: log.ipc.debug("Socket was disconnected immediately.") self.on_disconnected() @pyqtSlot() def on_disconnected(self): """Clean up socket when the client disconnected.""" log.ipc.debug("Client disconnected.") self._timer.stop() self._socket.deleteLater() self._socket = None # Maybe another connection is waiting. self.handle_connection() @pyqtSlot() def on_ready_read(self): """Read json data from the client.""" if self._socket is None: # this happened once and I don't know why log.ipc.warn("In on_ready_read with None socket!") return self._timer.start() while self._socket is not None and self._socket.canReadLine(): data = bytes(self._socket.readLine()) log.ipc.debug("Read from socket: {}".format(data)) try: decoded = data.decode('utf-8') except UnicodeDecodeError: log.ipc.error("Ignoring invalid IPC data.") log.ipc.debug("invalid data: {}".format( binascii.hexlify(data))) return log.ipc.debug("Processing: {}".format(decoded)) try: json_data = json.loads(decoded) except ValueError: log.ipc.error("Ignoring invalid IPC data.") log.ipc.debug("invalid json: {}".format(decoded.strip())) return try: args = json_data['args'] except KeyError: log.ipc.error("Ignoring invalid IPC data.") log.ipc.debug("no args: {}".format(decoded.strip())) return cwd = json_data.get('cwd', None) app = objreg.get('app') app.process_args(args, via_ipc=True, cwd=cwd) @pyqtSlot() def on_timeout(self): """Cancel the current connection if it was idle for too long.""" log.ipc.error("IPC connection timed out.") self._socket.close() def shutdown(self): """Shut down the IPC server cleanly.""" if self._socket is not None: self._socket.deleteLater() self._socket = None self._timer.stop() self._server.close() self._server.deleteLater() self._remove_server()
class IPCServer(QObject): """IPC server to which clients connect to. Attributes: ignored: Whether requests are ignored (in exception hook). _timer: A timer to handle timeouts. _server: A QLocalServer to accept new connections. _socket: The QLocalSocket we're currently connected to. """ def __init__(self, parent=None): """Start the IPC server and listen to commands.""" super().__init__(parent) self.ignored = False self._remove_server() self._timer = usertypes.Timer(self, 'ipc-timeout') self._timer.setInterval(READ_TIMEOUT) self._timer.timeout.connect(self.on_timeout) 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())) self._server.newConnection.connect(self.handle_connection) self._socket = None def _remove_server(self): """Remove an existing server.""" ok = QLocalServer.removeServer(SOCKETNAME) if not ok: raise IPCError("Error while removing server {}!".format( SOCKETNAME)) @pyqtSlot(int) def on_error(self, error): """Convenience method which calls _socket_error on an error.""" self._timer.stop() log.ipc.debug("Socket error {}: {}".format( self._socket.error(), self._socket.errorString())) if error != QLocalSocket.PeerClosedError: _socket_error("handling IPC connection", self._socket) @pyqtSlot() def handle_connection(self): """Handle a new connection to the server.""" if self.ignored: return if self._socket is not None: log.ipc.debug("Got new connection but ignoring it because we're " "still handling another one.") return socket = self._server.nextPendingConnection() if socket is None: log.ipc.debug("No new connection to handle.") return log.ipc.debug("Client connected.") self._timer.start() self._socket = socket socket.readyRead.connect(self.on_ready_read) if socket.canReadLine(): log.ipc.debug("We can read a line immediately.") self.on_ready_read() socket.error.connect(self.on_error) if socket.error() not in (QLocalSocket.UnknownSocketError, QLocalSocket.PeerClosedError): log.ipc.debug("We got an error immediately.") self.on_error(socket.error()) socket.disconnected.connect(self.on_disconnected) if socket.state() == QLocalSocket.UnconnectedState: log.ipc.debug("Socket was disconnected immediately.") self.on_disconnected() @pyqtSlot() def on_disconnected(self): """Clean up socket when the client disconnected.""" log.ipc.debug("Client disconnected.") self._timer.stop() self._socket.deleteLater() self._socket = None # Maybe another connection is waiting. self.handle_connection() @pyqtSlot() def on_ready_read(self): """Read json data from the client.""" if self._socket is None: # this happened once and I don't know why log.ipc.warn("In on_ready_read with None socket!") return self._timer.start() while self._socket is not None and self._socket.canReadLine(): data = bytes(self._socket.readLine()) log.ipc.debug("Read from socket: {}".format(data)) try: decoded = data.decode('utf-8') except UnicodeDecodeError: log.ipc.error("Ignoring invalid IPC data.") log.ipc.debug("invalid data: {}".format( binascii.hexlify(data))) return log.ipc.debug("Processing: {}".format(decoded)) try: json_data = json.loads(decoded) except ValueError: log.ipc.error("Ignoring invalid IPC data.") log.ipc.debug("invalid json: {}".format(decoded.strip())) return try: args = json_data['args'] except KeyError: log.ipc.error("Ignoring invalid IPC data.") log.ipc.debug("no args: {}".format(decoded.strip())) return cwd = json_data.get('cwd', None) app = objreg.get('app') app.process_pos_args(args, via_ipc=True, cwd=cwd) @pyqtSlot() def on_timeout(self): """Cancel the current connection if it was idle for too long.""" log.ipc.error("IPC connection timed out.") self._socket.close() def shutdown(self): """Shut down the IPC server cleanly.""" if self._socket is not None: self._socket.deleteLater() self._socket = None self._timer.stop() self._server.close() self._server.deleteLater() self._remove_server()
class Server(QDialog): def __init__(self, parent: QWidget = None): super().__init__(parent) self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint) self.server = QLocalServer(self) if not self.server.listen("fortune"): QMessageBox.critical( self, self.tr("Local Fortune Server"), self.tr("Unable to start the server: %s." % (self.server.errorString())), ) QTimer.singleShot(0, self.close) return statusLabel = QLabel() statusLabel.setWordWrap(True) statusLabel.setText( self. tr("The server is running.\nRun the Local Fortune Client example now." )) self.fortunes = ( self.tr( "You've been leading a dog's life. Stay off the furniture."), self.tr("You've got to think about tomorrow."), self.tr("You will be surprised by a loud noise."), self.tr("You will feel hungry again in another hour."), self.tr("You might have mail."), self.tr("You cannot kill time without injuring eternity."), self.tr( "Computers are not intelligent. They only think they are."), ) quitButton = QPushButton(self.tr("Quit")) quitButton.setAutoDefault(False) quitButton.clicked.connect(self.close) self.server.newConnection.connect(self.sendFortune) buttonLayout = QHBoxLayout() buttonLayout.addStretch(1) buttonLayout.addWidget(quitButton) buttonLayout.addStretch(1) mainLayout = QVBoxLayout(self) mainLayout.addWidget(statusLabel) mainLayout.addLayout(buttonLayout) self.setWindowTitle(QGuiApplication.applicationDisplayName()) @pyqtSlot() def sendFortune(self): block = QByteArray() out = QDataStream(block, QIODevice.WriteOnly) out.setVersion(QDataStream.Qt_5_10) message = random.choice(self.fortunes) out.writeUInt32(len(message)) out.writeQString(message) clientConnection = self.server.nextPendingConnection() clientConnection.disconnected.connect(clientConnection.deleteLater) clientConnection.write(block) clientConnection.flush() clientConnection.disconnectFromServer()
class IpcServer(QObject): @classmethod def get_sock_name(cls, instance): if instance == "default": return "webmacs.ipc" return "webmacs.{}.ipc".format(instance) @classmethod def list_all_instances(cls, check=True): if version.is_windows: logging.error("list all instances is not supported on windows") return [] # from qt sources, named pipes are created in QDir.tempPath() instances = [ n[8:-4] or "default" for n in os.listdir(QDir.tempPath()) if n.startswith("webmacs.") and n.endswith(".ipc") ] if check: new_instances = [] for instance in instances: local = cls.check_server_connection(instance) if local is not None: local.clear() new_instances.append(instance) instances = new_instances return instances @classmethod def instance_send(cls, instance, data, cb=None): """ Send some data to a webmacs instance asynchronously. """ conn = cls.check_server_connection(instance) if conn is None: return def callback(result): conn.clear() if cb is not None: cb(result) conn.message_received.connect(callback) conn.send_data(data) @classmethod def check_server_connection(cls, instance=None): sock = QLocalSocket() sock.connectToServer(cls.get_sock_name(instance)) if sock.waitForConnected(1000): return IPcReader(sock) return None def __init__(self, instance=None): QObject.__init__(self) sock_name = self.get_sock_name(instance) QLocalServer.removeServer(sock_name) self._server = QLocalServer() self._server.newConnection.connect(self._on_new_connection) if not self._server.listen(sock_name): logging.error("Can not start ipc: %s" % self._server.errorString()) self._readers = {} def cleanup(self): try: os.unlink(self._server.fullServerName()) except OSError: pass @Slot() def _on_new_connection(self): conn = self._server.nextPendingConnection() reader = IPcReader(conn) reader.message_received.connect(self.handle_data) conn.readyRead.connect(reader.on_ready_read) conn.disconnected.connect(self.reader_disconnected) self._readers[conn] = reader @Slot(object) def handle_data(self, data): reader = self.sender() try: res = ipc_dispatch(data) except Exception as exc: res = str(exc) if res in (True, None): reader.send_data({"result": True}) else: reader.send_data({"result": False, "message": res}) def reader_disconnected(self): conn = self.sender() reader = self._readers.pop(conn) reader.clear() reader.deleteLater()