private async Task ProvideLinkConfigurationAsync(IOnPremiseConnectionContext onPremiseConnectionContext)
        {
            try
            {
                var config = _linkRepository.GetLinkConfiguration(onPremiseConnectionContext.LinkId);
                config.ApplyDefaults(_configuration);

                var requestId = Guid.NewGuid().ToString();

                _logger?.Debug("Sending configuration to OPC. connection-id={ConnectionId}, link-id={LinkId}, connector-version={ConnectorVersion}, link-configuration={@LinkConfiguration}, request-id={RequestId}", onPremiseConnectionContext.ConnectionId, onPremiseConnectionContext.LinkId, onPremiseConnectionContext.ConnectorVersion, config, requestId);

                var request = new OnPremiseConnectorRequest()
                {
                    HttpMethod         = "CONFIG",
                    Url                = String.Empty,
                    RequestStarted     = DateTime.UtcNow,
                    OriginId           = OriginId,
                    RequestId          = requestId,
                    AcknowledgmentMode = AcknowledgmentMode.Auto,
                    Body               = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(config)),
                };

                // configs, like heartbeats, do not go through the message dispatcher but directly to the connection
                await onPremiseConnectionContext.RequestAction(request, CancellationToken.None).ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                _logger?.Error(ex, "An error happened while sending the link config to the connected OPC.");
            }
        }
示例#2
0
        private async Task SendHeartbeatAsync(IOnPremiseConnectionContext connectionContext, CancellationToken token)
        {
            if (connectionContext == null)
            {
                throw new ArgumentNullException(nameof(connectionContext));
            }

            if (connectionContext.NextHeartbeat > DateTime.UtcNow)
            {
                return;
            }

            connectionContext.NextHeartbeat = DateTime.UtcNow.Add(_heartbeatInterval);

            try
            {
                _logger?.Verbose("Sending {PingMethod}. connection-id={ConnectionId}", connectionContext.SupportsHeartbeat ? "Heartbeat" : "Ping (as heartbeat)", connectionContext.ConnectionId);

                var requestId = Guid.NewGuid().ToString();
                var request   = new OnPremiseConnectorRequest()
                {
                    HttpMethod         = connectionContext.SupportsHeartbeat ? "HEARTBEAT" : "PING",
                    Url                = String.Empty,
                    RequestStarted     = DateTime.UtcNow,
                    OriginId           = _backendCommunication.OriginId,
                    RequestId          = requestId,
                    AcknowledgmentMode = AcknowledgmentMode.Auto,
                    HttpHeaders        = connectionContext.SupportsConfiguration ? null : new Dictionary <string, string> {
                        ["X-TTRELAY-HEARTBEATINTERVAL"] = _heartbeatInterval.TotalSeconds.ToString(CultureInfo.InvariantCulture)
                    },
                };

                // wait for the response of the Heartbeat / Ping
                var task = _backendCommunication.GetResponseAsync(requestId, _configuration.ActiveConnectionTimeout);

                // heartbeats do NOT go through the message dispatcher as we want to heartbeat the connections directly
                await connectionContext.RequestAction(request, token).ConfigureAwait(false);

                var response = await task.ConfigureAwait(false);

                if (response != null)
                {
                    await _backendCommunication.RenewLastActivityAsync(connectionContext.ConnectionId).ConfigureAwait(false);
                }
            }
            catch (Exception ex)
            {
                _logger?.Error(ex, "Error during sending heartbeat to a client. link-id={LinkId}, connection-id={ConnectionId}, connector-version={ConnectorVersion}", connectionContext.LinkId, connectionContext.ConnectionId, connectionContext.ConnectorVersion);
            }
        }
        public async Task RegisterOnPremiseAsync(IOnPremiseConnectionContext onPremiseConnectionContext)
        {
            CheckDisposed();

            _logger?.Debug("Registering link. link-id={LinkId}, connection-id={ConnectionId}, user-name={UserName}, role={Role} connector-version={ConnectorVersion}, connector-assembly-version={ConnectorAssemblyVersion}",
                           onPremiseConnectionContext.LinkId,
                           onPremiseConnectionContext.ConnectionId,
                           onPremiseConnectionContext.UserName,
                           onPremiseConnectionContext.Role,
                           onPremiseConnectionContext.ConnectorVersion,
                           onPremiseConnectionContext.ConnectorAssemblyVersion);

            await _linkRepository.AddOrRenewActiveConnectionAsync(onPremiseConnectionContext.LinkId, OriginId, onPremiseConnectionContext.ConnectionId, onPremiseConnectionContext.ConnectorVersion, onPremiseConnectionContext.ConnectorAssemblyVersion).ConfigureAwait(false);

            lock (_requestSubscriptions)
            {
                if (!_requestSubscriptions.ContainsKey(onPremiseConnectionContext.ConnectionId))
                {
                    _requestSubscriptions[onPremiseConnectionContext.ConnectionId] = _messageDispatcher.OnRequestReceived(onPremiseConnectionContext.LinkId, onPremiseConnectionContext.ConnectionId, !onPremiseConnectionContext.SupportsAck)
                                                                                     .Subscribe(request => onPremiseConnectionContext.RequestAction(request, _cancellationToken));

                    onPremiseConnectionContext.IsActive = true;
                }
            }

            _connectionContexts.TryAdd(onPremiseConnectionContext.ConnectionId, onPremiseConnectionContext);

            if (onPremiseConnectionContext.SupportsConfiguration)
            {
                await ProvideLinkConfigurationAsync(onPremiseConnectionContext).ConfigureAwait(false);
            }
        }