def send_and_receive(self, command, **kwargs):
            # self.log_debug("send_and_receive: message %s" % command)

            # exit the loop if timeout happens
            timeout_timer = QtCore.QTimer(
                parent=QtCore.QCoreApplication.instance())

            loop = QtCore.QEventLoop()

            data = None

            def await_for_response(result):
                self.send_and_receive.data = result
                # self.log_debug("exiting the loop: result %s" % result)
                loop.quit()

            # self.log_debug("in the loop...")
            self.send_text_message(command,
                                   callback=await_for_response,
                                   **kwargs)

            timeout_timer.timeout.connect(loop.quit)
            timeout_timer.start(5 * 1000.0)

            loop.exec_()

            return self.send_and_receive.data
    def show(self, pos=None):
        pos = QtGui.QCursor.pos() if pos is None else QtCore.QPoint(pos[0], pos[1])
        qApp = QtWidgets.QApplication.instance()
        # qApp.setWindowState(QtCore.Qt.WindowActive)

        self.menu_handle.activateWindow()
        self.menu_handle.raise_()
        self.menu_handle.exec_(pos)
 def _jump_to_sg(self):
     """
     Jump to shotgun, launch web browser
     """
     url = self._engine.context.shotgun_url
     QtGui.QDesktopServices.openUrl(QtCore.QUrl(url))
 def connect_to_server(self):
     self.log_debug("Client start connection | %s " % QtCore.QUrl(self.url))
     result = self.client.open(QtCore.QUrl(self.url))
     self.log_debug("Client start connection | result | %s " % result)
class Client(QtCore.QObject):

    requestReceived = QtCore.Signal(str, object)

    def __init__(self, engine, parent=None, url="ws://localhost:12345"):
        super(Client, self).__init__(parent)
        self.engine = engine
        self.url = url
        self.client = QtWebSockets.QWebSocket(
            "", QtWebSockets.QWebSocketProtocol.Version13, None)

        self.client.connected.connect(self.on_connected)
        self.client.disconnected.connect(self.on_disconnected)
        self.client.error.connect(self.on_error)
        self.client.stateChanged.connect(self.on_state_changed)

        self.client.pong.connect(self.on_pong)
        self.client.textMessageReceived.connect(self.on_text_message_received)

        self.callbacks = {}
        self.max_attemps = 5
        self.wait_period = 1

        # borrow the engine logger
        self.log_info = engine.log_info
        self.log_debug = engine.log_debug
        self.log_warning = engine.log_warning
        self.log_error = engine.log_error

        self.log_debug("Client started. - %s " % url)

        # A bit of a hack to get responses from the server
        # I cannot wait for python3 concurrency!
        # reference: https://stackoverflow.com/questions/9523370/adding-attributes-to-instance-methods-in-python
        def send_and_receive(self, command, **kwargs):
            # self.log_debug("send_and_receive: message %s" % command)

            # exit the loop if timeout happens
            timeout_timer = QtCore.QTimer(
                parent=QtCore.QCoreApplication.instance())

            loop = QtCore.QEventLoop()

            data = None

            def await_for_response(result):
                self.send_and_receive.data = result
                # self.log_debug("exiting the loop: result %s" % result)
                loop.quit()

            # self.log_debug("in the loop...")
            self.send_text_message(command,
                                   callback=await_for_response,
                                   **kwargs)

            timeout_timer.timeout.connect(loop.quit)
            timeout_timer.start(5 * 1000.0)

            loop.exec_()

            return self.send_and_receive.data

        self.send_and_receive = partial(send_and_receive, self)

        # connect to server
        self.connect_to_server()

    def connect_to_server(self):
        self.log_debug("Client start connection | %s " % QtCore.QUrl(self.url))
        result = self.client.open(QtCore.QUrl(self.url))
        self.log_debug("Client start connection | result | %s " % result)

    def ping(self):
        self.log_debug("client: do_ping")
        self.client.ping()

    def on_connected(self):
        pass
        self.log_debug("client: on_connected")

    def on_disconnected(self):
        self.log_debug("client: on_disconnected")
        self.engine.process_request("QUIT")

    def on_error(self, error_code):
        self.log_error("client: on_error: {}".format(error_code))
        self.log_error(self.client.errorString())
        self.engine.process_request("QUIT")

    def on_state_changed(self, state):
        self.log_debug("client: on_state_changed: %s" % state)
        state = self.client.state()
        if state == QAbstractSocket.SocketState.ConnectingState:
            return

        attempts = 0
        while attempts < self.max_attemps and self.client.state() not in (
                QAbstractSocket.SocketState.ConnectedState, ):
            attempts += 1
            self.log_debug("client: attempted to reconnect : %s" % attempts)
            self.connect_to_server()
            time.sleep(self.wait_period)

    def on_text_message_received(self, message):
        # self.log_debug("client: on_text_message_received: %s" % (message))
        jsonData = json.loads(message)
        message_id = jsonData.get("id")

        # requesting data
        if jsonData.has_key("method"):
            # self.log_debug("client: request detected: %s" % (message))
            method = jsonData.get("method")
            params = jsonData.get("params")
            self.engine.process_request(method, **params)

        if jsonData.has_key("result"):
            # self.log_debug("client: result detected: %s" % (message))
            if message_id in self.callbacks:
                # self.log_debug(
                #     "client: requesting callback result for message: %s"
                #     % message_id
                # )
                result = jsonData.get("result")
                self.callbacks[message_id](result)
                del self.callbacks[message_id]

    def send_text_message(self,
                          command,
                          message_id=None,
                          callback=None,
                          **kwargs):
        if self.client.state() in (
                QAbstractSocket.SocketState.ClosingState,
                QAbstractSocket.SocketState.UnconnectedState,
        ):
            # self.log_debug(
            #     "client: is not connected!, ignoring message: %s" % message_id
            # )
            return

        # wait until connected
        while self.client.state(
        ) == QAbstractSocket.SocketState.ConnectingState:
            QCoreApplication.processEvents()
            # self.log_debug("client: waiting state: %s" % self.client.state())
            time.sleep(self.wait_period)
            pass

        if message_id is None:
            message_id = uuid.uuid4().hex

        if callback:
            self.callbacks[message_id] = callback

        message = json.dumps({
            "jsonrpc": "2.0",
            "method": command,
            "params": kwargs,
            "id": message_id,
        })

        # self.log_debug("client: send_message: %s" % message)
        self.client.sendTextMessage(message)
        return message_id

    def on_pong(self, elapsedTime, payload):
        # self.log_debug(
        #     "client: onPong - time: {} ; payload: {}".format(
        #         elapsedTime, payload
        #     )
        # )
        pass

    def close(self):
        self.log_debug("client: closed.")
        self.client.close()