Esempio n. 1
0
class QTZOCPNode(QWidget):
    def __init__(self):
        super(QTZOCPNode, self).__init__()
        self.qle = QTextEdit(self)
        self.qle.move(1, 1)
        self.qle.resize(640, 480)
        self.init_zocp()
        self.show()

    def init_zocp(self):
        self.z = ZOCP("QT UI TEST")
        self.z.register_float("myFloat", 2.3, 'rw', 0, 5.0, 0.1)
        self.notifier = QSocketNotifier(self.z.inbox.getsockopt(zmq.FD),
                                        QSocketNotifier.Read)
        self.notifier.setEnabled(True)
        self.notifier.activated.connect(self.zocp_event)
        self.z.on_modified = self.on_modified
        self.z.start()

    def zocp_event(self):
        print("ZOCP EVENT START")
        self.z.run_once(0)
        print("ZOCP EVENT END")

    def on_modified(self, peer, name, data, *args, **kwargs):
        t = self.qle.toPlainText()
        t = "{0}\n{1}".format(data, t)
        self.qle.setPlainText(t)

    def closeEvent(self, *args):
        print(args)
        self.z.stop()
        del self.z
Esempio n. 2
0
class Signal(QObject):
    signal = pyqtSignal(int)
    fds = {}

    def __init__(self, signum, parent):
        super(Signal, self).__init__(parent)
        self.signum = signum
        self.sn = None
        self.fd = [None, None]
        if self.setupHandler() < 0:
            return

        self.sn = QSocketNotifier(self.fd[1].fileno(), QSocketNotifier.Read,
                                  parent)
        self.sn.activated.connect(self.handleSignal)

    def __del__(self):
        #signal.signal( self.signum, signal.SIG_DFL)
        if self.signum in Signal.fds:
            Signal.fds.pop(self.signum)
        if self.fd[0] is not None:
            self.fd[0].close()
        if self.fd[1] is not None:
            self.fd[1].close()
        #super(Signal,self).__del__()

    @staticmethod
    def create(signum, parent):
        syslog.syslog(syslog.LOG_DEBUG,
                      "DEBUG  creating Signal instance for %d" % signum)
        if signum in Signal.fds:
            if Signal.fds[signum].sn:
                Signal.fds[signum].sn.deleteLater()
            del (Signal.fds[signum])
        return Signal(signum, parent)

    def handleSignal(self):
        syslog.syslog(syslog.LOG_DEBUG,
                      "DEBUG  handling signal %d" % self.signum)
        self.sn.setEnabled(False)
        self.fd[1].recv(1)
        self.signal.emit(self.signum)
        self.sn.setEnabled(True)

    def setupHandler(self):
        syslog.syslog(syslog.LOG_DEBUG,
                      "DEBUG  setting up handler for signal %d" % self.signum)
        self.fd = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM, 0)
        if not self.fd:
            return -1
        Signal.fds[self.signum] = self
        signal.signal(self.signum, self.handler)
        signal.siginterrupt(self.signum, False)
        return 0

    @staticmethod
    def handler(signum, frame):
        syslog.syslog(syslog.LOG_DEBUG, "DEBUG  handling signal %d" % signum)
        Signal.fds[signum].fd[0].send(bytes([1]))
Esempio n. 3
0
class ServerSocket(QObject):
    """
    This class is acts a bridge between a server socket and the Qt event loop.
    See the ClientSocket class for a more detailed explanation.
    """

    def __init__(self, logger, parent=None):
        QObject.__init__(self, parent)
        self._logger = logger
        self._socket = None
        self._connected = False
        self._accept_notifier = None

    @property
    def connected(self):
        """Is the underlying socket connected?"""
        return self._connected

    def connect(self, sock):
        """Sets the underlying socket to utilize."""
        self._accept_notifier = QSocketNotifier(
            sock.fileno(), QSocketNotifier.Read, self
        )
        self._accept_notifier.activated.connect(self._notify_accept)
        self._accept_notifier.setEnabled(True)

        self._socket = sock
        self._connected = True

    def disconnect(self, err=None):
        """Terminates the current connection."""
        if not self._socket:
            return
        if err:
            self._logger.warning("Connection lost")
            self._logger.exception(err)
        self._accept_notifier.setEnabled(False)
        try:
            self._socket.close()
        except socket.error:
            pass
        self._socket = None
        self._connected = False

    def _notify_accept(self):
        """Callback called when a client is connecting."""
        while True:
            try:
                sock, address = self._socket.accept()
            except socket.error as e:
                if e.errno in (errno.EAGAIN, errno.EWOULDBLOCK):
                    break
                self.disconnect(e)
                break
            self._accept(sock)

    def _accept(self, socket):
        """Handles the client who newly connected."""
        raise NotImplementedError("accept() is not implemented")
Esempio n. 4
0
class FileListStream(QObject):
    """FileListStream represents a stream of filenames read from stdin or
    from other sources that is visualized in the FileView.
    """

    sig_file_added = pyqtSignal(FileInfo)
    sig_end_of_stream = pyqtSignal()
    sig_error = pyqtSignal()

    @staticmethod
    def from_location(app, linesep, location):
        if location.get_path() in ["/stdin", "stdin"]:
            tee_fd, stream_id = app.stream_manager.get_stdin()
        else:
            raise Exception("FileListStream: unknown location: %s", location)

        return FileListStream(app.vfs, tee_fd, linesep)

    @property
    def sig_finished(self):
        return self.sig_end_of_stream

    def __init__(self, vfs: 'VirtualFilesystem',
                 fp: IO, linesep: str = "\n") -> None:
        super().__init__()

        self.vfs = vfs
        self.fp = fp
        self.linesep = linesep

        self.readliner = None
        self.socket_notifier: Optional[QSocketNotifier] = None

    def close(self):
        self.fp.close()

    def start(self):
        self.readliner = non_blocking_readline(self.fp, self.linesep)

        self.socket_notifier = QSocketNotifier(self.fp.fileno(), QSocketNotifier.Read)
        self.socket_notifier.activated.connect(self._on_activated)

    def _on_activated(self, fd: int) -> None:
        while True:
            try:
                filename: str = next(self.readliner)
            except StopIteration:
                self.socket_notifier.setEnabled(False)
                self.socket_notifier = None
                self.sig_end_of_stream.emit()
                return
            else:
                if filename is not None:
                    location = Location.from_path(filename)
                    self.sig_file_added.emit(self.vfs.get_fileinfo(location))
                else:
                    return
Esempio n. 5
0
class QWZMQListener(QWidget):
    def __init__(self, **kwargs):
        QWidget.__init__(self, parent=None)
        #logger.debug('In QWZMQListener.__init__')

        self.timeout = kwargs.get('timeout', 1000)
        _is_normal   = kwargs.get('is_normal', True)
        _on_poll     = kwargs.get('on_poll', self.on_zmq_poll)
        _host        = kwargs.get('host', 'localhost')
        _platform    = kwargs.get('platform', 6)
        _topicfilter = kwargs.get('topicfilter', b'') # b'10001'
        _uri         = 'tcp://%s:%d' % (_host, front_pub_port(_platform)) # 'tcp://localhost:30016'

        if _is_normal : self.init_connect_zmq(_on_poll, _uri, _topicfilter)


    def init_connect_zmq(self, on_poll, uri, topicfilter):
        logger.debug('QWZMQListener.init_connect_zmq uri=%s' % uri)
        self.zmq_context = zmq.Context(1)
        self.zmq_socket = self.zmq_context.socket(zmq.SUB)
        self.zmq_socket.connect(uri)
        self.zmq_socket.setsockopt(zmq.SUBSCRIBE, topicfilter)

        self.zmq_notifier = QSocketNotifier(self.zmq_socket.getsockopt(zmq.FD), QSocketNotifier.Read, self)
        self.zmq_notifier.activated.connect(on_poll)


    def on_zmq_poll(self):
        """Needs to be re-implemented to do real work with messages from zmq.
        """
        self.zmq_notifier.setEnabled(False)
        flags = self.zmq_socket.getsockopt(zmq.EVENTS)
        flag = 'UNKNOWN'
        msg = ''
        if flags & zmq.POLLIN :
            flag = 'POLLIN'
            msg = self.zmq_socket.recv_multipart()
            self.setWindowTitle(str(msg))
        elif flags & zmq.POLLOUT : flag = 'POLLOUT'
        elif flags & zmq.POLLERR : flag = 'POLLERR'
        else : pass
        print("Flag zmq.%s in %d msg: %s" % (flag, flags, msg))

        self.zmq_notifier.setEnabled(True)
        self.kick_zmq() # WITHOUT THIS LINE IT WOULD NOT CALL on_read_msg AGAIN!


    def kick_zmq(self):
        """ WITHOUT THIS LINE IT WOULD NOT CALL on_read_msg AGAIN!
        """
        _flags = self.zmq_socket.getsockopt(zmq.EVENTS)


    def closeEvent(self, e) :
        logger.debug('%s.closeEvent' % self._name)
        QWidget.closeEvent(self, e)
Esempio n. 6
0
class XMMSConnector(QObject):

    def __init__(self, xmms):
        QObject.__init__(self)
        fd = xmms.get_fd()
        self.xmms = xmms
        self.xmms.set_need_out_fun(self.checkWrite)

        self.rSock = QSocketNotifier(fd, QSocketNotifier.Read, self)
        self.rSock.activated.connect(self.handleRead)
        self.rSock.setEnabled(True)

        self.wSock = QSocketNotifier(fd, QSocketNotifier.Write, self)
        self.wSock.activated.connect(self.handleWrite)
        self.wSock.setEnabled(False)

    def checkWrite(self, i):
        if self.xmms.want_ioout():
            self.toggleWrite(True)
        else:
            self.toggleWrite(False)

    def toggleRead(self, bool_val):
        self.rSock.setEnabled(bool_val)

    def toggleWrite(self, bool_val):
        self.wSock.setEnabled(bool_val)

    def handleRead(self, i):
        self.xmms.ioin()

    def handleWrite(self, i):
        self.xmms.ioout()
Esempio n. 7
0
    def register_io(self, fd, callback, mode, *args, **kwargs):
        handler = six.next(self._handlers)
        notifier = QSocketNotifier(self.fd_number(fd), self.constants[mode])
        with self._mutex:
            self._io_handlers[handler] = notifier

        def _io_cb(*_):
            if not self._safe_callback(callback, fd, *args, **kwargs):
                self.unregister_io(handler)

        with self._mutex:
            # we need to store the closure callback to avoid the garbage collector
            # from collecting the closure
            self._io_handlers[handler] = (notifier, _io_cb)

        notifier.setEnabled(True)
        notifier.activated.connect(_io_cb)
Esempio n. 8
0
    def register_io(self, fd, callback, mode, *args, **kwargs):
        handler = six.next(self._handlers)
        notifier = QSocketNotifier(self.fd_number(fd), self.constants[mode])
        with self._mutex:
            self._io_handlers[handler] = notifier

        def _io_cb(*_):
            if not self._safe_callback(callback, fd, *args, **kwargs):
                self.unregister_io(handler)

        with self._mutex:
            # we need to store the closure callback to avoid the garbage collector
            # from collecting the closure
            self._io_handlers[handler] = (notifier, _io_cb)

        notifier.setEnabled(True)
        notifier.activated.connect(_io_cb)
Esempio n. 9
0
class _QtFIFOReader(QObject):
    """A FIFO reader based on a QSocketNotifier."""

    got_line = pyqtSignal(str)

    def __init__(self, filepath, parent=None):
        super().__init__(parent)
        self._filepath = filepath
        # We open as R/W so we never get EOF and have to reopen the pipe.
        # See http://www.outflux.net/blog/archives/2008/03/09/using-select-on-a-fifo/
        # We also use os.open and os.fdopen rather than built-in open so we
        # can add O_NONBLOCK.
        fd = os.open(filepath, os.O_RDWR | os.O_NONBLOCK)  # pylint: disable=no-member
        self.fifo = os.fdopen(fd, 'r')
        self._notifier = QSocketNotifier(fd, QSocketNotifier.Read, self)
        self._notifier.activated.connect(self.read_line)

    @pyqtSlot()
    def read_line(self):
        """(Try to) read a line from the FIFO."""
        log.procs.debug("QSocketNotifier triggered!")
        self._notifier.setEnabled(False)
        for line in self.fifo:
            self.got_line.emit(line.rstrip('\r\n'))
        self._notifier.setEnabled(True)

    def cleanup(self):
        """Clean up so the FIFO can be closed."""
        self._notifier.setEnabled(False)
Esempio n. 10
0
class _QtFIFOReader(QObject):

    """A FIFO reader based on a QSocketNotifier."""

    got_line = pyqtSignal(str)

    def __init__(self, filepath, parent=None):
        super().__init__(parent)
        self._filepath = filepath
        # We open as R/W so we never get EOF and have to reopen the pipe.
        # See http://www.outflux.net/blog/archives/2008/03/09/using-select-on-a-fifo/
        # We also use os.open and os.fdopen rather than built-in open so we
        # can add O_NONBLOCK.
        # pylint: disable=no-member,useless-suppression
        fd = os.open(filepath, os.O_RDWR | os.O_NONBLOCK)
        self.fifo = os.fdopen(fd, 'r')
        self._notifier = QSocketNotifier(fd, QSocketNotifier.Read, self)
        self._notifier.activated.connect(self.read_line)

    @pyqtSlot()
    def read_line(self):
        """(Try to) read a line from the FIFO."""
        log.procs.debug("QSocketNotifier triggered!")
        self._notifier.setEnabled(False)
        for line in self.fifo:
            self.got_line.emit(line.rstrip('\r\n'))
        self._notifier.setEnabled(True)

    def cleanup(self):
        """Clean up so the FIFO can be closed."""
        self._notifier.setEnabled(False)
Esempio n. 11
0
class QtListener:
    def __init__(self, evtype, fileno, cb, tb=None, mark_as_closed=False):
        self.evtype, self.fileno, self.cb = evtype, fileno, cb
        self.tb, self.mark_as_closed = tb, mark_as_closed
        self.notifier = QSocketNotifier(fileno, self.eventType(evtype))
        self.notifier.activated.connect(cb)
        self.spent = False

    def __del__(self):
        self.notifier.setEnabled(False)
        self.notifier = None

    def eventType(self, evtype):
        assert evtype in (BaseHub.READ, BaseHub.WRITE)
        if evtype == BaseHub.READ:
            return QSocketNotifier.Read
        elif evtype == BaseHub.WRITE:
            return QSocketNotifier.Write

    def defang(self):
        self.notifier.activated.disconnected(self.cb)
        if self.mark_as_closed is not None:
            self.mark_as_closed()
        self.spent = True
Esempio n. 12
0
class QTZOCPNode(QWidget):

    def __init__(self):
        super(QTZOCPNode, self).__init__()
        self.qle = QTextEdit(self)
        self.qle.move(1, 1)
        self.qle.resize(640,480)
        self.init_zocp()
        self.show()

    def init_zocp(self):
        self.z = ZOCP("QT UI TEST")
        self.z.register_float("myFloat", 2.3, 'rw', 0, 5.0, 0.1)
        self.notifier = QSocketNotifier(
                self.z.inbox.getsockopt(zmq.FD), 
                QSocketNotifier.Read
                )
        self.notifier.setEnabled(True)
        self.notifier.activated.connect(self.zocp_event)
        self.z.on_modified = self.on_modified
        self.z.start()

    def zocp_event(self):
        print("ZOCP EVENT START")
        self.z.run_once(0)
        print("ZOCP EVENT END")

    def on_modified(self, peer, name, data, *args, **kwargs):
        t = self.qle.toPlainText()
        t = "{0}\n{1}".format(data, t)
        self.qle.setPlainText(t)

    def closeEvent(self, *args):
        print(args)
        self.z.stop()
        del self.z
Esempio n. 13
0
class _QtFIFOReader(QObject):

    """A FIFO reader based on a QSocketNotifier.

    Attributes:
        _filepath: The path to the opened FIFO.
        _fifo: The Python file object for the FIFO.
        _notifier: The QSocketNotifier used.

    Signals:
        got_line: Emitted when a whole line arrived.
    """

    got_line = pyqtSignal(str)

    def __init__(self, filepath, parent=None):
        super().__init__(parent)
        self._filepath = filepath
        # We open as R/W so we never get EOF and have to reopen the pipe.
        # See http://www.outflux.net/blog/archives/2008/03/09/using-select-on-a-fifo/
        # We also use os.open and os.fdopen rather than built-in open so we
        # can add O_NONBLOCK.
        # pylint: disable=no-member,useless-suppression
        fd = os.open(filepath, os.O_RDWR | os.O_NONBLOCK)
        # pylint: enable=no-member,useless-suppression
        self._fifo = os.fdopen(fd, 'r')
        self._notifier = QSocketNotifier(typing.cast(sip.voidptr, fd),
                                         QSocketNotifier.Read, self)
        self._notifier.activated.connect(  # type: ignore[attr-defined]
            self.read_line)

    @pyqtSlot()
    def read_line(self):
        """(Try to) read a line from the FIFO."""
        log.procs.debug("QSocketNotifier triggered!")
        try:
            self._notifier.setEnabled(False)
            try:
                for line in self._fifo:
                    self.got_line.emit(line.rstrip('\r\n'))
                    self._notifier.setEnabled(True)
            except UnicodeDecodeError as e:
                log.misc.error("Invalid unicode in userscript output: {}"
                               .format(e))
        except RuntimeError as e:
            # For unknown reasons, read_line can still get called after the
            # QSocketNotifier was already deleted...
            log.procs.debug("While reading userscript output: {}".format(e))

    def cleanup(self):
        """Clean up so the FIFO can be closed."""
        self._notifier.setEnabled(False)
        for line in self._fifo:
            self.got_line.emit(line.rstrip('\r\n'))
        self._fifo.close()
