def async_publish(self, request, callback=None): """ Publish asynchronous without block, user should check if request is success with callback extends ResponseCallback""" if self.__state != MqttConnection.State.CONNECTED: raise EnvisionException('async publish is not allowed at state: {}, method is: {}' .format(self.__state, request.get_method())) if callback is None: self.fast_publish(request) try: self.__fill_request(request) request.check() self.__subscribe_response_if_needed(request) token = self.__get_token_with_callback(request, callback) self.get_processor().register_response_token(token.get_response_id(), token) try: self.__do_fast_publish(request) if token is None: raise EnvisionException('response token not set') self.__mqtt_processor.get_executor().submit( token.wait_for_response(self.__profile.get_operation_timeout())) except Exception as e: if token is not None: self.get_processor().deregister_response_token(token.get_response_id()) token.mark_failure(e) else: callback.on_failure() except Exception as e: raise EnvisionException('[async] publish error: {}, topic is {}' .format(str(e), request.get_message_topic()))
def publish(self, request): """ This method blocks until the response is received or action timeout is reached""" if self.__state != MqttConnection.State.CONNECTED: raise EnvisionException('publish is not allowed at state: {}, method is: {}' .format(self.__state, request.get_method())) try: self.__fill_request(request) request.check() self.__subscribe_response_if_needed(request) token = self.__get_token(request) self.get_processor().register_response_token(token.get_response_id(), token) try: self.__do_fast_publish(request) if token is None: raise EnvisionException('response token not set') response = token.wait_for_response(self.__profile.get_operation_timeout()) except Exception as e: MqttConnection.__logger.error('[sync] publish error: {}, topic is: {}' .format(str(e), request.get_message_topic())) if token is not None: self.get_processor().deregister_response_token(token.get_response_id()) token.mark_failure(e) raise e self.__post_publish(request, response) return response except Exception as e: raise EnvisionException('[sync] publish error: {}, topic is {}' .format(str(e), request.get_message_topic()))
def fast_publish(self, delivery): if self.__state != MqttConnection.State.CONNECTED: raise EnvisionException('fast publish is not allowed at state: {}, method is: {}' .format(self.__state, delivery.get_method())) try: self.__fill_request(delivery) delivery.check() self.__do_fast_publish(delivery) self.__post_publish(delivery) except Exception as e: raise EnvisionException('fast publish failed: {}'.format(str(e)))
def sign(cls, app_secret, params, sign_method): if StringUtil.is_empty(sign_method): raise EnvisionException('sign method is empty') content = SignUtil.__make_string(app_secret, params) if sign_method == cls.SHA256: return cls.sha256_sign(content) if sign_method == cls.MD5: return cls.md5_sign(content) if sign_method == cls.SHA1: return cls.sha1_sign(content) else: raise EnvisionException('invalid sign method')
def __do_fast_publish(self, delivery): """ Deliver request or reply to broker. This method blocks until request is sent out and mqtt ack is returned without response""" try: if self.__paho_client.is_connected(): if delivery.get_qos() == 0 or delivery.get_qos() == 1: self.__paho_client.publish(delivery.get_message_topic(), delivery.encode(), delivery.get_qos()) elif delivery.get_qos() == 2: raise EnvisionException('qos 2 not allowed') else: raise EnvisionException('invalid qos!') except Exception as e: raise EnvisionException('publish message failed, message topic: {} \n error message: {}' .format(delivery.get_message_topic(), str(e)))
def check_not_empty(value, field_name): if value is None: raise EnvisionException( "parameter check error: " + field_name + " is mandatory", CODE_ERROR_MISSING_ARGS.get_error_code()) if isinstance(value, str) and StringUtil.is_empty(value): raise EnvisionException( "parameter check error: " + field_name + " is mandatory", CODE_ERROR_MISSING_ARGS.get_error_code()) if isinstance(value, list) and not value: raise EnvisionException( "parameter check error: " + field_name + " is mandatory", CODE_ERROR_MISSING_ARGS.get_error_code()) if isinstance(value, dict) and not value: raise EnvisionException( "parameter check error: " + field_name + " is mandatory", CODE_ERROR_MISSING_ARGS.get_error_code())
def __parse_url(self): regions = self.__server_url.split(':') if len(regions) == 3: self.__protocol = regions[0] self.__host = regions[1].replace('//', '') self.__port = int(regions[2]) else: raise EnvisionException('invalid uri!')
def disconnect(self): with self.__client_lock: if self.__state == MqttConnection.State.DISCONNECTED: MqttConnection.__logger.warning('connection is already disconnected') return if self.__state != MqttConnection.State.CONNECTED: raise EnvisionException('client is not at connected state: ' + str(self.__state)) self.__disconnect_underlying_client() self.__state = MqttConnection.State.DISCONNECTED
def connect(self): with self.__client_lock: if self.__state != MqttConnection.State.NOT_CONNECTED: raise EnvisionException('connect is not allowed at illegal state: ' + str(self.__state)) rc = self.__do_connect() if rc == 0: with self.__connection_condition: got_it = self.__connection_condition.wait(MqttConnection.__connect_timeout) if not got_it: MqttConnection.__logger.error('Client id: [{}] connect timeout' .format(self.__profile.get_client_id()))
def __import_decoder(cls): try: for package in cls.packages.items(): model = __import__(package[0], fromlist=['mode']) if hasattr(model, package[1]): clazz = getattr(model, package[1]) if hasattr(clazz(), 'decode'): func = getattr(clazz(), 'decode') cls.decoder_list.append(func) except Exception as e: raise EnvisionException(e)
def connect_async(self): with self.__client_lock: if self.__state != MqttConnection.State.NOT_CONNECTED: raise EnvisionException('connect is not allowed at illegal state: ' + str(self.__state)) self.__state = MqttConnection.State.CONNECTING self.__initialize_underlying_client() self.__create_connection_options() self.__paho_client.connect_async(host=self.__profile.get_host(), port=self.__profile.get_port(), keepalive=self.__profile.get_keep_alive_interval()) self.__paho_client.loop_start()
def get_secure_mode(product_key, product_secret, device_key, device_secret): if StringUtil.is_not_empty(device_secret): return SecureMode(VIA_DEVICE_SECRET, device_key, device_secret) if StringUtil.is_not_empty(product_secret): if INTEGRATION_DK == device_key: # integration use product key as client id return SecureMode(VIA_PRODUCT_SECRET_FOR_INTEGRATION, product_key, product_secret) return SecureMode(VIA_PRODUCT_SECRET, device_key, product_secret) raise EnvisionException( "<device_secret> or <product_secret> should be provided")
def reconnect(self): with self.__client_lock: if self.__state != MqttConnection.State.CONNECTED and self.__state != MqttConnection.State.DISCONNECTED: raise EnvisionException('reconnect is not allowed at illegal state: ' + str(self.__state)) self.__disconnect_underlying_client() self.__state = MqttConnection.State.DISCONNECTED self.__do_connect() with self.__connection_condition: got_it = self.__connection_condition.wait(MqttConnection.__connect_timeout) if not got_it: MqttConnection.__logger.error('Client id: [{}] connect timeout' .format(self.__profile.get_client_id()))
def wait_for_response(self, timeout): timestamp = int(round(time.time() * 1000)) with self.__condition: while self.__is_completed() is False: try: self.__condition.wait(timeout) except Exception as e: self.__exception = e if self.__is_completed( ) is False and timeout > 0 and timestamp + timeout * 1000 <= int( round(time.time() * 1000)): self.__exception = EnvisionException( 'synchronize request timeout') self.__invoke_callback() if self.__exception is not None: raise self.__exception return self.__response
def decode(self, topic, payload): # format of match result: [(product_key, device_key),...] path_list = self.match(topic) if not path_list: return None try: path_list = path_list[0] arrived_msg = json.loads(payload) arrived_object = self.decode_to_object(arrived_msg) except Exception as e: raise EnvisionException(e) arrived_object.set_message_topic(topic) if len(path_list) > 0: arrived_object.set_product_key(path_list[0]) if len(path_list) > 1: arrived_object.set_device_key(path_list[1]) return DecodeResult(arrived_object, path_list)
def __do_connect(self): try: self.__initialize_underlying_client() self.__create_connection_options() rc = self.__paho_client.connect(host=self.__profile.get_host(), port=self.__profile.get_port(), keepalive=self.__profile.get_keep_alive_interval()) if rc == 0: self.__paho_client.loop_start() return rc except Exception as e: MqttConnection.__logger.error('connect failed, url: {}, err : ' + self.__profile.get_server_url() + str(e)) self.__state = MqttConnection.State.NOT_CONNECTED self.__disconnect_underlying_client() if self.__on_connect_failed is not None: self.__mqtt_processor.get_executor().submit(self.__on_connect_failed) raise EnvisionException('failed to connect: ' + self.__profile.get_server_url() + str(e))
def check(self): if self.get_message_size() > MAX_MESSAGE_SIZE: raise EnvisionException('message too large, max length is: %s' % MAX_MESSAGE_SIZE) CheckUtil.check_not_empty(self.get_product_key(), 'product key') CheckUtil.check_not_empty(self.get_device_key(), 'device key')
def create_params(self): raise EnvisionException('unsupported operation')
def set_topic_args(self, args): if len(args) != 3: raise EnvisionException('topic args size not match!') self.set_product_key(args[0]) self.set_device_key(args[1]) self.set_service_identifier(args[2])
def check_max_size(params, maxsize, field_name): if len(params) > maxsize: raise EnvisionException( CODE_ERROR_ARG_INVALID.getErrorCode(), "parameter check error: " + field_name + " is invalid, size cannot be large than " + maxsize)
def get_answer_topic(request): if request.get_id() is None: raise EnvisionException('request message id not set') return request.get_answer_topic() + '_' + request.get_id()
def timeout_schedule_task(): self.get_processor().deregister_response_token(answer_topic) callback.on_failure(EnvisionException('call back task timeout'))
def set_id(self, id): raise EnvisionException('cannot set raw request message id')
def create_params(self): raise EnvisionException('exception is null')
def set_message_topic(self, topic): raise EnvisionException("reply message type can't set topic")
def mark_success(self, response): if response is None: raise EnvisionException('response is null') self.__response = response self.__do_notify()
def mark_failure(self, exception): if exception is None: raise EnvisionException('exception is null') self.__exception = exception self.__do_notify()
def set_qos(self, qos): if qos < 0 or qos >= 2: raise EnvisionException('qos only support 0,1 in current version') self.__qos = qos