#if !BESTHTTP_DISABLE_SIGNALR
#if !BESTHTTP_DISABLE_SERVERSENT_EVENTS
using System;
using BestHTTP.ServerSentEvents;
using BestHTTP.SignalR.Messages;
namespace BestHTTP.SignalR.Transports
{
///
/// A SignalR transport implementation that uses the Server-Sent Events protocol.
///
public sealed class ServerSentEventsTransport : PostSendTransportBase
{
#region Overridden Properties
///
/// It's a persistent connection. We support the keep-alive mechanism.
///
public override bool SupportsKeepAlive { get { return true; } }
///
/// Type of the transport.
///
public override TransportTypes Type { get { return TransportTypes.ServerSentEvents; } }
#endregion
#region Privates
///
/// The EventSource object.
///
private EventSource EventSource;
#endregion
public ServerSentEventsTransport(Connection con)
: base("serverSentEvents", con)
{
}
#region Overrides from TransportBase
public override void Connect()
{
if (EventSource != null)
{
HTTPManager.Logger.Warning("ServerSentEventsTransport", "Start - EventSource already created!");
return;
}
// Skip the Connecting state if we are reconnecting. If the connect succeeds, we will set the Started state directly
if (this.State != TransportStates.Reconnecting)
this.State = TransportStates.Connecting;
RequestTypes requestType = this.State == TransportStates.Reconnecting ? RequestTypes.Reconnect : RequestTypes.Connect;
Uri uri = Connection.BuildUri(requestType, this);
EventSource = new EventSource(uri);
EventSource.OnOpen += OnEventSourceOpen;
EventSource.OnMessage += OnEventSourceMessage;
EventSource.OnError += OnEventSourceError;
EventSource.OnClosed += OnEventSourceClosed;
#if !UNITY_WEBGL || UNITY_EDITOR
// Disable internal retry
EventSource.OnRetry += (es) => false;
#endif
// Start connecting to the server.
EventSource.Open();
}
public override void Stop()
{
EventSource.OnOpen -= OnEventSourceOpen;
EventSource.OnMessage -= OnEventSourceMessage;
EventSource.OnError -= OnEventSourceError;
EventSource.OnClosed -= OnEventSourceClosed;
EventSource.Close();
EventSource = null;
}
protected override void Started()
{
// Nothing to do here for this transport
}
///
/// A custom Abort function where we will start to close the EventSource object.
///
public override void Abort()
{
base.Abort();
EventSource.Close();
}
protected override void Aborted()
{
if (this.State == TransportStates.Closing)
this.State = TransportStates.Closed;
}
#endregion
#region EventSource Event Handlers
private void OnEventSourceOpen(EventSource eventSource)
{
HTTPManager.Logger.Information("Transport - " + this.Name, "OnEventSourceOpen");
}
private void OnEventSourceMessage(EventSource eventSource, BestHTTP.ServerSentEvents.Message message)
{
if (message.Data.Equals("initialized"))
{
base.OnConnected();
return;
}
IServerMessage msg = TransportBase.Parse(Connection.JsonEncoder, message.Data);
if (msg != null)
Connection.OnMessage(msg);
}
private void OnEventSourceError(EventSource eventSource, string error)
{
HTTPManager.Logger.Information("Transport - " + this.Name, "OnEventSourceError");
// We are in a reconnecting phase, we have to connect now.
if (this.State == TransportStates.Reconnecting)
{
Connect();
return;
}
// Already closed?
if (this.State == TransportStates.Closed)
return;
// Closing? Then we are closed now.
if (this.State == TransportStates.Closing)
this.State = TransportStates.Closed;
else // Errored when we didn't expected it.
Connection.Error(error);
}
private void OnEventSourceClosed(ServerSentEvents.EventSource eventSource)
{
HTTPManager.Logger.Information("Transport - " + this.Name, "OnEventSourceClosed");
OnEventSourceError(eventSource, "EventSource Closed!");
}
#endregion
}
}
#endif
#endif