Esempio n. 14
0
class _QtFIFOReader(QObject):

    """A FIFO reader based on a QSocketNotifier.

    Attributes:
        _filepath: The path to the opened FIFO.
        _fifo: The Python file object for the FIFO.
        _notifier: The QSocketNotifier used.

    Signals:
        got_line: Emitted when a whole line arrived.
    """

    got_line = pyqtSignal(str)

    def __init__(self, filepath, parent=None):
        super().__init__(parent)
        self._filepath = filepath
        # We open as R/W so we never get EOF and have to reopen the pipe.
        # See http://www.outflux.net/blog/archives/2008/03/09/using-select-on-a-fifo/
        # We also use os.open and os.fdopen rather than built-in open so we
        # can add O_NONBLOCK.
        # pylint: disable=no-member,useless-suppression
        fd = os.open(filepath, os.O_RDWR | os.O_NONBLOCK)
        # pylint: enable=no-member,useless-suppression
        self._fifo = os.fdopen(fd, 'r')
        self._notifier = QSocketNotifier(fd, QSocketNotifier.Read, self)
        self._notifier.activated.connect(self.read_line)

    @pyqtSlot()
    def read_line(self):
        """(Try to) read a line from the FIFO."""
        log.procs.debug("QSocketNotifier triggered!")
        try:
            self._notifier.setEnabled(False)
            try:
                for line in self._fifo:
                    self.got_line.emit(line.rstrip('\r\n'))
                    self._notifier.setEnabled(True)
            except UnicodeDecodeError as e:
                log.misc.error("Invalid unicode in userscript output: {}"
                               .format(e))
        except RuntimeError as e:
            # For unknown reasons, read_line can still get called after the
            # QSocketNotifier was already deleted...
            log.procs.debug("While reading userscript output: {}".format(e))

    def cleanup(self):
        """Clean up so the FIFO can be closed."""
        self._notifier.setEnabled(False)
        for line in self._fifo:
            self.got_line.emit(line.rstrip('\r\n'))
        self._fifo.close()
Esempio n. 15
0
class ClientSocket(QObject):
    """
    A class wrapping a Python socket and integrated into the Qt event loop.
    """
    def __init__(self, logger, parent=None):
        """
        Initializes the client socket.

        :param logger: the logger to user
        :param parent: the parent object
        """
        QObject.__init__(self, parent)
        self._logger = logger
        self._socket = None

        self._read_buffer = b''
        self._read_notifier = None

        self._write_buffer = b''
        self._write_notifier = None

        self._connected = False
        self._outgoing = collections.deque()
        self._incoming = collections.deque()
        self._container = None

    @staticmethod
    def _chunkify(bs, n=65535):
        """
        Creates chunks of a specified size from a bytes string.

        :param bs: the bytes
        :param n: the size of a chunk
        :return: generator of chunks
        """
        for i in range(0, len(bs), n):
            yield bs[i:i + n]

    @property
    def connected(self):
        """
        Returns if the socket is connected.

        :return: is connected?
        """
        return self._connected

    def connect(self, sock):
        """
        Wraps the socket with the current object.

        :param sock: the socket
        """
        self._read_notifier = QSocketNotifier(sock.fileno(),
                                              QSocketNotifier.Read, self)
        self._read_notifier.activated.connect(self._notify_read)
        self._read_notifier.setEnabled(True)

        self._write_notifier = QSocketNotifier(sock.fileno(),
                                               QSocketNotifier.Write, self)
        self._write_notifier.activated.connect(self._notify_write)
        self._write_notifier.setEnabled(False)

        self._socket = sock
        self._connected = True

    def disconnect(self, err=None):
        """
        Terminates the current connection.

        :param err: the reason or None
        """
        if not self._socket:
            return
        if err:
            self._logger.warning("Connection lost")
            self._logger.exception(err)
        self._read_notifier.setEnabled(False)
        self._write_notifier.setEnabled(False)
        try:
            self._socket.close()
        except socket.error:
            pass
        self._socket = None
        self._connected = False

    def _notify_read(self):
        """
        Callback called when some data is ready to be read on the socket.
        """
        while True:
            try:
                data = self._socket.recv(4096)
            except socket.error as e:
                if e.errno not in (errno.EAGAIN, errno.EWOULDBLOCK):
                    self.disconnect(e)
                break
            if not data:
                break
            self._incoming.append(data)
        if self._incoming:
            QCoreApplication.instance().postEvent(self, PacketEvent())

    def _notify_write(self):
        """
        Callback called when some data is ready to written on the socket.
        """
        while True:
            if not self._write_buffer:
                if not self._outgoing:
                    break
                data = self._outgoing.popleft()
                if not data:
                    continue
                self._write_buffer = data
            try:
                count = self._socket.send(self._write_buffer)
            except socket.error as e:
                if e.errno not in (errno.EAGAIN, errno.EWOULDBLOCK):
                    self.disconnect(e)
                break
            self._write_buffer = self._write_buffer[count:]
        if not self._write_buffer:
            self._write_notifier.setEnabled(False)

    def event(self, event):
        """
        Callback called when a Qt event is fired.

        :param event: the event
        :return: was the event handled?
        """
        if isinstance(event, PacketEvent):
            self._dispatch()
            event.accept()
            return True
        else:
            event.ignore()
            return False

    def _dispatch(self):
        """
        Callback called when a packet event is fired.
        """
        while self._incoming:
            data = self._incoming.popleft()
            self._read_raw(data)

    def _read_raw(self, data):
        """
        Reads some raw from the underlying socket.

        :param data: the raw bytes
        """
        self._read_buffer += data

        while b'\n' in self._read_buffer and not self._container:
            lines = self._read_buffer.split(b'\n')
            self._read_buffer = b'\n'.join(lines[1:])
            self._read_line(lines[0])

        if self._container:
            # Append raw data to content already received
            if self._container.downback:  # trigger download callback
                self._container.downback(len(self._read_buffer),
                                         len(self._container))
            if len(self._read_buffer) >= len(self._container):
                content = self._read_buffer[:len(self._container)]
                self._read_buffer = self._read_buffer[len(content):]
                self._container.content = content
                self._handle_packet(self._container)
                self._container = None

    def _write_raw(self, data):
        """
        Writes some raw bytes to the underlying socket.

        :param data: the raw bytes
        """
        if not self._socket:
            return
        self._outgoing.append(data)
        if not self._write_notifier.isEnabled():
            self._write_notifier.setEnabled(True)

    def _read_line(self, line):
        """
        Reads a line from the underlying socket.

        :param line: the line
        """
        # Try to parse the line as a packet
        try:
            dct = json.loads(line.decode('utf-8'))
            packet = Packet.parse_packet(dct)
        except Exception as e:
            self._logger.warning("Invalid packet received: %s" % line)
            self._logger.exception(e)
            return

        # Wait for raw data if it is a container
        if isinstance(packet, Container):
            self._container = packet
            return  # do not go any further

        self._handle_packet(packet)

    def _write_line(self, line):
        """
        Writes a line to the underlying socket.

        :param line: the line
        """
        self._write_raw(line.encode('utf-8') + b'\n')

    def _handle_packet(self, packet):
        """
        Handle an incoming packet (used for replies).

        :param packet: the packet
        """
        self._logger.debug("Received packet: %s" % packet)

        # Notify for replies
        if isinstance(packet, Reply):
            packet.trigger_callback()

        # Otherwise forward to the subclass
        elif not self.recv_packet(packet):
            self._logger.warning("Unhandled packet received: %s" % packet)

    def send_packet(self, packet):
        """
        Sends a packet the other party.

        :param packet: the packet
        :return: a packet deferred if a reply is expected
        """
        if not self._connected:
            self._logger.warning("Sending packet while disconnected")
            return None

        # Try to build then sent the line
        try:
            line = json.dumps(packet.build_packet())
            self._write_line(line)
        except Exception as e:
            self._logger.warning("Invalid packet being sent: %s" % packet)
            self._logger.exception(e)

        self._logger.debug("Sending packet: %s" % packet)

        # Write raw data for containers
        if isinstance(packet, Container):
            data = packet.content
            count, total = 0, len(data)
            for chunk in self._chunkify(data):
                self._write_raw(chunk)
                count += len(chunk)
                if packet.upback:  # trigger upload callback
                    packet.upback(count, total)

        # Queries return a packet deferred
        if isinstance(packet, Query):
            d = PacketDeferred()
            packet.register_callback(d)
            return d
        return None

    def recv_packet(self, packet):
        """
        Receives a packet from the other party.

        :param packet: the packet
        :return: has the packet been handled?
        """
        raise NotImplementedError("recv_packet() not implemented")
Esempio n. 16
0
class ServerSocket(QObject):
    """
    A class wrapping a server socket and integrated into the Qt event loop.
    """
    def __init__(self, logger, parent=None):
        """
        Initialize the server socket.

        :param logger: the logger to use
        :param parent: the parent object
        """
        QObject.__init__(self, parent)
        self._logger = logger
        self._socket = None
        self._connected = False
        self._accept_notifier = None

    @property
    def connected(self):
        """
        Returns if the socket is connected.

        :return: is connected?
        """
        return self._connected

    def connect(self, sock):
        """
        Wraps the socket with the current object.

        :param sock: the socket
        """
        sock.settimeout(0)
        self._accept_notifier = QSocketNotifier(sock.fileno(),
                                                QSocketNotifier.Read, self)
        self._accept_notifier.activated.connect(self._notify_accept)
        self._accept_notifier.setEnabled(True)

        self._socket = sock
        self._connected = True

    def disconnect(self, err=None):
        """
        Terminates the current connection.

        :param err: the reason or None
        """
        if not self._socket:
            return
        if err:
            self._logger.warning("Connection lost")
            self._logger.exception(err)
        self._accept_notifier.setEnabled(False)
        try:
            self._socket.close()
        except socket.error:
            pass
        self._socket = None
        self._connected = False

    def _notify_accept(self):
        """
        Callback called when a client is connecting.
        """
        while True:
            try:
                sock, address = self._socket.accept()
            except socket.error as e:
                if e.errno in (errno.EAGAIN, errno.EWOULDBLOCK):
                    break
                self.disconnect(e)
                break
            sock.setblocking(False)
            self._accept(sock)

    def _accept(self, socket):
        """
        Handles the client who newly connected.

        :param socket: the socket
        """
        raise NotImplementedError('accept() is not implemented')
class ApplicationWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        # zmq
        self._zmq_context = zmq.Context()
        self._zmq_sock = self._zmq_context.socket(zmq.SUB)
        self._zmq_sock.connect("tcp://localhost:5555")
        self._zmq_sock.setsockopt(zmq.SUBSCRIBE, b'weights')
        self._zmq_sock.setsockopt(zmq.SUBSCRIBE, b'biases')
        #self._zmq_sock.setsockopt(zmq.SUBSCRIBE, b"bm_chat")
        self.read_noti = QSocketNotifier(self._zmq_sock.getsockopt(zmq.FD),
                                         QSocketNotifier.Read, self)
        self.read_noti.activated.connect(self.on_read_msg)

        self._zmq_sock2 = self._zmq_context.socket(zmq.SUB)
        self._zmq_sock2.connect("tcp://localhost:5557")
        self._zmq_sock2.setsockopt(zmq.SUBSCRIBE, b'progress')
        self.read_noti2 = QSocketNotifier(self._zmq_sock2.getsockopt(zmq.FD),
                                          QSocketNotifier.Read, self)
        self.read_noti2.activated.connect(self.on_read_msg2)

        self._main = QtWidgets.QWidget()
        self.setCentralWidget(self._main)
        vlayout = QtWidgets.QVBoxLayout(self._main)
        vlayout.setObjectName("verticalLayout")

        self.layout = QtWidgets.QHBoxLayout()
        self.layout.setObjectName("horizontalLayoutWithHeatMaps")

        self.heat_map_canvas = []
        #self.addToolBar(NavigationToolbar(static_canvas, self))

        #self.layout.addWidget(cost_canvas)
        #self.addToolBar(QtCore.Qt.BottomToolBarArea, NavigationToolbar(cost_canvas, self))

        layout2 = QtWidgets.QHBoxLayout()
        layout2.setObjectName("horizontalLayoutWithErrorGraphAndControls")

        layout3 = QtWidgets.QHBoxLayout()
        layout3.setObjectName("horizontalLayoutWithErrorGraph")

        #static_canvas = FigureCanvas(Figure(figsize=(5, 3)))
        cost_canvas = FigureCanvas(Figure(figsize=(5, 3)))
        eval_canvas = FigureCanvas(Figure(figsize=(5, 3)))
        layout3.addWidget(cost_canvas)
        layout3.addWidget(eval_canvas)

        self.learninRate = QDoubleSpinBox()
        self.learninRate.setValue(0.05)
        self.learninRate.setSingleStep(0.005)
        self.learninRate.setDecimals(3)

        self.l1 = QDoubleSpinBox()
        self.l1.setValue(0.05)
        self.l1.setSingleStep(0.005)
        self.l1.setDecimals(3)

        self.l2 = QDoubleSpinBox()
        self.l2.setValue(0.05)
        self.l2.setSingleStep(0.005)
        self.l2.setDecimals(3)

        self.sendButton = QPushButton()
        self.sendButton.setText("Send")
        self.sendButton.clicked.connect(self.sendHiperParameters)

        layout4 = QtWidgets.QVBoxLayout()
        layout4.setObjectName("vertiacalWithControls")
        layout4.addWidget(QLabel("Learning Rate"))
        layout4.addWidget(self.learninRate)
        layout4.addWidget(QLabel("L1"))
        layout4.addWidget(self.l1)
        layout4.addWidget(QLabel("L2"))
        layout4.addWidget(self.l2)
        layout4.addWidget(self.sendButton)

        layout2.addLayout(layout3)
        layout2.addLayout(layout4)

        vlayout.addLayout(self.layout)
        vlayout.addLayout(layout2)

        # seaborn !!!
        # sns.swarmplot(x="species", y="petal_length", data=iris, ax=self._seaborn_heatmap_ax)
        # seaborn !!!

        # self._static_ax = static_canvas.figure.subplots()
        # t = np.linspace(0, 10, 501)
        # self._static_ax.plot(t, np.tan(t), ".")

        self._cost_ax = cost_canvas.figure.subplots()
        self._eval_ax = eval_canvas.figure.subplots()
        # self._timer = cost_canvas.new_timer(
        #     100, [(self._update_canvas, (), {})])
        # self._timer.start()
        self.cost = np.array([])
        self.eval = np.array([])

        QtCore.QTimer.singleShot(1000, self.OnLoad)

    def sendHiperParameters(self):
        print(self.learninRate.value(), self.l1.value(), self.l2.value())

    def OnLoad(self):
        startRunCar()

    def updateProgress(self, cost, eval):
        self.cost = np.append(self.cost, [cost])
        self.eval = np.append(self.eval, [eval])

        self._cost_ax.clear()
        t = np.linspace(0, 10, 101)
        # Shift the sinusoid as a function of time.
        self._cost_ax.plot(self.cost)
        self._cost_ax.figure.canvas.draw()

        self._eval_ax.clear()
        t = np.linspace(0, 10, 101)
        # Shift the sinusoid as a function of time.
        self._eval_ax.plot(self.eval)
        self._eval_ax.figure.canvas.draw()

    def update_heatmaps(self, weights, biases):
        if (len(self.heat_map_canvas) == 0):
            self._seaborn_heatmap_ax = []
            for i in range(len(weights) + 1):
                figsize = (5, 3) if i < len(weights) else (5, 1)
                self.heat_map_canvas.append(
                    FigureCanvas(Figure(figsize=figsize)))
                self.layout.addWidget(self.heat_map_canvas[-1])
                self._seaborn_heatmap_ax.append(
                    self.heat_map_canvas[-1].figure.subplots())

        print('update weights')

        weights = np.abs(weights)
        vmin = 0
        vmax = max([np.amax(x) for x in weights])

        for (w, i) in zip(weights, range(len(weights))):
            a, b = w.shape
            self._seaborn_heatmap_ax[i].clear()

            if (i < len(weights) - 1):
                sns.heatmap(w,
                            ax=self._seaborn_heatmap_ax[i],
                            vmin=vmin,
                            vmax=vmax,
                            cbar=False)
            else:
                # Обновление еще и colormap
                self._seaborn_heatmap_ax[-1].clear()
                sns.heatmap(w,
                            ax=self._seaborn_heatmap_ax[i],
                            cbar_ax=self._seaborn_heatmap_ax[-1],
                            vmin=vmin,
                            vmax=vmax,
                            cbar=True)
                self._seaborn_heatmap_ax[-1].figure.canvas.draw()

            self._seaborn_heatmap_ax[i].figure.canvas.draw()

    def on_read_msg(self):
        self.read_noti.setEnabled(False)

        if self._zmq_sock.getsockopt(zmq.EVENTS) & zmq.POLLIN:
            while self._zmq_sock.getsockopt(zmq.EVENTS) & zmq.POLLIN:
                topic = self._zmq_sock.recv_string()
                data = self._zmq_sock.recv_pyobj()
                print(topic)
                weights, biases = data
                self.update_heatmaps(weights, biases)
        elif self._zmq_sock.getsockopt(zmq.EVENTS) & zmq.POLLOUT:
            print("[Socket] zmq.POLLOUT")
        elif self._zmq_sock.getsockopt(zmq.EVENTS) & zmq.POLLERR:
            print("[Socket] zmq.POLLERR")

        self.read_noti.setEnabled(True)

    def on_read_msg2(self):
        self.read_noti2.setEnabled(False)

        if self._zmq_sock2.getsockopt(zmq.EVENTS) & zmq.POLLIN:
            while self._zmq_sock2.getsockopt(zmq.EVENTS) & zmq.POLLIN:
                topic = self._zmq_sock2.recv_string()
                data = self._zmq_sock2.recv_pyobj()
                print(topic)
                cost, eval = data
                self.updateProgress(cost, eval)
        elif self._zmq_sock2.getsockopt(zmq.EVENTS) & zmq.POLLOUT:
            print("[Socket] zmq.POLLOUT")
        elif self._zmq_sock2.getsockopt(zmq.EVENTS) & zmq.POLLERR:
            print("[Socket] zmq.POLLERR")

        self.read_noti2.setEnabled(True)
