207 lines · 7.9 KB · C#
RawDownload
//******************************************************************************************************//  MetadataReceiver.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 System;using System.Data;using System.Threading;using GSF.TimeSeries.Transport;using ServerCommand = GSF.TimeSeries.Transport.ServerCommand; namespace GEPDataExtractor{    /// <summary>    /// Retrieves current meta-data from openHistorian using GEP    /// </summary>    internal sealed class MetadataRetriever : IDisposable    {        #region [ Members ]         // Fields        private DataSubscriber m_subscriber;        private DataSet m_metadata;        private Exception m_processException;        private ManualResetEventSlim m_waitHandle;        private bool m_disposed;         #endregion         #region [ Constructors ]         /// <summary>        /// Creates a new <see cref="MetadataRetriever"/> instance with the specified <paramref name="connectionString"/>.        /// </summary>        /// <param name="connectionString">GEP connection string for openHistorian.</param>        private MetadataRetriever(string connectionString)        {            m_subscriber = new DataSubscriber            {                ConnectionString = connectionString,                ReceiveInternalMetadata = true,                ReceiveExternalMetadata = true,                OperationalModes = OperationalModes.UseCommonSerializationFormat | OperationalModes.CompressMetadata,                CompressionModes = CompressionModes.GZip            };             // Attach to needed subscriber events            m_subscriber.ProcessException += m_subscriber_ProcessException;            m_subscriber.ConnectionEstablished += m_subscriber_ConnectionEstablished;            m_subscriber.MetaDataReceived += m_subscriber_MetaDataReceived;             // Initialize the subscriber            m_subscriber.Initialize();             // Create a wait handle to allow time to receive meta-data            m_waitHandle = new ManualResetEventSlim();             // Start subscriber connection cycle            m_subscriber.Start();        }         /// <summary>        /// Releases the unmanaged resources before the <see cref="MetadataRetriever"/> object is reclaimed by <see cref="GC"/>.        /// </summary>        ~MetadataRetriever()        {            Dispose(false);        }         #endregion         #region [ Methods ]         /// <summary>        /// Releases all the resources used by the <see cref="MetadataRetriever"/> object.        /// </summary>        public void Dispose()        {            Dispose(true);            GC.SuppressFinalize(this);        }         /// <summary>        /// Releases the unmanaged resources used by the <see cref="MetadataRetriever"/> object and optionally releases the managed resources.        /// </summary>        /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>        private void Dispose(bool disposing)        {            if (m_disposed)                return;             try            {                // This will be done regardless of whether the object is finalized or disposed.                 if (!disposing)                    return;                                if (!(m_subscriber is null))                {                    // Detach from subscriber events                    m_subscriber.ProcessException -= m_subscriber_ProcessException;                    m_subscriber.ConnectionEstablished -= m_subscriber_ConnectionEstablished;                    m_subscriber.MetaDataReceived -= m_subscriber_MetaDataReceived;                     m_subscriber.Dispose();                    m_subscriber = null;                }                 if (!(m_waitHandle is null))                {                    m_waitHandle.Set(); // Release any waiting threads                    m_waitHandle.Dispose();                    m_waitHandle = null;                }            }            finally            {                m_disposed = true; // Prevent duplicate dispose.            }        }         /// <summary>        /// Gets meta-data using GEP waiting no longer than specified <paramref name="timeout"/>.        /// </summary>        /// <param name="timeout">Specifies how long to wait, in milliseconds, for meta-data.</param>        /// <returns>The meta-data received from the GEP publisher in <see cref="DataSet"/> format.</returns>        private DataSet GetMetadata(int timeout)        {            // Wait for meta-data or an exception to occur for up to the specified maximum time, then time out with an exception            if (!m_waitHandle.Wait(timeout))                throw new TimeoutException($"Waited for {timeout / 1000.0D} seconds for meta-data, but none was received.");             // If meta-data was received, return it            if (!(m_metadata is null))                return m_metadata;             // If a processing exception occurred, re-throw it            if (!(m_processException is null))                throw new InvalidOperationException(m_processException.Message, m_processException);             // Otherwise return null (unlikely to ever get to this return)            return null;        }         private void m_subscriber_ConnectionEstablished(object sender, EventArgs e)        {            // Request meta-data upon successful connection            m_subscriber.SendServerCommand(ServerCommand.MetaDataRefresh);        }         private void m_subscriber_MetaDataReceived(object sender, GSF.EventArgs<DataSet> e)        {            m_metadata = e.Argument;             // Release waiting threads if meta-data received            m_waitHandle.Set();        }         private void m_subscriber_ProcessException(object sender, GSF.EventArgs<Exception> e)        {            m_processException = e.Argument;             // Release waiting threads if an error occurred            m_waitHandle.Set();        }         #endregion         #region [ Static ]         /// <summary>        /// Gets meta-data from the <paramref name="connectionString" /> waiting no longer than the specified <paramref name="timeout"/>.        /// </summary>        /// <param name="connectionString">GEP connection string.</param>        /// <param name="timeout">Specifies how long to wait, in milliseconds, for meta-data.</param>        /// <returns>The meta-data received from the GEP publisher in <see cref="DataSet"/> format.</returns>        public static DataSet GetMetadata(string connectionString, int timeout = Timeout.Infinite)        {            using (MetadataRetriever receiver = new MetadataRetriever(connectionString))            {                return receiver.GetMetadata(timeout);            }        }         #endregion    } }

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t