Пример #1
0
        /// <summary>
        /// Gets the instantaneous snapshot value for the tag.
        /// </summary>
        /// <param name="identity">The identity of the caller.</param>
        /// <returns>
        /// The snapshot tag value.
        /// </returns>
        /// <exception cref="ObjectDisposedException">The historian has been disposed.</exception>
        public TagValue ReadSnapshotValue(ClaimsPrincipal identity)
        {
            _historian.ThrowIfDisposed();

            if (!this.CanRead(identity))
            {
                return(TagValue.CreateUnauthorizedTagValue(DateTime.MinValue));
            }

            return(_snapshotValue);
        }
Пример #2
0
 /// <summary>
 /// Updates the snapshot value for the tag.  You do not need to call this method from your
 /// implementation unless you have disabled writing of new tag values from Aika (e.g. if
 /// you are integrating with an existing historian and do not want to allow writes via Aika).
 /// </summary>
 /// <param name="value">The updated value.</param>
 /// <exception cref="ArgumentNullException"><paramref name="value"/> is <see langword="null"/>.</exception>
 protected void UpdateSnapshotValue(TagValue value)
 {
     _historian.ThrowIfDisposed();
     _snapshotValue = value ?? throw new ArgumentNullException(nameof(value));
     DataFilter.ValueReceived(value);
     _historian.TaskRunner.RunBackgroundTask(ct => SaveSnapshotValue(value, ct));
     foreach (var subscriber in _snapshotSubscriptions.Keys)
     {
         try {
             subscriber.OnValueChange(value);
         }
         catch (Exception e) {
             _logger?.LogError("An error occurred while notifying a snapshot subscriber of a change.", e);
         }
     }
 }
Пример #3
0
        /// <summary>
        /// Attempts to validate an incoming tag value.
        /// </summary>
        /// <param name="tag">The tag that the value is for.</param>
        /// <param name="incoming">The incoming tag value.</param>
        /// <param name="stateSet">
        ///   The state set for the tag.  Can be <see langword="null"/> when the tag's data type is not
        ///   <see cref="TagDataType.State"/>.
        /// </param>
        /// <param name="validatedValue">The validated tag value.</param>
        /// <returns>
        /// <see langword="true"/> if the value could be validated, or <see langword="false"/> otherwise.
        /// When the result is <see langword="false"/>, <paramref name="validatedValue"/> will be
        /// <see langword="null"/>.
        /// </returns>
        internal static bool TryValidateIncomingTagValue(this TagDefinition tag, TagValue incoming, StateSet stateSet, out TagValue validatedValue)
        {
            if (tag == null)
            {
                throw new ArgumentNullException(nameof(tag));
            }
            if (incoming == null)
            {
                throw new ArgumentNullException(nameof(incoming));
            }

            bool result;

            switch (tag.DataType)
            {
            case TagDataType.FloatingPoint:
                result = TryValidateDoubleValue(tag, incoming, out validatedValue);
                break;

            case TagDataType.Integer:
                result = TryValidateInt32Value(tag, incoming, out validatedValue);
                break;

            case TagDataType.Text:
                result = TryValidateStringValue(tag, incoming, out validatedValue);
                break;

            case TagDataType.State:
                result = TryValidateStateValue(tag, incoming, stateSet, out validatedValue);
                break;

            default:
                validatedValue = null;
                result         = false;
                break;
            }

            return(result);
        }
Пример #4
0
 /// <summary>
 /// Sends a value change to the subscriber.
 /// </summary>
 /// <param name="value">The new value.</param>
 internal void OnValueChange(TagValue value)
 {
     _onValueChange?.Invoke(value);
 }
Пример #5
0
 /// <summary>
 /// When implemented in a derived type, saves a new snapshot value to the back-end historian.
 /// </summary>
 /// <param name="value">The new snapshot value for the tag.</param>
 /// <param name="cancellationToken">The cancellation token for the request.</param>
 /// <returns>
 /// A task that will save the new snapshot value.
 /// </returns>
 protected abstract Task SaveSnapshotValue(TagValue value, CancellationToken cancellationToken);