Esempio n. 18
0
class ClientsDiscovery(QObject):
    """
    This class is used by the server to discover client on the local network.
    It uses an UDP socket broadcasting the server hostname and port on the
    port 31013. A client will reply back with a simple message.
    """
    def __init__(self, logger, parent=None):
        super(ClientsDiscovery, self).__init__(parent)
        self._logger = logger
        self._info = None

        self._socket = None
        self._read_notifier = None
        self._started = False

        # Timer signaling that it's time to broadcast
        self._timer = QTimer()
        self._timer.setInterval(10000)
        self._timer.timeout.connect(self._send_request)

    def start(self, host, port, ssl):
        """Start the discovery process and broadcast the given information."""
        self._logger.debug("Starting clients discovery")
        self._info = "%s %d %s" % (host, port, ssl)
        # Create a datagram socket capable of broadcasting
        self._socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
        self._socket.settimeout(0)  # No timeout
        self._socket.setblocking(0)  # No blocking

        self._read_notifier = QSocketNotifier(self._socket.fileno(),
                                              QSocketNotifier.Read, self)
        self._read_notifier.activated.connect(self._notify_read)
        self._read_notifier.setEnabled(True)
        self._started = True
        self._timer.start()
        self._send_request()

    def stop(self):
        """Stop the discovery process."""
        self._logger.debug("Stopping clients discovery")
        self._read_notifier.setEnabled(False)
        if self._socket:
            try:
                self._socket.close()
            except socket.error:
                pass
        self._socket = None
        self._started = False
        self._timer.stop()

    def _send_request(self):
        """This function sends to discovery request packets."""
        # This is very verbose as it triggers every 1 sec so only enable when debugging
        #self._logger.trace("Sending discovery request")
        request = DISCOVERY_REQUEST + " " + self._info
        request = request.encode("utf-8")
        while len(request):
            try:
                self._socket.setblocking(0)
                sent = self._socket.sendto(request, 0, ("<broadcast>", 31013))
                request = request[sent:]
            except socket.error as e:
                self._logger.warning(
                    "Couldn't send discovery request: {}".format(e))
                # Force return, otherwise the while loop will halt IDA
                # This is a temporary fix, and it's gonna yield the above
                # warning every every n seconds..
                return

    def _notify_read(self):
        """This function is called when a discovery reply is received."""
        response, address = self._socket.recvfrom(4096)
        response = response.decode("utf-8")
        if response == DISCOVERY_REPLY:
            self._logger.trace("Received discovery reply from %s:%d" % address)
Esempio n. 19
0
class ServersDiscovery(QObject):
    """
    This class is used by the client to discover servers on the local network.
    It uses an UDP socket listening on port 31013 to received the request
    broadcasted by the server. Discovery server will be shown in the UI.
    """
    def __init__(self, logger, parent=None):
        super(ServersDiscovery, self).__init__(parent)
        self._logger = logger
        self._servers = []

        self._socket = None
        self._read_notifier = None
        self._started = False

    @property
    def servers(self):
        return self._servers

    def start(self):
        """Start the discovery process and listen for discovery requests."""
        self._logger.debug("Starting servers discovery")

        # Create a datagram socket bound on port 31013
        self._socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        if platform.system() == "Darwin":
            self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
        self._socket.bind(("", 31013))
        self._socket.settimeout(0)
        self._socket.setblocking(0)

        self._read_notifier = QSocketNotifier(self._socket.fileno(),
                                              QSocketNotifier.Read, self)
        self._read_notifier.activated.connect(self._notify_read)
        self._read_notifier.setEnabled(True)
        self._started = True

    def stop(self):
        """Stop the discovery process."""
        self._logger.debug("Stopping servers discovery")
        self._read_notifier.setEnabled(False)
        try:
            self._socket.close()
        except socket.errno:
            pass
        self._socket = None
        self._started = False

    def _notify_read(self):
        """This function is called when a discovery request is received."""
        request, address = self._socket.recvfrom(4096)
        request = request.decode("utf-8")
        if request.startswith(DISCOVERY_REQUEST):
            self._logger.trace("Received discovery request from %s:%d" %
                               address)
            # Get the server information
            _, host, port, ssl = request.split()
            server = {"host": host, "port": int(port), "no_ssl": ssl != "True"}

            # Remove the old value
            self._servers = [(s, t) for (s, t) in self._servers if s != server]
            # Append the new value
            self._servers.append((server, time.time()))

            self._logger.trace("Sending discovery reply to %s:%d" % address)
            # Reply to the discovery request
            reply = DISCOVERY_REPLY
            reply = reply.encode("utf-8")
            try:
                self._socket.sendto(reply, address)
            except socket.error:
                self._logger.warning("Couldn't send discovery reply")
