Пример #1
0
    def finalize_message(self, message):
        if "correlation_id" in message["body"]["headers"]:
            message["properties"]["correlation_id"] = message["body"][
                "headers"]["correlation_id"]
        if "reply_to" in message["body"]["headers"]:
            message["properties"]["reply_to"] = message["body"]["headers"][
                "reply_to"]
        # print("finalize message: %s" % message)
        message["body"] = msgpack.dumps(message["body"])

        # Lets test if we can compress. Set headers as needed.
        if len(message["body"]) > 800:
            beforeZlib = len(message["body"])
            message["body"] = zlib.compress(
                message["body"], 5
            )  # 5 appears to be the best speed/compression ratio - MSchwenk
            afterZlib = len(message["body"])
            message["meta"]["compression_percent"] = percentage(
                afterZlib, beforeZlib)

            message["properties"]["content_encoding"] = "zlib"
        else:
            message["properties"]["content_encoding"] = "text"
        message["meta"]["finalized_for_sending"] = True
        return message
Пример #2
0
    def finalize_message(self, message):
        if 'correlation_id' in message['body']['headers']:
            message['properties']['correlation_id'] = message['body'][
                'headers']['correlation_id']
        if 'reply_to' in message['body']['headers']:
            message['properties']['reply_to'] = message['body']['headers'][
                'reply_to']
        # print("finalize message: %s" % message)
        message['body'] = msgpack.dumps(message['body'])

        # Lets test if we can compress. Set headers as needed.
        if len(message['body']) > 800:
            beforeZlib = len(message['body'])
            message['body'] = zlib.compress(
                message['body'], 5
            )  # 5 appears to be the best speed/compression ratio - MSchwenk
            afterZlib = len(message['body'])
            message['meta']['compression_percent'] = percentage(
                afterZlib, beforeZlib)

            message['properties']['content_encoding'] = "zlib"
        else:
            message['properties']['content_encoding'] = 'text'
        # request_msg['meta']['content_encoding'] = request_msg['properties']['content_encoding']
        # request_msg['meta']['payload_size'] = len(request_msg['body'])
        message['meta']['finalized_for_sending'] = True
        return message
Пример #3
0
    def finalize_message(self, message: dict):
        if "correlation_id" in message["body"]["headers"]:
            message["properties"]["correlation_id"] = message["body"]["headers"]["correlation_id"]
        if "reply_correlation_id" in message["body"]["headers"]:
            message["properties"]["headers"]["reply_correlation_id"] = message["body"]["headers"]["reply_correlation_id"]
        message["body"] = msgpack.packb(message["body"])

        # Lets test if we can compress. Set headers as needed.

        beforeZlib = len(message["body"])
        if beforeZlib > 900:
            message["properties"]["content_type"] = "msgpack_zip"
            message["body"] = self._Tools.data_pickle(message["body"], "zip")
        message["meta"]["compression_percent"] = round(percentage(len(message["body"]), beforeZlib), 2)
        message["meta"]["finalized_for_sending"] = True
        return message
