Example #1
0
    async def load_from_data(self, data: GenericJSONDict) -> None:
        attrs_start = ['enabled']  # These will be loaded first, in this order
        attrs_end = ['expression']  # These will be loaded last, in this order

        attr_items = data.items()
        attr_items = [a for a in attr_items if (a[0] not in attrs_start) and (a[0] not in attrs_end)]

        attr_items_start = []
        for n in attrs_start:
            v = data.get(n)
            if v is not None:
                attr_items_start.append((n, v))

        # Sort the rest of the attributes alphabetically
        attr_items.sort(key=lambda i: i[0])

        attr_items_end = []
        for n in attrs_end:
            v = data.get(n)
            if v is not None:
                attr_items_end.append((n, v))

        attr_items = attr_items_start + attr_items + attr_items_end

        for name, value in attr_items:
            if name in ('id', 'value'):
                continue  # Value is also among the persisted fields

            try:
                self.debug('loading %s = %s', name, json_utils.dumps(value))
                await self.set_attr(name, value)

            except Exception as e:
                self.error('failed to set attribute %s = %s: %s', name, json_utils.dumps(value), e)

        # Value
        if await self.is_persisted() and data.get('value') is not None:
            self._value = data['value']
            self.debug('loaded value = %s', json_utils.dumps(self._value))

            if await self.is_writable():
                # Write the just-loaded value to the port
                value = self._value
                if self._transform_write:
                    value = await self.adapt_value_type(self._transform_write.eval())

                await self.write_value(value)

        elif self.is_enabled():
            try:
                value = await self.read_transformed_value()
                if value is not None:
                    self._value = value
                    self.debug('read value = %s', json_utils.dumps(self._value))

            except Exception as e:
                self.error('failed to read value: %s', e, exc_info=True)
Example #2
0
    async def load_from_data(self, data: GenericJSONDict) -> None:
        attrs = data.get('attrs')
        if attrs:
            if 'value' in data:
                attrs['value'] = data['value']

            self.update_cached_attrs(attrs)

        # Attributes that are kept on master
        for attr in ('tag', 'expression', 'last_sync', 'expires'):
            if attr in data:
                await self.set_attr(attr, data[attr])

        self._provisioning = set(data.get('provisioning', []))
Example #3
0
async def put_frontend(request: core_api.APIRequest, params: GenericJSONDict) -> None:
    # core_api.validate(panels, FRONTEND_SCHEMA)  TODO: validate against schema

    logger.debug('restoring frontend configuration')

    await persist.remove('frontend_prefs')

    prefs = params.get('prefs')
    if prefs:
        for p in prefs:
            logger.debug('restoring frontend prefs for username "%s"', p.get('id'))
            await persist.insert('frontend_prefs', p)

    dashboard_panels = params.get('dashboard_panels', [])
    logger.debug('restoring dashboard panels')
    await persist.set_value('dashboard_panels', dashboard_panels)

    await core_events.trigger(DashboardUpdateEvent(request=request, panels=dashboard_panels))
Example #4
0
async def add_slave_device_retry_disabled(properties: GenericJSONDict) -> slaves_devices.Slave:
    try:
        return await add_slave_device(properties)

    except core_api.APIError:
        if properties.get('enabled', True):
            core_api.logger.warning('adding device failed, adding it as disabled', exc_info=True)
            return await add_slave_device(dict(properties, enabled=False))

        else:
            raise
Example #5
0
    async def load_from_data(self, data: GenericJSONDict) -> None:
        # Only consider locally persisted attributes for permanently offline devices. For online devices, we always use
        # fresh attributes received from device.
        attrs = data.get('attrs')
        if attrs and self._slave.is_permanently_offline():
            if 'value' in data:
                attrs['value'] = data['value']

            self.update_cached_attrs(attrs)

        # Attributes that are kept on master
        for attr in MASTER_ATTRS:
            if attr in data:
                await self.set_attr(attr, data[attr])

        self._history_last_timestamp = data.get('history_last_timestamp', 0)
        self._provisioning = set(data.get('provisioning', []))

        # Enable if enabled remotely
        await self.update_enabled()
Example #6
0
async def add_virtual_port(attrs: GenericJSONDict) -> core_ports.BasePort:
    id_ = attrs['id']
    type_ = attrs['type']
    min_ = attrs.get('min')
    max_ = attrs.get('max')
    integer = attrs.get('integer')
    step = attrs.get('step')
    choices = attrs.get('choices')

    core_api.logger.debug('adding port "%s"', id_)

    if core_ports.get(id_):
        raise core_api.APIError(400, 'duplicate-port')

    if len(core_vports.all_port_args()) >= settings.core.virtual_ports:
        raise core_api.APIError(400, 'too-many-ports')

    await core_vports.add(id_, type_, min_, max_, integer, step, choices)
    port = await core_ports.load_one(
        'qtoggleserver.core.vports.VirtualPort',
        {
            'id_': id_,
            'type_': type_,
            'min_': min_,
            'max_': max_,
            'integer': integer,
            'step': step,
            'choices': choices
        },
        trigger_add=
        False  # Will trigger add event manually, later, after we've enabled the port
    )

    # A virtual port is enabled by default
    await port.enable()
    await port.save()
    await port.trigger_add()

    return port