Esempio n. 20
0
class Application(QApplication):

    """Main application instance.

    Attributes:
        _args: ArgumentParser instance.
        _shutting_down: True if we're currently shutting down.
        _quit_status: The current quitting status.
        _crashdlg: The crash dialog currently open.
        _crashlogfile: A file handler to the fatal crash logfile.
        _event_filter: The EventFilter for the application.
        _signal_notifier: A QSocketNotifier used for signals on Unix.
        _signal_timer: A QTimer used to poll for signals on Windows.
        geometry: The geometry of the last closed main window.
    """

    def __init__(self, args):
        """Constructor.

        Args:
            Argument namespace from argparse.
        """
        # pylint: disable=too-many-statements
        self._quit_status = {
            'crash': True,
            'tabs': False,
            'main': False,
        }
        self.geometry = None
        self._shutting_down = False
        self._crashdlg = None
        self._crashlogfile = None

        qt_args = qtutils.get_args(args)
        log.init.debug("Qt arguments: {}, based on {}".format(qt_args, args))
        super().__init__(qt_args)
        sys.excepthook = self._exception_hook

        self._args = args
        objreg.register('args', args)

        objreg.register('app', self)

        if self._args.version:
            print(version.version())
            print()
            print()
            print(qutebrowser.__copyright__)
            print()
            print(version.GPL_BOILERPLATE.strip())
            sys.exit(0)

        try:
            sent = ipc.send_to_running_instance(self._args.command)
            if sent:
                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_()
            # We didn't really initialize much so far, so we just quit hard.
            sys.exit(1)

        log.init.debug("Starting init...")
        self.setQuitOnLastWindowClosed(False)
        self.setOrganizationName("qutebrowser")
        self.setApplicationName("qutebrowser")
        self.setApplicationVersion(qutebrowser.__version__)
        self._init_icon()
        utils.actute_warning()
        try:
            self._init_modules()
        except (OSError, UnicodeDecodeError) as e:
            msgbox = QMessageBox(
                QMessageBox.Critical, "Error while initializing!",
                "Error while initializing: {}".format(e))
            msgbox.exec_()
            sys.exit(1)
        QTimer.singleShot(0, self._process_args)

        log.init.debug("Initializing eventfilter...")
        self._event_filter = modeman.EventFilter(self)
        self.installEventFilter(self._event_filter)

        log.init.debug("Connecting signals...")
        self._connect_signals()

        log.init.debug("Setting up signal handlers...")
        self._setup_signals()

        QDesktopServices.setUrlHandler('http', self.open_desktopservices_url)
        QDesktopServices.setUrlHandler('https', self.open_desktopservices_url)
        QDesktopServices.setUrlHandler('qute', self.open_desktopservices_url)

        log.init.debug("Init done!")

        if self._crashdlg is not None:
            self._crashdlg.raise_()

    def __repr__(self):
        return utils.get_repr(self)

    def _init_modules(self):
        """Initialize all 'modules' which need to be initialized."""
        # pylint: disable=too-many-statements
        log.init.debug("Initializing save manager...")
        save_manager = savemanager.SaveManager(self)
        objreg.register('save-manager', save_manager)
        save_manager.add_saveable('window-geometry', self._save_geometry)
        save_manager.add_saveable('version', self._save_version)
        log.init.debug("Initializing network...")
        networkmanager.init()
        log.init.debug("Initializing readline-bridge...")
        readline_bridge = readline.ReadlineBridge()
        objreg.register('readline-bridge', readline_bridge)
        log.init.debug("Initializing directories...")
        standarddir.init(self._args)
        log.init.debug("Initializing config...")
        config.init()
        save_manager.init_autosave()
        log.init.debug("Initializing web history...")
        history.init()
        log.init.debug("Initializing crashlog...")
        self._handle_segfault()
        log.init.debug("Initializing sessions...")
        session_manager = sessions.SessionManager(self)
        objreg.register('session-manager', session_manager)
        log.init.debug("Initializing js-bridge...")
        js_bridge = qutescheme.JSBridge(self)
        objreg.register('js-bridge', js_bridge)
        log.init.debug("Initializing websettings...")
        websettings.init()
        log.init.debug("Initializing adblock...")
        host_blocker = adblock.HostBlocker()
        host_blocker.read_hosts()
        objreg.register('host-blocker', host_blocker)
        log.init.debug("Initializing quickmarks...")
        quickmark_manager = quickmarks.QuickmarkManager()
        objreg.register('quickmark-manager', quickmark_manager)
        log.init.debug("Initializing proxy...")
        proxy.init()
        log.init.debug("Initializing cookies...")
        cookie_jar = cookies.CookieJar(self)
        objreg.register('cookie-jar', cookie_jar)
        log.init.debug("Initializing cache...")
        diskcache = cache.DiskCache(self)
        objreg.register('cache', diskcache)
        log.init.debug("Initializing completions...")
        completionmodels.init()

    def _init_icon(self):
        """Initialize the icon of qutebrowser."""
        icon = QIcon()
        for size in (16, 24, 32, 48, 64, 96, 128, 256, 512):
            filename = ':/icons/qutebrowser-{}x{}.png'.format(size, size)
            pixmap = QPixmap(filename)
            qtutils.ensure_not_null(pixmap)
            icon.addPixmap(pixmap)
        qtutils.ensure_not_null(icon)
        self.setWindowIcon(icon)

    def _handle_segfault(self):
        """Handle a segfault from a previous run."""
        logname = os.path.join(standarddir.data(), 'crash.log')
        try:
            # First check if an old logfile exists.
            if os.path.exists(logname):
                with open(logname, 'r', encoding='ascii') as f:
                    data = f.read()
                os.remove(logname)
                self._init_crashlogfile()
                if data:
                    # Crashlog exists and has data in it, so something crashed
                    # previously.
                    self._crashdlg = crashdialog.get_fatal_crash_dialog(
                        self._args.debug, data)
                    self._crashdlg.show()
            else:
                # There's no log file, so we can use this to display crashes to
                # the user on the next start.
                self._init_crashlogfile()
        except OSError:
            log.init.exception("Error while handling crash log file!")
            self._init_crashlogfile()

    def _init_crashlogfile(self):
        """Start a new logfile and redirect faulthandler to it."""
        logname = os.path.join(standarddir.data(), 'crash.log')
        try:
            self._crashlogfile = open(logname, 'w', encoding='ascii')
        except OSError:
            log.init.exception("Error while opening crash log file!")
        else:
            earlyinit.init_faulthandler(self._crashlogfile)

    def _process_args(self):
        """Open startpage etc. and process commandline args."""
        config_obj = objreg.get('config')
        for sect, opt, val in self._args.temp_settings:
            try:
                config_obj.set('temp', sect, opt, val)
            except (configexc.Error, configparser.Error) as e:
                message.error('current', "set: {} - {}".format(
                    e.__class__.__name__, e))

        if not self._args.override_restore:
            self._load_session(self._args.session)
        session_manager = objreg.get('session-manager')
        if not session_manager.did_load:
            log.init.debug("Initializing main window...")
            window = mainwindow.MainWindow()
            if not self._args.nowindow:
                window.show()
            self.setActiveWindow(window)

        self.process_pos_args(self._args.command)
        self._open_startpage()
        self._open_quickstart()

    def _load_session(self, name):
        """Load the default session.

        Args:
            name: The name of the session to load, or None to read state file.
        """
        state_config = objreg.get('state-config')
        if name is None:
            try:
                name = state_config['general']['session']
            except KeyError:
                # No session given as argument and none in the session file ->
                # start without loading a session
                return
        session_manager = objreg.get('session-manager')
        try:
            session_manager.load(name)
        except sessions.SessionNotFoundError:
            message.error('current', "Session {} not found!".format(name))
        except sessions.SessionError as e:
            message.error('current', "Failed to load session {}: {}".format(
                name, e))
        try:
            del state_config['general']['session']
        except KeyError:
            pass
        # If this was a _restart session, delete it.
        if name == '_restart':
            session_manager.delete('_restart')

    def _get_window(self, via_ipc, force_window=False, force_tab=False):
        """Helper function for process_pos_args to get a window id.

        Args:
            via_ipc: Whether the request was made via IPC.
            force_window: Whether to force opening in a window.
            force_tab: Whether to force opening in a tab.
        """
        if force_window and force_tab:
            raise ValueError("force_window and force_tab are mutually "
                             "exclusive!")
        if not via_ipc:
            # Initial main window
            return 0
        window_to_raise = None
        open_target = config.get('general', 'new-instance-open-target')
        if (open_target == 'window' or force_window) and not force_tab:
            window = mainwindow.MainWindow()
            window.show()
            win_id = window.win_id
            window_to_raise = window
        else:
            try:
                window = objreg.last_window()
            except objreg.NoWindow:
                # There is no window left, so we open a new one
                window = mainwindow.MainWindow()
                window.show()
                win_id = window.win_id
                window_to_raise = window
            win_id = window.win_id
            if open_target != 'tab-silent':
                window_to_raise = window
        if window_to_raise is not None:
            window_to_raise.setWindowState(window.windowState() &
                                           ~Qt.WindowMinimized |
                                           Qt.WindowActive)
            window_to_raise.raise_()
            window_to_raise.activateWindow()
            self.alert(window_to_raise)
        return win_id

    def process_pos_args(self, args, via_ipc=False, cwd=None):
        """Process positional commandline args.

        URLs to open have no prefix, commands to execute begin with a colon.

        Args:
            args: A list of arguments to process.
            via_ipc: Whether the arguments were transmitted over IPC.
            cwd: The cwd to use for fuzzy_url.
        """
        if via_ipc and not args:
            win_id = self._get_window(via_ipc, force_window=True)
            self._open_startpage(win_id)
            return
        win_id = None
        for cmd in args:
            if cmd.startswith(':'):
                if win_id is None:
                    win_id = self._get_window(via_ipc, force_tab=True)
                log.init.debug("Startup cmd {}".format(cmd))
                commandrunner = runners.CommandRunner(win_id)
                commandrunner.run_safely_init(cmd[1:])
            elif not cmd:
                log.init.debug("Empty argument")
                win_id = self._get_window(via_ipc, force_window=True)
            else:
                win_id = self._get_window(via_ipc)
                tabbed_browser = objreg.get('tabbed-browser', scope='window',
                                            window=win_id)
                log.init.debug("Startup URL {}".format(cmd))
                try:
                    url = urlutils.fuzzy_url(cmd, cwd, relative=True)
                except urlutils.FuzzyUrlError as e:
                    message.error(0, "Error in startup argument '{}': "
                                     "{}".format(cmd, e))
                else:
                    tabbed_browser.tabopen(url, background=False)

    def _open_startpage(self, win_id=None):
        """Open startpage.

        The startpage is never opened if the given windows are not empty.

        Args:
            win_id: If None, open startpage in all empty windows.
                    If set, open the startpage in the given window.
        """
        if win_id is not None:
            window_ids = [win_id]
        else:
            window_ids = objreg.window_registry
        for cur_win_id in window_ids:
            tabbed_browser = objreg.get('tabbed-browser', scope='window',
                                        window=cur_win_id)
            if tabbed_browser.count() == 0:
                log.init.debug("Opening startpage")
                for urlstr in config.get('general', 'startpage'):
                    try:
                        url = urlutils.fuzzy_url(urlstr, do_search=False)
                    except urlutils.FuzzyUrlError as e:
                        message.error(0, "Error when opening startpage: "
                                         "{}".format(e))
                        tabbed_browser.tabopen(QUrl('about:blank'))
                    else:
                        tabbed_browser.tabopen(url)

    def _open_quickstart(self):
        """Open quickstart if it's the first start."""
        state_config = objreg.get('state-config')
        try:
            quickstart_done = state_config['general']['quickstart-done'] == '1'
        except KeyError:
            quickstart_done = False
        if not quickstart_done:
            tabbed_browser = objreg.get('tabbed-browser', scope='window',
                                        window='last-focused')
            tabbed_browser.tabopen(
                QUrl('http://www.qutebrowser.org/quickstart.html'))
            state_config['general']['quickstart-done'] = '1'

    def _setup_signals(self):
        """Set up signal handlers.

        On Windows this uses a QTimer to periodically hand control over to
        Python so it can handle signals.

        On Unix, it uses a QSocketNotifier with os.set_wakeup_fd to get
        notified.
        """
        signal.signal(signal.SIGINT, self.interrupt)
        signal.signal(signal.SIGTERM, self.interrupt)

        if os.name == 'posix' and hasattr(signal, 'set_wakeup_fd'):
            import fcntl
            read_fd, write_fd = os.pipe()
            for fd in (read_fd, write_fd):
                flags = fcntl.fcntl(fd, fcntl.F_GETFL)
                fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK)
            self._signal_notifier = QSocketNotifier(
                read_fd, QSocketNotifier.Read, self)
            self._signal_notifier.activated.connect(self._handle_signal_wakeup)
            signal.set_wakeup_fd(write_fd)
        else:
            self._signal_timer = usertypes.Timer(self, 'python_hacks')
            self._signal_timer.start(1000)
            self._signal_timer.timeout.connect(lambda: None)

    @pyqtSlot()
    def _handle_signal_wakeup(self):
        """Handle a newly arrived signal.

        This gets called via self._signal_notifier when there's a signal.

        Python will get control here, so the signal will get handled.
        """
        log.destroy.debug("Handling signal wakeup!")
        self._signal_notifier.setEnabled(False)
        read_fd = self._signal_notifier.socket()
        try:
            os.read(read_fd, 1)
        except OSError:
            log.destroy.exception("Failed to read wakeup fd.")
        self._signal_notifier.setEnabled(True)

    def _connect_signals(self):
        """Connect all signals to their slots."""
        config_obj = objreg.get('config')
        self.lastWindowClosed.connect(self.on_last_window_closed)
        config_obj.style_changed.connect(style.get_stylesheet.cache_clear)
        self.focusChanged.connect(self.on_focus_changed)
        self.focusChanged.connect(message.on_focus_changed)

    def _get_widgets(self):
        """Get a string list of all widgets."""
        widgets = self.allWidgets()
        widgets.sort(key=repr)
        return [repr(w) for w in widgets]

    def _get_pyqt_objects(self, lines, obj, depth=0):
        """Recursive method for get_all_objects to get Qt objects."""
        for kid in obj.findChildren(QObject):
            lines.append('    ' * depth + repr(kid))
            self._get_pyqt_objects(lines, kid, depth + 1)

    def get_all_objects(self):
        """Get all children of an object recursively as a string."""
        output = ['']
        widget_lines = self._get_widgets()
        widget_lines = ['    ' + e for e in widget_lines]
        widget_lines.insert(0, "Qt widgets - {} objects".format(
            len(widget_lines)))
        output += widget_lines
        pyqt_lines = []
        self._get_pyqt_objects(pyqt_lines, self)
        pyqt_lines = ['    ' + e for e in pyqt_lines]
        pyqt_lines.insert(0, 'Qt objects - {} objects:'.format(
            len(pyqt_lines)))
        output += pyqt_lines
        output += ['']
        output += objreg.dump_objects()
        return '\n'.join(output)

    def _recover_pages(self, forgiving=False):
        """Try to recover all open pages.

        Called from _exception_hook, so as forgiving as possible.

        Args:
            forgiving: Whether to ignore exceptions.

        Return:
            A list containing a list for each window, which in turn contain the
            opened URLs.
        """
        pages = []
        for win_id in objreg.window_registry:
            win_pages = []
            tabbed_browser = objreg.get('tabbed-browser', scope='window',
                                        window=win_id)
            for tab in tabbed_browser.widgets():
                try:
                    urlstr = tab.cur_url.toString(
                        QUrl.RemovePassword | QUrl.FullyEncoded)
                    if urlstr:
                        win_pages.append(urlstr)
                except Exception:
                    if forgiving:
                        log.destroy.exception("Error while recovering tab")
                    else:
                        raise
            pages.append(win_pages)
        return pages

    def _save_geometry(self):
        """Save the window geometry to the state config."""
        if self.geometry is not None:
            state_config = objreg.get('state-config')
            geom = base64.b64encode(self.geometry).decode('ASCII')
            state_config['geometry']['mainwindow'] = geom

    def _save_version(self):
        """Save the current version to the state config."""
        state_config = objreg.get('state-config')
        state_config['general']['version'] = qutebrowser.__version__

    def _destroy_crashlogfile(self):
        """Clean up the crash log file and delete it."""
        if self._crashlogfile is None:
            return
        # We use sys.__stderr__ instead of sys.stderr here so this will still
        # work when sys.stderr got replaced, e.g. by "Python Tools for Visual
        # Studio".
        if sys.__stderr__ is not None:
            faulthandler.enable(sys.__stderr__)
        else:
            faulthandler.disable()
        try:
            self._crashlogfile.close()
            os.remove(self._crashlogfile.name)
        except OSError:
            log.destroy.exception("Could not remove crash log!")

    def _exception_hook(self, exctype, excvalue, tb):  # noqa
        """Handle uncaught python exceptions.

        It'll try very hard to write all open tabs to a file, and then exit
        gracefully.
        """
        exc = (exctype, excvalue, tb)

        if not self._quit_status['crash']:
            log.misc.error("ARGH, there was an exception while the crash "
                           "dialog is already shown:", exc_info=exc)
            return

        log.misc.error("Uncaught exception", exc_info=exc)

        is_ignored_exception = (exctype is bdb.BdbQuit or
                                not issubclass(exctype, Exception))

        if self._args.pdb_postmortem:
            pdb.post_mortem(tb)

        if (is_ignored_exception or self._args.no_crash_dialog or
                self._args.pdb_postmortem):
            # pdb exit, KeyboardInterrupt, ...
            status = 0 if is_ignored_exception else 2
            try:
                self.shutdown(status)
                return
            except Exception:
                log.init.exception("Error while shutting down")
                self.quit()
                return

        self._quit_status['crash'] = False

        try:
            pages = self._recover_pages(forgiving=True)
        except Exception:
            log.destroy.exception("Error while recovering pages")
            pages = []

        try:
            cmd_history = objreg.get('command-history')[-5:]
        except Exception:
            log.destroy.exception("Error while getting history: {}")
            cmd_history = []

        try:
            objects = self.get_all_objects()
        except Exception:
            log.destroy.exception("Error while getting objects")
            objects = ""

        try:
            objreg.get('ipc-server').ignored = True
        except Exception:
            log.destroy.exception("Error while ignoring ipc")

        try:
            self.lastWindowClosed.disconnect(self.on_last_window_closed)
        except TypeError:
            log.destroy.exception("Error while preventing shutdown")
        QApplication.closeAllWindows()
        self._crashdlg = crashdialog.ExceptionCrashDialog(
            self._args.debug, pages, cmd_history, exc, objects)
        ret = self._crashdlg.exec_()
        if ret == QDialog.Accepted:  # restore
            self._do_restart(pages)

        # We might risk a segfault here, but that's better than continuing to
        # run in some undefined state, so we only do the most needed shutdown
        # here.
        qInstallMessageHandler(None)
        self._destroy_crashlogfile()
        sys.exit(1)

    def _get_restart_args(self, pages=(), session=None):
        """Get the current working directory and args to relaunch qutebrowser.

        Args:
            pages: The pages to re-open.
            session: The session to load, or None.

        Return:
            An (args, cwd) tuple.
                args: The commandline as a list of strings.
                cwd: The current working directory as a string.
        """
        if os.path.basename(sys.argv[0]) == 'qutebrowser':
            # Launched via launcher script
            args = [sys.argv[0]]
            cwd = None
        elif hasattr(sys, 'frozen'):
            args = [sys.executable]
            cwd = os.path.abspath(os.path.dirname(sys.executable))
        else:
            args = [sys.executable, '-m', 'qutebrowser']
            cwd = os.path.join(os.path.abspath(os.path.dirname(
                               qutebrowser.__file__)), '..')
            if not os.path.isdir(cwd):
                # Probably running from an python egg. Let's fallback to
                # cwd=None and see if that works out.
                # See https://github.com/The-Compiler/qutebrowser/issues/323
                cwd = None

        # Add all open pages so they get reopened.
        page_args = []
        for win in pages:
            page_args.extend(win)
            page_args.append('')

        # Serialize the argparse namespace into json and pass that to the new
        # process via --json-args.
        # We do this as there's no way to "unparse" the namespace while
        # ignoring some arguments.
        argdict = vars(self._args)
        argdict['session'] = None
        argdict['url'] = []
        argdict['command'] = page_args[:-1]
        argdict['json_args'] = None
        # Ensure the given session (or none at all) gets opened.
        if session is None:
            argdict['session'] = None
            argdict['override_restore'] = True
        else:
            argdict['session'] = session
            argdict['override_restore'] = False
        # Dump the data
        data = json.dumps(argdict)
        args += ['--json-args', data]

        log.destroy.debug("args: {}".format(args))
        log.destroy.debug("cwd: {}".format(cwd))

        return args, cwd

    @cmdutils.register(instance='app')
    def restart(self):
        """Restart qutebrowser while keeping existing tabs open."""
        ok = self._do_restart(session='_restart')
        if ok:
            self.shutdown()

    def _do_restart(self, pages=(), session=None):
        """Inner logic to restart qutebrowser.

        The "better" way to restart is to pass a session (_restart usually) as
        that'll save the complete state.

        However we don't do that (and pass a list of pages instead) when we
        restart because of an exception, as that's a lot simpler and we don't
        want to risk anything going wrong.

        Args:
            pages: A list of URLs to open.
            session: The session to load, or None.

        Return:
            True if the restart succeeded, False otherwise.
        """
        log.destroy.debug("sys.executable: {}".format(sys.executable))
        log.destroy.debug("sys.path: {}".format(sys.path))
        log.destroy.debug("sys.argv: {}".format(sys.argv))
        log.destroy.debug("frozen: {}".format(hasattr(sys, 'frozen')))
        # Save the session if one is given.
        if session is not None:
            session_manager = objreg.get('session-manager')
            session_manager.save(session)
        # Open a new process and immediately shutdown the existing one
        try:
            args, cwd = self._get_restart_args(pages, session)
            if cwd is None:
                subprocess.Popen(args)
            else:
                subprocess.Popen(args, cwd=cwd)
        except OSError:
            log.destroy.exception("Failed to restart")
            return False
        else:
            return True

    @cmdutils.register(instance='app', maxsplit=0, debug=True)
    def debug_pyeval(self, s):
        """Evaluate a python string and display the results as a web page.

        //

        We have this here rather in utils.debug so the context of eval makes
        more sense and because we don't want to import much stuff in the utils.

        Args:
            s: The string to evaluate.
        """
        try:
            r = eval(s)
            out = repr(r)
        except Exception:
            out = traceback.format_exc()
        qutescheme.pyeval_output = out
        tabbed_browser = objreg.get('tabbed-browser', scope='window',
                                    window='last-focused')
        tabbed_browser.openurl(QUrl('qute:pyeval'), newtab=True)

    @cmdutils.register(instance='app')
    def report(self):
        """Report a bug in qutebrowser."""
        pages = self._recover_pages()
        cmd_history = objreg.get('command-history')[-5:]
        objects = self.get_all_objects()
        self._crashdlg = crashdialog.ReportDialog(pages, cmd_history, objects)
        self._crashdlg.show()

    def interrupt(self, signum, _frame):
        """Handler for signals to gracefully shutdown (SIGINT/SIGTERM).

        This calls self.shutdown and remaps the signal to call
        self.interrupt_forcefully the next time.
        """
        log.destroy.info("SIGINT/SIGTERM received, shutting down!")
        log.destroy.info("Do the same again to forcefully quit.")
        signal.signal(signal.SIGINT, self.interrupt_forcefully)
        signal.signal(signal.SIGTERM, self.interrupt_forcefully)
        # If we call shutdown directly here, we get a segfault.
        QTimer.singleShot(0, functools.partial(self.shutdown, 128 + signum))

    def interrupt_forcefully(self, signum, _frame):
        """Interrupt forcefully on the second SIGINT/SIGTERM request.

        This skips our shutdown routine and calls QApplication:exit instead.
        It then remaps the signals to call self.interrupt_really_forcefully the
        next time.
        """
        log.destroy.info("Forceful quit requested, goodbye cruel world!")
        log.destroy.info("Do the same again to quit with even more force.")
        signal.signal(signal.SIGINT, self.interrupt_really_forcefully)
        signal.signal(signal.SIGTERM, self.interrupt_really_forcefully)
        # This *should* work without a QTimer, but because of the trouble in
        # self.interrupt we're better safe than sorry.
        QTimer.singleShot(0, functools.partial(self.exit, 128 + signum))

    def interrupt_really_forcefully(self, signum, _frame):
        """Interrupt with even more force on the third SIGINT/SIGTERM request.

        This doesn't run *any* Qt cleanup and simply exits via Python.
        It will most likely lead to a segfault.
        """
        log.destroy.info("WHY ARE YOU DOING THIS TO ME? :(")
        sys.exit(128 + signum)

    @cmdutils.register(instance='app', name='wq',
                       completion=[usertypes.Completion.sessions])
    def save_and_quit(self, name='default'):
        """Save open pages and quit.

        Args:
            name: The name of the session.
        """
        self.shutdown(session=name)

    @pyqtSlot()
    def on_last_window_closed(self):
        """Slot which gets invoked when the last window was closed."""
        self.shutdown(last_window=True)

    @cmdutils.register(instance='app', name=['quit', 'q'], ignore_args=True)
    def shutdown(self, status=0, session=None, last_window=False):
        """Quit qutebrowser.

        Args:
            status: The status code to exit with.
            session: A session name if saving should be forced.
            last_window: If the shutdown was triggered due to the last window
                         closing.
        """
        if self._shutting_down:
            return
        self._shutting_down = True
        log.destroy.debug("Shutting down with status {}, session {}..."
                          .format(status, session))

        session_manager = objreg.get('session-manager')
        if session is not None:
            session_manager.save(session, last_window=last_window,
                                 load_next_time=True)
        elif config.get('general', 'save-session'):
            session_manager.save('default', last_window=last_window,
                                 load_next_time=True)

        deferrer = False
        for win_id in objreg.window_registry:
            prompter = objreg.get('prompter', None, scope='window',
                                  window=win_id)
            if prompter is not None and prompter.shutdown():
                deferrer = True
        if deferrer:
            # If shutdown was called while we were asking a question, we're in
            # a still sub-eventloop (which gets quit now) and not in the main
            # one.
            # This means we need to defer the real shutdown to when we're back
            # in the real main event loop, or we'll get a segfault.
            log.destroy.debug("Deferring real shutdown because question was "
                              "active.")
            QTimer.singleShot(0, functools.partial(self._shutdown, status))
        else:
            # If we have no questions to shut down, we are already in the real
            # event loop, so we can shut down immediately.
            self._shutdown(status)

    def _shutdown(self, status):  # noqa
        """Second stage of shutdown."""
        log.destroy.debug("Stage 2 of shutting down...")
        # Remove eventfilter
        try:
            log.destroy.debug("Removing eventfilter...")
            self.removeEventFilter(self._event_filter)
        except AttributeError:
            pass
        # Close all windows
        QApplication.closeAllWindows()
        # Shut down IPC
        try:
            objreg.get('ipc-server').shutdown()
        except KeyError:
            pass
        # Save everything
        try:
            save_manager = objreg.get('save-manager')
        except KeyError:
            log.destroy.debug("Save manager not initialized yet, so not "
                              "saving anything.")
        else:
            for key in save_manager.saveables:
                try:
                    save_manager.save(key, is_exit=True)
                except OSError as e:
                    msgbox = QMessageBox(
                        QMessageBox.Critical, "Error while saving!",
                        "Error while saving {}: {}".format(key, e))
                    msgbox.exec_()
        # Re-enable faulthandler to stdout, then remove crash log
        log.destroy.debug("Deactiving crash log...")
        self._destroy_crashlogfile()
        # If we don't kill our custom handler here we might get segfaults
        log.destroy.debug("Deactiving message handler...")
        qInstallMessageHandler(None)
        # Now we can hopefully quit without segfaults
        log.destroy.debug("Deferring QApplication::exit...")
        # We use a singleshot timer to exit here to minimize the likelihood of
        # segfaults.
        QTimer.singleShot(0, functools.partial(self.exit, status))

    def on_focus_changed(self, _old, new):
        """Register currently focused main window in the object registry."""
        if new is None:
            window = None
        else:
            window = new.window()
        if window is None or not isinstance(window, mainwindow.MainWindow):
            try:
                objreg.delete('last-focused-main-window')
            except KeyError:
                pass
        else:
            objreg.register('last-focused-main-window', window, update=True)

    @pyqtSlot(QUrl)
    def open_desktopservices_url(self, url):
        """Handler to open an URL via QDesktopServices."""
        win_id = self._get_window(via_ipc=True, force_window=False)
        tabbed_browser = objreg.get('tabbed-browser', scope='window',
                                    window=win_id)
        tabbed_browser.tabopen(url)

    def exit(self, status):
        """Extend QApplication::exit to log the event."""
        log.destroy.debug("Now calling QApplication::exit.")
        if self._args.debug_exit:
            if hunter is None:
                print("Not logging late shutdown because hunter could not be "
                      "imported!", file=sys.stderr)
            else:
                print("Now logging late shutdown.", file=sys.stderr)
                hunter.trace()
        super().exit(status)
Esempio n. 21
0
class TwistedSocketNotifier(QObject):
    """Connection between an fd event and reader/writer callbacks."""

    activated = pyqtSignal(int)

    def __init__(self, parent, reactor, watcher, socketType):
        QObject.__init__(self, parent)
        self.reactor = reactor
        self.watcher = watcher
        fd = watcher.fileno()
        self.notifier = QSocketNotifier(fd, socketType, parent)
        self.notifier.setEnabled(True)
        if socketType == QSocketNotifier.Read:
            self.fn = self.read
        else:
            self.fn = self.write
        self.notifier.activated.connect(self.fn)

    def shutdown(self):
        self.notifier.setEnabled(False)
        self.notifier.activated.disconnect(self.fn)
        self.fn = self.watcher = None
        self.notifier.deleteLater()
        self.deleteLater()

    def read(self, fd):
        if not self.watcher:
            return
        w = self.watcher

        # doRead can cause self.shutdown to be called so keep
        # a reference to self.watcher

        def _read():
            # Don't call me again, until the data has been read
            self.notifier.setEnabled(False)
            why = None
            try:
                why = w.doRead()
                inRead = True
            except:
                inRead = False
                log.err()
                why = sys.exc_info()[1]
            if why:
                self.reactor._disconnectSelectable(w, why, inRead)
            elif self.watcher:
                self.notifier.setEnabled(True)
                # Re enable notification following sucessfull read
            self.reactor._iterate(fromqt=True)

        log.callWithLogger(w, _read)

    def write(self, sock):
        if not self.watcher:
            return
        w = self.watcher

        def _write():
            why = None
            self.notifier.setEnabled(False)
            try:
                why = w.doWrite()
            except:
                log.err()
                why = sys.exc_info()[1]
            if why:
                self.reactor._disconnectSelectable(w, why, False)
            elif self.watcher:
                self.notifier.setEnabled(True)
            self.reactor._iterate(fromqt=True)

        log.callWithLogger(w, _write)
