<commit_before># -*- coding: utf-8 -*-
"""
ZMQ Client Implementation
"""

from __future__ import absolute_import

import weakref
from ..base import ClientService, ClientKeyword
from ..exc import CauldronAPINotImplementedWarning, CauldronAPINotImplemented, DispatcherError, TimeoutError
from .common import zmq_get_address, check_zmq, teardown, zmq_connect_socket
from .microservice import ZMQCauldronMessage, ZMQCauldronErrorResponse, FRAMEBLANK, FRAMEFAIL
from .tasker import Task, TaskQueue
from .. import registry
from ..config import get_configuration, get_timeout

import six
import threading
import logging
import warnings

__all__ = ["Service", "Keyword"]

registry.client.teardown_for('zmq')(teardown)

class _ZMQMonitorThread(threading.Thread):
    """A monitoring thread for ZMQ-powered Services which listens for broadcasts."""
    def __init__(self, service):
        super(_ZMQMonitorThread, self).__init__(name="ktl.Service.{0}.Broadcasts".format(service.name))
        self.service = weakref.proxy(service)
        self.shutdown = threading.Event()
        self.log = logging.getLogger(self.name)
        self.monitored = set()
        self.daemon = True
        self.address = None

    def stop(self):
        """Stop this thread."""
        self.shutdown.set()
        if not self.isAlive():
            return
        self.log.debug("Joining {0}".format(self.name))
        self.join()

    def run(self):
        """Run the monitoring thread."""
        zmq = check_zmq()
        try:
            ctx = self.service.ctx
        except weakref.ReferenceError:
            self.log.log(5, "Can't start ZMQ monitor, service has disappeared.")
            return
        socket = ctx.socket(zmq.SUB)
        try:
            zmq_connect_socket(socket, get_configuration(), "subscribe", log=self.log, label='client-monitor', address=self.address)
            # Accept everything belonging to this service.
            socket.setsockopt_string(zmq.SUBSCRIBE, six.text_type(self.service.name))

            while not self.shutdown.isSet():
                if socket.poll(timeout=1):
                    try:
                        message = ZMQCauldronMessage.parse(socket.recv_multipart())
                        message.verify(self.service)
                        keyword = self.service[message.keyword]
                        if keyword.name in self.monitored:
                            keyword._update(message.payload)
                            self.log.log(5, "Accepted broadcast for {0}: {1}".format(keyword.name, message.payload))
                        else:
                            self.log.log(5, "Ignored broadcast for {0}, not monitored.".format(keyword.name))
                    except ZMQCauldronErrorResponse as e:
                        self.log.error("Broadcast Message Error: {0!r}".format(e))
                    except (zmq.ContextTerminated, zmq.ZMQError):
                        raise
                    except Exception as e:
                        self.log.error("Broadcast Error: {0!r}".format(e))
        except (zmq.ContextTerminated, zmq.ZMQError) as e:
            self.log.log(6, "Service shutdown and context terminated, closing broadcast thread. {0}".format(repr(e)))
        else:
            try:
                socket.setsockopt(zmq.LINGER, 0)
                socket.close()
            except:
                pass
        finally:
            self.log.debug("Stopped Monitor Thread")

@registry.client.service_for("zmq")
class Service(ClientService):
    # Client service object for use with ZMQ.

    def __init__(self, name, populate=False):
        zmq = check_zmq()
        self.ctx = zmq.Context.instance()
        self._sockets = threading.local()
        self._monitor = None
        self._tasker = None
        self._lock = threading.RLock()
        self._type_ktl_cache = {}
        super(Service, self).__init__(name, populate)

    @property
    def socket(self):
        """A thread-local ZMQ socket for sending commands to the responder thread."""
        # Short out if we already have a socket.
        if hasattr(self._sockets, 'socket'):
            return self._sockets.socket

        zmq = check_zmq()
        socket = self.ctx.socket(zmq.REQ)
        zmq_connect_socket(socket, get_configuration(), "broker", log=self.log, label='client')
        self._sockets.socket = socket
        return socket

    def _prepare(self):
        """Prepare step."""
        self._monitor = _ZMQMonitorThread(self)
        self._tasker = TaskQueue(self.name, ctx=self.ctx, log=self.log)
        self._tasker.start()
        address = self._synchronous_command("lookup", "subscribe", direction="CBQ")
        self._monitor.address = address
        self._monitor.start()

    def _ktl_type(self, key):
        """Get the KTL type of a specific keyword."""
        name = key.upper()
        with self._lock:
            if name in self._type_ktl_cache:
                return self._type_ktl_cache[name]
            message = self._synchronous_command("identify", payload=name, keyword=name, direction="CSQ")
            items = list(set(message.split(":")))
            if len(items) == 1 and (items[0] not in (FRAMEBLANK.decode('utf-8'), FRAMEFAIL.decode('utf-8'))):
                ktl_type = items[0]
            else:
                raise KeyError("Keyword '{0}' does not exist.".format(name))
            self._type_ktl_cache[name] = ktl_type
            return ktl_type

    def __del__(self):
        """On delete, try to shutdown."""
        self.shutdown()

    def shutdown(self):
        if hasattr(self, '_monitor'):
            self._monitor.stop()
        if hasattr(self, '_tasker'):
            self._tasker.stop()

    def has_keyword(self, name):
        assert name.upper() != self.name.upper()
        name = name.upper()
        try:
            ktype = self._ktl_type(name)
        except KeyError as e:
            return False
        else:
            return True

    def keywords(self):
        message = self._synchronous_command("enumerate", FRAMEBLANK, direction="CSQ")
        return message.split(":")

    def _handle_response(self, message):
        """Handle a response, and return the payload."""
        self.log.log(5, "{0!r}.recv({1!s})".format(self, message))
        if message.iserror:
            raise DispatcherError("Dispatcher error on command: {0}".format(message.payload))
        message.verify(self)
        return message.payload

    def _asynchronous_command(self, command, payload, keyword=None, direction="CDQ", timeout=None, callback=None):
        """Run an asynchronous command."""
        request = ZMQCauldronMessage(command, direction=direction,
            service=self.name, dispatcher=FRAMEBLANK,
            keyword=keyword if keyword else FRAMEBLANK,
            payload=payload if payload else FRAMEBLANK)

        callback = callback or self._handle_response

        task = Task(request, callback, get_timeout(timeout))
        self._tasker.put(task)
        return task

    def _synchronous_command(self, command, payload, keyword=None, direction="CDQ", timeout=None, callback=None):
        """Execute a synchronous command."""
        timeout = get_timeout(timeout)
        task = self._asynchronous_command(command, payload, keyword, direction, timeout, callback)
        return task.get(timeout=timeout)

@registry.client.keyword_for("zmq")
class Keyword(ClientKeyword):
    # Client keyword object for use with ZMQ.

    def _ktl_reads(self):
        """Is this keyword readable?"""
        return True

    def _ktl_writes(self):
        """Is this keyword writable?"""
        return True

    def _ktl_monitored(self):
        """Is this keyword monitored."""
        return self.name in self.service._monitor.monitored

    def _handle_response(self, message):
        """Handle a response, and return the payload."""
        self.service.log.log(5, "{0!r}.recv({1!s})".format(self, message))
        if message.iserror:
            raise DispatcherError("Dispatcher error on command: {0}".format(message.payload))
        message.verify(self.service)
        self._update(message.payload)
        return self._current_value(binary=False, both=False)

    def _asynchronous_command(self, command, payload, timeout=None, callback=None):
        """Execute a synchronous command."""
        return self.service._asynchronous_command(command, payload, self.name, timeout=timeout, callback=self._handle_response)

    def _synchronous_command(self, command, payload, timeout=None):
        """Execute a synchronous command."""
        return self.service._synchronous_command(command, payload, self.name, timeout=timeout)

    def wait(self, timeout=None, operator=None, value=None, sequence=None, reset=False, case=False):
        if sequence is not None:
            return sequence.wait(timeout=get_timeout(timeout))
        raise CauldronAPINotImplemented("Asynchronous expression operations are not supported for Cauldron.zmq")

    def monitor(self, start=True, prime=True, wait=True):
        if start:
            if prime:
                self.read(wait=wait)
            self.service._monitor.monitored.add(self.name)
        else:
            self.service._monitor.monitored.remove(self.name)

    def read(self, binary=False, both=False, wait=True, timeout=None):
        _call_msg = lambda : "{0!r}.read(wait={1}, timeout={2})".format(self, wait, timeout)

        if not self['reads']:
            raise NotImplementedError("Keyword '{0}' does not support reads.".format(self.name))

        task = self._asynchronous_command("update", "", timeout=timeout)
        if wait:
            self.service.log.debug("{0} waiting.".format(_call_msg()))
            try:
                task.get(timeout=timeout)
            except TimeoutError:
                raise TimeoutError("{0} timed out.".format(_call_msg()))
            else:
                self.service.log.debug("{0} complete.".format(_call_msg()))
            return self._current_value(binary=binary, both=both)
        else:
            return task

    def write(self, value, wait=True, binary=False, timeout=None):
        _call_msg = lambda : "{0!r}.write(wait={1}, timeout={2})".format(self, wait, timeout)

        if not self['writes']:
            raise NotImplementedError("Keyword '{0}' does not support writes.".format(self.name))

        # User-facing convenience to make writes smoother.
        try:
            value = self.cast(value)
        except (TypeError, ValueError):
            pass
        task = self._asynchronous_command("modify", value, timeout=timeout)
        if wait:
            self.service.log.debug("{0} waiting.".format(_call_msg()))
            try:
                result = task.get(timeout=timeout)
            except TimeoutError:
                raise TimeoutError("{0} timed out.".format(_call_msg()))
            else:
                self.service.log.debug("{0} complete.".format(_call_msg()))
        else:
            return task

        <commit_msg>Remove unused socket from Client<commit_after># -*- coding: utf-8 -*-