Пример #4
0
    def generate_message(self,
                         exchange_name,
                         source,
                         destination,
                         header_type,
                         headers,
                         body,
                         callback=None,
                         correlation_id=None,
                         message_id=None):
        """
        When interacting with Yombo AMQP servers, we use a standard messaging layout. The below helps other functions
        and libraries conform to this standard.

        This only creates the message, it doesn't send it. Use the publish() function to complete that.

        **Usage**:

        .. code-block:: python

           requestData = {
               "exchange_name"  : "gw_config",
               "source"        : "yombo.gateway.lib.configurationupdate",
               "destination"   : "yombo.server.configs",
               "callback" : self.amqp_direct_incoming,
               "body"          : {
                 "DataType"        : "Object",
                 "Request"         : requestContent,
               },
           }
           request = self.AMQPYombo.generateRequest(**requestData)

        :param exchange_name: The exchange the request should go to.
        :type exchange_name: str
        :param source: Value for the 'source' field.
        :type source: str
        :param destination: Value of the 'destination' field.
        :type destination: str
        :param header_type: Type of header. Usually one of: request, response
        :type header_type: str
        :param headers: Extra headers
        :type headers: dict
        :param body: The part that will become the body, or payload, of the message.
        :type body: str, dict, list
        :param callback: A pointer to the function to return results to. This function will receive 4 arguments:
          sendInfo (Dict) - Various details of the sent packet. deliver (Dict) - Deliver fields as returned by Pika.
          props (Pika Object) - Message properties, includes headers. msg (dict) - The actual content of the message.
        :type callback: function
        :param body: The body contents for the mesage.
        :type body: dict

        :return: A dictionary that can be directly returned to Yombo Gateways via AMQP
        :rtype: dict
        """
        # print("body: %s" % body)
        request_msg = {
            "exchange_name": exchange_name,
            "routing_key": '*',
            "body": msgpack.dumps(body),
            "properties": {
                # "correlation_id" : correlation_id,
                "user_id": self.
                gateway_id,  # system id is required to be able to send it.
                "content_type": 'application/msgpack',
                "headers": {
                    # "requesting_user_id"        : user
                    "source": source + ":" + self.gateway_id,
                    "destination": destination,
                    "type": header_type,
                    "protocol_verion": PROTOCOL_VERSION,
                    "message_id": random_string(length=20),
                    "msg_created_at": str(time()),
                },
            },
            "meta": {
                "content_type": 'application/msgpack',
            },
            "created_at": time(),
        }

        if "callback" is not None:
            request_msg['callback'] = callback
            if correlation_id is None:
                request_msg['properties']['correlation_id'] = random_string(
                    length=24)
            else:
                request_msg['properties']['correlation_id'] = correlation_id

        if message_id is None:
            request_msg['properties']['message_id'] = random_string(length=26)
        else:
            request_msg['properties']['message_id'] = message_id

        # Lets test if we can compress. Set headers as needed.
        if len(request_msg['body']) > 800:
            beforeZlib = len(request_msg['body'])
            request_msg['body'] = zlib.compress(
                request_msg['body'], 5
            )  # 5 appears to be the best speed/compression ratio - MSchwenk
            afterZlib = len(request_msg['body'])
            request_msg['meta']['compression_percent'] = percentage(
                afterZlib, beforeZlib)

            request_msg['properties']['content_encoding'] = "zlib"
        else:
            request_msg['properties']['content_encoding'] = 'text'
        request_msg['properties']['headers'].update(headers)
        request_msg['meta']['content_encoding'] = request_msg['properties'][
            'content_encoding']
        request_msg['meta']['payload_size'] = len(request_msg['body'])
        return request_msg
Пример #5
0
    def amqp_incoming(self, deliver, properties, msg, queue):
        """
        All incoming messages come here. It will be parsed and sorted as needed.  Routing:

        1) Device updates, changes, deletes -> Devices library
        1) Command updates, changes, deletes -> Command library
        1) Module updates, changes, deletes -> Module library
        1) Device updates, changes, deletes -> Devices library
        1) Device updates, changes, deletes -> Devices library

        Summary of tasks:

        1) Validate incoming headers.
        2) Setup ACK/Nack responses.
        3) Route the message to the proper library for final handling.
        """
        # self._local_log("info", "AMQPLibrary::amqp_incoming")
        # print " !!!!!!!!!!!!!!!!!!!!!!!!! "
        # print "properties: %s" % properties