Esempio n. 22
0
class TunableDashboard(Ui_BaseDashboard):
    """GUI dashboard with asynchronous updates via IPC or network.

    TunableDashboard inherits from Ui_BaseDashboard, the bare-bones
    GUI window described by the QT Designer file 'dashboard_gui.ui'.
    The base class defines the various display widgets, but doesn't provide
    any way to update their content after the window has launched.
    TunableDashboard improves on this by accepting the input parameter
    'sock', a caller-provided socket over which the caller may send
    commands to update dashboard display fields.
    """
    def setup(self,
              db_widget,
              sock,
              width=960,
              ffmly='Fantasque Sans Mono',
              fscale=1.0):
        """Initialization routine for GUI dashboard widget: Call
           the base-class initialization routine, then establish a
           callback to receive messages over the socket.
        """

        self.db_widget, self.sock = db_widget, sock
        self.setupUi(db_widget, width=width, ffmly=ffmly, fscale=fscale)
        """ tabulate distinct fonts in widget for subsequent use in rescaling, etc. """
        self.font_set = set()

        def find_fonts(w):
            if hasattr(w, 'font'):
                self.font_set.add(w.font())
            for child in w.children():
                find_fonts(child)

        find_fonts(self.db_widget)
        log('Found {} fonts:'.format(len(self.font_set)))
        for font in self.font_set:
            log('  {}'.format(font.toString()))
        """ arrange for read_input to be called whenever data is available on the socket"""
        self.sock.setblocking(False)
        self.notifier = QSocketNotifier(sock.fileno(), QSocketNotifier.Read,
                                        db_widget)
        self.notifier.setEnabled(True)
        self.notifier.activated.connect(self.read_input)

    def read_input(self, fd):
        """ Callback invoked when there is input to read from the socket."""
        try:
            input = str(self.sock.recv(BUFSIZE), 'utf-8')
            if len(input) == 0:
                condition = 'received EOF on socket'
            elif self.process_input(input) == False:
                condition = "received 'terminate' command"
            else:
                return
        except:
            condition = get_exception_info(msg='socket error', warning=True)

        log('{}; closing dashboard'.format(condition))
        self.sock.close()
        self.notifier.setEnabled(False)
        self.db_widget.close()

    def process_input(self, input):
        """ Process a batch of input received over the socket.

        Args:
            input (str): input received over the socket

        Returns:
            False: a 'terminate' command was received; the socket
                   and window should be shut down.
            True: No 'terminate' commant received; carry on as before.
        """
        for (ln, n) in [(l, l.find(' ')) for l in input.split('\n') if l]:
            key, val = (ln.lower(), '') if n < 0 else (ln[:n].lower(),
                                                       ln[n + 1:])
            if key == 'terminate':
                return False
            elif key == 'title':
                self.db_widget.setWindowTitle(val)
            elif key == 'width':
                self.rescale(width_fraction=float(val))
            elif key == 'font_scale':
                for f in self.font_set:
                    f.setPointSize(int(float(val) * f.pointSize()))
            elif key == 'clear':
                for key in DASHBOARD_ELEMENTS:
                    self.update_item(key, '', redraw=False)
            elif key in DASHBOARD_ELEMENTS:
                self.update_item(key, val, redraw=False)
            else:
                log('ignoring unrecognized dashboard update: ' + ln)
        self.db_widget.update()
        return True

    def update_item(self, item, value, redraw=True):
        """ Set GUI dashboard element 'item' to value 'value.'
        """
        msg, w = None, self.get_widget_by_name(item)
        if isinstance(w, QLCDNumber):
            w.display(value)
        elif isinstance(w, QLabel):
            w.setText(value)
        elif isinstance(w, QProgressBar):
            tok = value.split()
            if len(tok) == 1 and tok[0].isdigit():
                w.setProperty('value', int(tok[0]))
            elif len(tok) == 3 and tok[0] == 'range' and tok[1].isdigit(
            ) and tok[2].isdigit():
                w.setRange(int(tok[1]), int(tok[2]))
                w.setProperty('value', int(tok[1]))
            elif len(tok) > 1:
                msg = 'failed to process progress-bar update: {} {}'.format(
                    item, value)
        else:
            msg = 'failed to process update for unknown dashboard element {}={}'.format(
                item, value)

        if msg:
            log('warning: {}'.format(msg))
        elif redraw:
            self.db_widget.update()

    def get_widget_by_name(self, name):
        if name.lower() == 'progress':
            return self.progress
        for w in self.db_widget.children():
            if w.objectName().strip(' :').lower() == name.lower():
                return w
        return None
Esempio n. 23
0
class ClientSocket(QObject):
    """
    A class wrapping a Python socket and integrated into the Qt event loop.
    """
    MAX_READ_SIZE = 4096
    MAX_WRITE_SIZE = 65535

    def __init__(self, logger, parent=None):
        """
        Initializes the client socket.

        :param logger: the logger to user
        """
        QObject.__init__(self, parent)
        self._logger = logger
        self._socket = None
        self._server = parent and isinstance(parent, ServerSocket)

        self._read_buffer = bytearray()
        self._read_notifier = None
        self._read_packet = None

        self._write_buffer = bytearray()
        self._write_notifier = None
        self._write_packet = None

        self._connected = False
        self._outgoing = collections.deque()
        self._incoming = collections.deque()

    @property
    def connected(self):
        """
        Returns if the socket is connected.

        :return: is connected?
        """
        return self._connected

    def connect(self, sock):
        """
        Wraps the socket with the current object.

        :param sock: the socket
        """
        self._read_notifier = QSocketNotifier(sock.fileno(),
                                              QSocketNotifier.Read, self)
        self._read_notifier.activated.connect(self._notify_read)
        self._read_notifier.setEnabled(True)

        self._write_notifier = QSocketNotifier(sock.fileno(),
                                               QSocketNotifier.Write, self)
        self._write_notifier.activated.connect(self._notify_write)
        self._write_notifier.setEnabled(False)

        self._socket = sock
        self._connected = True

    def disconnect(self, err=None):
        """
        Terminates the current connection.

        :param err: the reason or None
        """
        if not self._socket:
            return
        if err:
            self._logger.warning("Connection lost")
            self._logger.exception(err)
        self._read_notifier.setEnabled(False)
        self._write_notifier.setEnabled(False)
        try:
            self._socket.close()
        except socket.error:
            pass
        self._socket = None
        self._connected = False

    def set_keep_alive(self, cnt, intvl, idle):
        """
        Set the TCP keep-alive of the underlying socket.

         It activates after `idle` seconds of idleness, then sends a
         keep-alive ping once every `intvl` seconds, and closes the connection
         after `cnt` failed ping.
        """
        # Taken from https://github.com/markokr/skytools/
        TCP_KEEPCNT = getattr(socket, 'TCP_KEEPCNT', None)
        TCP_KEEPINTVL = getattr(socket, 'TCP_KEEPINTVL', None)
        TCP_KEEPIDLE = getattr(socket, 'TCP_KEEPIDLE', None)
        TCP_KEEPALIVE = getattr(socket, 'TCP_KEEPALIVE', None)
        SIO_KEEPALIVE_VALS = getattr(socket, 'SIO_KEEPALIVE_VALS', None)
        if TCP_KEEPIDLE is None and TCP_KEEPALIVE is None \
                and sys.platform == 'darwin':
            TCP_KEEPALIVE = 0x10

        self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
        if TCP_KEEPCNT is not None:
            self._socket.setsockopt(socket.IPPROTO_TCP, TCP_KEEPCNT, cnt)
        if TCP_KEEPINTVL is not None:
            self._socket.setsockopt(socket.IPPROTO_TCP, TCP_KEEPINTVL, intvl)
        if TCP_KEEPIDLE is not None:
            self._socket.setsockopt(socket.IPPROTO_TCP, TCP_KEEPIDLE, idle)
        elif TCP_KEEPALIVE is not None:
            self._socket.setsockopt(socket.IPPROTO_TCP, TCP_KEEPALIVE, idle)
        elif SIO_KEEPALIVE_VALS is not None:
            self._socket.ioctl(SIO_KEEPALIVE_VALS,
                               (1, idle * 1000, intvl * 1000))

    def _notify_read(self):
        """
        Callback called when some data is ready to be read on the socket.
        """
        # Read as much data as is available
        while True:
            try:
                data = self._socket.recv(ClientSocket.MAX_READ_SIZE)
                if not data:
                    self.disconnect()
                    break
            except socket.error as e:
                if e.errno not in (errno.EAGAIN, errno.EWOULDBLOCK) \
                        and not isinstance(e, ssl.SSLWantReadError) \
                        and not isinstance(e, ssl.SSLWantWriteError):
                    self.disconnect(e)
                break  # No more data available
            self._read_buffer.extend(data)

        while True:
            if self._read_packet is None:
                if b'\n' in self._read_buffer:
                    pos = self._read_buffer.index(b'\n')
                    line = self._read_buffer[:pos]
                    self._read_buffer = self._read_buffer[pos + 1:]

                    # Try to parse the line as a packet
                    try:
                        dct = json.loads(line.decode('utf-8'))
                        self._read_packet = Packet.parse_packet(
                            dct, self._server)
                    except Exception as e:
                        msg = "Invalid packet received: %s" % line
                        self._logger.warning(msg)
                        self._logger.exception(e)
                        continue
                else:
                    break  # Not enough data for a packet

            else:
                if isinstance(self._read_packet, Container):
                    avail = len(self._read_buffer)
                    total = self._read_packet.size

                    # Trigger the downback
                    if self._read_packet.downback:
                        self._read_packet.downback(min(avail, total), total)

                    # Read the container's content
                    if avail >= total:
                        self._read_packet.content = self._read_buffer[:total]
                        self._read_buffer = self._read_buffer[total:]
                    else:
                        break  # Not enough data for a packet

                self._incoming.append(self._read_packet)
                self._read_packet = None

        if self._incoming:
            QCoreApplication.instance().postEvent(self, PacketEvent())

    def _notify_write(self):
        """
        Callback called when some data is ready to written on the socket.
        """
        while True:
            if not self._write_buffer:
                if not self._outgoing:
                    break  # No more packets to send
                self._write_packet = self._outgoing.popleft()

                try:
                    line = json.dumps(self._write_packet.build_packet())
                    line = line.encode('utf-8') + b'\n'
                except Exception as e:
                    msg = "Invalid packet being sent: %s" % self._write_packet
                    self._logger.warning(msg)
                    self._logger.exception(e)
                    continue

                # Write the container's content
                self._write_buffer.extend(bytearray(line))
                if isinstance(self._write_packet, Container):
                    data = self._write_packet.content
                    self._write_buffer.extend(bytearray(data))
                    self._write_packet.size += len(line)

            # Send as many bytes as possible
            try:
                count = min(len(self._write_buffer),
                            ClientSocket.MAX_WRITE_SIZE)
                sent = self._socket.send(self._write_buffer[:count])
                self._write_buffer = self._write_buffer[sent:]
            except socket.error as e:
                if e.errno not in (errno.EAGAIN, errno.EWOULDBLOCK) \
                        and not isinstance(e, ssl.SSLWantReadError) \
                        and not isinstance(e, ssl.SSLWantWriteError):
                    self.disconnect(e)
                break  # Can't write anything

            # Trigger the upback
            if isinstance(self._write_packet, Container) \
                    and self._write_packet.upback:
                self._write_packet.size -= count
                total = len(self._write_packet.content)
                sent = max(total - self._write_packet.size, 0)
                self._write_packet.upback(sent, total)
                break

        if not self._write_buffer:
            self._write_notifier.setEnabled(False)

    def event(self, event):
        """
        Callback called when a Qt event is fired.

        :param event: the event
        :return: was the event handled?
        """
        if isinstance(event, PacketEvent):
            self._dispatch()
            event.accept()
            return True
        else:
            event.ignore()
            return False

    def _dispatch(self):
        """
        Callback called when a packet event is fired.
        """
        while self._incoming:
            packet = self._incoming.popleft()
            self._logger.debug("Received packet: %s" % packet)

            # Notify for replies
            if isinstance(packet, Reply):
                packet.trigger_callback()

            # Otherwise forward to the subclass
            elif not self.recv_packet(packet):
                self._logger.warning("Unhandled packet received: %s" % packet)

    def send_packet(self, packet):
        """
        Sends a packet the other party.

        :param packet: the packet
        :return: a packet deferred if a reply is expected
        """
        if not self._connected:
            self._logger.warning("Sending packet while disconnected")
            return None

        self._logger.debug("Sending packet: %s" % packet)

        # Enqueue the packet
        self._outgoing.append(packet)
        if not self._write_notifier.isEnabled():
            self._write_notifier.setEnabled(True)

        # Queries return a packet deferred
        if isinstance(packet, Query):
            d = PacketDeferred()
            packet.register_callback(d)
            return d
        return None

    def recv_packet(self, packet):
        """
        Receives a packet from the other party.

        :param packet: the packet
        :return: has the packet been handled?
        """
        raise NotImplementedError("recv_packet() not implemented")
Esempio n. 24
0
class SignalHandler(QObject):
    """Handler responsible for handling OS signals (SIGINT, SIGTERM, etc.).

    Attributes:
        _app: The QApplication instance.
        _quitter: The Quitter instance.
        _activated: Whether activate() was called.
        _notifier: A QSocketNotifier used for signals on Unix.
        _timer: A QTimer used to poll for signals on Windows.
        _orig_handlers: A {signal: handler} dict of original signal handlers.
        _orig_wakeup_fd: The original wakeup filedescriptor.
    """
    def __init__(self, *, app, quitter, parent=None):
        super().__init__(parent)
        self._app = app
        self._quitter = quitter
        self._notifier = None
        self._timer = usertypes.Timer(self, 'python_hacks')
        self._orig_handlers = {}
        self._activated = False
        self._orig_wakeup_fd = None

    def activate(self):
        """Set up signal handlers.

        On Windows this uses a QTimer to periodically hand control over to
        Python so it can handle signals.

        On Unix, it uses a QSocketNotifier with os.set_wakeup_fd to get
        notified.
        """
        self._orig_handlers[signal.SIGINT] = signal.signal(
            signal.SIGINT, self.interrupt)
        self._orig_handlers[signal.SIGTERM] = signal.signal(
            signal.SIGTERM, self.interrupt)

        if os.name == 'posix' and hasattr(signal, 'set_wakeup_fd'):
            # pylint: disable=import-error,no-member
            import fcntl
            read_fd, write_fd = os.pipe()
            for fd in (read_fd, write_fd):
                flags = fcntl.fcntl(fd, fcntl.F_GETFL)
                fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK)
            self._notifier = QSocketNotifier(read_fd, QSocketNotifier.Read,
                                             self)
            self._notifier.activated.connect(self.handle_signal_wakeup)
            self._orig_wakeup_fd = signal.set_wakeup_fd(write_fd)
        else:
            self._timer.start(1000)
            self._timer.timeout.connect(lambda: None)
        self._activated = True

    def deactivate(self):
        """Deactivate all signal handlers."""
        if not self._activated:
            return
        if self._notifier is not None:
            self._notifier.setEnabled(False)
            rfd = self._notifier.socket()
            wfd = signal.set_wakeup_fd(self._orig_wakeup_fd)
            os.close(rfd)
            os.close(wfd)
        for sig, handler in self._orig_handlers.items():
            signal.signal(sig, handler)
        self._timer.stop()
        self._activated = False

    @pyqtSlot()
    def handle_signal_wakeup(self):
        """Handle a newly arrived signal.

        This gets called via self._notifier when there's a signal.

        Python will get control here, so the signal will get handled.
        """
        log.destroy.debug("Handling signal wakeup!")
        self._notifier.setEnabled(False)
        read_fd = self._notifier.socket()
        try:
            os.read(read_fd, 1)
        except OSError:
            log.destroy.exception("Failed to read wakeup fd.")
        self._notifier.setEnabled(True)

    def _log_later(self, *lines):
        """Log the given text line-wise with a QTimer."""
        for line in lines:
            QTimer.singleShot(0, functools.partial(log.destroy.info, line))

    def interrupt(self, signum, _frame):
        """Handler for signals to gracefully shutdown (SIGINT/SIGTERM).

        This calls shutdown and remaps the signal to call
        interrupt_forcefully the next time.
        """
        signal.signal(signal.SIGINT, self.interrupt_forcefully)
        signal.signal(signal.SIGTERM, self.interrupt_forcefully)
        # Signals can arrive anywhere, so we do this in the main thread
        self._log_later("SIGINT/SIGTERM received, shutting down!",
                        "Do the same again to forcefully quit.")
        QTimer.singleShot(
            0, functools.partial(self._quitter.shutdown, 128 + signum))

    def interrupt_forcefully(self, signum, _frame):
        """Interrupt forcefully on the second SIGINT/SIGTERM request.

        This skips our shutdown routine and calls QApplication:exit instead.
        It then remaps the signals to call self.interrupt_really_forcefully the
        next time.
        """
        signal.signal(signal.SIGINT, self.interrupt_really_forcefully)
        signal.signal(signal.SIGTERM, self.interrupt_really_forcefully)
        # Signals can arrive anywhere, so we do this in the main thread
        self._log_later("Forceful quit requested, goodbye cruel world!",
                        "Do the same again to quit with even more force.")
        QTimer.singleShot(0, functools.partial(self._app.exit, 128 + signum))

    def interrupt_really_forcefully(self, signum, _frame):
        """Interrupt with even more force on the third SIGINT/SIGTERM request.

        This doesn't run *any* Qt cleanup and simply exits via Python.
        It will most likely lead to a segfault.
        """
        print("WHY ARE YOU DOING THIS TO ME? :(")
        sys.exit(128 + signum)