"""
ZMQ Client Implementation
"""

from __future__ import absolute_import

import weakref
from ..base import ClientService, ClientKeyword
from ..exc import CauldronAPINotImplementedWarning, CauldronAPINotImplemented, DispatcherError, TimeoutError
from .common import zmq_get_address, check_zmq, teardown, zmq_connect_socket
from .microservice import ZMQCauldronMessage, ZMQCauldronErrorResponse, FRAMEBLANK, FRAMEFAIL
from .tasker import Task, TaskQueue
from .. import registry
from ..config import get_configuration, get_timeout

import six
import threading
import logging
import warnings

__all__ = ["Service", "Keyword"]

registry.client.teardown_for('zmq')(teardown)

class _ZMQMonitorThread(threading.Thread):
    """A monitoring thread for ZMQ-powered Services which listens for broadcasts."""
    def __init__(self, service):
        super(_ZMQMonitorThread, self).__init__(name="ktl.Service.{0}.Broadcasts".format(service.name))
        self.service = weakref.proxy(service)
        self.shutdown = threading.Event()
        self.log = logging.getLogger(self.name)
        self.monitored = set()
        self.daemon = True
        self.address = None

    def stop(self):
        """Stop this thread."""
        self.shutdown.set()
        if not self.isAlive():
            return
        self.log.debug("Joining {0}".format(self.name))
        self.join()

    def run(self):
        """Run the monitoring thread."""
        zmq = check_zmq()
        try:
            ctx = self.service.ctx
        except weakref.ReferenceError:
            self.log.log(5, "Can't start ZMQ monitor, service has disappeared.")
            return
        socket = ctx.socket(zmq.SUB)
        try:
            zmq_connect_socket(socket, get_configuration(), "subscribe", log=self.log, label='client-monitor', address=self.address)
            # Accept everything belonging to this service.
            socket.setsockopt_string(zmq.SUBSCRIBE, six.text_type(self.service.name))

            while not self.shutdown.isSet():
                if socket.poll(timeout=1):
                    try:
                        message = ZMQCauldronMessage.parse(socket.recv_multipart())
                        message.verify(self.service)
                        keyword = self.service[message.keyword]
                        if keyword.name in self.monitored:
                            keyword._update(message.payload)
                            self.log.log(5, "Accepted broadcast for {0}: {1}".format(keyword.name, message.payload))
                        else:
                            self.log.log(5, "Ignored broadcast for {0}, not monitored.".format(keyword.name))
                    except ZMQCauldronErrorResponse as e:
                        self.log.error("Broadcast Message Error: {0!r}".format(e))
                    except (zmq.ContextTerminated, zmq.ZMQError):
                        raise
                    except Exception as e:
                        self.log.error("Broadcast Error: {0!r}".format(e))
        except (zmq.ContextTerminated, zmq.ZMQError) as e:
            self.log.log(6, "Service shutdown and context terminated, closing broadcast thread. {0}".format(repr(e)))
        else:
            try:
                socket.setsockopt(zmq.LINGER, 0)
                socket.close()
            except:
                pass
        finally:
            self.log.debug("Stopped Monitor Thread")

@registry.client.service_for("zmq")
class Service(ClientService):
    # Client service object for use with ZMQ.

    def __init__(self, name, populate=False):
        zmq = check_zmq()
        self.ctx = zmq.Context.instance()
        self._sockets = threading.local()
        self._monitor = None
        self._tasker = None
        self._lock = threading.RLock()
        self._type_ktl_cache = {}
        super(Service, self).__init__(name, populate)

    def _prepare(self):
        """Prepare step."""
        self._monitor = _ZMQMonitorThread(self)
        self._tasker = TaskQueue(self.name, ctx=self.ctx, log=self.log)
        self._tasker.start()
        address = self._synchronous_command("lookup", "subscribe", direction="CBQ")
        self._monitor.address = address
        self._monitor.start()

    def _ktl_type(self, key):
        """Get the KTL type of a specific keyword."""
        name = key.upper()
        with self._lock:
            if name in self._type_ktl_cache:
                return self._type_ktl_cache[name]
            message = self._synchronous_command("identify", payload=name, keyword=name, direction="CSQ")
            items = list(set(message.split(":")))
            if len(items) == 1 and (items[0] not in (FRAMEBLANK.decode('utf-8'), FRAMEFAIL.decode('utf-8'))):
                ktl_type = items[0]
            else:
                raise KeyError("Keyword '{0}' does not exist.".format(name))
            self._type_ktl_cache[name] = ktl_type
            return ktl_type

    def __del__(self):
        """On delete, try to shutdown."""
        self.shutdown()

    def shutdown(self):
        if hasattr(self, '_monitor'):
            self._monitor.stop()
        if hasattr(self, '_tasker'):
            self._tasker.stop()

    def has_keyword(self, name):
        assert name.upper() != self.name.upper()
        name = name.upper()
        try:
            ktype = self._ktl_type(name)
        except KeyError as e:
            return False
        else:
            return True

    def keywords(self):
        message = self._synchronous_command("enumerate", FRAMEBLANK, direction="CSQ")
        return message.split(":")

    def _handle_response(self, message):
        """Handle a response, and return the payload."""
        self.log.log(5, "{0!r}.recv({1!s})".format(self, message))
        if message.iserror:
            raise DispatcherError("Dispatcher error on command: {0}".format(message.payload))
        message.verify(self)
        return message.payload

    def _asynchronous_command(self, command, payload, keyword=None, direction="CDQ", timeout=None, callback=None):
        """Run an asynchronous command."""
        request = ZMQCauldronMessage(command, direction=direction,
            service=self.name, dispatcher=FRAMEBLANK,
            keyword=keyword if keyword else FRAMEBLANK,
            payload=payload if payload else FRAMEBLANK)

        callback = callback or self._handle_response

        task = Task(request, callback, get_timeout(timeout))
        self._tasker.put(task)
        return task

    def _synchronous_command(self, command, payload, keyword=None, direction="CDQ", timeout=None, callback=None):
        """Execute a synchronous command."""
        timeout = get_timeout(timeout)
        task = self._asynchronous_command(command, payload, keyword, direction, timeout, callback)
        return task.get(timeout=timeout)

@registry.client.keyword_for("zmq")
class Keyword(ClientKeyword):
    # Client keyword object for use with ZMQ.

    def _ktl_reads(self):
        """Is this keyword readable?"""
        return True

    def _ktl_writes(self):
        """Is this keyword writable?"""
        return True

    def _ktl_monitored(self):
        """Is this keyword monitored."""
        return self.name in self.service._monitor.monitored

    def _handle_response(self, message):
        """Handle a response, and return the payload."""
        self.service.log.log(5, "{0!r}.recv({1!s})".format(self, message))
        if message.iserror:
            raise DispatcherError("Dispatcher error on command: {0}".format(message.payload))
        message.verify(self.service)
        self._update(message.payload)
        return self._current_value(binary=False, both=False)

    def _asynchronous_command(self, command, payload, timeout=None, callback=None):
        """Execute a synchronous command."""
        return self.service._asynchronous_command(command, payload, self.name, timeout=timeout, callback=self._handle_response)

    def _synchronous_command(self, command, payload, timeout=None):
        """Execute a synchronous command."""
        return self.service._synchronous_command(command, payload, self.name, timeout=timeout)

    def wait(self, timeout=None, operator=None, value=None, sequence=None, reset=False, case=False):
        if sequence is not None:
            return sequence.wait(timeout=get_timeout(timeout))
        raise CauldronAPINotImplemented("Asynchronous expression operations are not supported for Cauldron.zmq")

    def monitor(self, start=True, prime=True, wait=True):
        if start:
            if prime:
                self.read(wait=wait)
            self.service._monitor.monitored.add(self.name)
        else:
            self.service._monitor.monitored.remove(self.name)

    def read(self, binary=False, both=False, wait=True, timeout=None):
        _call_msg = lambda : "{0!r}.read(wait={1}, timeout={2})".format(self, wait, timeout)

        if not self['reads']:
            raise NotImplementedError("Keyword '{0}' does not support reads.".format(self.name))

        task = self._asynchronous_command("update", "", timeout=timeout)
        if wait:
            self.service.log.debug("{0} waiting.".format(_call_msg()))
            try:
                task.get(timeout=timeout)
            except TimeoutError:
                raise TimeoutError("{0} timed out.".format(_call_msg()))
            else:
                self.service.log.debug("{0} complete.".format(_call_msg()))
            return self._current_value(binary=binary, both=both)
        else:
            return task

    def write(self, value, wait=True, binary=False, timeout=None):
        _call_msg = lambda : "{0!r}.write(wait={1}, timeout={2})".format(self, wait, timeout)

        if not self['writes']:
            raise NotImplementedError("Keyword '{0}' does not support writes.".format(self.name))

        # User-facing convenience to make writes smoother.
        try:
            value = self.cast(value)
        except (TypeError, ValueError):
            pass
        task = self._asynchronous_command("modify", value, timeout=timeout)
        if wait:
            self.service.log.debug("{0} waiting.".format(_call_msg()))
            try:
                result = task.get(timeout=timeout)
            except TimeoutError:
                raise TimeoutError("{0} timed out.".format(_call_msg()))
            else:
                self.service.log.debug("{0} complete.".format(_call_msg()))
        else:
            return task

        <|endoftext|>


