//****************************************************************************************************** // DataReceiver.cs - Gbtc // // Copyright © 2019, Grid Protection Alliance. All Rights Reserved. // // Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See // the NOTICE file distributed with this work for additional information regarding copyright ownership. // The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this // file except in compliance with the License. You may obtain a copy of the License at: // // http://opensource.org/licenses/MIT // // Unless agreed to in writing, the subject software distributed under the License is distributed on an // "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the // License for the specific language governing permissions and limitations. // // Code Modification History: // ---------------------------------------------------------------------------------------------------- // 02/11/2019 - J. Ritchie Carroll // Generated original version of source code. // //****************************************************************************************************** using GSF; using GSF.TimeSeries; using GSF.TimeSeries.Transport; using System; using System.Collections.Generic; namespace DataExtractor { /// /// Retrieves data from openHistorian using GEP /// internal sealed class DataReceiver : IDisposable { #region [ Members ] // Fields private DataSubscriber m_subscriber; private readonly UnsynchronizedSubscriptionInfo m_subscriptionInfo; private bool m_disposed; #endregion #region [ Constructors ] /// /// Creates a new instance with the specified . /// /// GEP connection string for openHistorian. /// Filter expression defining measurements to query. /// Temporal subscription start time. /// Temporal subscription stop time. public DataReceiver(string connectionString, string filterExpression, DateTime startTime, DateTime stopTime) { m_subscriber = new DataSubscriber { ConnectionString = connectionString, OperationalModes = OperationalModes.UseCommonSerializationFormat | OperationalModes.CompressPayloadData, CompressionModes = CompressionModes.TSSC }; m_subscriptionInfo = new UnsynchronizedSubscriptionInfo(false) { FilterExpression = filterExpression, StartTime = startTime.ToString(TimeTagBase.DefaultFormat), StopTime = stopTime.ToString(TimeTagBase.DefaultFormat), ProcessingInterval = 0, // Zero value requests data as fast as possible UseMillisecondResolution = true }; // Attach to needed subscriber events m_subscriber.ConnectionEstablished += m_subscriber_ConnectionEstablished; m_subscriber.NewMeasurements += m_subscriber_NewMeasurements; m_subscriber.StatusMessage += m_subscriber_StatusMessage; m_subscriber.ProcessException += m_subscriber_ProcessException; m_subscriber.ProcessingComplete += m_subscriber_ProcessingComplete; // Initialize the subscriber m_subscriber.Initialize(); // Start subscriber connection cycle m_subscriber.Start(); } /// /// Releases the unmanaged resources before the object is reclaimed by . /// ~DataReceiver() => Dispose(false); public Action> NewMeasurementsCallback { get; set; } public Action StatusMessageCallback { get; set; } public Action ProcessExceptionCallback { get; set; } public Action ReadCompletedCallback { get; set; } #endregion #region [ Methods ] /// /// Releases all the resources used by the object. /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// /// Releases the unmanaged resources used by the object and optionally releases the managed resources. /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. private void Dispose(bool disposing) { if (!m_disposed) { try { if (disposing) { if ((object)m_subscriber != null) { m_subscriber.Unsubscribe(); m_subscriber.Stop(); // Detach from subscriber events m_subscriber.ConnectionEstablished -= m_subscriber_ConnectionEstablished; m_subscriber.NewMeasurements -= m_subscriber_NewMeasurements; m_subscriber.StatusMessage -= m_subscriber_StatusMessage; m_subscriber.ProcessException -= m_subscriber_ProcessException; m_subscriber.ProcessingComplete -= m_subscriber_ProcessingComplete; m_subscriber.Dispose(); m_subscriber = null; } } } finally { m_disposed = true; // Prevent duplicate dispose. } } } private void m_subscriber_ConnectionEstablished(object sender, EventArgs e) => m_subscriber.UnsynchronizedSubscribe(m_subscriptionInfo); private void m_subscriber_NewMeasurements(object sender, EventArgs> e) => NewMeasurementsCallback?.Invoke(e.Argument); private void m_subscriber_StatusMessage(object sender, EventArgs e) => StatusMessageCallback?.Invoke(e.Argument); private void m_subscriber_ProcessException(object sender, EventArgs e) => ProcessExceptionCallback?.Invoke(e.Argument); private void m_subscriber_ProcessingComplete(object sender, EventArgs e) => ReadCompletedCallback?.Invoke(); #endregion } }