Files
ChunilENG/Packages/com.tivadar.best.http/Runtime/Shared/Extensions/Timer.cs
정영민 2dd5d814a7 update
2025-02-20 09:59:37 +09:00

117 lines
3.8 KiB
C#

using System;
using System.Collections.Generic;
using System.Threading;
using Best.HTTP.Shared;
using Best.HTTP.Shared.PlatformSupport.Threading;
namespace Best.HTTP.Shared.Extensions
{
public readonly struct TimerData
{
public readonly DateTime Created;
public readonly TimeSpan Interval;
public readonly object Context;
public readonly Func<DateTime, object, bool> OnTimer;
public bool IsOnTime(DateTime now)
{
return now >= this.Created + this.Interval;
}
public TimerData(TimeSpan interval, object context, Func<DateTime, object, bool> onTimer)
{
this.Created = DateTime.Now;
this.Interval = interval;
this.Context = context;
this.OnTimer = onTimer;
}
/// <summary>
/// Create a new TimerData but the Created field will be set to the current time.
/// </summary>
public TimerData CreateNew()
{
return new TimerData(this.Interval, this.Context, this.OnTimer);
}
public override string ToString()
{
return string.Format("[TimerData Created: {0}, Interval: {1}, IsOnTime: {2}]", this.Created.ToString(System.Globalization.CultureInfo.InvariantCulture), this.Interval, this.IsOnTime(DateTime.Now));
}
}
public static class Timer
{
private static List<TimerData> _timers = new List<TimerData>(1);
private static ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
private static int _isSubscribed;
#if UNITY_EDITOR
[UnityEngine.RuntimeInitializeOnLoadMethod(UnityEngine.RuntimeInitializeLoadType.SubsystemRegistration)]
public static void ResetSetup()
{
HTTPManager.Logger.Information(nameof(Timer), "Reset called!");
Interlocked.Exchange(ref _isSubscribed, 0);
}
#endif
public static void Add(TimerData timer)
{
using (var _ = new WriteLock(_lock))
_timers.Add(timer);
if (Interlocked.CompareExchange(ref _isSubscribed, 1, 0) == 0)
{
HTTPManager.Logger.Information(nameof(Timer), "Subscribing timer to heartbeats!");
HTTPManager.Heartbeats.Subscribe(new TimerImplementation());
}
}
private sealed class TimerImplementation : IHeartbeat
{
public void OnHeartbeatUpdate(DateTime now, TimeSpan dif)
{
using var __ = new Unity.Profiling.ProfilerMarker(nameof(Timer)).Auto();
using (var _ = new WriteLock(_lock))
{
if (_timers.Count == 0)
{
HTTPManager.Heartbeats.Unsubscribe(this);
Interlocked.Exchange(ref _isSubscribed, 0);
HTTPManager.Logger.Information(nameof(Timer), "Unsubscribing timer from heartbeats!");
return;
}
for (int i = 0; i < _timers.Count; ++i)
{
TimerData timer = _timers[i];
if (timer.IsOnTime(now))
{
try
{
bool repeat = timer.OnTimer(now, timer.Context);
if (repeat)
_timers[i] = timer.CreateNew();
else
_timers.RemoveAt(i--);
}
catch (Exception ex)
{
HTTPManager.Logger.Exception(nameof(Timer), "OnTimer", ex);
}
}
}
}
}
}
}
}