Пример #6
0
        /// <summary>
        /// Creates a new <see cref="TagDefinition"/> object.
        /// </summary>
        /// <param name="historian">The <see cref="IHistorian"/> instance that the tag belongs to.</param>
        /// <param name="id">The tag ID.  If <see langword="null"/>, a new tag ID will ge generated automatically.</param>
        /// <param name="settings">The tag settings.</param>
        /// <param name="metadata">The tag metadata.</param>
        /// <param name="security">The tag security settings.</param>
        /// <param name="initialTagValues">The initial values to configure the tag's exception and compression filters with.</param>
        /// <param name="changeHistory">The change history for the tag.</param>
        /// <exception cref="ArgumentNullException"><paramref name="historian"/> is <see langword="null"/>.</exception>
        /// <exception cref="ArgumentNullException"><paramref name="settings"/> is <see langword="null"/>.</exception>
        /// <exception cref="ArgumentNullException"><paramref name="metadata"/> is <see langword="null"/>.</exception>
        /// <exception cref="ArgumentNullException"><paramref name="security"/> is <see langword="null"/>.</exception>
        /// <exception cref="ValidationException"><paramref name="settings"/> is not valid.</exception>
        protected TagDefinition(HistorianBase historian, string id, TagSettings settings, TagMetadata metadata, TagSecurity security, InitialTagValues initialTagValues, IEnumerable <TagChangeHistoryEntry> changeHistory)
        {
            _historian = historian ?? throw new ArgumentNullException(nameof(historian));
            _historian.ThrowIfDisposed();
            _logger = _historian.LoggerFactory?.CreateLogger <TagDefinition>();

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

            Validator.ValidateObject(settings, new ValidationContext(settings), true);

            Id          = id ?? CreateTagId();
            Name        = settings.Name;
            Description = settings.Description;
            Units       = settings.Units;
            DataType    = settings.DataType;
            StateSet    = settings.StateSet;
            Metadata    = metadata ?? throw new ArgumentNullException(nameof(metadata));
            Security    = security ?? throw new ArgumentNullException(nameof(security));
            var exceptionFilterSettings   = settings.ExceptionFilterSettings?.ToTagValueFilterSettings() ?? new TagValueFilterSettings(false, TagValueFilterDeviationType.Absolute, 0, TimeSpan.FromDays(1));
            var compressionFilterSettings = settings.CompressionFilterSettings?.ToTagValueFilterSettings() ?? new TagValueFilterSettings(false, TagValueFilterDeviationType.Absolute, 0, TimeSpan.FromDays(1));

            if (changeHistory != null)
            {
                _changeHistory.AddRange(changeHistory);
            }

            _snapshotValue   = initialTagValues?.SnapshotValue;
            DataFilter       = new DataFilter(Name, new ExceptionFilterState(exceptionFilterSettings, _snapshotValue), new CompressionFilterState(compressionFilterSettings, initialTagValues?.LastArchivedValue, initialTagValues?.LastExceptionValue, initialTagValues?.CompressionAngleMinimum ?? Double.NaN, initialTagValues?.CompressionAngleMaximum ?? Double.NaN), _historian.LoggerFactory);
            DataFilter.Emit += (values, nextArchiveCandidate) => {
                if (values.Length > 0 && _logger.IsEnabled(LogLevel.Trace))
                {
                    _logger.LogTrace($"[{Name}] Archiving {values.Count()} values emitted by the compression filter.");
                }

                _pendingArchiveWrites.Enqueue(new PendingArchiveWrite()
                {
                    ArchiveValues = values, NextArchiveCandidate = nextArchiveCandidate
                });

                _historian.TaskRunner.RunBackgroundTask(async ct => {
                    if (Interlocked.CompareExchange(ref _archiveLock, 1, 0) != 0)
                    {
                        return;
                    }

                    try {
                        while (!ct.IsCancellationRequested && _pendingArchiveWrites.TryDequeue(out var item))
                        {
                            await InsertArchiveValuesInternal(ClaimsPrincipal.Current, item.ArchiveValues, item.NextArchiveCandidate, false, ct).ConfigureAwait(false);
                        }
                    }
                    catch (OperationCanceledException) {
                        // App is shutting down...
                    }
                    catch (Exception e) {
                        _logger?.LogError($"[{Name}] An error occurred while archiving values emitted by the compression filter.", e);
                    }
                    finally {
                        _archiveLock = 0;
                    }
                });
            };
        }
