HeartbeatManager.cs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Threading;
  4. using Best.HTTP.Shared.Logger;
  5. using Best.HTTP.Shared.PlatformSupport.Threading;
  6. namespace Best.HTTP.Shared.Extensions
  7. {
  8. sealed class RunOnceOnMainThread : IHeartbeat
  9. {
  10. private Action _action;
  11. private int _subscribed;
  12. private LoggingContext _context;
  13. public RunOnceOnMainThread(Action action, LoggingContext context)
  14. {
  15. this._action = action;
  16. this._context = context;
  17. }
  18. public void Subscribe()
  19. {
  20. if (Interlocked.CompareExchange(ref this._subscribed, 1, 0) == 0)
  21. HTTPManager.Heartbeats.Subscribe(this);
  22. }
  23. public void OnHeartbeatUpdate(DateTime now, TimeSpan dif)
  24. {
  25. try
  26. {
  27. this._action?.Invoke();
  28. }
  29. catch (Exception ex)
  30. {
  31. HTTPManager.Logger.Exception(nameof(RunOnceOnMainThread.OnHeartbeatUpdate), $"{nameof(_action)}", ex, this._context);
  32. }
  33. finally
  34. {
  35. HTTPManager.Heartbeats.Unsubscribe(this);
  36. }
  37. }
  38. }
  39. public interface IHeartbeat
  40. {
  41. void OnHeartbeatUpdate(DateTime now, TimeSpan dif);
  42. }
  43. /// <summary>
  44. /// A manager class that can handle subscribing and unsubscribeing in the same update.
  45. /// </summary>
  46. public sealed class HeartbeatManager
  47. {
  48. private ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
  49. private List<IHeartbeat> Heartbeats = new List<IHeartbeat>();
  50. private IHeartbeat[] UpdateArray;
  51. private DateTime LastUpdate = DateTime.MinValue;
  52. public void Subscribe(IHeartbeat heartbeat)
  53. {
  54. using var _ = new WriteLock(rwLock);
  55. if (!Heartbeats.Contains(heartbeat))
  56. Heartbeats.Add(heartbeat);
  57. }
  58. public void Unsubscribe(IHeartbeat heartbeat)
  59. {
  60. using var _ = new WriteLock(rwLock);
  61. Heartbeats.Remove(heartbeat);
  62. }
  63. public void Update()
  64. {
  65. var now = HTTPManager.CurrentFrameDateTime;
  66. if (LastUpdate == DateTime.MinValue)
  67. LastUpdate = now;
  68. else
  69. {
  70. TimeSpan dif = now - LastUpdate;
  71. LastUpdate = now;
  72. int count = 0;
  73. using (var _ = new ReadLock(rwLock))
  74. {
  75. if (UpdateArray == null || UpdateArray.Length < Heartbeats.Count)
  76. Array.Resize(ref UpdateArray, Heartbeats.Count);
  77. Heartbeats.CopyTo(0, UpdateArray, 0, Heartbeats.Count);
  78. Array.Clear(UpdateArray, Heartbeats.Count, UpdateArray.Length - Heartbeats.Count);
  79. count = Heartbeats.Count;
  80. }
  81. for (int i = 0; i < count; ++i)
  82. {
  83. try
  84. {
  85. UpdateArray[i].OnHeartbeatUpdate(now, dif);
  86. }
  87. catch
  88. { }
  89. }
  90. }
  91. }
  92. public void Clear()
  93. {
  94. using var _ = new WriteLock(rwLock);
  95. Heartbeats.Clear();
  96. }
  97. }
  98. }