ServerSentEventsTransport.cs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. #if !BESTHTTP_DISABLE_SIGNALR
  2. #if !BESTHTTP_DISABLE_SERVERSENT_EVENTS
  3. using System;
  4. using BestHTTP.ServerSentEvents;
  5. using BestHTTP.SignalR.Messages;
  6. namespace BestHTTP.SignalR.Transports
  7. {
  8. /// <summary>
  9. /// A SignalR transport implementation that uses the Server-Sent Events protocol.
  10. /// </summary>
  11. public sealed class ServerSentEventsTransport : PostSendTransportBase
  12. {
  13. #region Overridden Properties
  14. /// <summary>
  15. /// It's a persistent connection. We support the keep-alive mechanism.
  16. /// </summary>
  17. public override bool SupportsKeepAlive { get { return true; } }
  18. /// <summary>
  19. /// Type of the transport.
  20. /// </summary>
  21. public override TransportTypes Type { get { return TransportTypes.ServerSentEvents; } }
  22. #endregion
  23. #region Privates
  24. /// <summary>
  25. /// The EventSource object.
  26. /// </summary>
  27. private EventSource EventSource;
  28. #endregion
  29. public ServerSentEventsTransport(Connection con)
  30. : base("serverSentEvents", con)
  31. {
  32. }
  33. #region Overrides from TransportBase
  34. public override void Connect()
  35. {
  36. if (EventSource != null)
  37. {
  38. HTTPManager.Logger.Warning("ServerSentEventsTransport", "Start - EventSource already created!");
  39. return;
  40. }
  41. // Skip the Connecting state if we are reconnecting. If the connect succeeds, we will set the Started state directly
  42. if (this.State != TransportStates.Reconnecting)
  43. this.State = TransportStates.Connecting;
  44. RequestTypes requestType = this.State == TransportStates.Reconnecting ? RequestTypes.Reconnect : RequestTypes.Connect;
  45. Uri uri = Connection.BuildUri(requestType, this);
  46. EventSource = new EventSource(uri);
  47. EventSource.OnOpen += OnEventSourceOpen;
  48. EventSource.OnMessage += OnEventSourceMessage;
  49. EventSource.OnError += OnEventSourceError;
  50. EventSource.OnClosed += OnEventSourceClosed;
  51. #if !UNITY_WEBGL || UNITY_EDITOR
  52. // Disable internal retry
  53. EventSource.OnRetry += (es) => false;
  54. #endif
  55. // Start connecting to the server.
  56. EventSource.Open();
  57. }
  58. public override void Stop()
  59. {
  60. EventSource.OnOpen -= OnEventSourceOpen;
  61. EventSource.OnMessage -= OnEventSourceMessage;
  62. EventSource.OnError -= OnEventSourceError;
  63. EventSource.OnClosed -= OnEventSourceClosed;
  64. EventSource.Close();
  65. EventSource = null;
  66. }
  67. protected override void Started()
  68. {
  69. // Nothing to do here for this transport
  70. }
  71. /// <summary>
  72. /// A custom Abort function where we will start to close the EventSource object.
  73. /// </summary>
  74. public override void Abort()
  75. {
  76. base.Abort();
  77. EventSource.Close();
  78. }
  79. protected override void Aborted()
  80. {
  81. if (this.State == TransportStates.Closing)
  82. this.State = TransportStates.Closed;
  83. }
  84. #endregion
  85. #region EventSource Event Handlers
  86. private void OnEventSourceOpen(EventSource eventSource)
  87. {
  88. HTTPManager.Logger.Information("Transport - " + this.Name, "OnEventSourceOpen");
  89. }
  90. private void OnEventSourceMessage(EventSource eventSource, BestHTTP.ServerSentEvents.Message message)
  91. {
  92. if (message.Data.Equals("initialized"))
  93. {
  94. base.OnConnected();
  95. return;
  96. }
  97. IServerMessage msg = TransportBase.Parse(Connection.JsonEncoder, message.Data);
  98. if (msg != null)
  99. Connection.OnMessage(msg);
  100. }
  101. private void OnEventSourceError(EventSource eventSource, string error)
  102. {
  103. HTTPManager.Logger.Information("Transport - " + this.Name, "OnEventSourceError");
  104. // We are in a reconnecting phase, we have to connect now.
  105. if (this.State == TransportStates.Reconnecting)
  106. {
  107. Connect();
  108. return;
  109. }
  110. // Already closed?
  111. if (this.State == TransportStates.Closed)
  112. return;
  113. // Closing? Then we are closed now.
  114. if (this.State == TransportStates.Closing)
  115. this.State = TransportStates.Closed;
  116. else // Errored when we didn't expected it.
  117. Connection.Error(error);
  118. }
  119. private void OnEventSourceClosed(ServerSentEvents.EventSource eventSource)
  120. {
  121. HTTPManager.Logger.Information("Transport - " + this.Name, "OnEventSourceClosed");
  122. OnEventSourceError(eventSource, "EventSource Closed!");
  123. }
  124. #endregion
  125. }
  126. }
  127. #endif
  128. #endif