#        log.msg('%s (%s): %s' % (deliver.exchange, deliver.routing_key, repr(msg)), system='Pika:<=')

        if properties.user_id is None:
            self._Statistics.increment("lib.amqpyombo.received.discarded.nouserid", bucket_time=15, anon=True)
            raise YomboWarning("user_id missing.")
        if properties.content_type is None:
            self._Statistics.increment("lib.amqpyombo.received.discarded.content_type_missing", bucket_time=15, anon=True)
            raise YomboWarning("content_type missing.")
        if properties.content_encoding is None:
            self._Statistics.increment("lib.amqpyombo.received.discarded.content_encoding_missing", bucket_time=15, anon=True)
            raise YomboWarning("content_encoding missing.")
        if properties.content_encoding != 'text' and properties.content_encoding != 'zlib':
            self._Statistics.increment("lib.amqpyombo.received.discarded.content_encoding_invalid", bucket_time=15, anon=True)
            raise YomboWarning("Content Encoding must be either  'text' or 'zlib'. Got: " + properties.content_encoding)
        if properties.content_type != 'text/plain' and properties.content_type != 'application/msgpack' and  properties.content_type != 'application/json':
            self._Statistics.increment("lib.amqpyombo.received.discarded.content_type_invalid", bucket_time=15, anon=True)
            logger.warn('Error with contentType!')
            raise YomboWarning("Content type must be 'application/msgpack', 'application/json' or 'text/plain'. Got: " + properties.content_type)

        if properties.content_encoding == 'zlib':
            beforeZlib = len(msg)
            msg = zlib.decompress(msg)
            afterZlib = len(msg)
            logger.debug("Message sizes: msg_size_compressed = {compressed}, non-compressed = {uncompressed}, percent: {percent}",
                         compressed=beforeZlib, uncompressed=afterZlib, percent=percentage(beforeZlib, afterZlib))
            self._Statistics.increment("lib.amqpyombo.received.compressed", bucket_time=15, anon=True)
            self._Statistics.averages("lib.amqpyombo.received.compressed.percentage", percentage(beforeZlib, afterZlib), bucket_time=15, anon=True)
        else:
            self._Statistics.increment("lib.amqpyombo.received.uncompressed", bucket_time=15, anon=True)
        self._Statistics.averages("lib.amqpyombo.received.payload.size", len(msg), bucket_time=15, anon=True)

        if properties.content_type == 'application/json':
            if self.is_json(msg):
                msg = json.loads(msg)
            else:
                raise YomboWarning("Receive msg reported json, but isn't.")
        elif properties.content_type == 'application/msgpack':
            if self.is_msgpack(msg):
                msg = msgpack.loads(msg)
            else:
                raise YomboWarning("Received msg reported msgpack, but isn't.")

        if properties.headers['type'] == 'request':
            self._Statistics.increment("lib.amqpyombo.received.request", bucket_time=15, anon=True)

        # if a response, lets make sure it's something we asked for!
        elif properties.headers['type'] == "response":
            # print "send_correlation_ids: %s" % self.amqp.send_correlation_ids
            if properties.correlation_id not in self.amqp.send_correlation_ids:
                self._Statistics.increment("lib.amqpyombo.received.discarded.correlation_id_missing", bucket_time=15,
                                           anon=True)
                raise YomboWarning("correlation_id missing.")

            time_info = self.amqp.send_correlation_ids[properties.correlation_id]
            daate_time = time_info['time_received'] - time_info['time_sent']
            milliseconds = (
                           daate_time.days * 24 * 60 * 60 + daate_time.seconds) * 1000 + daate_time.microseconds / 1000.0
            logger.debug("Time between sending and receiving a response:: {milliseconds}", milliseconds=milliseconds)
            self._Statistics.averages("lib.amqpyombo.amqp.response.time", milliseconds, bucket_time=15, anon=True)

            if properties.correlation_id is None or not isinstance(properties.correlation_id, six.string_types):
                self._Statistics.increment("lib.amqpyombo.received.discarded.correlation_id_invalid", bucket_time=15, anon=True)
                raise YomboWarning("Correlation_id must be present for 'Response' types, and must be a string.")
            if properties.correlation_id not in self.amqp.send_correlation_ids:
                logger.debug("{correlation_id} not in list of ids: {send_correlation_ids} ",
                             correlation_id=properties.correlation_id, send_correlation_ids=self.amqp.send_correlation_ids.keys())
                self._Statistics.increment("lib.amqpyombo.received.discarded.nocorrelation", bucket_time=15, anon=True)
                raise YomboWarning("Received request {correlation_id}, but never asked for it. Discarding",
                                   correlation_id=properties.correlation_id)
        else:
            self._Statistics.increment("lib.amqpyombo.received.discarded.unknown_msg_type", bucket_time=15, anon=True)
            raise YomboWarning("Unknown message type recieved.")

        # self._local_log("debug", "PikaProtocol::receive_item4")

        # if we are here.. we have a valid message....

        if properties.headers['type'] == 'request':
            try:
                logger.debug("headers: {headers}", headers=properties.headers)
                if properties.headers['request_type'] == 'control':
                    self.controlHandler.process_control(msg, properties)
                elif properties.headers['request_type'] == 'system':
                    self.process_system_request(msg, properties)

            except Exception, e:
                logger.error("--------==(Error: in response processing     )==--------")
                logger.error("--------------------------------------------------------")
                logger.error("{error}", error=sys.exc_info())
                logger.error("---------------==(Traceback)==--------------------------")
                logger.error("{trace}", trace=traceback.print_exc(file=sys.stdout))
                logger.error("--------------------------------------------------------")
