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; 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 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)); } } /// /// Gets or sets the channel address. /// public String Address { get; set; } private TransportComponentState _state; /// /// Gets the component state. /// public TransportComponentState State { get { return _state; } protected set { _state = value; OnStateChanged(_state); } } #endregion #region Virtual Methods /// /// Called when the adapter has failed. /// /// The ex. protected virtual void OnFailed(Exception ex) { Disconnect().Wait(); State = TransportComponentState.Failed; LogManager.Log(ex, "Adapter 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("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 private 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. public abstract void Write(byte[] data); /// /// 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 } }