<commit_before># -*- coding: utf-8 -*-

# Copyright(C) 2013  Florent Fourcot
#
# This file is part of weboob.
#
# weboob is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# weboob is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with weboob. If not, see <http://www.gnu.org/licenses/>.

from weboob.capabilities.gauge import ICapGauge, SensorNotFound
from weboob.tools.application.repl import ReplApplication, defaultcount
from weboob.tools.application.formatters.iformatter import IFormatter, PrettyFormatter

import sys

__all__ = ['Boobsize']

class CitiesFormatter(PrettyFormatter):
    MANDATORY_FIELDS = ('id', 'name')

    def get_title(self, obj):
        return obj.name

class Boobsize(ReplApplication):
    APPNAME = 'Boosize'
    VERSION = '0.h'
    COPYRIGHT = 'Copyright(C) 2013 Florent Fourcot'
    DESCRIPTION = "Console application allowing to display various sensors and gauges values."
    SHORT_DESCRIPTION = "display sensors and gauges values"
    CAPS = (ICapGauge)
    DEFAULT_FORMATTER = 'table'

    def main(self, argv):
        self.load_config()
        return ReplApplication.main(self, argv)

    def bcall_error_handler(self, backend, error, backtrace):
        if isinstance(error, SensorNotFound):
            msg = unicode(error) or 'Sensor not found (hint: try sensors command)'
            print >>sys.stderr, 'Error(%s): %s' % (backend.name, msg)
        else:
            return ReplApplication.bcall_error_handler(self, backend, error, backtrace)

    def do_search(self, pattern):
        """
        search [PATTERN]

        Display all gauges. If PATTERN is specified, search on a pattern.
        """
        self.change_path([u'gauges'])
        self.start_format()
        for backend, gauge in self.do('iter_gauges', pattern or None, caps=ICapGauge):
            self.cached_format(gauge)

    def complete_search(self, text, line, *ignored):
        args = line.split(' ')
        if len(args) == 2:
            return self._complete_object()

    def do_details(self, line):
        """
        details GAUGE_ID

        Display details of all sensors of the gauge.
        """
        gauge, pattern = self.parse_command_args(line, 2, 1)
        _id, backend_name = self.parse_id(gauge)

        self.start_format()
        for backend, sensor in self.do('iter_sensors', _id, pattern=pattern, backends=backend_name, caps=ICapGauge):
            self.format(sensor)

    def do_history(self, line):
        """
        history SENSOR_ID

        Get history of a specific sensor (use 'search' to find a gauge, and sensors GAUGE_ID to list sensors attached to the gauge).
        """
        gauge, = self.parse_command_args(line, 1, 1)
        _id, backend_name = self.parse_id(gauge)

        self.start_format()
        for backend, measure in self.do('iter_gauge_history', _id, backends=backend_name, caps=ICapGauge):
            self.format(measure)

    def complete_last_sensor_measure(self, text, line, *ignored):
        args = line.split(' ')
        if len(args) == 2:
            return self._complete_object()

    def do_last_sensor_measure(self, line):
        """
        last_sensor_measure SENSOR_ID

        Get last measure of a sensor.
        """
        gauge, = self.parse_command_args(line, 1, 1)
        _id, backend_name = self.parse_id(gauge)

        self.start_format()
        for backend, measure in self.do('get_last_measure', _id, backends=backend_name, caps=ICapGauge):
            self.format(measure)
<commit_msg>Remove dead code<commit_after># -*- coding: utf-8 -*-

# Copyright(C) 2013  Florent Fourcot
#
# This file is part of weboob.
#
# weboob is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# weboob is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with weboob. If not, see <http://www.gnu.org/licenses/>.

from weboob.capabilities.gauge import ICapGauge, SensorNotFound
from weboob.tools.application.repl import ReplApplication
from weboob.tools.application.formatters.iformatter import IFormatter, PrettyFormatter

import sys

__all__ = ['Boobsize']

class Boobsize(ReplApplication):
    APPNAME = 'Boosize'
    VERSION = '0.h'
    COPYRIGHT = 'Copyright(C) 2013 Florent Fourcot'
    DESCRIPTION = "Console application allowing to display various sensors and gauges values."
    SHORT_DESCRIPTION = "display sensors and gauges values"
    CAPS = (ICapGauge)
    DEFAULT_FORMATTER = 'table'

    def main(self, argv):
        self.load_config()
        return ReplApplication.main(self, argv)

    def bcall_error_handler(self, backend, error, backtrace):
        if isinstance(error, SensorNotFound):
            msg = unicode(error) or 'Sensor not found (hint: try sensors command)'
            print >>sys.stderr, 'Error(%s): %s' % (backend.name, msg)
        else:
            return ReplApplication.bcall_error_handler(self, backend, error, backtrace)

    def do_search(self, pattern):
        """
        search [PATTERN]

        Display all gauges. If PATTERN is specified, search on a pattern.
        """
        self.change_path([u'gauges'])
        self.start_format()
        for backend, gauge in self.do('iter_gauges', pattern or None, caps=ICapGauge):
            self.cached_format(gauge)

    def complete_search(self, text, line, *ignored):
        args = line.split(' ')
        if len(args) == 2:
            return self._complete_object()

    def do_details(self, line):
        """
        details GAUGE_ID

        Display details of all sensors of the gauge.
        """
        gauge, pattern = self.parse_command_args(line, 2, 1)
        _id, backend_name = self.parse_id(gauge)

        self.start_format()
        for backend, sensor in self.do('iter_sensors', _id, pattern=pattern, backends=backend_name, caps=ICapGauge):
            self.format(sensor)

    def do_history(self, line):
        """
        history SENSOR_ID

        Get history of a specific sensor (use 'search' to find a gauge, and sensors GAUGE_ID to list sensors attached to the gauge).
        """
        gauge, = self.parse_command_args(line, 1, 1)
        _id, backend_name = self.parse_id(gauge)

        self.start_format()
        for backend, measure in self.do('iter_gauge_history', _id, backends=backend_name, caps=ICapGauge):
            self.format(measure)

    def complete_last_sensor_measure(self, text, line, *ignored):
        args = line.split(' ')
        if len(args) == 2:
            return self._complete_object()

    def do_last_sensor_measure(self, line):
        """
        last_sensor_measure SENSOR_ID

        Get last measure of a sensor.
        """
        gauge, = self.parse_command_args(line, 1, 1)
        _id, backend_name = self.parse_id(gauge)

        self.start_format()
        for backend, measure in self.do('get_last_measure', _id, backends=backend_name, caps=ICapGauge):
            self.format(measure)
<|endoftext|>


<commit_before># This is a simple implementation of a credential server using
# the python 3 async framework. It is meant to be used as a
# backend to generate and clear credentials.

# The general imports

import sys
sys.path += ["../examples"]

import asyncio
from io import BytesIO
from msgpack import Unpacker

from petlib.pack import encode, decode, make_encoder, make_decoder

