using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Timers; using Tango.Core; using Tango.Logging; namespace Tango.Transport { /// /// Represents an base class. /// /// public abstract class TransportAdapterBase : ExtendedObject, ITransportAdapter { protected long _totalBytes; protected static long _component_counter = 1; private long _transferRateTotalBytes; private Timer _transferRateTimer; protected const int MAX_BUFFER_SIZE = 1024; //10 MB. #region Events /// /// Occurs when component state changes. /// public event EventHandler StateChanged; /// /// Occurs when new data is available. /// public event EventHandler DataAvailable; #endregion #region Properties /// /// Gets or sets the name of the transport component. /// public String ComponentName { get; set; } = "Not Set"; private long _totalBytesReceived; /// /// Gets the total bytes received. /// public long TotalBytesReceived { get { return _totalBytesReceived; } protected set { _totalBytesReceived = value; RaisePropertyChanged(nameof(TotalBytesReceived)); } } private long _totalBytesSent; /// /// Gets the total bytes sent. /// public long TotalBytesSent { get { return _totalBytesSent; } protected set { _totalBytesSent = value; RaisePropertyChanged(nameof(TotalBytesSent)); } } private long _transferRate; /// /// Gets the adapter current transfer rate. /// public long TransferRate { get { return _transferRate; } protected set { _transferRate = value; RaisePropertyChanged(nameof(TransferRate)); } } private String _address; /// /// Gets or sets the channel address. /// public String Address { get { return _address; } set { _address = value; RaisePropertyChangedAuto(); } } /// /// Gets the last failed state exception/reason. /// public Exception FailedStateException { get; private set; } private TransportComponentState _state; /// /// Gets the component state. /// public TransportComponentState State { get { return _state; } protected set { if (_state != value) { _state = value; OnStateChanged(_state); } } } private bool _enableCompression; /// /// Gets or sets a value indicating whether to enable compression/decompression of data. /// public bool EnableCompression { get { return _enableCompression; } set { _enableCompression = value; RaisePropertyChangedAuto(); } } #endregion #region Virtual Methods /// /// Called when the adapter has failed. /// /// The ex. protected virtual void OnFailed(Exception ex) { FailedStateException = ex; LogManager.Log(ex, $"{ComponentName}: Adapter failed."); Disconnect().Wait(); State = TransportComponentState.Failed; } /// /// Called when there is new data available. /// /// The data. protected virtual void OnDataAvailable(byte[] data) { TotalBytesReceived += data.Length; _totalBytes += data.Length; AppendTransferRateBytes(data.Length); DataAvailable?.Invoke(this, data); } /// /// Called when the adapter state has changed. /// /// The state. protected virtual void OnStateChanged(TransportComponentState state) { StateChanged?.Invoke(this, state); if (state == TransportComponentState.Connected) { _totalBytes = 0; TransferRate = 0; if (_transferRateTimer != null) { _transferRateTimer.Stop(); _transferRateTimer.Dispose(); } _transferRateTimer = new Timer(1000); _transferRateTimer.Elapsed += _transferRateTimer_Elapsed; _transferRateTimer.Start(); } else { if (_transferRateTimer != null) { _transferRateTimer.Stop(); _transferRateTimer.Dispose(); } } } /// /// Throws an exception if adapter is in a failed or disposed state. /// protected virtual void ThrowIfDisposed() { if (State == TransportComponentState.Disposed) { throw LogManager.Log(new ObjectDisposedException($"{ComponentName}: The adapter is in a " + State + " state.")); } } /// /// Applies any additional headers if required. /// /// The data. /// protected virtual byte[] PostProcessBuffer(byte[] data) { byte[] postData = data; postData = BitConverter.GetBytes(data.Length).Concat(data).ToArray(); TotalBytesSent += postData.Length; _totalBytes += postData.Length; AppendTransferRateBytes(postData.Length); return postData; } #endregion #region Private Methods protected void AppendTransferRateBytes(long dataLength) { _transferRateTotalBytes += dataLength; } #endregion #region Dispose /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public virtual void Dispose() { Disconnect().Wait(); State = TransportComponentState.Disposed; } #endregion #region Abstract Methods /// /// Writes the specified data to the stream. /// /// The data. /// Writes the data as soon as possible while ignoring any message queuing and batching. public abstract void Write(byte[] data, bool immidiate = false); /// /// Connects the transport component. /// /// public abstract Task Connect(); /// /// Disconnects the transport component. /// /// public abstract Task Disconnect(); #endregion #region Override Methods /// /// Returns a that represents this instance. /// /// /// A that represents this instance. /// public override string ToString() { return this.GetType().Name; } #endregion #region Calculate Transfer Rate private void _transferRateTimer_Elapsed(object sender, ElapsedEventArgs e) { TransferRate = _transferRateTotalBytes; _transferRateTotalBytes = 0; } #endregion } }