Esempio n. 25
0
class TwistedSocketNotifier(QObject):

    """
    Connection between an fd event and reader/writer callbacks.
    """

    activated = pyqtSignal(int)

    def __init__(self, parent, reactor, watcher, socketType):
        QObject.__init__(self, parent)
        self.reactor = reactor
        self.watcher = watcher
        fd = watcher.fileno()
        self.notifier = QSocketNotifier(fd, socketType, parent)
        self.notifier.setEnabled(True)
        if socketType == QSocketNotifier.Read:
            self.fn = self.read
        else:
            self.fn = self.write
        self.notifier.activated.connect(self.fn)

    def shutdown(self):
        self.notifier.setEnabled(False)
        self.notifier.activated.disconnect(self.fn)
        self.fn = self.watcher = None
        self.notifier.deleteLater()
        self.deleteLater()

    def read(self, fd):
        if not self.watcher:
            return
        w = self.watcher
        # doRead can cause self.shutdown to be called so keep
        # a reference to self.watcher

        def _read():
            #Don't call me again, until the data has been read
            self.notifier.setEnabled(False)
            why = None
            try:
                why = w.doRead()
                inRead = True
            except:
                inRead = False
                log.err()
                why = sys.exc_info()[1]
            if why:
                self.reactor._disconnectSelectable(w, why, inRead)
            elif self.watcher:
                self.notifier.setEnabled(True)
                # Re enable notification following sucessfull read
            self.reactor._iterate(fromqt=True)
        log.callWithLogger(w, _read)

    def write(self, sock):
        if not self.watcher:
            return
        w = self.watcher

        def _write():
            why = None
            self.notifier.setEnabled(False)

            try:
                why = w.doWrite()
            except:
                log.err()
                why = sys.exc_info()[1]
            if why:
                self.reactor._disconnectSelectable(w, why, False)
            elif self.watcher:
                self.notifier.setEnabled(True)
            self.reactor._iterate(fromqt=True)
        log.callWithLogger(w, _write)
Esempio n. 26
0
class ServersDiscovery(QObject):
    def __init__(self, logger, parent=None):
        super(ServersDiscovery, self).__init__(parent)
        self._logger = logger
        self._active = []
        self._servers = []

        self._socket = None
        self._read_notifier = None
        self._started = False

        self._timer = QTimer()
        self._timer.setInterval(10000)
        self._timer.timeout.connect(self._trim_replies)

    @property
    def servers(self):
        return self._servers

    @property
    def started(self):
        return self._started

    def start(self):
        self._logger.debug("Starting servers discovery....")
        self._socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self._socket.bind(("", 31013))
        self._socket.settimeout(0)
        self._socket.setblocking(0)

        self._read_notifier = QSocketNotifier(self._socket.fileno(),
                                              QSocketNotifier.Read, self)
        self._read_notifier.activated.connect(self._notify_read)
        self._read_notifier.setEnabled(True)
        self._started = True
        self._timer.start()

    def stop(self):
        self._logger.debug("Stopping servers discovery...")
        self._read_notifier.setEnabled(False)
        try:
            self._socket.close()
        except socket.errno:
            pass
        self._socket = None
        self._started = False
        self._timer.stop()

    def _notify_read(self):
        request, address = self._socket.recvfrom(4096)
        request = request.decode("utf-8")
        if request.startswith(DISCOVERY_REQUEST):
            self._logger.debug("Received discovery request from %s:%d" %
                               address)
            _, host, port, ssl = request.split()
            server = {"host": host, "port": int(port), "no_ssl": ssl != "True"}
            if server not in self._active:
                self._active.append(server)
            if server not in self._servers:
                self._servers.append(server)
            self._logger.debug("Server discovered: %s" % server)
            self._logger.debug("Sending discovery reply to %s:%d..." % address)
            reply = DISCOVERY_REPLY
            reply = reply.encode("utf-8")
            self._socket.sendto(reply, address)

    def _trim_replies(self):
        self._logger.debug("Discovered %d servers: %s" %
                           (len(self.servers), self.servers))
        self._servers = self._active
        self._active = []
Esempio n. 27
0
class ClientsDiscovery(QObject):
    def __init__(self, logger, parent=None):
        super(ClientsDiscovery, self).__init__(parent)
        self._logger = logger
        self._info = None

        self._socket = None
        self._read_notifier = None
        self._started = False

        self._timer = QTimer()
        self._timer.setInterval(10000)
        self._timer.timeout.connect(self._send_request)

    @property
    def started(self):
        return self._started

    def start(self, host, port, ssl):
        self._logger.debug("Starting clients discovery...")
        self._info = "%s %d %s" % (host, port, ssl)

        self._socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
        self._socket.settimeout(0)
        self._socket.setblocking(0)

        self._read_notifier = QSocketNotifier(self._socket.fileno(),
                                              QSocketNotifier.Read, self)
        self._read_notifier.activated.connect(self._notify_read)
        self._read_notifier.setEnabled(True)
        self._started = True
        self._timer.start()
        self._send_request()

    def stop(self):
        self._logger.debug("Stopping clients discovery...")
        self._read_notifier.setEnabled(False)
        try:
            self._socket.close()
        except socket.error:
            pass
        self._socket = None
        self._started = False
        self._timer.stop()

    def _send_request(self):
        self._logger.debug("Sending discovery request...")
        request = DISCOVERY_REQUEST + " " + self._info
        request = request.encode("utf-8")
        while len(request):
            try:
                sent = self._socket.sendto(request, ("<broadcast>", 31013))
            except socket.error:
                self._logger.warning("Couldn't send discovery request")
            request = request[sent:]

    def _notify_read(self):
        response, address = self._socket.recvfrom(4096)
        response = response.decode("utf-8")
        if response == DISCOVERY_REPLY:
            self._logger.debug("Received discovery reply from %s:%d" % address)
Esempio n. 28
0
class WindowClass(QMainWindow, form_class):
    #class WindowClass(QMainWindow) :
    def __init__(self):
        super().__init__()
        #        uic.loadUi('button.ui',self)

        pg.setConfigOptions(antialias=True)
        self._client = Client()
        socket = self._client.socket
        self._notifier = QSocketNotifier(socket.getsockopt(zmq.FD),
                                         QSocketNotifier.Read, self)
        self._notifier.activated.connect(self._socket_activity)
        self._counter = 0
        self.setupUi(self)
        self._log('[UI] started')

        s_thrd = Thread(target=self.sub_thrd)
        s_thrd.start()
        self._log('[Thread] started')
        self.buff_size = 200
        #버튼에 기능을 연결하는 코드
        self.pBut.clicked.connect(self.button1Function)
        self.p = self.gview

        self.p.setRange(xRange=[0, self.buff_size], yRange=[0, 500])
        self.p2 = self.gview_2
        self.p2.setRange(xRange=[0, self.buff_size], yRange=[-250, 250])
        #        self.p.enableAutoRange(axis='x')
        #        self.p2.enableAutoRange(axis='x')
        self.data = np.empty(self.buff_size)
        self.data2 = np.empty(self.buff_size)
        self.time = np.empty(self.buff_size)
        self.sizeArray = (np.random.random(500) * 20.).astype(int)
        self.ptr = 0

        self.lastTime = time()

        self.nowTime = time()
        dt = self.nowTime - self.lastTime
        self.fps = -1.0  #1.0/dt
        self.timer = QtCore.QTimer()
        self.timer.timeout.connect(self._update)
        self.timer.start(0)

        #sub_msg = self._sub.recv()
        #self._log(sub_msg)
    def sub_thrd(self):
        _sub = Subscriber()
        print("thrd sub start")
        while True:
            msg = dict(zip('topic1', (x.decode() for x in _sub.recv())))
            #id, msg = _sub.recv();
            #msg = _sub.recv();
            #print("[sub_thrd][%s] : %s" %(id, msg))
            #print("[sub_thrd] : %s" %( msg))
            for k, v in msg.items():
                print(f'{k}: {v}')
            #self._log(msg)
    def _update(self):

        self.p.clear()
        self.p2.clear()
        if self.ptr > self.buff_size:
            self.p.enableAutoRange(axis='x')
            self.p2.enableAutoRange(axis='x')
        if self.randCheck.isChecked():
            self.size = self.sizeArray
        else:
            self.size = self.sizeSpin.value()
        rtval = np.random.randint(0, 100)
        self.data[:-1] = self.data[1:]
        self.data[-1] = float(rtval)
        self.data2 = self.data + 50
        self.time[:-1] = self.time[1:]
        self.time[-1] = self.ptr
        curve = pg.PlotCurveItem(x=self.time,
                                 y=self.data,
                                 pen='g',
                                 brush='b',
                                 size=self.size)
        curve2 = pg.PlotCurveItem(x=self.time,
                                  y=self.data2,
                                  pen='r',
                                  brush='b',
                                  size=self.size)
        self.p.addItem(curve)
        self.p2.addItem(curve2)
        self.ptr += 1
        now = time()
        dt = now - self.lastTime
        self.lastTime = time()
        if self.fps < 0:
            self.fps = 1.0 / dt
        else:
            s = np.clip(dt * 3., 0, 1)
            self.fps = self.fps * (1 - s) + (1.0 / dt) * s
        self.p.setTitle('%0.2f fps' % self.fps)
        self.p.repaint()

    def _log(self, data):
        text = self.txtBrw.toPlainText()
        self.txtBrw.setPlainText(text + data + '\n')

    def _send_data(self):
        msg = "Test message #" + str(self._counter)
        self._client.dispatch(msg)
        self._log("[UI] sent: " + msg)
        self._counter += 1

    def _socket_activity(self):
        self._notifier.setEnabled(False)

        flags = self._client.socket.getsockopt(zmq.EVENTS)
        self._log("[Socket] socket.getsockopt(zmq.EVENTS): " + repr(flags))

        if flags & zmq.POLLIN:
            received = self._client.recv()
            self._log("[Socket] zmq.POLLIN")
            self._log("[Socket] received: " + repr(received))
        elif flags & zmq.POLLOUT:
            self._log("[Socket] zmq.POLLOUT")
        elif flags & zmq.POLLERR:
            self._log("[Socket] FAILURE")

        self._notifier.setEnabled(True)

        flags = self._client.socket.getsockopt(zmq.EVENTS)
        self._log("[Socket] socket.getsockopt(zmq.EVENTS): " + repr(flags))

    def button1Function(self):
        print("btn_1 Clicked")
        self.txtBrw.append("pBut clicked")
        self._send_data()
Esempio n. 29
0
class SignalHandler(QObject):

    """Handler responsible for handling OS signals (SIGINT, SIGTERM, etc.).

    Attributes:
        _app: The QApplication instance.
        _quitter: The Quitter instance.
        _activated: Whether activate() was called.
        _notifier: A QSocketNotifier used for signals on Unix.
        _timer: A QTimer used to poll for signals on Windows.
        _orig_handlers: A {signal: handler} dict of original signal handlers.
        _orig_wakeup_fd: The original wakeup filedescriptor.
    """

    def __init__(self, *, app, quitter, parent=None):
        super().__init__(parent)
        self._app = app
        self._quitter = quitter
        self._notifier = None
        self._timer = usertypes.Timer(self, 'python_hacks')
        self._orig_handlers = {}
        self._activated = False
        self._orig_wakeup_fd = None

    def activate(self):
        """Set up signal handlers.

        On Windows this uses a QTimer to periodically hand control over to
        Python so it can handle signals.

        On Unix, it uses a QSocketNotifier with os.set_wakeup_fd to get
        notified.
        """
        self._orig_handlers[signal.SIGINT] = signal.signal(
            signal.SIGINT, self.interrupt)
        self._orig_handlers[signal.SIGTERM] = signal.signal(
            signal.SIGTERM, self.interrupt)

        if os.name == 'posix' and hasattr(signal, 'set_wakeup_fd'):
            # pylint: disable=import-error,no-member,useless-suppression
            import fcntl
            read_fd, write_fd = os.pipe()
            for fd in [read_fd, write_fd]:
                flags = fcntl.fcntl(fd, fcntl.F_GETFL)
                fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK)
            self._notifier = QSocketNotifier(read_fd, QSocketNotifier.Read,
                                             self)
            self._notifier.activated.connect(self.handle_signal_wakeup)
            self._orig_wakeup_fd = signal.set_wakeup_fd(write_fd)
        else:
            self._timer.start(1000)
            self._timer.timeout.connect(lambda: None)
        self._activated = True

    def deactivate(self):
        """Deactivate all signal handlers."""
        if not self._activated:
            return
        if self._notifier is not None:
            self._notifier.setEnabled(False)
            rfd = self._notifier.socket()
            wfd = signal.set_wakeup_fd(self._orig_wakeup_fd)
            os.close(rfd)
            os.close(wfd)
        for sig, handler in self._orig_handlers.items():
            signal.signal(sig, handler)
        self._timer.stop()
        self._activated = False

    @pyqtSlot()
    def handle_signal_wakeup(self):
        """Handle a newly arrived signal.

        This gets called via self._notifier when there's a signal.

        Python will get control here, so the signal will get handled.
        """
        log.destroy.debug("Handling signal wakeup!")
        self._notifier.setEnabled(False)
        read_fd = self._notifier.socket()
        try:
            os.read(read_fd, 1)
        except OSError:
            log.destroy.exception("Failed to read wakeup fd.")
        self._notifier.setEnabled(True)

    def _log_later(self, *lines):
        """Log the given text line-wise with a QTimer."""
        for line in lines:
            QTimer.singleShot(0, functools.partial(log.destroy.info, line))

    def interrupt(self, signum, _frame):
        """Handler for signals to gracefully shutdown (SIGINT/SIGTERM).

        This calls shutdown and remaps the signal to call
        interrupt_forcefully the next time.
        """
        signal.signal(signal.SIGINT, self.interrupt_forcefully)
        signal.signal(signal.SIGTERM, self.interrupt_forcefully)
        # Signals can arrive anywhere, so we do this in the main thread
        self._log_later("SIGINT/SIGTERM received, shutting down!",
                        "Do the same again to forcefully quit.")
        QTimer.singleShot(0, functools.partial(
            self._quitter.shutdown, 128 + signum))

    def interrupt_forcefully(self, signum, _frame):
        """Interrupt forcefully on the second SIGINT/SIGTERM request.

        This skips our shutdown routine and calls QApplication:exit instead.
        It then remaps the signals to call self.interrupt_really_forcefully the
        next time.
        """
        signal.signal(signal.SIGINT, self.interrupt_really_forcefully)
        signal.signal(signal.SIGTERM, self.interrupt_really_forcefully)
        # Signals can arrive anywhere, so we do this in the main thread
        self._log_later("Forceful quit requested, goodbye cruel world!",
                        "Do the same again to quit with even more force.")
        QTimer.singleShot(0, functools.partial(self._app.exit, 128 + signum))

    def interrupt_really_forcefully(self, signum, _frame):
        """Interrupt with even more force on the third SIGINT/SIGTERM request.

        This doesn't run *any* Qt cleanup and simply exits via Python.
        It will most likely lead to a segfault.
        """
        print("WHY ARE YOU DOING THIS TO ME? :(")
        sys.exit(128 + signum)