Example #7
0
async def patch_firmware(request: core_api.APIRequest,
                         params: GenericJSONDict) -> None:
    core_api_schema.validate(params, core_api_schema.PATCH_FIRMWARE)

    status = await fwupdate.get_status()
    if status not in (fwupdate.STATUS_IDLE, fwupdate.STATUS_ERROR):
        raise core_api.APIError(503, 'busy')

    if params.get('url'):
        await fwupdate.update_to_url(params['url'])

    else:  # Assuming params['version']
        await fwupdate.update_to_version(params['version'])
Example #8
0
async def post_ports(request: core_api.APIRequest, params: GenericJSONDict) -> Attributes:
    core_api_schema.validate(params, core_api_schema.POST_PORTS)

    port_id = params['id']
    port_type = params['type']
    _min = params.get('min')
    _max = params.get('max')
    integer = params.get('integer')
    step = params.get('step')
    choices = params.get('choices')

    if core_ports.get(port_id):
        raise core_api.APIError(400, 'duplicate port')

    if len(core_vports.all_settings()) >= settings.core.virtual_ports:
        raise core_api.APIError(400, 'too many ports')

    core_vports.add(port_id, port_type, _min, _max, integer, step, choices)
    port = await core_ports.load_one(
        'qtoggleserver.core.vports.VirtualPort',
        {
            'port_id': port_id,
            '_type': port_type,
            '_min': _min,
            '_max': _max,
            'integer': integer,
            'step': step,
            'choices': choices
        }
    )

    # A virtual port is enabled by default
    await port.enable()
    await port.save()

    return await port.to_json()
Example #9
0
async def post_reset(request: core_api.APIRequest,
                     params: GenericJSONDict) -> None:
    core_api_schema.validate(params, core_api_schema.POST_RESET)

    factory = params.get('factory')

    if factory:
        core_api.logger.info('resetting to factory defaults')

        core_ports.reset()
        core_vports.reset()
        core_device.reset()
        if settings.webhooks.enabled:
            core_webhooks.reset()
        if settings.reverse.enabled:
            core_reverse.reset()
        if settings.slaves.enabled:
            slaves.reset()

    main.loop.call_later(2, system.reboot)
Example #10
0
async def post_introspect(request: core_api.APIRequest,
                          params: GenericJSONDict) -> GenericJSONDict:
    core_api_schema.validate(params, core_api_schema.POST_INTROSPECT)

    exc_str = None
    res_str = None

    try:
        imports = params.get('imports', [])
        extra_locals = {}
        for imp in imports:
            extra_locals[imp.split('.')[0]] = importlib.__import__(imp)

        result = eval(params['code'], globals(), dict(locals(),
                                                      **extra_locals))
        if inspect.isawaitable(result):
            result = await result

        res_str = str(result)

    except Exception:
        exc_str = traceback.format_exc()

    return {'result': res_str, 'exception': exc_str}
Example #11
0
async def patch_slave_device(request: core_api.APIRequest, name: str,
                             params: GenericJSONDict) -> None:
    core_api_schema.validate(params, api_schema.PATCH_SLAVE_DEVICE)

    slave = slaves_devices.get(name)
    if not slave:
        raise core_api.APIError(404, 'no such device')

    if params.get('enabled') is True and not slave.is_enabled():
        await slave.enable()

    elif params.get('enabled') is False and slave.is_enabled():
        await slave.disable()

    if params.get('poll_interval') and params.get('listen_enabled'):
        raise core_api.APIError(400, 'listening and polling')

    if params.get('poll_interval') is not None:
        slave.set_poll_interval(params['poll_interval'])

    if params.get('listen_enabled') is not None:
        if params['listen_enabled']:
            # We need to know if device supports listening; we therefore call GET /device before enabling it

            if slave.is_enabled():
                try:
                    attrs = await slave.api_call('GET', '/device')

                except Exception as e:
                    raise exceptions.adapt_api_error(e) from e

                if 'listen' not in attrs['flags']:
                    raise core_api.APIError(400, 'no listen support')

            slave.enable_listen()

        else:
            slave.disable_listen()

    slave.save()
    slave.trigger_update()