def __init__(self, auth_provider, pipeline_configuration): """ Constructor for instantiating a pipeline adapter object :param auth_provider: The authentication provider :param pipeline_configuration: The configuration generated based on user inputs """ self.feature_enabled = { constant.C2D_MSG: False, constant.INPUT_MSG: False, constant.METHODS: False, constant.TWIN: False, constant.TWIN_PATCHES: False, } # Event Handlers - Will be set by Client after instantiation of this object self.on_connected = None self.on_disconnected = None self.on_c2d_message_received = None self.on_input_message_received = None self.on_method_request_received = None self.on_twin_patch_received = None # Currently a single timeout stage and a single retry stage for MQTT retry only. # Later, a higher level timeout and a higher level retry stage. self._pipeline = (pipeline_stages_base.PipelineRootStage( pipeline_configuration=pipeline_configuration ).append_stage(pipeline_stages_iothub.UseAuthProviderStage( )).append_stage(pipeline_stages_iothub.TwinRequestResponseStage( )).append_stage(pipeline_stages_base.CoordinateRequestAndResponseStage( )).append_stage( pipeline_stages_iothub_mqtt.IoTHubMQTTTranslationStage() ).append_stage(pipeline_stages_base.ReconnectStage()).append_stage( pipeline_stages_base.AutoConnectStage()).append_stage( pipeline_stages_base.ConnectionLockStage()).append_stage( pipeline_stages_base.RetryStage()).append_stage( pipeline_stages_base.OpTimeoutStage()).append_stage( pipeline_stages_mqtt.MQTTTransportStage())) def _on_pipeline_event(event): if isinstance(event, pipeline_events_iothub.C2DMessageEvent): if self.on_c2d_message_received: self.on_c2d_message_received(event.message) else: logger.warning( "C2D message event received with no handler. dropping." ) elif isinstance(event, pipeline_events_iothub.InputMessageEvent): if self.on_input_message_received: self.on_input_message_received(event.input_name, event.message) else: logger.warning( "input message event received with no handler. dropping." ) elif isinstance(event, pipeline_events_iothub.MethodRequestEvent): if self.on_method_request_received: self.on_method_request_received(event.method_request) else: logger.warning( "Method request event received with no handler. Dropping." ) elif isinstance( event, pipeline_events_iothub.TwinDesiredPropertiesPatchEvent): if self.on_twin_patch_received: self.on_twin_patch_received(event.patch) else: logger.warning( "Twin patch event received with no handler. Dropping.") else: logger.warning("Dropping unknown pipeline event {}".format( event.name)) def _on_connected(): if self.on_connected: self.on_connected() def _on_disconnected(): if self.on_disconnected: self.on_disconnected() self._pipeline.on_pipeline_event_handler = _on_pipeline_event self._pipeline.on_connected_handler = _on_connected self._pipeline.on_disconnected_handler = _on_disconnected callback = EventedCallback() if isinstance(auth_provider, X509AuthenticationProvider): op = pipeline_ops_iothub.SetX509AuthProviderOperation( auth_provider=auth_provider, callback=callback) else: # Currently everything else goes via this block. op = pipeline_ops_iothub.SetAuthProviderOperation( auth_provider=auth_provider, callback=callback) self._pipeline.run_op(op) callback.wait_for_completion()
def __init__(self, pipeline_configuration): """ Constructor for instantiating a pipeline :param security_client: The security client which stores credentials """ self.responses_enabled = {provisioning_constants.REGISTER: False} # Event Handlers - Will be set by Client after instantiation of pipeline self.on_connected = None self.on_disconnected = None self.on_message_received = None self._registration_id = pipeline_configuration.registration_id self._pipeline = ( # # The root is always the root. By definition, it's the first stage in the pipeline. # pipeline_stages_base.PipelineRootStage( pipeline_configuration=pipeline_configuration) # # SasTokenRenewalStage comes near the root by default because it should be as close # to the top of the pipeline as possible, and does not need to be after anything. # .append_stage(pipeline_stages_base.SasTokenRenewalStage()) # # RegistrationStage needs to come early because this is the stage that converts registration # or query requests into request and response objects which are used by later stages # .append_stage(pipeline_stages_provisioning.RegistrationStage()) # # PollingStatusStage needs to come after RegistrationStage because RegistrationStage counts # on PollingStatusStage to poll until the registration is complete. # .append_stage(pipeline_stages_provisioning.PollingStatusStage()) # # CoordinateRequestAndResponseStage needs to be after RegistrationStage and PollingStatusStage # because these 2 stages create the request ops that CoordinateRequestAndResponseStage # is coordinating. It needs to be before ProvisioningMQTTTranslationStage because that stage # operates on ops that CoordinateRequestAndResponseStage produces # .append_stage( pipeline_stages_base.CoordinateRequestAndResponseStage()) # # ProvisioningMQTTTranslationStage comes here because this is the point where we can translate # all operations directly into MQTT. After this stage, only pipeline_stages_base stages # are allowed because ProvisioningMQTTTranslationStage removes all the provisioning-ness from the ops # .append_stage(pipeline_stages_provisioning_mqtt. ProvisioningMQTTTranslationStage()) # # AutoConnectStage comes here because only MQTT ops have the need_connection flag set # and this is the first place in the pipeline wherer we can guaranetee that all network # ops are MQTT ops. # .append_stage(pipeline_stages_base.AutoConnectStage()) # # ReconnectStage needs to be after AutoConnectStage because ReconnectStage sets/clears # the virtually_conencted flag and we want an automatic connection op to set this flag so # we can reconnect autoconnect operations. # .append_stage(pipeline_stages_base.ReconnectStage()) # # ConnectionLockStage needs to be after ReconnectStage because we want any ops that # ReconnectStage creates to go through the ConnectionLockStage gate # .append_stage(pipeline_stages_base.ConnectionLockStage()) # # RetryStage needs to be near the end because it's retrying low-level MQTT operations. # .append_stage(pipeline_stages_base.RetryStage()) # # OpTimeoutStage needs to be after RetryStage because OpTimeoutStage returns the timeout # errors that RetryStage is watching for. # .append_stage(pipeline_stages_base.OpTimeoutStage()) # # MQTTTransportStage needs to be at the very end of the pipeline because this is where # operations turn into network traffic # .append_stage(pipeline_stages_mqtt.MQTTTransportStage())) def _on_pipeline_event(event): logger.warning("Dropping unknown pipeline event {}".format( event.name)) def _on_connected(): if self.on_connected: self.on_connected("connected") def _on_disconnected(): if self.on_disconnected: self.on_disconnected("disconnected") self._pipeline.on_pipeline_event_handler = _on_pipeline_event self._pipeline.on_connected_handler = _on_connected self._pipeline.on_disconnected_handler = _on_disconnected callback = EventedCallback() op = pipeline_ops_base.InitializePipelineOperation(callback=callback) self._pipeline.run_op(op) callback.wait_for_completion()
def __init__(self, auth_provider, pipeline_configuration): """ Constructor for instantiating a pipeline adapter object :param auth_provider: The authentication provider :param pipeline_configuration: The configuration generated based on user inputs """ self.feature_enabled = { constant.C2D_MSG: False, constant.INPUT_MSG: False, constant.METHODS: False, constant.TWIN: False, constant.TWIN_PATCHES: False, } # Event Handlers - Will be set by Client after instantiation of this object self.on_connected = None self.on_disconnected = None self.on_c2d_message_received = None self.on_input_message_received = None self.on_method_request_received = None self.on_twin_patch_received = None # Currently a single timeout stage and a single retry stage for MQTT retry only. # Later, a higher level timeout and a higher level retry stage. self._pipeline = ( # # The root is always the root. By definition, it's the first stage in the pipeline. # pipeline_stages_base.PipelineRootStage( pipeline_configuration=pipeline_configuration) # # UseAuthProviderStage comes near the root by default because it doesn't need to be after # anything, but it does need to be before IoTHubMQTTTranslationStage. # .append_stage(pipeline_stages_iothub.UseAuthProviderStage()) # # TwinRequestResponseStage comes near the root by default because it doesn't need to be # after anything # .append_stage(pipeline_stages_iothub.TwinRequestResponseStage()) # # CoordinateRequestAndResponseStage needs to be after TwinRequestResponseStage because # TwinRequestResponseStage creates the request ops that CoordinateRequestAndResponseStage # is coordinating. It needs to be before IoTHubMQTTTranslationStage because that stage # operates on ops that CoordinateRequestAndResponseStage produces # .append_stage( pipeline_stages_base.CoordinateRequestAndResponseStage()) # # IoTHubMQTTTranslationStage comes here because this is the point where we can translate # all operations directly into MQTT. After this stage, only pipeline_stages_base stages # are allowed because IoTHubMQTTTranslationStage removes all the IoTHub-ness from the ops # .append_stage( pipeline_stages_iothub_mqtt.IoTHubMQTTTranslationStage()) # # AutoConnectStage comes here because only MQTT ops have the need_connection flag set # and this is the first place in the pipeline wherer we can guaranetee that all network # ops are MQTT ops. # .append_stage(pipeline_stages_base.AutoConnectStage()) # # ReconnectStage needs to be after AutoConnectStage because ReconnectStage sets/clears # the virtually_conencted flag and we want an automatic connection op to set this flag so # we can reconnect autoconnect operations. This is important, for example, if a # send_message causes the transport to automatically connect, but that connection fails. # When that happens, the ReconenctState will hold onto the ConnectOperation until it # succeeds, and only then will return success to the AutoConnectStage which will # allow the publish to continue. # .append_stage(pipeline_stages_base.ReconnectStage()) # # ConnectionLockStage needs to be after ReconnectStage because we want any ops that # ReconnectStage creates to go through the ConnectionLockStage gate # .append_stage(pipeline_stages_base.ConnectionLockStage()) # # RetryStage needs to be near the end because it's retrying low-level MQTT operations. # .append_stage(pipeline_stages_base.RetryStage()) # # OpTimeoutStage needs to be after RetryStage because OpTimeoutStage returns the timeout # errors that RetryStage is watching for. # .append_stage(pipeline_stages_base.OpTimeoutStage()) # # MQTTTransportStage needs to be at the very end of the pipeline because this is where # operations turn into network traffic # .append_stage(pipeline_stages_mqtt.MQTTTransportStage())) def _on_pipeline_event(event): if isinstance(event, pipeline_events_iothub.C2DMessageEvent): if self.on_c2d_message_received: self.on_c2d_message_received(event.message) else: logger.warning( "C2D message event received with no handler. dropping." ) elif isinstance(event, pipeline_events_iothub.InputMessageEvent): if self.on_input_message_received: self.on_input_message_received(event.input_name, event.message) else: logger.warning( "input message event received with no handler. dropping." ) elif isinstance(event, pipeline_events_iothub.MethodRequestEvent): if self.on_method_request_received: self.on_method_request_received(event.method_request) else: logger.warning( "Method request event received with no handler. Dropping." ) elif isinstance( event, pipeline_events_iothub.TwinDesiredPropertiesPatchEvent): if self.on_twin_patch_received: self.on_twin_patch_received(event.patch) else: logger.warning( "Twin patch event received with no handler. Dropping.") else: logger.warning("Dropping unknown pipeline event {}".format( event.name)) def _on_connected(): if self.on_connected: self.on_connected() def _on_disconnected(): if self.on_disconnected: self.on_disconnected() self._pipeline.on_pipeline_event_handler = _on_pipeline_event self._pipeline.on_connected_handler = _on_connected self._pipeline.on_disconnected_handler = _on_disconnected callback = EventedCallback() if isinstance(auth_provider, X509AuthenticationProvider): op = pipeline_ops_iothub.SetX509AuthProviderOperation( auth_provider=auth_provider, callback=callback) else: # Currently everything else goes via this block. op = pipeline_ops_iothub.SetAuthProviderOperation( auth_provider=auth_provider, callback=callback) self._pipeline.run_op(op) callback.wait_for_completion()
def __init__(self, pipeline_configuration): """ Constructor for instantiating a pipeline adapter object :param auth_provider: The authentication provider :param pipeline_configuration: The configuration generated based on user inputs """ self.feature_enabled = { constant.C2D_MSG: False, constant.INPUT_MSG: False, constant.METHODS: False, constant.TWIN: False, constant.TWIN_PATCHES: False, } # Handlers - Will be set by Client after instantiation of this object self.on_connected = None self.on_disconnected = None self.on_new_sastoken_required = None self.on_background_exception = None self.on_c2d_message_received = None self.on_input_message_received = None self.on_method_request_received = None self.on_twin_patch_received = None # Contains data and information shared globally within the pipeline self._nucleus = pipeline_nucleus.PipelineNucleus(pipeline_configuration) self._pipeline = ( # # The root is always the root. By definition, it's the first stage in the pipeline. # pipeline_stages_base.PipelineRootStage(self._nucleus) # # SasTokenStage comes near the root by default because it should be as close # to the top of the pipeline as possible, and does not need to be after anything. # .append_stage(pipeline_stages_base.SasTokenStage()) # # EnsureDesiredPropertiesStage needs to be above TwinRequestResponseStage because it # sends GetTwinOperation ops and that stage handles those ops. # .append_stage(pipeline_stages_iothub.EnsureDesiredPropertiesStage()) # # TwinRequestResponseStage comes near the root by default because it doesn't need to be # after anything # .append_stage(pipeline_stages_iothub.TwinRequestResponseStage()) # # CoordinateRequestAndResponseStage needs to be after TwinRequestResponseStage because # TwinRequestResponseStage creates the request ops that CoordinateRequestAndResponseStage # is coordinating. It needs to be before IoTHubMQTTTranslationStage because that stage # operates on ops that CoordinateRequestAndResponseStage produces # .append_stage(pipeline_stages_base.CoordinateRequestAndResponseStage()) # # IoTHubMQTTTranslationStage comes here because this is the point where we can translate # all operations directly into MQTT. After this stage, only pipeline_stages_base stages # are allowed because IoTHubMQTTTranslationStage removes all the IoTHub-ness from the ops # .append_stage(pipeline_stages_iothub_mqtt.IoTHubMQTTTranslationStage()) # # AutoConnectStage comes here because only MQTT ops have the need_connection flag set # and this is the first place in the pipeline where we can guarantee that all network # ops are MQTT ops. # .append_stage(pipeline_stages_base.AutoConnectStage()) # # ConnectionStateStage needs to be after AutoConnectStage because the AutoConnectStage # can create ConnectOperations and we (may) want to queue connection related operations # in the ConnectionStateStage # .append_stage(pipeline_stages_base.ConnectionStateStage()) # # ConnectionLockStage needs to be after ConnectionStateStage because we want any ops that # ConnectionStateStage creates to go through the ConnectionLockStage gate # .append_stage(pipeline_stages_base.ConnectionLockStage()) # # RetryStage needs to be near the end because it's retrying low-level MQTT operations. # .append_stage(pipeline_stages_base.RetryStage()) # # OpTimeoutStage needs to be after RetryStage because OpTimeoutStage returns the timeout # errors that RetryStage is watching for. # .append_stage(pipeline_stages_base.OpTimeoutStage()) # # MQTTTransportStage needs to be at the very end of the pipeline because this is where # operations turn into network traffic # .append_stage(pipeline_stages_mqtt.MQTTTransportStage()) ) # Define behavior for domain-specific events def _on_pipeline_event(event): if isinstance(event, pipeline_events_iothub.C2DMessageEvent): if self.on_c2d_message_received: self.on_c2d_message_received(event.message) else: logger.error("C2D message event received with no handler. dropping.") elif isinstance(event, pipeline_events_iothub.InputMessageEvent): if self.on_input_message_received: self.on_input_message_received(event.message) else: logger.error("input message event received with no handler. dropping.") elif isinstance(event, pipeline_events_iothub.MethodRequestEvent): if self.on_method_request_received: self.on_method_request_received(event.method_request) else: logger.error("Method request event received with no handler. Dropping.") elif isinstance(event, pipeline_events_iothub.TwinDesiredPropertiesPatchEvent): if self.on_twin_patch_received: self.on_twin_patch_received(event.patch) else: logger.error("Twin patch event received with no handler. Dropping.") else: logger.error("Dropping unknown pipeline event {}".format(event.name)) def _on_connected(): if self.on_connected: self.on_connected() else: logger.debug("IoTHub Pipeline was connected, but no handler was set") def _on_disconnected(): if self.on_disconnected: self.on_disconnected() else: logger.debug("IoTHub Pipeline was disconnected, but no handler was set") def _on_new_sastoken_required(): if self.on_new_sastoken_required: self.on_new_sastoken_required() else: logger.debug("IoTHub Pipeline requires new SASToken, but no handler was set") def _on_background_exception(e): if self.on_background_exception: self.on_background_exception(e) else: logger.debug( "IoTHub Pipeline experienced background exception, but no handler was set" ) # Set internal event handlers self._pipeline.on_pipeline_event_handler = _on_pipeline_event self._pipeline.on_connected_handler = _on_connected self._pipeline.on_disconnected_handler = _on_disconnected self._pipeline.on_new_sastoken_required_handler = _on_new_sastoken_required self._pipeline.on_background_exception_handler = _on_background_exception # Initialize the pipeline callback = EventedCallback() op = pipeline_ops_base.InitializePipelineOperation(callback=callback) self._pipeline.run_op(op) callback.wait_for_completion() # Set the running flag self._running = True
def __init__(self, security_client, pipeline_configuration): """ Constructor for instantiating a pipeline :param security_client: The security client which stores credentials """ self.responses_enabled = {provisioning_constants.REGISTER: False} # Event Handlers - Will be set by Client after instantiation of pipeline self.on_connected = None self.on_disconnected = None self.on_message_received = None self._registration_id = security_client.registration_id self._pipeline = ( pipeline_stages_base.PipelineRootStage( pipeline_configuration=pipeline_configuration).append_stage( pipeline_stages_provisioning.UseSecurityClientStage()). append_stage( pipeline_stages_provisioning.RegistrationStage()).append_stage( pipeline_stages_provisioning.PollingStatusStage()). append_stage( pipeline_stages_base.CoordinateRequestAndResponseStage() ).append_stage(pipeline_stages_provisioning_mqtt. ProvisioningMQTTTranslationStage()).append_stage( pipeline_stages_base.ReconnectStage()). append_stage(pipeline_stages_base.AutoConnectStage()).append_stage( pipeline_stages_base.ConnectionLockStage()).append_stage( pipeline_stages_base.RetryStage()).append_stage( pipeline_stages_base.OpTimeoutStage()).append_stage( pipeline_stages_mqtt.MQTTTransportStage())) def _on_pipeline_event(event): logger.warning("Dropping unknown pipeline event {}".format( event.name)) def _on_connected(): if self.on_connected: self.on_connected("connected") def _on_disconnected(): if self.on_disconnected: self.on_disconnected("disconnected") self._pipeline.on_pipeline_event_handler = _on_pipeline_event self._pipeline.on_connected_handler = _on_connected self._pipeline.on_disconnected_handler = _on_disconnected callback = EventedCallback() if isinstance(security_client, X509SecurityClient): op = pipeline_ops_provisioning.SetX509SecurityClientOperation( security_client=security_client, callback=callback) elif isinstance(security_client, SymmetricKeySecurityClient): op = pipeline_ops_provisioning.SetSymmetricKeySecurityClientOperation( security_client=security_client, callback=callback) else: logger.error( "Provisioning not equipped to handle other security client.") self._pipeline.run_op(op) callback.wait_for_completion()
def stage(self): return pipeline_stages_base.OpTimeoutStage()