Пример #1
0
        /// <summary>
        /// Adds tags to the subscription.
        /// </summary>
        /// <param name="identity">The identity of the caller.</param>
        /// <param name="tagNames">The tags to subscribe to.</param>
        /// <param name="cancellationToken">The cancellation token for the request.</param>
        /// <returns>
        /// A task that will add the tag subscriptions.
        /// </returns>
        /// <exception cref="ObjectDisposedException">The object has been disposed.</exception>
        /// <exception cref="ArgumentNullException"><paramref name="identity"/> is <see langword="null"/>.</exception>
        /// <exception cref="ArgumentException"><paramref name="tagNames"/> does not contain any non-null-or-empty entries.</exception>
        public async Task AddTags(ClaimsPrincipal identity, IEnumerable <string> tagNames, CancellationToken cancellationToken)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException(GetType().FullName);
            }

            if (identity == null)
            {
                throw new ArgumentNullException(nameof(identity));
            }

            var distinctTagNames = tagNames?.Where(x => !String.IsNullOrWhiteSpace(x))
                                   .Select(x => x.Trim())
                                   .Distinct(StringComparer.OrdinalIgnoreCase)
                                   .ToArray();

            if (distinctTagNames?.Length == 0)
            {
                throw new ArgumentException(Resources.Error_AtLeastOneTagNameRequired, nameof(tagNames));
            }

            var tags = await _historian.GetTags(identity, distinctTagNames, cancellationToken).ConfigureAwait(false);

            foreach (var item in tags.Values)
            {
                if (!_subscribedTags.TryAdd(item.Id, item))
                {
                    continue;
                }

                Action <TagValue> onValueReceived = value => {
                    if (_isDisposed)
                    {
                        return;
                    }

                    ValuesReceived?.Invoke(new Dictionary <string, IEnumerable <TagValue> >(StringComparer.OrdinalIgnoreCase)
                    {
                        { item.Name, new [] { value } }
                    });
                };

                _subscriptions[item.Id] = item.CreateSnapshotSubscription(onValueReceived);

                var snapshot = item.ReadSnapshotValue(identity);
                if (snapshot != null)
                {
                    onValueReceived.Invoke(snapshot);
                }

                item.Deleted += UnsubscribeTag;
            }
        }
Пример #2
0
        /// <summary>
        /// Starts the SignalR connection.
        /// </summary>
        /// <param name="cancellationToken">The cancellation token for the request.</param>
        /// <returns>
        /// A task that will start the connection.
        /// </returns>
        public async Task Start(CancellationToken cancellationToken)
        {
            if (IsConnected)
            {
                return;
            }

            await Stop(cancellationToken).ConfigureAwait(false);

            var connectionBuilder = new HubConnectionBuilder().WithJsonProtocol();

            connectionBuilder.WithMessageHandler(_client.MessageHandler);
            if (_loggerFactory != null)
            {
                connectionBuilder.WithLoggerFactory(_loggerFactory);
            }

            // If the API client has an Authorization header configured, we'll grab the token and pass
            // it as a query string parameter to SignalR, since we cannot pass authorization headers
            // to the websocket.
            if (_client.Authorization != null)
            {
                connectionBuilder.WithUrl($"{_client.HttpClient.BaseAddress}/hubs/snapshot?token={Uri.EscapeDataString(_client.Authorization.Parameter)}");
            }
            else
            {
                connectionBuilder.WithUrl($"{_client.HttpClient.BaseAddress}/hubs/snapshot");
            }

            _hubConnection = connectionBuilder.WithMessagePackProtocol().Build();

            _hubConnection.Connected += () => {
                IsConnected = true;
                if (_logger?.IsEnabled(LogLevel.Information) ?? false)
                {
                    _logger.LogInformation("Connected to SignalR hub.");
                }

                return(Task.CompletedTask);
            };
            _hubConnection.Connected += () => Connected != null?Connected.Invoke() : Task.CompletedTask;

            _hubConnection.Closed += ex => {
                IsConnected = false;
                if (ex != null)
                {
                    _logger?.LogError("Disconnected from SignalR hub due to an exception.", ex);
                }
                else
                {
                    if (_logger?.IsEnabled(LogLevel.Information) ?? false)
                    {
                        _logger.LogInformation("Disconnected from SignalR hub.");
                    }
                }
                return(Task.CompletedTask);
            };
            _hubConnection.Closed += ex => Closed != null?Closed.Invoke(ex) : Task.CompletedTask;

            _hubConnection.On <IDictionary <string, TagValueDto[]> >("ValuesReceived", x => {
                if (x?.Count == 0)
                {
                    return;
                }

                // Invoke ValuesReceived in a background task so that we don't block the websocket
                // input stream while the handlers are executing.
                Task.Run(() => {
                    if (_logger?.IsEnabled(LogLevel.Trace) ?? false)
                    {
                        _logger.LogTrace($"Received {x.Sum(tag => tag.Value?.Length ?? 0)} values for {x.Count} tags.");
                    }
                    ValuesReceived?.Invoke(x);
                });
            });

            if (_logger?.IsEnabled(LogLevel.Information) ?? false)
            {
                _logger.LogInformation("Connecting to SignalR hub.");
            }
            await Task.WhenAny(_hubConnection.StartAsync(), Task.Delay(-1, cancellationToken)).ConfigureAwait(false);

            cancellationToken.ThrowIfCancellationRequested();
        }