class SReader():
    """ Define an asyncio msgpack stream decoder. """

    def __init__(self, reader, writer):
        """ Pass ina  stream reader to unmarshall msgpack objects from. """
        self.reader = reader
        self.writer = writer
        self.decoder = make_decoder()
        self.unpacker = Unpacker(ext_hook=self.decoder, encoding="utf8")
        self.obj_buf = []

    @asyncio.coroutine
    def get(self):
        """ The co-routine providing objects. """

        while len(self.obj_buf) == 0:
            buf = yield from self.reader.read(1000)

            self.unpacker.feed(buf)
            for o in self.unpacker:
                self.obj_buf.append(o)

        return self.obj_buf.pop(0)

    def put(self, obj):
        """ Write an object to the channel. """
        self.writer.write(encode(obj))

## The crypto imports

from amacscreds import cred_setup, cred_CredKeyge, cred_UserKeyge, cred_secret_issue_user, cred_secret_issue, cred_secret_issue_user_decrypt, cred_show, cred_show_check, cred_secret_issue_user_check
from genzkp import *
from petlib.pack import encode, decode

class CredentialServer():
    def __init__(self, num_pub = 1, num_priv = 1):
        self.n = num_pub + num_priv
        self.params = cred_setup()
        self.ipub, self.isec = cred_CredKeyge(self.params, self.n)

    @asyncio.coroutine
    def handle_cmd(self, reader, writer):
        try:
            sr = SReader(reader, writer)

            CMD = yield from sr.get()

            print("Executing: %s" % CMD)
            if CMD == "INFO":
                yield from self.handle_info(sr, reader, writer)
            elif CMD == "ISSUE":
                yield from self.handle_issue(sr, reader, writer)
            elif CMD == "SHOW":
                yield from self.handle_show(sr, reader, writer)

        except Exception as e:
            print(e)
            sr.put("Error")

    @asyncio.coroutine
    def handle_info(self, sr, reader, writer):
        try:
            # Part 1. First we write the params and the ipub values
            sr.put( (self.params, self.ipub) )

        except Exception as e:
            print(e)
            sr.put("Error")

    @asyncio.coroutine
    def handle_issue(self, sr, reader, writer):

        try:

            # Part 2. Get the public key an Encrypted cred from user
            (pub, EGenc, sig_u), public_attr  = yield from sr.get()

            # Part 3. Check and generate the credential
            if not cred_secret_issue_user_check(self.params, pub, EGenc, sig_u):
                raise Exception("Error: Issuing checks failed")

            cred_issued = cred_secret_issue(self.params, pub, EGenc, self.ipub, self.isec, public_attr)
            sr.put(cred_issued)

        except Exception as e:
            print(e)
            sr.put("Error")

    @asyncio.coroutine
    def handle_show(self, sr, reader, writer):

        try:
            (G, g, h, o) = self.params

            # Part 4. Get a blinded credential & check it
            creds, sig_o, sig_openID, Service_name, Uid, public_attr = yield from sr.get()
            (u, Cmis, Cup) = creds

            [ timeout ] = public_attr

            if not cred_show_check(self.params, self.ipub, self.isec, creds, sig_o):
                raise Exception("Error: aMAC failed")

            # Execute the verification on the proof 'sig'
            Gid = G.hash_to_point(Service_name)

            zk = define_proof(G)
            env2 = ZKEnv(zk)
            env2.u, env2.h = u, h
            env2.Cm0p, env2.Cm1 = Cmis[0] - (timeout * u), Cmis[1]
            env2.Uid, env2.Gid = Uid, Gid

            if not  zk.verify_proof(env2.get(), sig_openID):
                raise Exception("Error: ZKP failed")

            sr.put("SUCCESS")

            yield from writer.drain()
            writer.close()

        except Exception as e:
            print(e)
            sr.put("Error")

def define_proof(G):
    zk = ZKProof(G)
    u, h = zk.get(ConstGen, ["u", "h"])
    LT_ID, z0, z1 = zk.get(Sec, ["LT_ID", "z0", "z1"])
    Cm0p = zk.get(ConstGen, "Cm0p")
    Cm1 = zk.get(ConstGen, "Cm1")
    Uid = zk.get(ConstGen, "Uid")
    Gid = zk.get(ConstGen, "Gid")

    zk.add_proof(Cm0p, z0 * h)
    zk.add_proof(Cm1, LT_ID*u + z1 * h)
    zk.add_proof(Uid, LT_ID * Gid)

    return zk

import pytest # requires pytest-asyncio!

@asyncio.coroutine
def info_client(ip, port, loop):
    ## Setup the channel
    reader, writer = yield from asyncio.open_connection(
                ip, port, loop=loop)
    sr = SReader(reader, writer)

    # Send the FULL command
    sr.put("INFO")

    # Part 1. Get the params and the ipub
    (params, ipub) = yield from sr.get()
    (G, g, h, o) = params
    return params, ipub

@asyncio.coroutine
def issue_client(ip, port, params, ipub, keypair, public_attr, private_attr, loop):
    ## Setup the channel
    reader, writer = yield from asyncio.open_connection(
                ip, port, loop=loop)
    sr = SReader(reader, writer)

    # Send the FULL command
    sr.put("ISSUE")

    # Part 2. Send the encrypted attributes to server
    user_token = cred_secret_issue_user(params, keypair, private_attr)
    (pub, EGenc, sig_u) = user_token

    sr.put( (user_token, public_attr) )

    # Part 3. Get the credential back
    cred = yield from sr.get()
    (u, EncE, sig_s) = cred
    mac = cred_secret_issue_user_decrypt(params, keypair, u, EncE, ipub, public_attr, EGenc, sig_s)

    return mac, user_token, cred

@asyncio.coroutine
def show_client(ip, port, params, ipub, mac, sig_s, public_attr, private_attr, Service_name, loop):

    reader, writer = yield from asyncio.open_connection(
                ip, port, loop=loop)
    sr = SReader(reader, writer)

    # Send the FULL command
    sr.put("SHOW")

    # Part 1. Get the params and the ipub
    (G, g, h, o) = params

    ## User Shows back full credential to issuer
    (creds, sig_o, zis) = cred_show(params, ipub, mac, sig_s, public_attr + private_attr, export_zi=True)

    [ LT_user_ID ] = private_attr
    [ timeout ] = public_attr

    ## The credential contains a number of commitments to the attributes
    (u, Cmis, Cup) = creds

    assert len(Cmis) == 2
    assert Cmis[0] == timeout * u + zis[0] * h
    assert Cmis[1] == LT_user_ID * u + zis[1] * h

    # Derive a service specific User ID
    #Service_name = b"ServiceNameRP"

    Gid = G.hash_to_point(Service_name)
    Uid = LT_user_ID * Gid

    # Define the statements to be proved
    zk = define_proof(G)

    # Define the proof environemnt
    env = ZKEnv(zk)
    env.u, env.h = u, h
    env.Cm0p, env.Cm1 = Cmis[0] - (timeout * u), Cmis[1]
    env.Uid, env.Gid = Uid, Gid
    env.LT_ID = LT_user_ID
    env.z0, env.z1 = zis[0], zis[1]

    sig_openID = zk.build_proof(env.get())

    sr.put( (creds, sig_o, sig_openID, Service_name, Uid , public_attr) )

    # Check status
    resp = yield from sr.get()
    writer.close()

    return resp

def test_info_server(event_loop, unused_tcp_port):
    cs = CredentialServer()
    coro = asyncio.start_server(cs.handle_cmd,
                '127.0.0.1', unused_tcp_port, loop=event_loop)

    event_loop.create_task(coro)
    resp = event_loop.run_until_complete(info_client('127.0.0.1', unused_tcp_port, event_loop))

    assert tuple(resp[0]) == tuple(cs.params)

def test_issue_server(event_loop, unused_tcp_port):
    cs = CredentialServer()
    coro = asyncio.start_server(cs.handle_cmd,
                '127.0.0.1', unused_tcp_port, loop=event_loop)

    event_loop.create_task(coro)

    (G, g, h, o) = cs.params

    # User creates a public / private key pair
    keypair = cred_UserKeyge(cs.params)

    # User packages credentials
    LT_user_ID = o.random()
    timeout = 100
    public_attr = [ timeout ]
    private_attr = [ LT_user_ID ]

    resp = event_loop.run_until_complete(issue_client('127.0.0.1', unused_tcp_port,
        cs.params, cs.ipub, keypair, public_attr, private_attr, event_loop))

def test_show_server(event_loop, unused_tcp_port):
    cs = CredentialServer()
    coro = asyncio.start_server(cs.handle_cmd,
                '127.0.0.1', unused_tcp_port, loop=event_loop)

    event_loop.create_task(coro)

    (G, g, h, o) = cs.params

    # User creates a public / private key pair
    keypair = cred_UserKeyge(cs.params)

    # User packages credentials
    LT_user_ID = o.random()
    timeout = 100
    public_attr = [ timeout ]
    private_attr = [ LT_user_ID ]

    resp = event_loop.run_until_complete(issue_client('127.0.0.1', unused_tcp_port,
        cs.params, cs.ipub, keypair, public_attr, private_attr, event_loop))
    mac, user_token, cred = resp

    pub, EGenc, sig_u = user_token
    u, EncE, sig_s = cred

    Service_name = b"TestService"
    resp = event_loop.run_until_complete(show_client('127.0.0.1', unused_tcp_port,
        cs.params, cs.ipub, mac, sig_s, public_attr, private_attr, Service_name,
        event_loop))

    assert resp == "SUCCESS"

