using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace BestHTTP.Extensions
{
public interface IHeartbeat
{
void OnHeartbeatUpdate(TimeSpan dif);
}
///
/// A manager class that can handle subscribing and unsubscribeing in the same update.
///
public sealed class HeartbeatManager
{
private ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
private List Heartbeats = new List();
private IHeartbeat[] UpdateArray;
private DateTime LastUpdate = DateTime.MinValue;
public void Subscribe(IHeartbeat heartbeat)
{
rwLock.EnterWriteLock();
try
{
if (!Heartbeats.Contains(heartbeat))
Heartbeats.Add(heartbeat);
}
finally
{
rwLock.ExitWriteLock();
}
}
public void Unsubscribe(IHeartbeat heartbeat)
{
rwLock.EnterWriteLock();
try
{
Heartbeats.Remove(heartbeat);
}
finally
{
rwLock.ExitWriteLock();
}
}
public void Update()
{
if (LastUpdate == DateTime.MinValue)
LastUpdate = DateTime.UtcNow;
else
{
TimeSpan dif = DateTime.UtcNow - LastUpdate;
LastUpdate = DateTime.UtcNow;
int count = 0;
rwLock.EnterReadLock();
try
{
if (UpdateArray == null || UpdateArray.Length < Heartbeats.Count)
Array.Resize(ref UpdateArray, Heartbeats.Count);
Heartbeats.CopyTo(0, UpdateArray, 0, Heartbeats.Count);
count = Heartbeats.Count;
}
finally
{
rwLock.ExitReadLock();
}
for (int i = 0; i < count; ++i)
{
try
{
UpdateArray[i].OnHeartbeatUpdate(dif);
}
catch
{ }
}
}
}
public void Clear()
{
rwLock.EnterWriteLock();
try
{
Heartbeats.Clear();
}
finally
{
rwLock.ExitWriteLock();
}
}
}
}