Пример #6
0
    def generate_message(self, exchange_name, source, destination, header_type, headers, body, callback=None):
        """
        When interacting with Yombo AMQP servers, we use a standard messaging layout. The below helps other functions
        and libraries conform to this standard.

        This only creates the message, it doesn't send it. Use the publish() function to complete that.

        **Usage**:

        .. code-block:: python

           requestData = {
               "exchange_name"  : "gw_config",
               "source"        : "yombo.gateway.lib.configurationupdate",
               "destination"   : "yombo.server.configs",
               "callback" : self.amqp_direct_incoming,
               "body"          : {
                 "DataType"        : "Object",
                 "Request"         : requestContent,
               },
           }
           request = self.AMQPYombo.generateRequest(**requestData)

        :param exchange_name: The exchange the request should go to.
        :type exchange_name: str
        :param source: Value for the 'source' field.
        :type source: str
        :param destination: Value of the 'destination' field.
        :type destination: str
        :param callback: A pointer to the function to return results to. This function will receive 4 arguments:
          sendInfo (Dict) - Various details of the sent packet. deliver (Dict) - Deliver fields as returned by Pika.
          props (Pika Object) - Message properties, includes headers. msg (dict) - The actual content of the message.
        :type callback: function
        :param body: The body contents for the mesage.
        :type body: dict

        :return: A dictionary that can be directly returned to Yombo Gateways via AMQP
        :rtype: dict
        """
        request_msg = {
            "exchange_name"    : exchange_name,
            "routing_key"      : '*',
            "body"             : msgpack.dumps(body),
            "properties" : {
                # "correlation_id" : correlation_id,
                "user_id"        : self.user_id,
                "content_type"   : 'application/msgpack',
                "headers"        : {
                    "source"        : source + ":" + self.user_id,
                    "destination"   : destination,
                    "type"          : header_type,
                    "protocol_verion": PROTOCOL_VERSION,
                    },
                },
            "callback": callback,
            }

        # Lets test if we can compress. Set headers as needed.

        self._Statistics.averages("lib.amqpyombo.sent.size", len(request_msg['body']), bucket_time=15, anon=True)
        if len(request_msg['body']) > 800:
            beforeZlib = len(request_msg['body'])
            request_msg['body'] = zlib.compress(request_msg['body'], 5)  # 5 appears to be the best speed/compression ratio - MSchwenk
            request_msg['properties']['content_encoding'] = "zlib"
            afterZlib = len(request_msg['body'])
            self._Statistics.increment("lib.amqpyombo.sent.compressed", bucket_time=15, anon=True)
            self._Statistics.averages("lib.amqpyombo.sent.compressed.percentage", percentage(afterZlib, beforeZlib), anon=True)
        else:
            request_msg['properties']['content_encoding'] = 'text'
            self._Statistics.increment("lib.amqpyombo.sent.uncompressed", bucket_time=15, anon=True)
        request_msg['properties']['headers'].update(headers)

        return request_msg
Пример #7
0
    def status_update(self, house, unit, command, status=None, deviceObj=None):
        """
        Called by interface modules when a device has a change of status.
        """
        logger.info("x10api - status update: {house}{unit}:{command}",
                    house=house,
                    unit=unit,
                    command=command)
        unit = int(unit)
        if deviceObj is None:
            if house in self.x10_devices and unit in self.x10_devices[house]:
                deviceObj = self.x10_devices[house][unit]
            else:
                YomboWarning(
                    "X10 API received a status update, but no device object to reference it."
                )

        newstatus = None
        humanstatus = None
        tempcmd = command.upper()

        #        self._DevicesByType('x10_appliance')
        device_type = self._DeviceTypes[deviceObj.device_type_id]
        logger.debug(
            "self._DevicesByType('x10_appliance'): {dt}",
            dt=self._DeviceTypes.devices_by_device_type('x10_appliance'))
        logger.debug("device_type: {dt}", dt=device_type.label)
        if device_type.machine_label == 'x10_appliance':
            logger.debug("in x10 appliance")
            if tempcmd == 'ON':
                newstatus = 1
                humanstatus = 'On'
            elif tempcmd == 'OFF':
                newstatus = 0
                humanstatus = 'Off'
        elif device_type.machine_label == 'x10_lamp':  # basic lamp
            logger.debug("in x10 lamp")
            if tempcmd == 'ON':
                newstatus = 1
                humanstatus = '100%'
            elif tempcmd == 'OFF':
                newstatus = 0
                humanstatus = 'Off'
            elif tempcmd == 'DIM':
                if type(deviceObj.status[0]['status']) is int:
                    newstatus = percentage(deviceObj.status[0]['status'] -
                                           12 / 100)
                else:
                    newstatus = 0.88
                    humanstatus = '88%'
            elif tempcmd == 'BRIGHT':
                if type(deviceObj.status[0]['status']) is int:
                    newstatus = percentage(deviceObj.status[0]['status'] +
                                           12 / 100)
                else:
                    newstatus = 100
                    humanstatus = '100%'

            if type(newstatus) is int:
                if newstatus > 1:
                    newstatus = 1
                    humanstatus = '100%'
                elif newstatus < 0:
                    newstatus = 0
                    humanstatus = 'Off'
            else:
                newstatus = 0
                humanstatus = 'Off'

        logger.debug(
            "status update.  Machine: {newstatus}   Human: {humanstatus}",
            newstatus=newstatus,
            humanstatus=humanstatus)

        human_message = "%s is now %s. " % (deviceObj.area_label,
                                            humanstatus.lower())

        deviceObj.set_status(machine_status=newstatus,
                             human_status=humanstatus,
                             human_message=human_message,
                             source="x10api")