61 lines
1.5 KiB
C#
61 lines
1.5 KiB
C#
using System;
|
|
using System.Threading;
|
|
|
|
namespace Laservall.Solidworks.Server
|
|
{
|
|
internal sealed class HeartbeatMonitor : IDisposable
|
|
{
|
|
private readonly TimeSpan _timeout;
|
|
private readonly Action _onTimeout;
|
|
private Timer _timer;
|
|
private long _lastPingTicks;
|
|
private bool _running;
|
|
private bool _disposed;
|
|
|
|
public HeartbeatMonitor(TimeSpan timeout, Action onTimeout)
|
|
{
|
|
_timeout = timeout;
|
|
_onTimeout = onTimeout;
|
|
}
|
|
|
|
public void Start()
|
|
{
|
|
_lastPingTicks = DateTime.UtcNow.Ticks;
|
|
_running = true;
|
|
_timer = new Timer(CheckTimeout, null, _timeout, _timeout);
|
|
}
|
|
|
|
public void Stop()
|
|
{
|
|
_running = false;
|
|
_timer?.Change(Timeout.Infinite, Timeout.Infinite);
|
|
}
|
|
|
|
public void Ping()
|
|
{
|
|
Interlocked.Exchange(ref _lastPingTicks, DateTime.UtcNow.Ticks);
|
|
}
|
|
|
|
private void CheckTimeout(object state)
|
|
{
|
|
if (!_running) return;
|
|
|
|
long lastPing = Interlocked.Read(ref _lastPingTicks);
|
|
var elapsed = TimeSpan.FromTicks(DateTime.UtcNow.Ticks - lastPing);
|
|
|
|
if (elapsed > _timeout)
|
|
{
|
|
_running = false;
|
|
_onTimeout?.Invoke();
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
if (_disposed) return;
|
|
_disposed = true;
|
|
_timer?.Dispose();
|
|
}
|
|
}
|
|
}
|