using System;
using System.Collections.Generic;
using GSF;
using GSF.TimeSeries;
using GSF.TimeSeries.Transport;
namespace GEPDataExtractor
{
///
/// 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)
return;
try
{
if (!disposing)
return;
if (m_subscriber is null)
return;
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
}
}