if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    coro = asyncio.start_server(handle_cmd, '127.0.0.1', 8888, loop=loop)
    server = loop.run_until_complete(coro)

    # Serve requests until Ctrl+C is pressed
    print('Serving on {}'.format(server.sockets[0].getsockname()))
    try:
        loop.run_forever()
    except KeyboardInterrupt:
        pass

    # Close the server
    server.close()
    loop.run_until_complete(server.wait_closed())
    loop.close()
<commit_msg>Added a key/valueset of attributes<commit_after># This is a simple implementation of a credential server using
# the python 3 async framework. It is meant to be used as a
# backend to generate and clear credentials.

# The general imports

import sys
sys.path += ["../examples"]

import asyncio
from io import BytesIO
from msgpack import Unpacker

from petlib.pack import encode, decode, make_encoder, make_decoder

class SReader():
    """ Define an asyncio msgpack stream decoder. """

    def __init__(self, reader, writer):
        """ Pass ina  stream reader to unmarshall msgpack objects from. """
        self.reader = reader
        self.writer = writer
        self.decoder = make_decoder()
        self.unpacker = Unpacker(ext_hook=self.decoder, encoding="utf8")
        self.obj_buf = []

    @asyncio.coroutine
    def get(self):
        """ The co-routine providing objects. """

        while len(self.obj_buf) == 0:
            buf = yield from self.reader.read(1000)

            self.unpacker.feed(buf)
            for o in self.unpacker:
                self.obj_buf.append(o)

        return self.obj_buf.pop(0)

    def put(self, obj):
        """ Write an object to the channel. """
        self.writer.write(encode(obj))

## The crypto imports

from amacscreds import cred_setup, cred_CredKeyge, cred_UserKeyge, cred_secret_issue_user, cred_secret_issue, cred_secret_issue_user_decrypt, cred_show, cred_show_check, cred_secret_issue_user_check
from genzkp import *
from petlib.pack import encode, decode

class CredentialServer():
    def __init__(self, num_pub = 3, num_priv = 1):
        self.n = num_pub + num_priv
        self.params = cred_setup()
        self.ipub, self.isec = cred_CredKeyge(self.params, self.n)

    @asyncio.coroutine
    def handle_cmd(self, reader, writer):
        try:
            sr = SReader(reader, writer)

            CMD = yield from sr.get()

            print("Executing: %s" % CMD)
            if CMD == "INFO":
                yield from self.handle_info(sr)
            elif CMD == "ISSUE":
                yield from self.handle_issue(sr)
            elif CMD == "SHOW":
                yield from self.handle_show(sr)

        except Exception as e:
            print(e)
            sr.put("Error")

    @asyncio.coroutine
    def handle_info(self, sr):
        try:
            # Part 1. First we write the params and the ipub values
            sr.put( (self.params, self.ipub) )

        except Exception as e:
            print(e)
            sr.put("Error")

        finally:
            sr.writer.close()

    @asyncio.coroutine
    def handle_issue(self, sr):

        try:

            # Part 2. Get the public key an Encrypted cred from user
            (pub, EGenc, sig_u), public_attr  = yield from sr.get()
            k, v, timeout = public_attr

            # Part 3. Check and generate the credential
            if not cred_secret_issue_user_check(self.params, pub, EGenc, sig_u):
                raise Exception("Error: Issuing checks failed")

            cred_issued = cred_secret_issue(self.params, pub, EGenc, self.ipub, self.isec, public_attr)
            sr.put(cred_issued)

        except Exception as e:
            print(e)
            sr.put("Error")

    @asyncio.coroutine
    def handle_show(self, sr):

        try:
            (G, g, h, o) = self.params

            # Part 4. Get a blinded credential & check it
            creds, sig_o, sig_openID, Service_name, Uid, public_attr = yield from sr.get()
            (u, Cmis, Cup) = creds

            [ key, value, timeout ] = public_attr

            if not cred_show_check(self.params, self.ipub, self.isec, creds, sig_o):
                raise Exception("Error: aMAC failed")

            # Execute the verification on the proof 'sig'
            Gid = G.hash_to_point(Service_name)

            zk = define_proof(G)
            env2 = ZKEnv(zk)
            env2.u, env2.h = u, h
            env2.Cm0p = Cmis[0] - (key * u)
            env2.Cm1p = Cmis[1] - (value * u)
            env2.Cm2p = Cmis[2] - (timeout * u)

            env2.Cm3 = Cmis[3]

            assert len(Cmis) == 4
            env2.Uid, env2.Gid = Uid, Gid

            if not  zk.verify_proof(env2.get(), sig_openID):
                raise Exception("Error: ZKP failed")

            sr.put("SUCCESS")

            yield from writer.drain()
            writer.close()

        except Exception as e:
            print(e)
            sr.put("Error")

def define_proof(G):
    zk = ZKProof(G)
    u, h = zk.get(ConstGen, ["u", "h"])
    LT_ID, z0, z1, z2, z3 = zk.get(Sec, ["LT_ID", "z0", "z1", "z2", "z3"])
    Cm0p = zk.get(ConstGen, "Cm0p")
    Cm1p = zk.get(ConstGen, "Cm1p")
    Cm2p = zk.get(ConstGen, "Cm2p")

    Cm3 = zk.get(ConstGen, "Cm3")
    Uid = zk.get(ConstGen, "Uid")
    Gid = zk.get(ConstGen, "Gid")

    zk.add_proof(Cm0p, z0 * h)
    zk.add_proof(Cm1p, z1 * h)
    zk.add_proof(Cm2p, z2 * h)

    zk.add_proof(Cm3, LT_ID*u + z3 * h)
    zk.add_proof(Uid, LT_ID * Gid)

    return zk

import pytest # requires pytest-asyncio!

@asyncio.coroutine
def info_client(ip, port, loop):
    """ Implement a client for the INFO command. """

    ## Setup the channel
    reader, writer = yield from asyncio.open_connection(
                ip, port, loop=loop)
    sr = SReader(reader, writer)

    # Send the FULL command
    sr.put("INFO")

    # Part 1. Get the params and the ipub
    (params, ipub) = yield from sr.get()
    (G, g, h, o) = params

    return params, ipub

@asyncio.coroutine
def issue_client(ip, port, params, ipub, keypair, public_attr, private_attr, loop):
    """ Implements a client for the ISSUE protocol. """

    ## Setup the channel
    reader, writer = yield from asyncio.open_connection(
                ip, port, loop=loop)
    sr = SReader(reader, writer)

    # Send the FULL command
    sr.put("ISSUE")

    # Part 2. Send the encrypted attributes to server
    user_token = cred_secret_issue_user(params, keypair, private_attr)
    (pub, EGenc, sig_u) = user_token

    sr.put( (user_token, public_attr) )

    # Part 3. Get the credential back
    cred = yield from sr.get()
    (u, EncE, sig_s) = cred
    mac = cred_secret_issue_user_decrypt(params, keypair, u, EncE, ipub, public_attr, EGenc, sig_s)

    return mac, user_token, cred

@asyncio.coroutine
def show_client(ip, port, params, ipub, mac, sig_s, public_attr, private_attr, Service_name, loop):
    """ Implements a client for the SHOW command. """

    reader, writer = yield from asyncio.open_connection(
                ip, port, loop=loop)
    sr = SReader(reader, writer)

    # Send the FULL command
    sr.put("SHOW")

    # Part 1. Get the params and the ipub
    (G, g, h, o) = params

    ## User Shows back full credential to issuer
    (creds, sig_o, zis) = cred_show(params, ipub, mac, sig_s, public_attr + private_attr, export_zi=True)

    [ LT_user_ID ] = private_attr
    [ key, value, timeout ] = public_attr

    ## The credential contains a number of commitments to the attributes
    (u, Cmis, Cup) = creds

    assert len(Cmis) == 4
    assert Cmis[0] == key * u + zis[0] * h
    assert Cmis[1] == value * u + zis[1] * h
    assert Cmis[2] == timeout * u + zis[2] * h

    assert Cmis[3] == LT_user_ID * u + zis[3] * h

    # Derive a service specific User ID
    Gid = G.hash_to_point(Service_name)
    Uid = LT_user_ID * Gid

    # Define the statements to be proved
    zk = define_proof(G)

    # Define the proof environemnt
    env = ZKEnv(zk)
    env.u, env.h = u, h

    env.Cm0p = Cmis[0] - (key * u)
    env.Cm1p = Cmis[1] - (value * u)
    env.Cm2p = Cmis[2] - (timeout * u)

    env.Cm3 = Cmis[3]

    env.Uid, env.Gid = Uid, Gid
    env.LT_ID = LT_user_ID
    env.z0, env.z1, env.z2, env.z3  = zis[0], zis[1], zis[2], zis[3]

    sig_openID = zk.build_proof(env.get())

    sr.put( (creds, sig_o, sig_openID, Service_name, Uid , public_attr) )

    # Check status
    resp = yield from sr.get()
    writer.close()

    return resp

