def Start(self):
        '''Start client side'''
        client_log.debug('[dbus] start client')

        if self._status >= constants.CLIENT_STATUS_STARTED:
            client_log.warn('[dbus] already started: %s' % self._status)
            return

        self.main_window = MainWindow()

        # Stop host service when main window is closed
        if not self.main_window:
            client_host.critical('[dbus] Failed to init main window!')
            self.Stop()
        self.main_window.windowClosed.connect(self.Stop)
        self.main_window.show()

        self.client_host = Client(self)
        self.client_host.start()

        self.StatusChanged(constants.CLIENT_STATUS_STARTED)

        # Init webserver-connection-timed-out timer
        QtCore.QTimer.singleShot(constants.WEBSERVER_CONNECTION_TIMEOUT,
                                 self.on_webserver_connection_timeout)

        screensaver_iface = ScreenSaver()
        if screensaver_iface.check():
            self.screensaver_iface = screensaver_iface
            self.screensaver_iface.inhibit()
    def Start(self):
        '''Start client side'''
        client_log.debug('[dbus] start client')

        if self._status >= constants.CLIENT_STATUS_STARTED:
            client_log.warn('[dbus] already started: %s' % self._status)
            return

        self.main_window = MainWindow()

        # Stop host service when main window is closed
        if not self.main_window:
            client_host.critical('[dbus] Failed to init main window!')
            self.Stop()
        self.main_window.windowClosed.connect(self.Stop)
        self.main_window.show()

        self.client_host = Client(self)
        self.client_host.start()

        self.StatusChanged(constants.CLIENT_STATUS_STARTED)

        # Init webserver-connection-timed-out timer
        QtCore.QTimer.singleShot(constants.WEBSERVER_CONNECTION_TIMEOUT,
                                 self.on_webserver_connection_timeout)

        screensaver_iface = ScreenSaver()
        if screensaver_iface.check():
            self.screensaver_iface = screensaver_iface
            self.screensaver_iface.inhibit()
