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)
Ejemplo n.º 2
0
    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
Ejemplo n.º 3
0
 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
Ejemplo n.º 4
0
    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
Ejemplo n.º 5
0
    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,
        )
Ejemplo n.º 6
0
    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
Ejemplo n.º 7
0
    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
Ejemplo n.º 8
0
    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,
        )