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
}
}