Пример #7
0
 /// <summary>
 /// Creates a new <see cref="ArchiveCandidateValue"/> object.
 /// </summary>
 /// <param name="value">The tag value.</param>
 /// <param name="compressionAngleMinimum">
 ///   The minimum compression angle value that was calculated when the <paramref name="value"/>
 ///   was received by the tag's compression filter.
 /// </param>
 /// <param name="compressionAngleMaximum">
 ///   The minimum compression angle value that was calculated when the <paramref name="value"/>
 ///   was received by the tag's compression filter.
 /// </param>
 public ArchiveCandidateValue(TagValue value, double compressionAngleMinimum, double compressionAngleMaximum)
 {
     Value = value;
     CompressionAngleMinimum = compressionAngleMinimum;
     CompressionAngleMaximum = compressionAngleMaximum;
 }
Пример #8
0
        /// <summary>
        /// Attempts to validate an incoming integer tag value.
        /// </summary>
        /// <param name="tag">The tag for the value.</param>
        /// <param name="originalValue">The incoming value.</param>
        /// <param name="validatedValue">The validated value.</param>
        /// <returns>
        /// A flag that indicates if the value was validated.
        /// </returns>
        private static bool TryValidateInt32Value(TagDefinition tag, TagValue originalValue, out TagValue validatedValue)
        {
            var intValue = (int)originalValue.NumericValue;

            validatedValue = new TagValue(originalValue.UtcSampleTime, intValue, Convert.ToString(intValue, CultureInfo.InvariantCulture), originalValue.Quality, tag.Units);
            return(true);
        }
Пример #9
0
        /// <summary>
        /// Attempts to validate an incoming floating-point tag value.
        /// </summary>
        /// <param name="tag">The tag for the value.</param>
        /// <param name="originalValue">The incoming value.</param>
        /// <param name="stateSet">The state set for the <paramref name="tag"/>.</param>
        /// <param name="validatedValue">The validated value.</param>
        /// <returns>
        /// A flag that indicates if the value was validated.  If <paramref name="stateSet"/>
        /// is <see langword="null"/>, or if it does not match the name specified in the
        /// <see cref="TagDefinition.StateSet"/> property of the <paramref name="tag"/>, the
        /// result will be <see langword="false"/>.
        /// </returns>
        private static bool TryValidateStateValue(TagDefinition tag, TagValue originalValue, StateSet stateSet, out TagValue validatedValue)
        {
            if (stateSet == null || !stateSet.Name.Equals(tag.StateSet, StringComparison.OrdinalIgnoreCase))
            {
                validatedValue = null;
                return(false);
            }

            StateSetItem state = null;

            if (!String.IsNullOrWhiteSpace(originalValue.TextValue))
            {
                state = stateSet[originalValue.TextValue];
            }

            if (state == null)
            {
                var valAsInt = (int)originalValue.NumericValue;
                state = stateSet.States.FirstOrDefault(x => x.Value == valAsInt);
            }

            if (state == null)
            {
                validatedValue = null;
                return(false);
            }

            validatedValue = new TagValue(originalValue.UtcSampleTime, state.Value, state.Name, originalValue.Quality, null);
            return(true);
        }
Пример #10
0
 /// <summary>
 /// Attempts to validate an incoming string tag value.
 /// </summary>
 /// <param name="tag">The tag for the value.</param>
 /// <param name="originalValue">The incoming value.</param>
 /// <param name="validatedValue">The validated value.</param>
 /// <returns>
 /// A flag that indicates if the value was validated.
 /// </returns>
 private static bool TryValidateStringValue(TagDefinition tag, TagValue originalValue, out TagValue validatedValue)
 {
     validatedValue = new TagValue(originalValue.UtcSampleTime, Double.NaN, originalValue.TextValue, originalValue.Quality, null);
     return(true);
 }