Esempio n. 30
0
class Eldasi(QWidget):

    def __init__(self):
        super(Eldasi, self).__init__()
        self.initUI()
        self.client_available = False

    def initUI(self):
        # widgets to enable/disable depending on connection status
        self.toggle_widgets = []

        # Log widget
        self.log_text = QPlainTextEdit(self)

        # Quick connections layout
        connections_layout = QHBoxLayout()
        self.address_text = QLineEdit(self, text='tcp://127.0.0.1:5000')
        self.connect_button = QPushButton("Start server")
        connections_layout.addWidget(self.address_text)
        connections_layout.addWidget(self.connect_button)
        self.connect_button.clicked.connect(self.start_server)

        # Text send widgets
        send_button = QPushButton("Send")
        send_button.clicked.connect(lambda: self._send_data(self.data_text.text()))
        self.data_text = QLineEdit(self)
        send_layout = QHBoxLayout()
        send_layout.addWidget(send_button)
        send_layout.addWidget(self.data_text)
        self.toggle_widgets.extend([send_button, self.data_text])

        # Quick ELSA commands widgets
        commands_layout = QHBoxLayout()
        commands_layout2 = QHBoxLayout()
        commands_layout3 = QHBoxLayout()
        start_button = QPushButton("Start")
        start_button.clicked.connect(lambda: self._send_data("init"))
        commands_layout.addWidget(start_button)
        stop_button = QPushButton("Stop")
        stop_button.clicked.connect(lambda: self._send_data("stop"))
        commands_layout.addWidget(stop_button)
        status_button = QPushButton("Status")
        status_button.clicked.connect(lambda: self._send_data("status"))
        commands_layout.addWidget(status_button)
        init_button = QPushButton("Scan_self")
        init_button.clicked.connect(lambda: self._send_data("startself"))
        commands_layout.addWidget(init_button)
        
        tune_button = QPushButton("GDAC/TDAC")
        tune_button.clicked.connect(lambda: self._send_data("tune"))
        commands_layout2.addWidget(tune_button)
        fix_button = QPushButton("fix")
        fix_button.clicked.connect(lambda: self._send_data("fix"))
        commands_layout2.addWidget(fix_button)
        threshold_button = QPushButton("Threshold")
        threshold_button.clicked.connect(lambda: self._send_data("threshold"))
        commands_layout2.addWidget(threshold_button)        
        framerate_button = QPushButton("Framerate")
        framerate_button.clicked.connect(lambda: self._send_data("framerate"))
        commands_layout2.addWidget(framerate_button)     
        
        
        external_button = QPushButton("Scan_ext")
        external_button.clicked.connect(lambda: self._send_data("startexternal"))
        commands_layout3.addWidget(external_button)
        poweron_button = QPushButton("Power on")
        poweron_button.clicked.connect(lambda: self._send_data("poweron"))
        commands_layout3.addWidget(poweron_button)
        poweroff_button = QPushButton("Power off")
        poweroff_button.clicked.connect(lambda: self._send_data("poweroff"))
        commands_layout3.addWidget(poweroff_button)
        exit_button = QPushButton("EXIT")
        exit_button.clicked.connect(lambda: self._send_data("exit"))
        commands_layout3.addWidget(exit_button)        
        
        self.toggle_widgets.extend([start_button, stop_button, tune_button, init_button, fix_button, poweron_button, poweroff_button, status_button, external_button, threshold_button, framerate_button, exit_button])
        
        
        # Combine widgets to layout
        layout = QGridLayout()
        layout.addWidget(self.log_text, 1, 1)
        layout.addLayout(connections_layout, 2, 1)
        layout.addLayout(commands_layout, 3, 1)
        layout.addLayout(commands_layout2, 4, 1)
        layout.addLayout(commands_layout3, 5, 1)
        layout.addLayout(send_layout, 6, 1)
        self.setLayout(layout)

        # Window settings
        self.setGeometry(200, 200, 480, 400)
        self.setWindowTitle('ELSA DAQ Simulation')
        self.show()

        self._switch_widgets()

        self._log('[UI] started')

    def start_server(self):
        self._server = Server()
        ret = self._server.start(self.address_text.text())
        if ret is not True:
            self._log("[ZMQError]: " + repr(ret))
            return
        socket = self._server.socket
        self._notifier = QSocketNotifier(socket.getsockopt(zmq.FD),
                                         QSocketNotifier.Read, self)
        self._notifier.activated.connect(self._socket_activity)
        self._notifier.setEnabled(True)
        self.connect_button.clicked.disconnect()
        self.connect_button.clicked.connect(self.stop_server)
        self.connect_button.setText('Stop server')
        self._log("[Socket] Start server")

    def stop_server(self):
        self._notifier.setEnabled(False)
        self._server.socket.close()
        self._notifier.activated.disconnect()
        self._switch_widgets(False)
        self.connect_button.clicked.disconnect()
        self.connect_button.clicked.connect(self.start_server)
        self.connect_button.setText('Start server')
        self._log("[Socket] Stop server")

    def _switch_widgets(self, status=None):
        if status is None:
            self._switch_widgets(status=not self.toggle_widgets[0].isEnabled())
        else:
            for w in self.toggle_widgets:
                w.setEnabled(status)

    def _log(self, data):
        self.log_text.appendPlainText(data)

    def _send_data(self, data):
        if data:
            self._server.dispatch(data)
            self._log("[UI] sent: " + data)

    def _socket_activity(self):
        self._notifier.setEnabled(False)
        socket = self._server.socket
        if socket.getsockopt(zmq.EVENTS) & zmq.POLLIN:
            while socket.getsockopt(zmq.EVENTS) & zmq.POLLIN:
                received = self._server.recv()
                self._log("[Socket] received: " + repr(received))
        # Called when client connects
        elif socket.getsockopt(zmq.EVENTS) & zmq.POLLOUT:
            self._log("[Socket] Client connected")
            self.client_available = True
            self._switch_widgets(True)
        else:
            self.client_available = False
            self._switch_widgets(False)
        self._notifier.setEnabled(True)
Esempio n. 31
0
class VNCClient(QObject):
    started = pyqtSignal()
    finished = pyqtSignal()
    imageSizeChanged = pyqtSignal(QSize)
    imageChanged = pyqtSignal(int, int, int, int)
    passwordRequested = pyqtSignal(bool)
    textCut = pyqtSignal(unicode)

    def __init__(self, host, port, settings, parent=None):
        super(VNCClient, self).__init__(parent)
        self.thread = QThread()
        self.moveToThread(self.thread)
        self.host = host
        self.port = port
        self.settings = settings
        self.username = None
        self.password = None
        self.rfb_client = None
        self.socket_notifier = None
        self.thread.started.connect(self._SH_ThreadStarted)
        self.thread.finished.connect(self._SH_ThreadFinished)

    def _get_settings(self):
        return self.__dict__['settings']

    def _set_settings(self, settings):
        old_settings = self.__dict__.get('settings', None)
        if settings == old_settings:
            return
        self.__dict__['settings'] = settings
        if self.thread.isRunning():
            QApplication.postEvent(self, RFBConfigureClientEvent())

    settings = property(_get_settings, _set_settings)
    del _get_settings, _set_settings

    @property
    def image(self):
        return self.rfb_client.image if self.rfb_client is not None else None

    def start(self):
        self.thread.start()

    def stop(self):
        self.thread.quit()

    def key_event(self, key, down):
        if self.thread.isRunning():
            QApplication.postEvent(self, RFBKeyEvent(key, down))

    def mouse_event(self, x, y, button_mask):
        if self.thread.isRunning():
            QApplication.postEvent(self, RFBMouseEvent(x, y, button_mask))

    def cut_text_event(self, text):
        if text and self.thread.isRunning():
            QApplication.postEvent(self, RFBCutTextEvent(text))

    def _SH_ThreadStarted(self):
        self.started.emit()
        notification_center = NotificationCenter()
        notification_center.post_notification('VNCClientWillStart', sender=self)
        self.rfb_client = RFBClient(parent=self)
        try:
            self.rfb_client.connect()
        except RFBClientError:
            self.thread.quit()
        else:
            self.socket_notifier = QSocketNotifier(self.rfb_client.socket, QSocketNotifier.Read, self)
            self.socket_notifier.activated.connect(self._SH_SocketNotifierActivated)
            notification_center.post_notification('VNCClientDidStart', sender=self)

    def _SH_ThreadFinished(self):
        self.finished.emit()
        notification_center = NotificationCenter()
        notification_center.post_notification('VNCClientWillEnd', sender=self)
        if self.socket_notifier is not None:
            self.socket_notifier.activated.disconnect(self._SH_SocketNotifierActivated)
            self.socket_notifier = None
        self.rfb_client = None
        notification_center.post_notification('VNCClientDidEnd', sender=self)

    def _SH_SocketNotifierActivated(self, sock):
        self.socket_notifier.setEnabled(False)
        try:
            self.rfb_client.handle_server_message()
        except RFBClientError:
            self.thread.quit()
        else:
            self.socket_notifier.setEnabled(True)

    def _SH_ConfigureRFBClient(self):
        if self.rfb_client is not None:
            self.rfb_client.configure()

    def customEvent(self, event):
        handler = getattr(self, '_EH_%s' % event.name, Null)
        handler(event)

    def _EH_RFBConfigureClientEvent(self, event):
        if self.rfb_client is not None:
            self.rfb_client.configure()

    def _EH_RFBKeyEvent(self, event):
        if self.rfb_client is not None:
            self.rfb_client.send_key_event(event.key, event.down)

    def _EH_RFBMouseEvent(self, event):
        if self.rfb_client is not None:
            self.rfb_client.send_pointer_event(event.x, event.y, event.button_mask)

    def _EH_RFBCutTextEvent(self, event):
        if self.rfb_client is not None:
            self.rfb_client.send_client_cut_text(event.text)
Esempio n. 32
0
class QtSocket(QObject):
    """
        This class is the glue between the communication from the server
        and the Qt event loop and by using the QSocketNotifier we can get
        notified when data is ready to be sent / received without openining
        an additional thread
    """
    def __init__(self, gotten_packet_callback, parent=None):
        super(QtSocket, self).__init__(parent)
        self._socket = None
        self._connected = False

        self._gotten_packet_callback = gotten_packet_callback

        self._incoming = []
        self._outgoing = []

    @property
    def connected(self):
        return self._connected

    def initialize_socket(self, sock):
        self._recv_notifier = QSocketNotifier(sock.fileno(),
                                              QSocketNotifier.Read, self)
        self._recv_notifier.activated.connect(self._handle_recv_ready)
        self._recv_notifier.setEnabled(True)

        self._send_notifier = QSocketNotifier(sock.fileno(),
                                              QSocketNotifier.Write, self)
        self._send_notifier.activated.connect(self._handle_send_ready)
        self._send_notifier.setEnabled(True)

        self._socket = sock
        self._connected = True
        self._incoming = []
        self._outgoing = []

    def disconnect(self):
        if not self._socket:
            return

        self._recv_notifier.setEnabled(False)
        self._send_notifier.setEnabled(False)

        try:
            self._socket.close()
        except socket.error:
            pass

        self._socket = None
        self._connected = False
        self._incoming = []
        self._outgoing = []

    def _handle_recv_ready(self):
        if not self.connected:
            return

        try:
            pkt = RevetherPacket.parse_stream(ClientSocket(self._socket))
        except construct.StreamError:
            self.disconnect()
            return
        self._incoming.append(pkt)

        if self._incoming:
            QCoreApplication.instance().postEvent(self, SocketEvent())

    def send_packet(self, pkt, callback=None, err_callback=None):
        item = (pkt, callback, err_callback)
        self._outgoing.append(item)

    def _handle_send_ready(self):
        if not self.connected:
            return

        if not self._outgoing:
            return

        pkt, callback, err_callback = self._outgoing.pop(0)

        try:
            self._socket.send(pkt)
            if callback:
                callback()
        except socket.error:
            if err_callback:
                err_callback()
            return

    def event(self, event):
        """
            Callback for the when a SocketEvent is happening
        """
        if isinstance(event, SocketEvent):
            self._gotten_packet_callback(self._incoming)
            self._incoming = []
            event.accept()
            return True
        else:
            event.ignore()
            return False
Esempio n. 33
0
class ClientSocket(QObject):
    """
    This class is acts a bridge between a client socket and the Qt event loop.
    By using a QSocketNotifier, we can be notified when some data is ready to
    be read or written on the socket, not requiring an extra thread.
    """

    MAX_DATA_SIZE = 65535

    def __init__(self, logger, parent=None):
        QObject.__init__(self, parent)
        self._logger = logger
        self._socket = None
        self._server = parent and isinstance(parent, ServerSocket)

        self._read_buffer = bytearray()
        self._read_notifier = None
        self._read_packet = None

        self._write_buffer = bytearray()
        self._write_notifier = None
        self._write_packet = None

        self._connected = False
        self._outgoing = collections.deque()
        self._incoming = collections.deque()

    @property
    def connected(self):
        """Is the underlying socket connected?"""
        return self._connected

    def wrap_socket(self, sock):
        """Sets the underlying socket to use."""
        self._read_notifier = QSocketNotifier(sock.fileno(),
                                              QSocketNotifier.Read, self)
        self._read_notifier.activated.connect(self._notify_read)
        self._read_notifier.setEnabled(True)

        self._write_notifier = QSocketNotifier(sock.fileno(),
                                               QSocketNotifier.Write, self)
        self._write_notifier.activated.connect(self._notify_write)
        self._write_notifier.setEnabled(True)

        self._socket = sock

    def disconnect(self, err=None):
        """Terminates the current connection."""
        if not self._socket:
            return

        self._logger.debug("Disconnected")
        if err:
            self._logger.exception(err)
        self._read_notifier.setEnabled(False)
        self._write_notifier.setEnabled(False)
        try:
            self._socket.shutdown(socket.SHUT_RDWR)
            self._socket.close()
        except socket.error:
            pass
        self._socket = None
        self._connected = False

    def set_keep_alive(self, cnt, intvl, idle):
        """
        Set the TCP keep-alive of the underlying socket.

        It activates after idle seconds of idleness, sends a keep-alive ping
        once every intvl seconds, and disconnects after `cnt`failed pings.
        """
        # Taken from https://github.com/markokr/skytools/
        tcp_keepcnt = getattr(socket, "TCP_KEEPCNT", None)
        tcp_keepintvl = getattr(socket, "TCP_KEEPINTVL", None)
        tcp_keepidle = getattr(socket, "TCP_KEEPIDLE", None)
        tcp_keepalive = getattr(socket, "TCP_KEEPALIVE", None)
        sio_keeplive_vals = getattr(socket, "SIO_KEEPALIVE_VALS", None)
        if (tcp_keepidle is None and tcp_keepalive is None
                and sys.platform == "darwin"):
            tcp_keepalive = 0x10

        self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
        if tcp_keepcnt is not None:
            self._socket.setsockopt(socket.IPPROTO_TCP, tcp_keepcnt, cnt)
        if tcp_keepintvl is not None:
            self._socket.setsockopt(socket.IPPROTO_TCP, tcp_keepintvl, intvl)
        if tcp_keepidle is not None:
            self._socket.setsockopt(socket.IPPROTO_TCP, tcp_keepidle, idle)
        elif tcp_keepalive is not None:
            self._socket.setsockopt(socket.IPPROTO_TCP, tcp_keepalive, idle)
        elif sio_keeplive_vals is not None:
            self._socket.ioctl(sio_keeplive_vals,
                               (1, idle * 1000, intvl * 1000))

    def _check_socket(self):
        """Check if the connection has been established yet."""
        # Ignore if you're already connected
        if self._connected:
            return True

        # Check if the connection was successful
        ret = self._socket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR)
        if ret != 0 and ret != errno.EINPROGRESS and ret != errno.EWOULDBLOCK:
            self.disconnect(socket.error(ret, os.strerror(ret)))
            return False
        else:
            # Do SSL handshake if needed
            if isinstance(self._socket, ssl.SSLSocket):
                try:
                    self._socket.do_handshake()
                except socket.error as e:
                    if not isinstance(e,
                                      ssl.SSLWantReadError) and not isinstance(
                                          e, ssl.SSLWantReadError):
                        self.disconnect(e)
                    return False

            self._connected = True
            self._logger.debug("Connected")
            return True

    def _notify_read(self):
        """Callback called when some data is ready to be read on the socket."""
        if not self._check_socket():
            return

        # Read as many bytes as possible
        try:
            data = self._socket.recv(ClientSocket.MAX_DATA_SIZE)
            if not data:
                self.disconnect()
                return
        except socket.error as e:
            if (e.errno not in (errno.EAGAIN, errno.EWOULDBLOCK)
                    and not isinstance(e, ssl.SSLWantReadError)
                    and not isinstance(e, ssl.SSLWantWriteError)):
                self.disconnect(e)
            return  # No more data available
        self._read_buffer.extend(data)

        # Split the received data on new lines (= packets)
        while True:
            if self._read_packet is None:
                if b"\n" in self._read_buffer:
                    pos = self._read_buffer.index(b"\n")
                    line = self._read_buffer[:pos]
                    self._read_buffer = self._read_buffer[pos +
                                                          1:  # noqa: E203
                                                          ]

                    # Try to parse the line (= packet)
                    try:
                        dct = json.loads(line.decode("utf-8"))
                        self._read_packet = Packet.parse_packet(
                            dct, self._server)
                    except Exception as e:
                        msg = "Invalid packet received: %s" % line
                        self._logger.warning(msg)
                        self._logger.exception(e)
                        continue
                else:
                    break  # Not enough data for a packet

            else:
                if isinstance(self._read_packet, Container):
                    avail = len(self._read_buffer)
                    total = self._read_packet.size

                    # Trigger the downback
                    if self._read_packet.downback:
                        self._read_packet.downback(min(avail, total), total)

                    # Read the container's content
                    if avail >= total:
                        self._read_packet.content = self._read_buffer[:total]
                        self._read_buffer = self._read_buffer[total:]
                    else:
                        break  # Not enough data for a packet

                self._incoming.append(self._read_packet)
                self._read_packet = None

        if self._incoming:
            QCoreApplication.instance().postEvent(self, PacketEvent())

    def _notify_write(self):
        """Callback called when some data is ready to written on the socket."""
        if not self._check_socket():
            return

        if not self._write_buffer:
            if not self._outgoing:
                return  # No more packets to send
            self._write_packet = self._outgoing.popleft()

            # Dump the packet as a line
            try:
                line = json.dumps(self._write_packet.build_packet())
                line = line.encode("utf-8") + b"\n"
            except Exception as e:
                msg = "Invalid packet being sent: %s" % self._write_packet
                self._logger.warning(msg)
                self._logger.exception(e)
                return

            # Write the container's content
            self._write_buffer.extend(bytearray(line))
            if isinstance(self._write_packet, Container):
                data = self._write_packet.content
                self._write_buffer.extend(bytearray(data))
                self._write_packet.size += len(line)

        # Send as many bytes as possible
        try:
            count = min(len(self._write_buffer), ClientSocket.MAX_DATA_SIZE)
            sent = self._socket.send(self._write_buffer[:count])
            self._write_buffer = self._write_buffer[sent:]
        except socket.error as e:
            if (e.errno not in (errno.EAGAIN, errno.EWOULDBLOCK)
                    and not isinstance(e, ssl.SSLWantReadError)
                    and not isinstance(e, ssl.SSLWantWriteError)):
                self.disconnect(e)
            return  # Can't write anything

        # Trigger the upback
        if (isinstance(self._write_packet, Container)
                and self._write_packet.upback):
            self._write_packet.size -= count
            total = len(self._write_packet.content)
            sent = max(total - self._write_packet.size, 0)
            self._write_packet.upback(sent, total)

        if not self._write_buffer and not self._outgoing:
            self._write_notifier.setEnabled(False)

    def event(self, event):
        """Callback called when a Qt event is fired."""
        if isinstance(event, PacketEvent):
            self._dispatch()
            event.accept()
            return True
        else:
            event.ignore()
            return False

    def _dispatch(self):
        """Callback called when a PacketEvent is received."""
        while self._incoming:
            packet = self._incoming.popleft()
            self._logger.debug("Received packet: %s" % packet)

            # Notify for replies
            if isinstance(packet, Reply):
                packet.trigger_callback()

            # Otherwise forward to the subclass
            elif not self.recv_packet(packet):
                self._logger.warning("Unhandled packet received: %s" % packet)

    def send_packet(self, packet):
        """Sends a packet the other party."""
        if not self._connected:
            self._logger.warning("Sending packet while disconnected")
            return None

        self._logger.debug("Sending packet: %s" % packet)

        # Enqueue the packet
        self._outgoing.append(packet)
        if not self._write_notifier.isEnabled():
            self._write_notifier.setEnabled(True)

        # Queries return a packet deferred
        if isinstance(packet, Query):
            d = PacketDeferred()
            packet.register_callback(d)
            return d
        return None

    def recv_packet(self, packet):
        """Receives a packet from the other party."""
        raise NotImplementedError("recv_packet() not implemented")