class ClientDBus(dbus.service.Object):
    def __init__(self):
        # Init dbus main loop
        #loop = DBusQtMainLoop(set_as_default=True)
        loop = DBusGMainLoop(set_as_default=True)

        session_bus = dbus.SessionBus(loop)
        bus_name = dbus.service.BusName(constants.DBUS_NAME, bus=session_bus)
        server_path = dbus.service.ObjectPath(constants.DBUS_CLIENT_PATH)
        super().__init__(bus_name=bus_name, object_path=server_path)

        self.properties = {
            constants.DBUS_ROOT_IFACE: self._get_root_iface_properties(),
        }

        # MainWindow object
        self.main_window = None

        # Client object
        self.client_host = None

        # Connected to web server or not
        self.connected_to_webserver = False

        # To mark remoting connection has been established
        self.remoting_connected = False

        # To mark status of client side
        self._status = constants.CLIENT_STATUS_UNINITIALIZED

        # ScreenSaver interface instance
        self.screensaver_iface = None

    def _get_root_iface_properties(self):
        return {
            'Status': (self._get_status, None),
        }

    # interface properties
    @dbus.service.method(dbus.PROPERTIES_IFACE,
                         in_signature='ss',
                         out_signature='v')
    def Get(self, interface, prop):
        (getter, _) = self.properties[interface][prop]
        if callable(getter):
            return getter()
        else:
            return getter

    def _get_status(self):
        return self._status

    @dbus.service.method(dbus.PROPERTIES_IFACE,
                         in_signature='s',
                         out_signature='a{sv}')
    def GetAll(self, interface=constants.DBUS_ROOT_IFACE):
        '''Get all properties'''
        getters = {}
        for key, (getter, _) in self.properties[interface].items():
            if callable(getter):
                getters[key] = getter()
            else:
                getters[key] = getter
        return getters

    @dbus.service.method(dbus.PROPERTIES_IFACE,
                         in_signature='ssv',
                         out_signature='')
    def Set(self, interface, prop, value):
        _, setter = self.properties[interface][prop]
        if setter:
            setter(value)
            self.PropertiesChanged(interface,
                                   {prop: self.Get(interface, prop)}, [])

    @dbus.service.signal(dbus.PROPERTIES_IFACE, signature='sa{sv}as')
    def PropertiesChanged(self, interface, changed_properties,
                          invalidated_properties):
        client_log.debug(
            '[dbus] properties changed: %s:%s:%s' %
            (interface, changed_properties, invalidated_properties))

    # root iface signals
    @dbus.service.signal(constants.DBUS_ROOT_IFACE, signature='i')
    def StatusChanged(self, status):
        '''Client status has been changed'''
        client_log.info('[dbus] client status changed: %s' % status)
        self._status = status

        # Connect to web server OK
        if self._status == constants.CLIENT_STATUS_PAGE_READY:
            self.connected_to_webserver = True

        # Connect to web server failed
        elif self._status == constants.CLIENT_STATUS_CONNECT_FAILED:
            self.Stop()

        # Peer id is invalid
        elif self._status == constants.CLIENT_STATUS_UNAVAILABLE:
            self.Stop()

        # Connect to remote peer OK
        elif self._status == constants.CLIENT_STATUS_CONNECT_OK:
            self.remoting_connected = True

        # Disconnected, by remote peer or network failed
        elif self._status == constants.CLIENT_STATUS_DISCONNECTED:
            notify(_('Remoting service terminated!'))
            self.Stop()

    # root iface methods
    @dbus.service.method(constants.DBUS_ROOT_IFACE,
                         in_signature='',
                         out_signature='i')
    def GetStatus(self):
        return self._status

    @dbus.service.method(constants.DBUS_ROOT_IFACE)
    def Start(self):
        '''Start client side'''
        client_log.debug('[dbus] start client')

        if self._status >= constants.CLIENT_STATUS_STARTED:
            client_log.warn('[dbus] already started: %s' % self._status)
            return

        self.main_window = MainWindow()

        # Stop host service when main window is closed
        if not self.main_window:
            client_host.critical('[dbus] Failed to init main window!')
            self.Stop()
        self.main_window.windowClosed.connect(self.Stop)
        self.main_window.show()

        self.client_host = Client(self)
        self.client_host.start()

        self.StatusChanged(constants.CLIENT_STATUS_STARTED)

        # Init webserver-connection-timed-out timer
        QtCore.QTimer.singleShot(constants.WEBSERVER_CONNECTION_TIMEOUT,
                                 self.on_webserver_connection_timeout)

        screensaver_iface = ScreenSaver()
        if screensaver_iface.check():
            self.screensaver_iface = screensaver_iface
            self.screensaver_iface.inhibit()

    @dbus.service.method(constants.DBUS_ROOT_IFACE)
    def Stop(self):
        '''Stop client side'''
        client_log.debug('[dbus] stop client')
        self.StatusChanged(constants.CLIENT_STATUS_STOPPED)
        if self.client_host:
            self.client_host.stop()

        if self.screensaver_iface:
            self.screensaver_iface.uninhibit()

        self.kill()

    def kill(self):
        QtWidgets.qApp.quit()

    @dbus.service.method(constants.DBUS_ROOT_IFACE,
                         in_signature='s',
                         out_signature='')
    def Connect(self, remote_peer_id):
        '''Connect to remote peer'''
        # Send remote peer id to browser side
        client_log.info('[dbus] Connect: %s' % remote_peer_id)
        self.StatusChanged(constants.CLIENT_STATUS_CONNECTING)
        cmd.init_remoting(remote_peer_id)

        # Init webrtc-connection-timeout timer
        QtCore.QTimer.singleShot(constants.WEBRTC_CONNECTION_TIMEOUT,
                                 self.on_webrtc_connection_timeout)

    @QtCore.pyqtSlot()
    def on_webserver_connection_timeout(self):
        '''Handle webserver connection timeout signal'''
        if not self.connected_to_webserver:
            client_log.warn('[dbus] connected to webserver timeout')
            self.StatusChanged(constants.CLIENT_STATUS_CONNECT_FAILED)

    @QtCore.pyqtSlot()
    def on_webrtc_connection_timeout(self):
        '''Handle WebRTC connection timeout signal'''
        if not self.remoting_connected:
            client_log.warn('[dbus] connected to remote peer timeout')
            self.StatusChanged(constants.CLIENT_STATUS_CONNECT_FAILED)
