PageRenderTime 44ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/PushSharp.Common/PushChannelBase.cs

https://github.com/mustafagenc/PushSharp
C# | 144 lines | 103 code | 29 blank | 12 comment | 15 complexity | 3ad4e1562669b7fb024a3b28290e16e4 MD5 | raw file
Possible License(s): Apache-2.0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Collections.Concurrent;
  4. using System.Security.Cryptography.X509Certificates;
  5. using System.Linq;
  6. using System.Net.Sockets;
  7. using System.Net.Security;
  8. using System.Text;
  9. using System.Threading;
  10. using System.Threading.Tasks;
  11. using System.Net;
  12. namespace PushSharp.Common
  13. {
  14. public abstract class PushChannelBase : IDisposable
  15. {
  16. public ChannelEvents Events = new ChannelEvents();
  17. public PushChannelSettings ChannelSettings { get; private set; }
  18. public PushServiceSettings ServiceSettings { get; private set; }
  19. internal event Action<double> OnQueueTimed;
  20. object queuedNotificationsLock = new object();
  21. ConcurrentQueue<Notification> queuedNotifications;
  22. ManualResetEventSlim waitQueuedNotification;
  23. protected bool stopping;
  24. protected Task taskSender;
  25. protected CancellationTokenSource CancelTokenSource;
  26. protected CancellationToken CancelToken;
  27. protected abstract void SendNotification(Notification notification);
  28. public abstract PlatformType PlatformType { get; }
  29. public PushChannelBase(PushChannelSettings channelSettings, PushServiceSettings serviceSettings = null)
  30. {
  31. this.stopping = false;
  32. this.CancelTokenSource = new CancellationTokenSource();
  33. this.CancelToken = CancelTokenSource.Token;
  34. this.queuedNotifications = new ConcurrentQueue<Notification>();
  35. this.ChannelSettings = channelSettings;
  36. this.ServiceSettings = serviceSettings ?? new PushServiceSettings();
  37. this.waitQueuedNotification = new ManualResetEventSlim();
  38. //Start our sending task
  39. taskSender = new Task(() => Sender(), TaskCreationOptions.LongRunning);
  40. taskSender.ContinueWith((t) => { var ex = t.Exception; }, TaskContinuationOptions.OnlyOnFaulted);
  41. taskSender.Start();
  42. }
  43. public virtual void Stop(bool waitForQueueToDrain)
  44. {
  45. stopping = true;
  46. if (waitQueuedNotification != null)
  47. waitQueuedNotification.Set();
  48. //See if we want to wait for the queue to drain before stopping
  49. if (waitForQueueToDrain)
  50. {
  51. while (QueuedNotificationCount > 0)
  52. Thread.Sleep(50);
  53. }
  54. //Sleep a bit to prevent any race conditions
  55. Thread.Sleep(2000);
  56. if (!CancelTokenSource.IsCancellationRequested)
  57. CancelTokenSource.Cancel();
  58. //Wait on our tasks for a maximum of 30 seconds
  59. Task.WaitAll(new Task[] { taskSender }, 30000);
  60. }
  61. public virtual void Dispose()
  62. {
  63. //Stop without waiting
  64. if (!stopping)
  65. Stop(false);
  66. }
  67. public int QueuedNotificationCount
  68. {
  69. get { return queuedNotifications.Count; }
  70. }
  71. public void QueueNotification(Notification notification, bool countsAsRequeue = true)
  72. {
  73. if (this.CancelToken.IsCancellationRequested)
  74. {
  75. Events.RaiseChannelException(new ObjectDisposedException("Channel", "Channel has already been signaled to stop"), this.PlatformType, notification);
  76. return;
  77. }
  78. //If the count is -1, it can be queued infinitely, otherwise check that it's less than the max
  79. if (this.ServiceSettings.MaxNotificationRequeues < 0 || notification.QueuedCount <= this.ServiceSettings.MaxNotificationRequeues)
  80. {
  81. //Reset the Enqueued time in case this is a requeue
  82. notification.EnqueuedTimestamp = DateTime.UtcNow;
  83. //Increase the queue counter
  84. if (countsAsRequeue)
  85. notification.QueuedCount++;
  86. queuedNotifications.Enqueue(notification);
  87. //Signal a possibly wait-stated Sender loop that there's work to do
  88. waitQueuedNotification.Set();
  89. }
  90. else
  91. Events.RaiseNotificationSendFailure(notification, new MaxSendAttemptsReachedException());
  92. }
  93. void Sender()
  94. {
  95. while (!this.CancelToken.IsCancellationRequested || QueuedNotificationCount > 0)
  96. {
  97. Notification notification = null;
  98. if (!queuedNotifications.TryDequeue(out notification))
  99. {
  100. //No notifications in queue, go into wait state
  101. waitQueuedNotification.Reset();
  102. try { waitQueuedNotification.Wait(5000, this.CancelToken); }
  103. catch { }
  104. continue;
  105. }
  106. //Report back the time in queue
  107. var timeInQueue = DateTime.UtcNow - notification.EnqueuedTimestamp;
  108. if (OnQueueTimed != null)
  109. OnQueueTimed(timeInQueue.TotalMilliseconds);
  110. //Send it
  111. this.SendNotification(notification);
  112. }
  113. }
  114. }
  115. }