def test_info_server(event_loop, unused_tcp_port):
    cs = CredentialServer()
    coro = asyncio.start_server(cs.handle_cmd,
                '127.0.0.1', unused_tcp_port, loop=event_loop)

    event_loop.create_task(coro)
    resp = event_loop.run_until_complete(info_client('127.0.0.1', unused_tcp_port, event_loop))

    assert tuple(resp[0]) == tuple(cs.params)

def test_issue_server(event_loop, unused_tcp_port):
    cs = CredentialServer()
    coro = asyncio.start_server(cs.handle_cmd,
                '127.0.0.1', unused_tcp_port, loop=event_loop)

    event_loop.create_task(coro)
    (G, g, h, o) = cs.params

    # User creates a public / private key pair
    keypair = cred_UserKeyge(cs.params)

    # User packages credentials
    LT_user_ID = o.random()
    timeout = 100
    key = 200
    value = 300
    public_attr = [ key, value, timeout ]
    private_attr = [ LT_user_ID ]

    resp = event_loop.run_until_complete(issue_client('127.0.0.1', unused_tcp_port,
        cs.params, cs.ipub, keypair, public_attr, private_attr, event_loop))

def test_show_server(event_loop, unused_tcp_port):
    cs = CredentialServer()
    coro = asyncio.start_server(cs.handle_cmd,
                '127.0.0.1', unused_tcp_port, loop=event_loop)

    event_loop.create_task(coro)

    (G, g, h, o) = cs.params

    # User creates a public / private key pair
    keypair = cred_UserKeyge(cs.params)

    # User packages credentials
    LT_user_ID = o.random()
    timeout = 100
    key = 200
    value = 300

    public_attr = [ key, value, timeout ]
    private_attr = [ LT_user_ID ]

    resp = event_loop.run_until_complete(issue_client('127.0.0.1', unused_tcp_port,
        cs.params, cs.ipub, keypair, public_attr, private_attr, event_loop))
    mac, user_token, cred = resp

    pub, EGenc, sig_u = user_token
    u, EncE, sig_s = cred

    Service_name = b"TestService"
    resp = event_loop.run_until_complete(show_client('127.0.0.1', unused_tcp_port,
        cs.params, cs.ipub, mac, sig_s, public_attr, private_attr, Service_name,
        event_loop))

    assert resp == "SUCCESS"

if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    coro = asyncio.start_server(handle_cmd, '127.0.0.1', 8888, loop=loop)
    server = loop.run_until_complete(coro)

    # Serve requests until Ctrl+C is pressed
    print('Serving on {}'.format(server.sockets[0].getsockname()))
    try:
        loop.run_forever()
    except KeyboardInterrupt:
        pass

    # Close the server
    server.close()
    loop.run_until_complete(server.wait_closed())
    loop.close()
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

# Copyright(C) 2013  Florent Fourcot
#
# This file is part of weboob.
#
# weboob is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# weboob is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with weboob. If not, see <http://www.gnu.org/licenses/>.

from weboob.capabilities.base import empty
from weboob.capabilities.gauge import ICapGauge, SensorNotFound
from weboob.tools.application.repl import ReplApplication
from weboob.tools.application.formatters.iformatter import IFormatter

import sys

__all__ = ['Boobsize']

class GaugeFormatter(IFormatter):
    MANDATORY_FIELDS = ('name', 'object', 'sensors')

    def start_format(self, **kwargs):
        # Name = 27   Object = 10   City = 10  Sensors = 33
        self.output(' Name and ID                  Object     City       Sensors                         ')
        self.output('----------------------------+----------+----------+---------------------------------')

    def format_obj(self, obj, alias):
        name = obj.name
        city = u""
        if not empty(obj.city):
            city = obj.city

        # TODO: can happens ?
        if len(obj.sensors) == 0:
            return u' %s %s %s' %\
                   (self.colored('%-27s' % name[:27], 'red'),
                    self.colored('%-10s' % obj.object[:10], 'yellow'),
                    self.colored('%-10s' % city[:10], 'yellow')
                    )
        else:
            first = True
            firstaddress = obj.sensors[0].address
            for sensor in obj.sensors:
                sensorname = sensor.name
                # This is a int value, do not display it as a float
                if int(sensor.lastvalue.level) == sensor.lastvalue.level:
                    lastvalue = "%d " % sensor.lastvalue.level
                else:
                    lastvalue = "%r " % sensor.lastvalue.level
                if not empty(sensor.unit):
                    lastvalue += "%s" % sensor.unit
                if first:
                    result = u' %s %s %s ' %\
                             (self.colored('%-27s' % name[:27], 'red'),
                              self.colored('%-10s' % obj.object[:10], 'yellow'),
                              self.colored('%-10s' % city[:10], 'yellow'),
                              )
                    if not empty(firstaddress):
                        result += u'%s' % self.colored('%-33s' % sensor.address[:33], 'yellow')
                    result += u'\n'
                    result += u' %s' % self.colored('%-47s' % obj.fullid[:47], 'blue')
                    result += u'   %s %s\n' %\
                              (self.colored('%-20s' % sensorname[:20], 'magenta'),
                               self.colored('%-13s' % lastvalue[:13], 'red')
                               )
                    first = False
                else:
                    result += u'                                                   %s %s\n' %\
                              (self.colored('%-20s' % sensorname[:20], 'magenta'),
                               self.colored('%-13s' % lastvalue[:13], 'red')
                               )
                    if not empty(sensor.address) and sensor.address != firstaddress:
                        result += u'                                                   %s \n' %\
                                  self.colored('%-33s' % sensor.address[:33], 'yellow')

            return result

class Boobsize(ReplApplication):
    APPNAME = 'Boobsize'
    VERSION = '0.h'
    COPYRIGHT = 'Copyright(C) 2013 Florent Fourcot'
    DESCRIPTION = "Console application allowing to display various sensors and gauges values."
    SHORT_DESCRIPTION = "display sensors and gauges values"
    CAPS = (ICapGauge)
    DEFAULT_FORMATTER = 'table'
    EXTRA_FORMATTERS = {'gauge_list':   GaugeFormatter, }
    COMMANDS_FORMATTERS = {'search':    'gauge_list',
                           }

    def main(self, argv):
        self.load_config()
        return ReplApplication.main(self, argv)

    def bcall_error_handler(self, backend, error, backtrace):
        if isinstance(error, SensorNotFound):
            msg = unicode(error) or 'Sensor not found (hint: try sensors command)'
            print >>sys.stderr, 'Error(%s): %s' % (backend.name, msg)
        else:
            return ReplApplication.bcall_error_handler(self, backend, error, backtrace)

    def do_search(self, pattern):
        """
        search [PATTERN]

        Display all gauges. If PATTERN is specified, search on a pattern.
        """
        self.change_path([u'gauges'])
        self.start_format()
        for backend, gauge in self.do('iter_gauges', pattern or None, caps=ICapGauge):
            self.cached_format(gauge)

    def complete_search(self, text, line, *ignored):
        args = line.split(' ')
        if len(args) == 2:
            return self._complete_object()

    def do_details(self, line):
        """
        details GAUGE_ID

        Display details of all sensors of the gauge.
        """
        gauge, pattern = self.parse_command_args(line, 2, 1)
        _id, backend_name = self.parse_id(gauge)

        self.start_format()
        for backend, sensor in self.do('iter_sensors', _id, pattern=pattern, backends=backend_name, caps=ICapGauge):
            self.format(sensor)

    def do_history(self, line):
        """
        history SENSOR_ID

        Get history of a specific sensor (use 'search' to find a gauge, and sensors GAUGE_ID to list sensors attached to the gauge).
        """
        gauge, = self.parse_command_args(line, 1, 1)
        _id, backend_name = self.parse_id(gauge)

        self.start_format()
        for backend, measure in self.do('iter_gauge_history', _id, backends=backend_name, caps=ICapGauge):
            self.format(measure)

    def complete_last_sensor_measure(self, text, line, *ignored):
        args = line.split(' ')
        if len(args) == 2:
            return self._complete_object()

    def do_last_sensor_measure(self, line):
        """
        last_sensor_measure SENSOR_ID

        Get last measure of a sensor.
        """
        gauge, = self.parse_command_args(line, 1, 1)
        _id, backend_name = self.parse_id(gauge)

        self.start_format()
        for backend, measure in self.do('get_last_measure', _id, backends=backend_name, caps=ICapGauge):
            self.format(measure)
