def connect(*, ipc_socket: str = None, authtoken: str = None, lifecycle_handler: Optional[LifecycleHandler] = None, timeout=10.0) -> GreengrassCoreIPCClient: """ Creates an IPC client and connects to the GreengrassCoreIPC service. Args: ipc_socket: Path to the Unix domain socket of Greengrass Nucleus, defaults to environment variable AWS_GG_NUCLEUS_DOMAIN_SOCKET_FILEPATH_FOR_COMPONENT authtoken: Authentication token, defaults to environment variable SVCUID lifecycle_handler: Handler for events over the course of this network connection. See :class:`LifecycleHandler` for more info. Handler methods will only be invoked if the connect attempt succeeds. timeout: The number of seconds to wait for establishing the connection. Returns: Client for the GreengrassCoreIPC service. """ if not ipc_socket: ipc_socket = os.environ[ "AWS_GG_NUCLEUS_DOMAIN_SOCKET_FILEPATH_FOR_COMPONENT"] if not authtoken: authtoken = os.environ["SVCUID"] if not lifecycle_handler: lifecycle_handler = LifecycleHandler() elg = EventLoopGroup(num_threads=1) resolver = DefaultHostResolver(elg) bootstrap = ClientBootstrap(elg, resolver) socket_options = SocketOptions() socket_options.domain = SocketDomain.Local amender = MessageAmendment.create_static_authtoken_amender(authtoken) connection = Connection( host_name=ipc_socket, port=0, # dummy port number, not needed for Unix domain sockets bootstrap=bootstrap, socket_options=socket_options, connect_message_amender=amender, ) connect_future = connection.connect(lifecycle_handler) connect_future.result(timeout) return GreengrassCoreIPCClient(connection)
def connect( cls, *, handler: ClientConnectionHandler, host_name: str, port: int, bootstrap: ClientBootstrap = None, socket_options: Optional[SocketOptions] = None, tls_connection_options: Optional[TlsConnectionOptions] = None ) -> 'concurrent.futures.Future': """Asynchronously establish a new ClientConnection. Args: handler: Handler for connection events. host_name: Connect to host. port: Connect to port. bootstrap: Client bootstrap to use when initiating socket connection. If None is provided, the default singleton is used. socket_options: Optional socket options. If None is provided, then default options are used. tls_connection_options: Optional TLS connection options. If None is provided, then the connection will be attempted over plain-text. Returns: concurrent.futures.Future: A Future which completes when the connection succeeds or fails. If successful, the Future will contain None. Otherwise it will contain an exception. If the connection is successful, it will be made available via the handler's on_connection_setup callback. Note that this network connection stays alive until it is closed, even if no local references to the connection object remain. The user should store a reference to any connections, and call :meth:`close()` when they are done with them to avoid leaking resources. """ if not socket_options: socket_options = SocketOptions() # Connection is not made available to user until setup callback fires connection = cls(host_name, port, handler) if not bootstrap: bootstrap = ClientBootstrap.get_or_create_static_default() # connection._binding is set within the following call */ _awscrt.event_stream_rpc_client_connection_connect( host_name, port, bootstrap, socket_options, tls_connection_options, connection) return connection._connect_future
def connect(self): elg = EventLoopGroup() resolver = DefaultHostResolver(elg) bootstrap = ClientBootstrap(elg, resolver) socket_options = SocketOptions() socket_options.domain = SocketDomain.Local amender = MessageAmendment.create_static_authtoken_amender(getenv("SVCUID")) hostname = getenv("AWS_GG_NUCLEUS_DOMAIN_SOCKET_FILEPATH_FOR_COMPONENT") connection = Connection( host_name=hostname, port=8033, bootstrap=bootstrap, socket_options=socket_options, connect_message_amender=amender, ) self.lifecycle_handler = LifecycleHandler() connect_future = connection.connect(self.lifecycle_handler) connect_future.result(config_utils.TIMEOUT) return connection
def connect( cls, *, handler: EventStreamRpcClientConnectionHandler, host_name: str, port: int, bootstrap: ClientBootstrap, socket_options: Optional[SocketOptions] = None, tls_connection_options: Optional[TlsConnectionOptions] = None ) -> Future: """Asynchronously establish a new EventStreamRpcClientConnection. Args: TODO (int): fill this out Returns: concurrent.futures.Future: A Future which completes when the connection succeeds or fails. If successful, the Future will contain None. Otherwise it will contain an exception. If the connection is successful, it is accessible via `handler.connection`. """ if not socket_options: socket_options = SocketOptions() future = Future() # Connection is not made available to user until setup callback fires connection = cls(host_name, port) # We must be careful to avoid circular references that prevent the connection from getting GC'd. # Only the internal _on_setup callback binds strong references to the connection and handler. # This is ok because it fires exactly once, and references to it are cleared afterwards. # All other callbacks must bind weak references to the handler, # or references to futures within the connection rather than the connection itself. handler_weakref = weakref.ref(handler) connection._binding = _awscrt.event_stream_rpc_client_connection_connect( host_name, port, bootstrap, socket_options, tls_connection_options, partial(cls._on_connection_setup, future, handler, connection), partial(cls._on_connection_shutdown, connection.shutdown_future, handler_weakref), partial(cls._on_protocol_message, handler_weakref)) return future
def __init__( self, client, host_name, port, client_id, clean_session=True, on_connection_interrupted=None, on_connection_resumed=None, reconnect_min_timeout_secs=5, reconnect_max_timeout_secs=60, keep_alive_secs=1200, ping_timeout_ms=3000, will=None, username=None, password=None, socket_options=None, use_websockets=False, websocket_proxy_options=None, websocket_handshake_transform=None, ): assert isinstance(client, Client) assert callable( on_connection_interrupted) or on_connection_interrupted is None assert callable(on_connection_resumed) or on_connection_resumed is None assert isinstance(will, Will) or will is None assert isinstance(socket_options, SocketOptions) or socket_options is None assert isinstance(websocket_proxy_options, HttpProxyOptions) or websocket_proxy_options is None assert callable(websocket_handshake_transform ) or websocket_handshake_transform is None if reconnect_min_timeout_secs > reconnect_max_timeout_secs: raise ValueError( "'reconnect_min_timeout_secs' cannot exceed 'reconnect_max_timeout_secs'" ) if keep_alive_secs * 1000 <= ping_timeout_ms: raise ValueError( "'keep_alive_secs' duration must be longer than 'ping_timeout_ms'" ) super().__init__() # init-only self.client = client self._on_connection_interrupted_cb = on_connection_interrupted self._on_connection_resumed_cb = on_connection_resumed self._use_websockets = use_websockets self._ws_handshake_transform_cb = websocket_handshake_transform # may be changed at runtime, take effect the the next time connect/reconnect occurs self.client_id = client_id self.host_name = host_name self.port = port self.clean_session = clean_session self.reconnect_min_timeout_secs = reconnect_min_timeout_secs self.reconnect_max_timeout_secs = reconnect_max_timeout_secs self.keep_alive_secs = keep_alive_secs self.ping_timeout_ms = ping_timeout_ms self.will = will self.username = username self.password = password self.socket_options = socket_options if socket_options else SocketOptions( ) self.websocket_proxy_options = websocket_proxy_options self._binding = _awscrt.mqtt_client_connection_new( self, client, use_websockets, )
def new(cls, host_name, port, bootstrap, socket_options=None, tls_connection_options=None, proxy_options=None): """ Initiates a new connection to host_name and port using socket_options and tls_connection_options if supplied. if tls_connection_options is None, then the connection will be attempted over plain-text. Returns a future where the result is a new instance to HttpClientConnection, once the connection has completed and is ready for use. """ assert isinstance(bootstrap, ClientBootstrap) or bootstrap is None assert isinstance_str(host_name) assert isinstance(port, int) assert isinstance( tls_connection_options, TlsConnectionOptions) or tls_connection_options is None assert isinstance(socket_options, SocketOptions) or socket_options is None assert isinstance(proxy_options, HttpProxyOptions) or proxy_options is None future = Future() try: if not socket_options: socket_options = SocketOptions() if not bootstrap: event_loop_group = EventLoopGroup(1) host_resolver = DefaultHostResolver(event_loop_group) bootstrap = ClientBootstrap(event_loop_group, host_resolver) connection = cls() connection._host_name = host_name connection._port = port def on_connection_setup(binding, error_code): if error_code == 0: connection._binding = binding future.set_result(connection) else: future.set_exception( awscrt.exceptions.from_code(error_code)) # on_shutdown MUST NOT reference the connection itself, just the shutdown_future within it. # Otherwise we create a circular reference that prevents the connection from getting GC'd. shutdown_future = connection.shutdown_future def on_shutdown(error_code): if error_code: shutdown_future.set_exception( awscrt.exceptions.from_code(error_code)) else: shutdown_future.set_result(None) _awscrt.http_client_connection_new(bootstrap, on_connection_setup, on_shutdown, host_name, port, socket_options, tls_connection_options, proxy_options) except Exception as e: future.set_exception(e) return future
def new(cls, host_name, port, bootstrap, socket_options=None, tls_connection_options=None, proxy_options=None): """ Asynchronously establish a new HttpClientConnection. Args: host_name (str): Connect to host. port (int): Connect to port. bootstrap (ClientBootstrap): Client bootstrap to use when initiating socket connection. socket_options (Optional[SocketOptions]): Optional socket options. If None is provided, then default options are used. tls_connection_options (Optional[TlsConnectionOptions]): Optional TLS connection options. If None is provided, then the connection will be attempted over plain-text. proxy_options (Optional[HttpProxyOptions]): Optional proxy options. If None is provided then a proxy is not used. Returns: concurrent.futures.Future: A Future which completes when connection succeeds or fails. If successful, the Future will contain a new :class:`HttpClientConnection`. Otherwise, it will contain an exception. """ assert isinstance(bootstrap, ClientBootstrap) or bootstrap is None assert isinstance(host_name, str) assert isinstance(port, int) assert isinstance( tls_connection_options, TlsConnectionOptions) or tls_connection_options is None assert isinstance(socket_options, SocketOptions) or socket_options is None assert isinstance(proxy_options, HttpProxyOptions) or proxy_options is None future = Future() try: if not socket_options: socket_options = SocketOptions() if not bootstrap: event_loop_group = EventLoopGroup(1) host_resolver = DefaultHostResolver(event_loop_group) bootstrap = ClientBootstrap(event_loop_group, host_resolver) connection = cls() connection._host_name = host_name connection._port = port def on_connection_setup(binding, error_code, http_version): if error_code == 0: connection._binding = binding connection._version = HttpVersion(http_version) future.set_result(connection) else: future.set_exception( awscrt.exceptions.from_code(error_code)) # on_shutdown MUST NOT reference the connection itself, just the shutdown_future within it. # Otherwise we create a circular reference that prevents the connection from getting GC'd. shutdown_future = connection.shutdown_future def on_shutdown(error_code): if error_code: shutdown_future.set_exception( awscrt.exceptions.from_code(error_code)) else: shutdown_future.set_result(None) _awscrt.http_client_connection_new(bootstrap, on_connection_setup, on_shutdown, host_name, port, socket_options, tls_connection_options, proxy_options) except Exception as e: future.set_exception(e) return future
def __init__( self, client, host_name, port, client_id, clean_session=True, on_connection_interrupted=None, on_connection_resumed=None, reconnect_min_timeout_secs=5, reconnect_max_timeout_secs=60, keep_alive_secs=3600, ping_timeout_ms=3000, will=None, username=None, password=None, socket_options=None, use_websockets=False, websocket_proxy_options=None, websocket_handshake_transform=None, ): """ Arguments: client (Client): MQTT Client host_name (str): Server name to connect to. port (int): Server port to connect to. client_id (str): ID to place in CONNECT packet. Must be unique across all devices/clients. If an ID is already in use, the other client will be disconnected. clean_session (bool): Whether or not to start a clean session with each reconnect. If True, the server will forget all subscriptions with each reconnect. Set False to request that the server resume an existing session or start a new session that may be resumed after a connection loss. The `session_present` bool in the connection callback informs whether an existing session was successfully resumed. If an existing session is resumed, the server remembers previous subscriptions and sends mesages (with QoS1 or higher) that were published while the client was offline. on_connection_interrupted (function): Optional callback invoked whenever the MQTT connection is lost. The MQTT client will automatically attempt to reconnect. The function should take the following arguments return nothing. connection (Connection): This MQTT Connection. error (awscrt.exceptions.AwsCrtError): Exception which caused connection loss. **kwargs (dict): Forward-compatibility kwargs. on_connection_resumed (function): Optional callback invoked whenever the MQTT connection is automatically resumed. Function should take the following arguments and return nothing: connection (Connection): This MQTT Connection return_code (ConnectReturnCode): Connect return code received from the server. session_present (bool): True if resuming existing session. False if new session. Note that the server has forgotten all previous subscriptions if this is False. Subscriptions can be re-established via resubscribe_existing_topics(). **kwargs (dict): Forward-compatibility kwargs. reconnect_min_timeout_secs (int): Minimum time to wait between reconnect attempts. Wait starts at min and doubles with each attempt until max is reached. reconnect_max_timeout_secs (int): Maximum time to wait between reconnect attempts. Wait starts at min and doubles with each attempt until max is reached. keep_alive_secs (int): The keep alive value, in seconds, to send in CONNECT packet. A PING will automatically be sent at this interval. The server will assume the connection is lost if no PING is received after 1.5X this value. This value must be higher than ping_timeout_ms. ping_timeout_ms (int): Milliseconds to wait for ping response before client assumes the connection is invalid and attempts to reconnect. This value must be less than keep_alive. Alternatively, TCP keep-alive may accomplish this in a more efficient (low-power) scenario, but keep-alive options may not work the same way on every platform and OS version. will (awscrt.mqtt.Will): Will to send with CONNECT packet. The will is published by the server when its connection to the client is unexpectedly lost. username (str): Username to connect with. password (str): Password to connect with. socket_options: awscrt.io.SocketOptions use_websocket: If true, connect to MQTT over websockets. websocket_proxy_options: optional awscrt.http.HttpProxyOptions for websocket connections. websocket_handshake_transform: optional function to transform websocket handshake request. If provided, function is called each time a websocket connection is attempted. The function may modify the request before it is sent to the server. See WebsocketHandshakeTransformArgs for more info. Function should take the following arguments and return nothing: transform_args (WebsocketHandshakeTransformArgs): Contains request to be transformed. Function must call transform_args.done() when complete. **kwargs (dict): Forward-compatibility kwargs. """ assert isinstance(client, Client) assert callable( on_connection_interrupted) or on_connection_interrupted is None assert callable(on_connection_resumed) or on_connection_resumed is None assert isinstance(will, Will) or will is None assert isinstance(socket_options, SocketOptions) or socket_options is None assert isinstance(websocket_proxy_options, HttpProxyOptions) or websocket_proxy_options is None assert callable(websocket_handshake_transform ) or websocket_handshake_transform is None super(Connection, self).__init__() # init-only self.client = client self._on_connection_interrupted_cb = on_connection_interrupted self._on_connection_resumed_cb = on_connection_resumed self._use_websockets = use_websockets self._ws_handshake_transform_cb = websocket_handshake_transform # may be changed at runtime, take effect the the next time connect/reconnect occurs self.client_id = client_id self.host_name = host_name self.port = port self.clean_session = clean_session self.keep_alive_secs = keep_alive_secs self.ping_timeout_ms = ping_timeout_ms self.will = will self.username = username self.password = password self.socket_options = socket_options if socket_options else SocketOptions( ) self.websocket_proxy_options = websocket_proxy_options # TODO: reconnect_min_timeout_secs & reconnect_max_timeout_secs currently unused self._binding = _awscrt.mqtt_client_connection_new( self, client, use_websockets, )