Esempio n. 34
0
class QWZMQListener(QWidget):
    def __init__(self, **kwargs):
        QWidget.__init__(self, parent=None)
        #logger.debug('In QWZMQListener.__init__')

        self.vold = -1

        self.timeout = kwargs.get('timeout', 1000)  # milliseconds
        _is_normal = kwargs.get('is_normal', True)
        _on_poll = kwargs.get('on_poll', self.on_zmq_poll)
        _host = kwargs.get('host', 'localhost')
        _platform = kwargs.get('platform', 6)
        _topicfilter = kwargs.get('topicfilter', b'')  # b'10001'
        _uri = 'tcp://%s:%d' % (_host, front_pub_port(_platform)
                                )  # 'tcp://localhost:30016'

        if _is_normal: self.init_connect_zmq(_on_poll, _uri, _topicfilter)

    def init_connect_zmq(self, on_poll, uri, topicfilter):
        logger.debug('QWZMQListener.init_connect_zmq uri=%s' % uri)
        self.zmq_context = zmq.Context(1)
        self.zmq_socket = self.zmq_context.socket(zmq.SUB)
        self.zmq_socket.connect(uri)
        self.zmq_socket.setsockopt(zmq.SUBSCRIBE, topicfilter)
        self.zmq_socket.setsockopt(zmq.RCVTIMEO, self.timeout)  # milliseconds

        self.zmq_notifier = QSocketNotifier(self.zmq_socket.getsockopt(zmq.FD),
                                            QSocketNotifier.Read, self)
        self.zmq_notifier.activated.connect(on_poll)

        #print("QWZMQListener flags zmq.POLLIN:%d POLLOUT:%d POLLERR:%d" % (zmq.POLLIN, zmq.POLLOUT, zmq.POLLERR))

    def on_zmq_poll(self):
        """Needs to be re-implemented to do real work with messages from zmq.
        """
        self.zmq_notifier.setEnabled(False)
        flags = self.zmq_socket.getsockopt(zmq.EVENTS)
        flag = 'UNKNOWN'
        msg = ''
        #print("A")
        if flags & zmq.POLLIN:
            while self.zmq_socket.getsockopt(zmq.EVENTS) & zmq.POLLIN:
                flag = 'POLLIN'
                msg = self.zmq_socket.recv_multipart()
                self.process_zmq_message(msg)
                #print("L")

        elif flags & zmq.POLLOUT:
            flag = 'POLLOUT'
        elif flags & zmq.POLLERR:
            flag = 'POLLERR'
        else:
            pass
        print("QWZMQListener Flag zmq.%s in %d msg: %s" % (flag, flags, msg))
        #print("B")

        self.zmq_notifier.setEnabled(True)

        #self.kick_zmq() # WITHOUT THIS LINE IT WOULD NOT CALL on_read_msg AGAIN!
        _flags = self.zmq_socket.getsockopt(zmq.EVENTS)
        if _flags & zmq.POLLIN: self.on_zmq_poll()
        #print("E")

    def process_zmq_message(self, msg):
        s = msg[1].decode('utf-8')
        v = int(s.split(' ', 1)[0])
        #self.setWindowTitle(s)
        self.edi_text.append(s)
        self.edi_text.moveCursor(
            23, 0)  # QTextCursor.NextRow, QTextCursor.MoveAnchor
        if v != self.vold + 1: self.edi_text.append('   ===== got it!')
        self.vold = v
        if v % 50 == 0: self.edi_text.setText('')
        #scrollbar = self.edi_text.verticalScrollBar()
        #scrollbar.setValue(scrollbar.maximum());

    def kick_zmq(self):
        """ WITHOUT THIS LINE IT WOULD NOT CALL on_read_msg AGAIN!
        """
        _flags = self.zmq_socket.getsockopt(zmq.EVENTS)
        print("kick_zmq _flags:", _flags)

        if _flags == 1: print('GRRRRRRRRRRRRRRRRRRRRRRR!')

    def closeEvent(self, e):
        logger.debug('%s.closeEvent' % self._name)
        QWidget.closeEvent(self, e)
Esempio n. 35
0
class ZmqClient(QObject):
    nucleo_firmware_version = pyqtSignal(str)
    message_received = pyqtSignal(object)
    heartbeat = pyqtSignal(int)
    start_of_match = pyqtSignal(int)
    match_state_change = pyqtSignal(int, int)
    comm_stats = pyqtSignal(object)
    propulsion_telemetry = pyqtSignal(object)
    propulsion_telemetry_ex = pyqtSignal(object)
    rplidar_plot = pyqtSignal(object)
    rplidar_robot_detection = pyqtSignal(object)
    astar_dbg_map = pyqtSignal(object)
    odometry_config = pyqtSignal(object)
    propulsion_controller_config = pyqtSignal(object)
    dynamixel_registers = pyqtSignal(int, int, object)
    fpga_registers = pyqtSignal(int, int)
    fpga_registers_crc = pyqtSignal(int, int, int)
    asserv_plot = pyqtSignal(int, int)
    sensors = pyqtSignal(int)
    gpio = pyqtSignal(int)
    debug_goldo = pyqtSignal(int)
    robot_end_load_config_status = pyqtSignal(bool)
    sequence_event = pyqtSignal(int, object)
    odrive_response = pyqtSignal(object)
    camera_image = pyqtSignal(object)

    def __init__(self, ip=None, parent=None):
        super(ZmqClient, self).__init__(None)
        self._context = zmq.Context()

        self._push_socket = self._context.socket(zmq.PUB)
        self._push_socket.connect('tcp://{}:3002'.format(ip))

        self._socket_main_sub = self._context.socket(zmq.SUB)
        self._socket_main_sub.connect('tcp://{}:3801'.format(ip))
        self._socket_main_sub.setsockopt(zmq.SUBSCRIBE, b'')

        self._socket_main_pub = self._context.socket(zmq.PUB)
        self._socket_main_pub.connect('tcp://{}:3802'.format(ip))

        self._notifier_main = QSocketNotifier(
            self._socket_main_sub.getsockopt(zmq.FD), QSocketNotifier.Read,
            self)
        self._notifier_main.activated.connect(self._on_socket_main_sub)

        self._callbacks = []
        self._goldo_log_fd = open("goldo_log.txt", "wt")

    def send_message(self, message_type, message_body):
        self._push_socket.send_multipart(
            [struct.pack('<H', message_type), message_body])

    def publishTopic(self, topic, msg=None):
        if msg is None:
            msg = _sym_db.GetSymbol('google.protobuf.Empty')()
        self._socket_main_pub.send_multipart([
            topic.encode('utf8'),
            msg.DESCRIPTOR.full_name.encode('utf8'),
            msg.SerializeToString()
        ])

    def registerCallback(self, pattern: str, callback):
        pattern = (pattern.replace('*', r'([^/]+)').replace(
            '/#', r'(/[^/]+)*').replace('#/', r'([^/]+/)*'))
        self._callbacks.append((re.compile(f"^{pattern}$"), callback))

    def _on_socket_main_sub(self):
        self._notifier_main.setEnabled(False)
        socket = self._socket_main_sub
        flags = socket.getsockopt(zmq.EVENTS)
        while flags & zmq.POLLIN:
            topic, full_name, payload = socket.recv_multipart()
            flags = socket.getsockopt(zmq.EVENTS)
            topic = topic.decode('utf8')
            full_name = full_name.decode('utf8')

            msg_class = _sym_db.GetSymbol(full_name)
            if msg_class is not None:
                msg = msg_class()
                msg.ParseFromString(payload)
            else:
                msg = None
            callback_matches = ((regexp.match(topic), callback)
                                for regexp, callback in self._callbacks)
            for match, callback in callback_matches:
                if match:
                    callback(*match.groups(), msg)
            if topic.startswith('nucleo'):
                pass  #print(topic)
            if topic == 'nucleo/out/os/heartbeat':
                self.heartbeat.emit(msg.timestamp)
            if topic == 'nucleo/out/robot/config/load_status':
                self.robot_end_load_config_status.emit(msg.status == 0)
            if topic == 'nucleo/out/odrive/response':
                self.odrive_response.emit(msg)
            if topic == 'nucleo/out/odometry/config':
                self.odometry_config.emit(msg)
            if topic == 'nucleo/out/propulsion/telemetry':
                self.propulsion_telemetry.emit(msg)
            if topic == 'nucleo/out/propulsion/telemetry_ex':
                self.propulsion_telemetry_ex.emit(msg)
            if topic == 'nucleo/out/propulsion/config':
                self.propulsion_controller_config.emit(msg)
            if topic == 'nucleo/out/fpga/reg':
                self.fpga_registers.emit(msg.apb_address, msg.apb_value)
            if topic == 'rplidar/out/scan':
                self.rplidar_plot.emit(msg)
            if topic == 'nucleo/out/dbg_goldo':
                #print("nucleo/out/dbg_goldo : {:8x}".format(msg.value))
                val = msg.value
                ts = val & 0xffff0000
                ts = ts >> 16
                pos = val & 0x0000ffff
                if pos & 0x00008000 == 0x00008000: pos -= 0x10000
                self._goldo_log_fd.write("{} {}\n".format(ts, pos))
                self._goldo_log_fd.flush()
                self.asserv_plot.emit(ts, pos)
        self._notifier_main.setEnabled(True)

    def _on_message_received(self, msg):
        return
        self.message_received.emit(msg)
        msg_type = struct.unpack('<H', msg[0:2])[0]

        if msg_type == message_types.GetNucleoFirmwareVersion:
            firm_ver = NucleoFirmwareVersion(msg[2:])
            #print("firm_ver : " + firm_ver.s)
            self.nucleo_firmware_version.emit(firm_ver.s)

        if msg_type == message_types.SensorsChange:
            self.sensors.emit(struct.unpack('<I', msg[2:])[0])
        if msg_type == message_types.GPIODebug:
            self.gpio.emit(struct.unpack('<I', msg[2:])[0])
        if msg_type == message_types.SequenceEvent:
            event_id = struct.unpack('<B', msg[2:3])[0]
            self.sequence_event.emit(event_id, msg[3:])
            print(event_id, msg[3:])
        if msg_type == message_types.DebugGoldo:
            self.debug_goldo.emit(struct.unpack('<I', msg[2:])[0])

        if msg_type == message_types.MatchStateChange:
            state, side = struct.unpack('<BB', msg[2:4])
            self.match_state_change.emit(state, side)

        if msg_type == message_types.PropulsionTelemetryEx:
            telemetry = PropulsionTelemetryEx(msg[2:])
            self.propulsion_telemetry_ex.emit(telemetry)

        if msg_type == message_types.RplidarPlot:
            my_plot = RplidarPlot(msg[2:])
            self.rplidar_plot.emit(my_plot)

        if msg_type == message_types.RplidarRobotDetection:
            other_robot = RplidarRobotDetection(msg[2:])
            self.rplidar_robot_detection.emit(other_robot)

        if msg_type == message_types.RobotStratDbgAstarMap:
            astar_dbg_map_bytes = msg[3:]
            self.astar_dbg_map.emit(astar_dbg_map_bytes)

        if msg_type == message_types.StartOfMatch:
            timestamp = struct.unpack('<I', msg[2:6])[0]
            self.start_of_match.emit(timestamp)

        if msg_type == message_types.CommStats:
            #self.comm_stats.emit(struct.unpack('<HHIIIII', msg[2:]))
            pass

        if msg_type == message_types.DbgDynamixelGetRegisters:
            id_, address = struct.unpack('<BB', msg[2:4])
            self.dynamixel_registers.emit(id_, address, msg[4:])

        if msg_type == message_types.NucleoLog:
            log = msg[2:].split(bytes([0]), 1)[0].decode("utf-8")
            print("" + log)

        if msg_type == 90:
            print(struct.unpack('<BB', msg[2:]))
Esempio n. 36
0
class ZmqClient(QObject, ZmqCodecMixin):
    notifyScore = pyqtSignal()
    notifyHeartbeat = pyqtSignal()
    notifyConfigStatus = pyqtSignal()
    notifyMatchTimer = pyqtSignal()
    notifyMatchState = pyqtSignal()
    notifySide = pyqtSignal()

    notifyODrive = pyqtSignal()

    notifyTirette = pyqtSignal()
    notifyEmergencyStop = pyqtSignal()

    cameraFrameReceived = pyqtSignal(object)
    cameraDetectionsReceived = pyqtSignal(object)

    def __init__(self, parent=None):
        super().__init__(parent)
        self._context = zmq.Context()

        self._sub_socket = self._context.socket(zmq.SUB)
        self._sub_socket.bind('tcp://*:3901')
        self._sub_socket.setsockopt(zmq.SUBSCRIBE, b'')

        self._pub_socket = self._context.socket(zmq.PUB)
        self._pub_socket.bind('tcp://*:3902')

        self._notifier = QSocketNotifier(self._sub_socket.getsockopt(zmq.FD),
                                         QSocketNotifier.Read, self)
        self._notifier.activated.connect(self._on_sub_socket_event)

        self._config_status = 0
        self._score = 0
        self._heartbeat = 0
        self._match_timer = 0
        self._side = 0
        self._match_state = 0
        self._odrive_state = '00'
        self._odrive_error = False
        self._tirette = False
        self._emergency_stop = False

    @pyqtSlot()
    def configNucleo(self):
        msg = Int32Value(value=0)
        self.publishTopic('gui/out/commands/config_nucleo', msg)

    @pyqtSlot()
    def preMatch(self):
        msg = Int32Value(value=0)
        self.publishTopic('gui/out/commands/prematch', msg)

    @pyqtSlot()
    def odriveCalibration(self):
        msg = Int32Value(value=0)
        self.publishTopic('nucleo/in/propulsion/calibrate_odrive', msg)

    def publishTopic(self, topic, msg):
        self._pub_socket.send_multipart(self._encodeTopic(topic, msg))

    def _on_sub_socket_event(self):
        self._notifier.setEnabled(False)
        flags = self._sub_socket.getsockopt(zmq.EVENTS)
        while flags & zmq.POLLIN:
            topic, msg = self._decodeTopic(self._sub_socket.recv_multipart())
            self._on_message_received(topic, msg)
            flags = self._sub_socket.getsockopt(zmq.EVENTS)
        self._notifier.setEnabled(True)

    def _on_message_received(self, topic, msg):
        if topic == 'gui/in/heartbeat':
            self._heartbeat = msg.timestamp
            self.notifyHeartbeat.emit()
        if topic == 'gui/in/match_state':
            self._match_state = msg.value
            self.notifyMatchState.emit()
        if topic == 'gui/in/score':
            self._score = msg.value
            self.notifyScore.emit()
        if topic == 'gui/in/side':
            self._side = msg.value
            self.notifySide.emit()
        if topic == 'gui/in/match_timer':
            self._match_timer = msg.value
            self.notifyMatchTimer.emit()
        if topic == 'gui/in/camera/image':
            self.cameraFrameReceived.emit(msg)
        if topic == 'gui/in/camera/detections':
            self.cameraDetectionsReceived.emit(msg)
        if topic == 'gui/in/nucleo_config_status':
            self._config_status = msg.status + 1
            self.notifyConfigStatus.emit()
        if topic == 'gui/in/nucleo_reset':
            self._config_status = 0
            self.notifyConfigStatus.emit()
        if topic == 'gui/in/odrive_state':
            self._odrive_state = msg.value
            self.notifyODrive.emit()
        if topic == 'gui/in/odrive_error':
            self._odrive_error = msg.value
            self.notifyODrive.emit()

        if topic == 'gui/in/sensors/start_match':
            self._tirette = msg.value
            self.notifyTirette.emit()
        if topic == 'gui/in/sensors/emergency_stop':
            self._emergency_stop = msg.value
            self.notifyEmergencyStop.emit()

    @pyqtProperty(int, notify=notifyScore)
    def score(self):
        return self._score

    @pyqtProperty(int, notify=notifyHeartbeat)
    def heartbeat(self):
        return self._heartbeat

    @pyqtProperty(int, notify=notifyMatchState)
    def match_state(self):
        return self._match_state

    @pyqtProperty(int, notify=notifyConfigStatus)
    def config_status(self):
        return self._config_status

    @pyqtProperty(int, notify=notifyMatchTimer)
    def match_timer(self):
        return self._match_timer

    @pyqtProperty(str, notify=notifyODrive)
    def odrive_state(self):
        return self._odrive_state

    @pyqtProperty(bool, notify=notifyODrive)
    def odrive_error(self):
        return self._odrive_error

    @pyqtProperty(bool, notify=notifyTirette)
    def tirette(self):
        return self._tirette

    @pyqtProperty(bool, notify=notifyEmergencyStop)
    def emergency_stop(self):
        return self._emergency_stop

    def setSide(self, side):
        self._side = side
        self.notifySide.emit()
        msg = Int32Value(value=side)
        self.publishTopic('gui/out/side', msg)

    @pyqtProperty(int, fset=setSide, notify=notifySide)
    def side(self):
        return self._side