<commit_msg>Test if lastvalue is available<commit_after># -*- coding: utf-8 -*-

# Copyright(C) 2013  Florent Fourcot
#
# This file is part of weboob.
#
# weboob is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# weboob is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with weboob. If not, see <http://www.gnu.org/licenses/>.

from weboob.capabilities.base import empty
from weboob.capabilities.gauge import ICapGauge, SensorNotFound
from weboob.tools.application.repl import ReplApplication
from weboob.tools.application.formatters.iformatter import IFormatter

import sys

__all__ = ['Boobsize']

class GaugeFormatter(IFormatter):
    MANDATORY_FIELDS = ('name', 'object', 'sensors')

    def start_format(self, **kwargs):
        # Name = 27   Object = 10   City = 10  Sensors = 33
        self.output(' Name and ID                  Object     City       Sensors                         ')
        self.output('----------------------------+----------+----------+---------------------------------')

    def format_obj(self, obj, alias):
        name = obj.name
        city = u""
        if not empty(obj.city):
            city = obj.city

        # TODO: can happens ?
        if len(obj.sensors) == 0:
            return u' %s %s %s' %\
                   (self.colored('%-27s' % name[:27], 'red'),
                    self.colored('%-10s' % obj.object[:10], 'yellow'),
                    self.colored('%-10s' % city[:10], 'yellow')
                    )
        else:
            first = True
            firstaddress = obj.sensors[0].address
            for sensor in obj.sensors:
                sensorname = sensor.name
                # This is a int value, do not display it as a float
                if sensor.lastvalue.level:
                    if int(sensor.lastvalue.level) == sensor.lastvalue.level:
                        lastvalue = "%d " % sensor.lastvalue.level
                    else:
                        lastvalue = "%r " % sensor.lastvalue.level
                else:
                    lastvalue = u"? "
                if not empty(sensor.unit):
                    lastvalue += "%s" % sensor.unit
                if first:
                    result = u' %s %s %s ' %\
                             (self.colored('%-27s' % name[:27], 'red'),
                              self.colored('%-10s' % obj.object[:10], 'yellow'),
                              self.colored('%-10s' % city[:10], 'yellow'),
                              )
                    if not empty(firstaddress):
                        result += u'%s' % self.colored('%-33s' % sensor.address[:33], 'yellow')
                    result += u'\n'
                    result += u' %s' % self.colored('%-47s' % obj.fullid[:47], 'blue')
                    result += u'   %s %s\n' %\
                              (self.colored('%-20s' % sensorname[:20], 'magenta'),
                               self.colored('%-13s' % lastvalue[:13], 'red')
                               )
                    first = False
                else:
                    result += u'                                                   %s %s\n' %\
                              (self.colored('%-20s' % sensorname[:20], 'magenta'),
                               self.colored('%-13s' % lastvalue[:13], 'red')
                               )
                    if not empty(sensor.address) and sensor.address != firstaddress:
                        result += u'                                                   %s \n' %\
                                  self.colored('%-33s' % sensor.address[:33], 'yellow')

            return result

class Boobsize(ReplApplication):
    APPNAME = 'Boobsize'
    VERSION = '0.h'
    COPYRIGHT = 'Copyright(C) 2013 Florent Fourcot'
    DESCRIPTION = "Console application allowing to display various sensors and gauges values."
    SHORT_DESCRIPTION = "display sensors and gauges values"
    CAPS = (ICapGauge)
    DEFAULT_FORMATTER = 'table'
    EXTRA_FORMATTERS = {'gauge_list':   GaugeFormatter, }
    COMMANDS_FORMATTERS = {'search':    'gauge_list',
                           }

    def main(self, argv):
        self.load_config()
        return ReplApplication.main(self, argv)

    def bcall_error_handler(self, backend, error, backtrace):
        if isinstance(error, SensorNotFound):
            msg = unicode(error) or 'Sensor not found (hint: try sensors command)'
            print >>sys.stderr, 'Error(%s): %s' % (backend.name, msg)
        else:
            return ReplApplication.bcall_error_handler(self, backend, error, backtrace)

    def do_search(self, pattern):
        """
        search [PATTERN]

        Display all gauges. If PATTERN is specified, search on a pattern.
        """
        self.change_path([u'gauges'])
        self.start_format()
        for backend, gauge in self.do('iter_gauges', pattern or None, caps=ICapGauge):
            self.cached_format(gauge)

    def complete_search(self, text, line, *ignored):
        args = line.split(' ')
        if len(args) == 2:
            return self._complete_object()

    def do_details(self, line):
        """
        details GAUGE_ID

        Display details of all sensors of the gauge.
        """
        gauge, pattern = self.parse_command_args(line, 2, 1)
        _id, backend_name = self.parse_id(gauge)

        self.start_format()
        for backend, sensor in self.do('iter_sensors', _id, pattern=pattern, backends=backend_name, caps=ICapGauge):
            self.format(sensor)

    def do_history(self, line):
        """
        history SENSOR_ID

        Get history of a specific sensor (use 'search' to find a gauge, and sensors GAUGE_ID to list sensors attached to the gauge).
        """
        gauge, = self.parse_command_args(line, 1, 1)
        _id, backend_name = self.parse_id(gauge)

        self.start_format()
        for backend, measure in self.do('iter_gauge_history', _id, backends=backend_name, caps=ICapGauge):
            self.format(measure)

    def complete_last_sensor_measure(self, text, line, *ignored):
        args = line.split(' ')
        if len(args) == 2:
            return self._complete_object()

    def do_last_sensor_measure(self, line):
        """
        last_sensor_measure SENSOR_ID

        Get last measure of a sensor.
        """
        gauge, = self.parse_command_args(line, 1, 1)
        _id, backend_name = self.parse_id(gauge)

        self.start_format()
        for backend, measure in self.do('get_last_measure', _id, backends=backend_name, caps=ICapGauge):
            self.format(measure)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

# Copyright(C) 2010-2011 Romain Bignon
#
# This file is part of weboob.
#
# weboob is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# weboob is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with weboob. If not, see <http://www.gnu.org/licenses/>.

import re
import datetime
import urllib

from weboob.capabilities import NotAvailable
from weboob.tools.capabilities.thumbnail import Thumbnail
from weboob.tools.json import json as simplejson
from weboob.tools.browser import BaseBrowser
from weboob.tools.browser.decorators import id2url

from .pages import ArteLivePage, ArteLiveCategorieVideoPage, ArteLiveVideoPage
from .video import ArteVideo, ArteLiveVideo

__all__ = ['ArteBrowser']

