Ejemplo n.º 1
0
        /// <summary>
        /// Notify about new connectivity state using any status callback registered.
        /// </summary>
        /// <param name="state"></param>
        /// <returns></returns>
        private async Task NotifyConnectivityStateChangeAsync(EndpointConnectivityState state)
        {
            var previous = _lastState;

            if (previous == state)
            {
                return;
            }
            if (previous != EndpointConnectivityState.Connecting &&
                previous != EndpointConnectivityState.Ready &&
                state == EndpointConnectivityState.Error)
            {
                // Do not change state to generic error once we have
                // a specific error state already set...
                _logger.Debug(
                    "{session}: Error, but leaving {url} via {endpoint} state at {previous}.",
                    _sessionId, _endpoint.Url, _endpointUrl, previous);
                return;
            }
            _lastState = state;
            _logger.Information(
                "{session}: Endpoint {url} via {endpoint} changed from {previous} to {state}",
                _sessionId, _endpoint.Url, _endpointUrl, previous, state);
            try {
                await _statusCb?.Invoke(_endpoint, state);
            }
            catch (Exception ex) {
                _logger.Error(ex, "{session}: Exception during state callback", _sessionId);
            }
        }
Ejemplo n.º 2
0
        internal static string ToSerializedValue(this EndpointConnectivityState value)
        {
            switch (value)
            {
            case EndpointConnectivityState.Connecting:
                return("Connecting");

            case EndpointConnectivityState.NotReachable:
                return("NotReachable");

            case EndpointConnectivityState.Busy:
                return("Busy");

            case EndpointConnectivityState.NoTrust:
                return("NoTrust");

            case EndpointConnectivityState.CertificateInvalid:
                return("CertificateInvalid");

            case EndpointConnectivityState.Ready:
                return("Ready");

            case EndpointConnectivityState.Error:
                return("Error");
            }
            return(null);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Notify about session/endpoint state changes
        /// </summary>
        /// <param name="ep"></param>
        /// <param name="state"></param>
        /// <returns></returns>
        private Task NotifyStateChangeAsync(EndpointModel ep, EndpointConnectivityState state)
        {
            var id = new EndpointIdentifier(ep);

            if (_callbacks.TryGetValue(id, out var cb))
            {
                return(cb(state));
            }
            return(Task.CompletedTask);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Notify about session/endpoint state changes
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="state"></param>
        /// <returns></returns>
        private Task NotifyStateChangeAsync(ConnectionModel connection,
                                            EndpointConnectivityState state)
        {
            var id = new ConnectionIdentifier(connection);

            if (_callbacks.TryGetValue(id, out var list))
            {
                lock (list) {
                    if (list.Count > 0)
                    {
                        return(Task.WhenAll(list.Select(cb => cb.Callback.Invoke(state)))
                               .ContinueWith(_ => Task.CompletedTask));
                    }
                }
            }
            return(Task.CompletedTask);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Notify about new connectivity state using any status callback registered.
        /// </summary>
        /// <param name="state"></param>
        /// <returns></returns>
        private async Task NotifyConnectivityStateChangeAsync(EndpointConnectivityState state)
        {
            var previous = _lastState;

            if (previous == state)
            {
                return;
            }
            if (previous != EndpointConnectivityState.Connecting &&
                previous != EndpointConnectivityState.Ready &&
                state == EndpointConnectivityState.Error)
            {
                // Do not change state to generic error once we have
                // a specific error state already set...
                _logger.Debug(
                    "Error, connection to {endpoint} - leaving state at {previous}.",
                    _endpointUrl, previous);
                return;
            }

            _lastState = state;
            _logger.Information(
                "Connecting to {endpoint} changed from {previous} to {state}",
                _endpointUrl, previous, state);
            try {
                await _statusCb?.Invoke(_connection, state);
            }
            catch (Exception ex) {
                _logger.Error(ex, "Exception during state callback");
            }

            if (state == EndpointConnectivityState.Ready)
            {
                // Notify waiting threads that a session is ready
                _acquired.TrySetResult(_session);
            }
            else
            {
                // Keep any thread waiting
                if (_acquired.Task.IsCompleted)
                {
                    _acquired = new TaskCompletionSource <Session>();
                }
            }
        }
Ejemplo n.º 6
0
        /// <inheritdoc/>
        public async Task SetEndpointAsync(EndpointModel endpoint)
        {
            await _lock.WaitAsync();

            try {
                var previous = _endpoint.Task.IsCompleted ? _endpoint.Task.Result : null;
                if (!endpoint.IsSameAs(previous))
                {
                    _logger.Debug(
                        "Updating twin {device} endpoint from {previous} to {endpoint}...",
                        _events?.DeviceId, previous?.Url, endpoint?.Url);

                    if (_endpoint.Task.IsCompleted)
                    {
                        _endpoint = new TaskCompletionSource <EndpointModel>();
                    }

                    // Unregister old endpoint
                    if (previous != null)
                    {
                        _callback?.Dispose();
                        _callback = null;
                        _session?.Dispose();
                        _session = null;

                        // Clear state
                        State = EndpointConnectivityState.Disconnected;
                    }

                    // Register callback to report endpoint state property
                    if (endpoint != null)
                    {
                        var connection = new ConnectionModel {
                            Endpoint = endpoint
                        };
                        _session = _client.GetSessionHandle(connection);

                        // Set initial state
                        State = _session.State;

                        // update reported state
                        _callback = _client.RegisterCallback(connection,
                                                             state => {
                            State = state;
                            return(_events?.ReportAsync("State",
                                                        state));
                        });
                        _logger.Information("Endpoint {endpoint} ({device}, {module}) updated.",
                                            endpoint?.Url, _events.DeviceId, _events.ModuleId);

                        // ready to use
                        _endpoint.TrySetResult(endpoint);
                    }

                    _logger.Information("Twin {device} endpoint updated to {endpoint}.",
                                        _events?.DeviceId, endpoint?.Url);
                }
            }
            finally {
                _lock.Release();
            }
        }