class ClientDBus(dbus.service.Object):

    def __init__(self):
        # Init dbus main loop
        #loop = DBusQtMainLoop(set_as_default=True)
        loop = DBusGMainLoop(set_as_default=True)

        session_bus = dbus.SessionBus(loop)
        bus_name = dbus.service.BusName(constants.DBUS_NAME, bus=session_bus)
        server_path = dbus.service.ObjectPath(constants.DBUS_CLIENT_PATH)
        super().__init__(bus_name=bus_name, object_path=server_path)

        self.properties = {
                constants.DBUS_ROOT_IFACE: self._get_root_iface_properties(),
        }

        # MainWindow object
        self.main_window = None

        # Client object
        self.client_host = None

        # Connected to web server or not
        self.connected_to_webserver = False

        # To mark remoting connection has been established
        self.remoting_connected = False

        # To mark status of client side
        self._status = constants.CLIENT_STATUS_UNINITIALIZED

        # ScreenSaver interface instance
        self.screensaver_iface = None

    def _get_root_iface_properties(self):
        return {
            'Status': (self._get_status, None),
        }

    # interface properties
    @dbus.service.method(dbus.PROPERTIES_IFACE, in_signature='ss',
                         out_signature='v')
    def Get(self, interface, prop):
        (getter, _) = self.properties[interface][prop]
        if callable(getter):
            return getter()
        else:
            return getter

    def _get_status(self):
        return self._status

    @dbus.service.method(dbus.PROPERTIES_IFACE, in_signature='s',
                         out_signature='a{sv}')
    def GetAll(self, interface=constants.DBUS_ROOT_IFACE):
        '''Get all properties'''
        getters = {}
        for key, (getter, _) in self.properties[interface].items():
            if callable(getter):
                getters[key] = getter()
            else:
                getters[key] = getter
        return getters

    @dbus.service.method(dbus.PROPERTIES_IFACE, in_signature='ssv',
                         out_signature='')
    def Set(self, interface, prop, value):
        _, setter = self.properties[interface][prop]
        if setter:
            setter(value)
            self.PropertiesChanged(interface,
                                   {prop: self.Get(interface, prop)}, [])

    @dbus.service.signal(dbus.PROPERTIES_IFACE, signature='sa{sv}as')
    def PropertiesChanged(self, interface, changed_properties,
                          invalidated_properties):
        client_log.debug('[dbus] properties changed: %s:%s:%s' %
                (interface, changed_properties, invalidated_properties))

    # root iface signals
    @dbus.service.signal(constants.DBUS_ROOT_IFACE, signature='i')
    def StatusChanged(self, status):
        '''Client status has been changed'''
        client_log.info('[dbus] client status changed: %s' % status)
        self._status = status

        # Connect to web server OK
        if self._status == constants.CLIENT_STATUS_PAGE_READY:
            self.connected_to_webserver = True

        # Connect to web server failed
        elif self._status == constants.CLIENT_STATUS_CONNECT_FAILED:
            self.Stop()

        # Peer id is invalid
        elif self._status == constants.CLIENT_STATUS_UNAVAILABLE:
            self.Stop()

        # Connect to remote peer OK
        elif self._status == constants.CLIENT_STATUS_CONNECT_OK:
            self.remoting_connected = True

        # Disconnected, by remote peer or network failed
        elif self._status == constants.CLIENT_STATUS_DISCONNECTED:
            notify(_('Remoting service terminated!'))
            self.Stop()

    # root iface methods
    @dbus.service.method(constants.DBUS_ROOT_IFACE, in_signature='',
                         out_signature='i')
    def GetStatus(self):
        return self._status

    @dbus.service.method(constants.DBUS_ROOT_IFACE)
    def Start(self):
        '''Start client side'''
        client_log.debug('[dbus] start client')

        if self._status >= constants.CLIENT_STATUS_STARTED:
            client_log.warn('[dbus] already started: %s' % self._status)
            return

        self.main_window = MainWindow()

        # Stop host service when main window is closed
        if not self.main_window:
            client_host.critical('[dbus] Failed to init main window!')
            self.Stop()
        self.main_window.windowClosed.connect(self.Stop)
        self.main_window.show()

        self.client_host = Client(self)
        self.client_host.start()

        self.StatusChanged(constants.CLIENT_STATUS_STARTED)

        # Init webserver-connection-timed-out timer
        QtCore.QTimer.singleShot(constants.WEBSERVER_CONNECTION_TIMEOUT,
                                 self.on_webserver_connection_timeout)

        screensaver_iface = ScreenSaver()
        if screensaver_iface.check():
            self.screensaver_iface = screensaver_iface
            self.screensaver_iface.inhibit()

    @dbus.service.method(constants.DBUS_ROOT_IFACE)
    def Stop(self):
        '''Stop client side'''
        client_log.debug('[dbus] stop client')
        self.StatusChanged(constants.CLIENT_STATUS_STOPPED)
        if self.client_host:
            self.client_host.stop()

        if self.screensaver_iface:
            self.screensaver_iface.uninhibit()

        self.kill()

    def kill(self):
        QtWidgets.qApp.quit()

    @dbus.service.method(constants.DBUS_ROOT_IFACE, in_signature='s',
                         out_signature='')
    def Connect(self, remote_peer_id):
        '''Connect to remote peer'''
        # Send remote peer id to browser side
        client_log.info('[dbus] Connect: %s' % remote_peer_id)
        self.StatusChanged(constants.CLIENT_STATUS_CONNECTING)
        cmd.init_remoting(remote_peer_id)

        # Init webrtc-connection-timeout timer
        QtCore.QTimer.singleShot(constants.WEBRTC_CONNECTION_TIMEOUT,
                                 self.on_webrtc_connection_timeout)

    @QtCore.pyqtSlot()
    def on_webserver_connection_timeout(self):
        '''Handle webserver connection timeout signal'''
        if not self.connected_to_webserver:
            client_log.warn('[dbus] connected to webserver timeout')
            self.StatusChanged(constants.CLIENT_STATUS_CONNECT_FAILED)

    @QtCore.pyqtSlot()
    def on_webrtc_connection_timeout(self):
        '''Handle WebRTC connection timeout signal'''
        if not self.remoting_connected:
            client_log.warn('[dbus] connected to remote peer timeout')
            self.StatusChanged(constants.CLIENT_STATUS_CONNECT_FAILED)