class ArteBrowser(BaseBrowser):
    DOMAIN = u'videos.arte.tv'
    ENCODING = None
    PAGES = {r'http://liveweb.arte.tv/\w+': ArteLivePage,
             r'http://liveweb.arte.tv/\w+/cat/.*': ArteLiveCategorieVideoPage,
             r'http://arte.vo.llnwd.net/o21/liveweb/events/event-(?P<id>.+).xml': ArteLiveVideoPage,
             }

    LIVE_LANG = {'F': 'fr',
                 'D': 'de'
                 }
    API_URL = 'http://arte.tv/papi/tvguide'

    def __init__(self, lang, quality, order, *args, **kwargs):
        self.lang = lang
        self.quality = quality
        self.order = order
        BaseBrowser.__init__(self, *args, **kwargs)

    @id2url(ArteVideo.id2url)
    def get_video(self, url, video=None):

        result = self.get_video_by_quality(url, self.quality)

        if video is None:
            video = self.create_video(result['video'])
        try:
            video.url = u'%s' % result['video']['VSR'][0]['VUR']
        except:
            video.url = self.get_default_url(url)

        return video

    def get_default_url(self, url):
        result = self.get_video_by_quality(url, 'ALL')
        try:
            return u'%s' % result['video']['VSR'][0]['VUR']
        except:
            return NotAvailable

    def get_video_by_quality(self, url, quality):
        _url = url \
            + '/' + quality \
            + '.json'

        response = self.openurl(_url)
        return simplejson.loads(response.read(), self.ENCODING)

    @id2url(ArteLiveVideo.id2url)
    def get_live_video(self, url, video=None):
        self.location(url)
        assert self.is_on_page(ArteLiveVideoPage)
        return self.page.get_video(video, self.lang, self.quality)

    def home(self):
        self.location('http://videos.arte.tv/%s/videos/toutesLesVideos' % self.lang)

    def get_video_from_program_id(self, _id):
        class_name = 'epg'
        method_name = 'program'
        level = 'L2'
        url = self.API_URL \
            + '/' + class_name \
            + '/' + method_name \
            + '/' + self.lang \
            + '/' + level \
            + '/' + _id \
            + '.json'

        response = self.openurl(url)
        result = simplejson.loads(response.read(), self.ENCODING)
        video = self.create_video(result['abstractProgram']['VDO'])
        return self.get_video(video.id, video)

    def search_videos(self, pattern):
        class_name = 'videos/plus7'
        method_name = 'search'
        level = 'L1'
        cluster = 'ALL'
        channel = 'ALL'
        limit = '10'
        offset = '0'

        url = self.create_url_plus7(class_name, method_name, level, cluster, channel, limit, offset, pattern)
        response = self.openurl(url)
        result = simplejson.loads(response.read(), self.ENCODING)
        return self.create_video_from_plus7(result['videoList'])

    def create_video_from_plus7(self, result):
        for item in result:
            yield self.create_video(item)

    def create_video(self, item):
        video = ArteVideo(item['VID'])
        if 'VSU' in item:
            video.title = u'%s : %s' % (item['VTI'], item['VSU'])
        else:
            video.title = u'%s' % (item['VTI'])
        video.rating = int(item['VRT'])
        video.thumbnail = Thumbnail(u'%s' % item['programImage'])
        video.duration = datetime.timedelta(seconds=int(item['videoDurationSeconds']))
        video.set_empty_fields(NotAvailable, ('url',))
        if 'VDE' in item:
            video.description = u'%s' % item['VDE']
        m = re.match('(\d{2})\s(\d{2})\s(\d{4})(.*?)', item['VDA'])
        if m:
            dd = int(m.group(1))
            mm = int(m.group(2))
            yyyy = int(m.group(3))
            video.date = datetime.date(yyyy, mm, dd)
        return video

    def create_url_plus7(self, class_name, method_name, level, cluster, channel, limit, offset, pattern=None):
        url = self.API_URL \
            + '/' + class_name \
            + '/' + method_name \
            + '/' + self.lang \
            + '/' + level

        if pattern:
            url += '/' + urllib.quote(pattern)

        url += '/' + channel \
            + '/' + cluster \
            + '/' + '-1' \
            + '/' + self.order \
            + '/' + limit \
            + '/' + offset \
            + '.json'

        return url

    def latest_videos(self):
        class_name = 'videos'
        method_name = 'plus7'
        level = 'L1'
        cluster = 'ALL'
        channel = 'ALL'
        limit = '10'
        offset = '0'

        url = self.create_url_plus7(class_name, method_name, level, cluster, channel, limit, offset)
        response = self.openurl(url)
        result = simplejson.loads(response.read(), self.ENCODING)
        return self.create_video_from_plus7(result['videoList'])

    def get_arte_live_categories(self):
        self.location('http://liveweb.arte.tv/%s' % self.LIVE_LANG[self.lang])
        assert self.is_on_page(ArteLivePage)
        return self.page.iter_resources()

    def live_videos(self, url):
        self.location(url)
        assert self.is_on_page(ArteLiveCategorieVideoPage)
        return self.page.iter_videos(self.LIVE_LANG[self.lang])
<commit_msg>modify arte module to use the new BaseVideo/ICapVideo classes<commit_after># -*- coding: utf-8 -*-

# Copyright(C) 2010-2011 Romain Bignon
#
# This file is part of weboob.
#
# weboob is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# weboob is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with weboob. If not, see <http://www.gnu.org/licenses/>.

import re
import datetime
import urllib

from weboob.capabilities import NotAvailable
from weboob.capabilities.image import BaseImage
from weboob.tools.json import json as simplejson
from weboob.tools.browser import BaseBrowser
from weboob.tools.browser.decorators import id2url

from .pages import ArteLivePage, ArteLiveCategorieVideoPage, ArteLiveVideoPage
from .video import ArteVideo, ArteLiveVideo

__all__ = ['ArteBrowser']

class ArteBrowser(BaseBrowser):
    DOMAIN = u'videos.arte.tv'
    ENCODING = None
    PAGES = {r'http://liveweb.arte.tv/\w+': ArteLivePage,
             r'http://liveweb.arte.tv/\w+/cat/.*': ArteLiveCategorieVideoPage,
             r'http://arte.vo.llnwd.net/o21/liveweb/events/event-(?P<id>.+).xml': ArteLiveVideoPage,
             }

    LIVE_LANG = {'F': 'fr',
                 'D': 'de'
                 }
    API_URL = 'http://arte.tv/papi/tvguide'

    def __init__(self, lang, quality, order, *args, **kwargs):
        self.lang = lang
        self.quality = quality
        self.order = order
        BaseBrowser.__init__(self, *args, **kwargs)

    @id2url(ArteVideo.id2url)
    def get_video(self, url, video=None):

        result = self.get_video_by_quality(url, self.quality)

        if video is None:
            video = self.create_video(result['video'])
        try:
            video.url = u'%s' % result['video']['VSR'][0]['VUR']
        except:
            video.url = self.get_default_url(url)

        return video

    def get_default_url(self, url):
        result = self.get_video_by_quality(url, 'ALL')
        try:
            return u'%s' % result['video']['VSR'][0]['VUR']
        except:
            return NotAvailable

    def get_video_by_quality(self, url, quality):
        _url = url \
            + '/' + quality \
            + '.json'

        response = self.openurl(_url)
        return simplejson.loads(response.read(), self.ENCODING)

    @id2url(ArteLiveVideo.id2url)
    def get_live_video(self, url, video=None):
        self.location(url)
        assert self.is_on_page(ArteLiveVideoPage)
        return self.page.get_video(video, self.lang, self.quality)

    def home(self):
        self.location('http://videos.arte.tv/%s/videos/toutesLesVideos' % self.lang)

    def get_video_from_program_id(self, _id):
        class_name = 'epg'
        method_name = 'program'
        level = 'L2'
        url = self.API_URL \
            + '/' + class_name \
            + '/' + method_name \
            + '/' + self.lang \
            + '/' + level \
            + '/' + _id \
            + '.json'

        response = self.openurl(url)
        result = simplejson.loads(response.read(), self.ENCODING)
        video = self.create_video(result['abstractProgram']['VDO'])
        return self.get_video(video.id, video)

    def search_videos(self, pattern):
        class_name = 'videos/plus7'
        method_name = 'search'
        level = 'L1'
        cluster = 'ALL'
        channel = 'ALL'
        limit = '10'
        offset = '0'

        url = self.create_url_plus7(class_name, method_name, level, cluster, channel, limit, offset, pattern)
        response = self.openurl(url)
        result = simplejson.loads(response.read(), self.ENCODING)
        return self.create_video_from_plus7(result['videoList'])

    def create_video_from_plus7(self, result):
        for item in result:
            yield self.create_video(item)

    def create_video(self, item):
        video = ArteVideo(item['VID'])
        if 'VSU' in item:
            video.title = u'%s : %s' % (item['VTI'], item['VSU'])
        else:
            video.title = u'%s' % (item['VTI'])
        video.rating = int(item['VRT'])
        url = u'%s' % item['programImage']
        video.thumbnail = BaseImage(url)
        video.thumbnail.url=video.thumbnail.id
        video.duration = datetime.timedelta(seconds=int(item['videoDurationSeconds']))
        video.set_empty_fields(NotAvailable, ('url',))
        if 'VDE' in item:
            video.description = u'%s' % item['VDE']
        m = re.match('(\d{2})\s(\d{2})\s(\d{4})(.*?)', item['VDA'])
        if m:
            dd = int(m.group(1))
            mm = int(m.group(2))
            yyyy = int(m.group(3))
            video.date = datetime.date(yyyy, mm, dd)
        return video

    def create_url_plus7(self, class_name, method_name, level, cluster, channel, limit, offset, pattern=None):
        url = self.API_URL \
            + '/' + class_name \
            + '/' + method_name \
            + '/' + self.lang \
            + '/' + level

        if pattern:
            url += '/' + urllib.quote(pattern)

        url += '/' + channel \
            + '/' + cluster \
            + '/' + '-1' \
            + '/' + self.order \
            + '/' + limit \
            + '/' + offset \
            + '.json'

        return url

    def latest_videos(self):
        class_name = 'videos'
        method_name = 'plus7'
        level = 'L1'
        cluster = 'ALL'
        channel = 'ALL'
        limit = '10'
        offset = '0'

        url = self.create_url_plus7(class_name, method_name, level, cluster, channel, limit, offset)
        response = self.openurl(url)
        result = simplejson.loads(response.read(), self.ENCODING)
        return self.create_video_from_plus7(result['videoList'])

    def get_arte_live_categories(self):
        self.location('http://liveweb.arte.tv/%s' % self.LIVE_LANG[self.lang])
        assert self.is_on_page(ArteLivePage)
        return self.page.iter_resources()

    def live_videos(self, url):
        self.location(url)
        assert self.is_on_page(ArteLiveCategorieVideoPage)
        return self.page.iter_videos(self.LIVE_LANG[self.lang])
<|endoftext|>