1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306 |
- #if !BESTHTTP_DISABLE_SIGNALR
- using System;
- using System.Text;
- using System.Collections.Generic;
- using BestHTTP.Extensions;
- using BestHTTP.SignalR.Hubs;
- using BestHTTP.SignalR.Messages;
- using BestHTTP.SignalR.Transports;
- using BestHTTP.SignalR.JsonEncoders;
- using BestHTTP.SignalR.Authentication;
- using PlatformSupport.Collections.ObjectModel;
- #if !NETFX_CORE
- using PlatformSupport.Collections.Specialized;
- #else
- using System.Collections.Specialized;
- #endif
- namespace BestHTTP.SignalR
- {
- public delegate void OnNonHubMessageDelegate(Connection connection, object data);
- public delegate void OnConnectedDelegate(Connection connection);
- public delegate void OnClosedDelegate(Connection connection);
- public delegate void OnErrorDelegate(Connection connection, string error);
- public delegate void OnStateChanged(Connection connection, ConnectionStates oldState, ConnectionStates newState);
- public delegate void OnPrepareRequestDelegate(Connection connection, HTTPRequest req, RequestTypes type);
-
-
-
- public interface IConnection
- {
- ProtocolVersions Protocol { get; }
- NegotiationData NegotiationResult { get; }
- IJsonEncoder JsonEncoder { get; set; }
- void OnMessage(IServerMessage msg);
- void TransportStarted();
- void TransportReconnected();
- void TransportAborted();
- void Error(string reason);
- Uri BuildUri(RequestTypes type);
- Uri BuildUri(RequestTypes type, TransportBase transport);
- HTTPRequest PrepareRequest(HTTPRequest req, RequestTypes type);
- string ParseResponse(string responseStr);
- }
-
-
-
- public enum ProtocolVersions : byte
- {
- Protocol_2_0,
- Protocol_2_1,
- Protocol_2_2
- }
-
-
-
- public sealed class Connection : IHeartbeat, IConnection
- {
- #region Public Properties
-
-
-
- public static IJsonEncoder DefaultEncoder =
- #if BESTHTTP_SIGNALR_WITH_JSONDOTNET
- new JSonDotnetEncoder();
- #else
- new DefaultJsonEncoder();
- #endif
-
-
-
- public Uri Uri { get; private set; }
-
-
-
- public ConnectionStates State
- {
- get { return _state; }
- private set
- {
- ConnectionStates old = _state;
- _state = value;
- if (OnStateChanged != null)
- OnStateChanged(this, old, _state);
- }
- }
- private ConnectionStates _state;
-
-
-
- public NegotiationData NegotiationResult { get; private set; }
-
-
-
- public Hub[] Hubs { get; private set; }
-
-
-
- public TransportBase Transport { get; private set; }
-
-
-
- public ProtocolVersions Protocol { get; private set; }
-
-
-
-
- public ObservableDictionary<string, string> AdditionalQueryParams
- {
- get { return additionalQueryParams; }
- set
- {
-
- if (additionalQueryParams != null)
- additionalQueryParams.CollectionChanged -= AdditionalQueryParams_CollectionChanged;
- additionalQueryParams = value;
-
- BuiltQueryParams = null;
-
- if (value != null)
- value.CollectionChanged += AdditionalQueryParams_CollectionChanged;
- }
- }
- private ObservableDictionary<string, string> additionalQueryParams;
-
-
-
- public bool QueryParamsOnlyForHandshake { get; set; }
-
-
-
- public IJsonEncoder JsonEncoder { get; set; }
-
-
-
- public IAuthenticationProvider AuthenticationProvider { get; set; }
-
-
-
- public TimeSpan PingInterval { get; set; }
-
-
-
- public TimeSpan ReconnectDelay { get; set; }
- #endregion
- #region Public Events
-
-
-
- public event OnConnectedDelegate OnConnected;
-
-
-
- public event OnClosedDelegate OnClosed;
-
-
-
- public event OnErrorDelegate OnError;
-
-
-
- public event OnConnectedDelegate OnReconnecting;
-
-
-
- public event OnConnectedDelegate OnReconnected;
-
-
-
- public event OnStateChanged OnStateChanged;
-
-
-
- public event OnNonHubMessageDelegate OnNonHubMessage;
-
-
-
- public OnPrepareRequestDelegate RequestPreparator { get; set; }
- #endregion
- #region Indexers
-
-
-
- public Hub this[int idx] { get { return Hubs[idx] as Hub; } }
-
-
-
- public Hub this[string hubName]
- {
- get
- {
- for (int i = 0; i < Hubs.Length; ++i)
- {
- Hub hub = Hubs[i] as Hub;
- if (hub.Name.Equals(hubName, StringComparison.OrdinalIgnoreCase))
- return hub;
- }
- return null;
- }
- }
- #endregion
- #region Internals
-
-
-
- internal object SyncRoot = new object();
-
-
-
- internal UInt64 ClientMessageCounter { get; set; }
- #endregion
- #region Privates
-
-
-
- private readonly string[] ClientProtocols = new string[] { "1.3", "1.4", "1.5" };
-
-
-
- private UInt32 Timestamp { get { return (UInt32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).Ticks; } }
-
-
-
- private UInt64 RequestCounter;
-
-
-
- private MultiMessage LastReceivedMessage;
-
-
-
-
- private string GroupsToken;
-
-
-
- private List<IServerMessage> BufferedMessages;
-
-
-
- private DateTime LastMessageReceivedAt;
-
-
-
- private DateTime ReconnectStartedAt;
- private DateTime ReconnectDelayStartedAt;
-
-
-
- private bool ReconnectStarted;
-
-
-
- private DateTime LastPingSentAt;
-
-
-
- private HTTPRequest PingRequest;
-
-
-
- private DateTime? TransportConnectionStartedAt;
-
-
-
- private StringBuilder queryBuilder = new StringBuilder();
-
-
-
- private string ConnectionData
- {
- get
- {
- if (!string.IsNullOrEmpty(BuiltConnectionData))
- return BuiltConnectionData;
- StringBuilder sb = new StringBuilder("[", Hubs.Length * 4);
- if (Hubs != null)
- for (int i = 0; i < Hubs.Length; ++i)
- {
- sb.Append(@"{""Name"":""");
- sb.Append(Hubs[i].Name);
- sb.Append(@"""}");
- if (i < Hubs.Length - 1)
- sb.Append(",");
- }
- sb.Append("]");
- return BuiltConnectionData = Uri.EscapeUriString(sb.ToString());
- }
- }
-
-
-
- private string BuiltConnectionData;
-
-
-
- private string QueryParams
- {
- get
- {
- if (AdditionalQueryParams == null || AdditionalQueryParams.Count == 0)
- return string.Empty;
- if (!string.IsNullOrEmpty(BuiltQueryParams))
- return BuiltQueryParams;
- StringBuilder sb = new StringBuilder(AdditionalQueryParams.Count * 4);
- foreach (var kvp in AdditionalQueryParams)
- {
- sb.Append("&");
- sb.Append(kvp.Key);
- if (!string.IsNullOrEmpty(kvp.Value))
- {
- sb.Append("=");
- sb.Append(Uri.EscapeDataString(kvp.Value));
- }
- }
- return BuiltQueryParams = sb.ToString();
- }
- }
-
-
-
- private string BuiltQueryParams;
- private SupportedProtocols NextProtocolToTry;
- #endregion
- #region Constructors
- public Connection(Uri uri, params string[] hubNames)
- : this(uri)
- {
- if (hubNames != null && hubNames.Length > 0)
- {
- this.Hubs = new Hub[hubNames.Length];
- for (int i = 0; i < hubNames.Length; ++i)
- this.Hubs[i] = new Hub(hubNames[i], this);
- }
- }
- public Connection(Uri uri, params Hub[] hubs)
- :this(uri)
- {
- this.Hubs = hubs;
- if (hubs != null)
- for (int i = 0; i < hubs.Length; ++i)
- (hubs[i] as IHub).Connection = this;
- }
- public Connection(Uri uri)
- {
- this.State = ConnectionStates.Initial;
- this.Uri = uri;
- this.JsonEncoder = Connection.DefaultEncoder;
- this.PingInterval = TimeSpan.FromMinutes(5);
-
- this.Protocol = ProtocolVersions.Protocol_2_2;
- this.ReconnectDelay = TimeSpan.FromSeconds(5);
- }
- #endregion
- #region Starting the protocol
-
-
-
- public void Open()
- {
- if (State != ConnectionStates.Initial && State != ConnectionStates.Closed)
- return;
- if (AuthenticationProvider != null && AuthenticationProvider.IsPreAuthRequired)
- {
- this.State = ConnectionStates.Authenticating;
- AuthenticationProvider.OnAuthenticationSucceded += OnAuthenticationSucceded;
- AuthenticationProvider.OnAuthenticationFailed += OnAuthenticationFailed;
-
- AuthenticationProvider.StartAuthentication();
- }
- else
- StartImpl();
- }
-
-
-
-
- private void OnAuthenticationSucceded(IAuthenticationProvider provider)
- {
- provider.OnAuthenticationSucceded -= OnAuthenticationSucceded;
- provider.OnAuthenticationFailed -= OnAuthenticationFailed;
- StartImpl();
- }
-
-
-
- private void OnAuthenticationFailed(IAuthenticationProvider provider, string reason)
- {
- provider.OnAuthenticationSucceded -= OnAuthenticationSucceded;
- provider.OnAuthenticationFailed -= OnAuthenticationFailed;
- (this as IConnection).Error(reason);
- }
-
-
-
- private void StartImpl()
- {
- this.State = ConnectionStates.Negotiating;
- NegotiationResult = new NegotiationData(this);
- NegotiationResult.OnReceived = OnNegotiationDataReceived;
- NegotiationResult.OnError = OnNegotiationError;
- NegotiationResult.Start();
- }
- #region Negotiation Event Handlers
-
-
-
- private void OnNegotiationDataReceived(NegotiationData data)
- {
-
- int protocolIdx = -1;
- for (int i = 0; i < ClientProtocols.Length && protocolIdx == -1; ++i)
- if (data.ProtocolVersion == ClientProtocols[i])
- protocolIdx = i;
-
- if (protocolIdx == -1)
- {
- protocolIdx = (byte)ProtocolVersions.Protocol_2_2;
- HTTPManager.Logger.Warning("SignalR Connection", "Unknown protocol version: " + data.ProtocolVersion);
- }
- this.Protocol = (ProtocolVersions)protocolIdx;
- #if !BESTHTTP_DISABLE_WEBSOCKET
- if (data.TryWebSockets)
- {
- Transport = new WebSocketTransport(this);
- #if !BESTHTTP_DISABLE_SERVERSENT_EVENTS
- NextProtocolToTry = SupportedProtocols.ServerSentEvents;
- #else
- NextProtocolToTry = SupportedProtocols.HTTP;
- #endif
- }
- else
- #endif
- {
- #if !BESTHTTP_DISABLE_SERVERSENT_EVENTS
- Transport = new ServerSentEventsTransport(this);
-
- NextProtocolToTry = SupportedProtocols.HTTP;
- #else
- Transport = new PollingTransport(this);
- NextProtocolToTry = SupportedProtocols.Unknown;
- #endif
- }
- this.State = ConnectionStates.Connecting;
- TransportConnectionStartedAt = DateTime.UtcNow;
- Transport.Connect();
- }
-
-
-
- private void OnNegotiationError(NegotiationData data, string error)
- {
- (this as IConnection).Error(error);
- }
- #endregion
- #endregion
- #region Public Interface
-
-
-
- public void Close()
- {
- if (this.State == ConnectionStates.Closed)
- return;
- this.State = ConnectionStates.Closed;
-
- ReconnectStarted = false;
- TransportConnectionStartedAt = null;
- if (Transport != null)
- {
- Transport.Abort();
- Transport = null;
- }
- NegotiationResult = null;
- HTTPManager.Heartbeats.Unsubscribe(this);
- LastReceivedMessage = null;
- if (Hubs != null)
- for (int i = 0; i < Hubs.Length; ++i)
- (Hubs[i] as IHub).Close();
- if (BufferedMessages != null)
- {
- BufferedMessages.Clear();
- BufferedMessages = null;
- }
- if (OnClosed != null)
- {
- try
- {
- OnClosed(this);
- }
- catch (Exception ex)
- {
- HTTPManager.Logger.Exception("SignalR Connection", "OnClosed", ex);
- }
- }
- }
-
-
-
- public void Reconnect()
- {
-
- if (ReconnectStarted)
- return;
- ReconnectStarted = true;
-
-
- if (this.State != ConnectionStates.Reconnecting)
- ReconnectStartedAt = DateTime.UtcNow;
- this.State = ConnectionStates.Reconnecting;
- HTTPManager.Logger.Warning("SignalR Connection", "Reconnecting");
- Transport.Reconnect();
- if (PingRequest != null)
- PingRequest.Abort();
- if (OnReconnecting != null)
- {
- try
- {
- OnReconnecting(this);
- }
- catch (Exception ex)
- {
- HTTPManager.Logger.Exception("SignalR Connection", "OnReconnecting", ex);
- }
- }
- }
-
-
-
-
- public bool Send(object arg)
- {
- if (arg == null)
- throw new ArgumentNullException("arg");
- lock(SyncRoot)
- {
- if (this.State != ConnectionStates.Connected)
- return false;
- string json = JsonEncoder.Encode(arg);
- if (string.IsNullOrEmpty(json))
- HTTPManager.Logger.Error("SignalR Connection", "Failed to JSon encode the given argument. Please try to use an advanced JSon encoder(check the documentation how you can do it).");
- else
- Transport.Send(json);
- }
- return true;
- }
-
-
-
-
- public bool SendJson(string json)
- {
- if (json == null)
- throw new ArgumentNullException("json");
- lock(SyncRoot)
- {
- if (this.State != ConnectionStates.Connected)
- return false;
- Transport.Send(json);
- }
- return true;
- }
- #endregion
- #region IManager Functions
-
-
-
- void IConnection.OnMessage(IServerMessage msg)
- {
- if (this.State == ConnectionStates.Closed)
- return;
-
- if (this.State == ConnectionStates.Connecting)
- {
- if (BufferedMessages == null)
- BufferedMessages = new List<IServerMessage>();
- BufferedMessages.Add(msg);
- return;
- }
- LastMessageReceivedAt = DateTime.UtcNow;
- switch(msg.Type)
- {
- case MessageTypes.Multiple:
- LastReceivedMessage = msg as MultiMessage;
-
- if (LastReceivedMessage.IsInitialization)
- HTTPManager.Logger.Information("SignalR Connection", "OnMessage - Init");
- if (LastReceivedMessage.GroupsToken != null)
- GroupsToken = LastReceivedMessage.GroupsToken;
- if (LastReceivedMessage.ShouldReconnect)
- {
- HTTPManager.Logger.Information("SignalR Connection", "OnMessage - Should Reconnect");
- Reconnect();
-
-
- }
- if (LastReceivedMessage.Data != null)
- for (int i = 0; i < LastReceivedMessage.Data.Count; ++i)
- (this as IConnection).OnMessage(LastReceivedMessage.Data[i]);
- break;
- case MessageTypes.MethodCall:
- MethodCallMessage methodCall = msg as MethodCallMessage;
- Hub hub = this[methodCall.Hub];
- if (hub != null)
- (hub as IHub).OnMethod(methodCall);
- else
- HTTPManager.Logger.Warning("SignalR Connection", string.Format("Hub \"{0}\" not found!", methodCall.Hub));
- break;
- case MessageTypes.Result:
- case MessageTypes.Failure:
- case MessageTypes.Progress:
- UInt64 id = (msg as IHubMessage).InvocationId;
- hub = FindHub(id);
- if (hub != null)
- (hub as IHub).OnMessage(msg);
- else
- HTTPManager.Logger.Warning("SignalR Connection", string.Format("No Hub found for Progress message! Id: {0}", id.ToString()));
- break;
- case MessageTypes.Data:
- if (OnNonHubMessage != null)
- OnNonHubMessage(this, (msg as DataMessage).Data);
- break;
- case MessageTypes.KeepAlive:
- break;
- default:
- HTTPManager.Logger.Warning("SignalR Connection", "Unknown message type received: " + msg.Type.ToString());
- break;
- }
- }
-
-
-
- void IConnection.TransportStarted()
- {
- if (this.State != ConnectionStates.Connecting)
- return;
- InitOnStart();
- if (OnConnected != null)
- {
- try
- {
- OnConnected(this);
- }
- catch (Exception ex)
- {
- HTTPManager.Logger.Exception("SignalR Connection", "OnOpened", ex);
- }
- }
-
-
- if (BufferedMessages != null)
- {
- for (int i = 0; i < BufferedMessages.Count; ++i)
- (this as IConnection).OnMessage(BufferedMessages[i]);
- BufferedMessages.Clear();
- BufferedMessages = null;
- }
- }
-
-
-
- void IConnection.TransportReconnected()
- {
- if (this.State != ConnectionStates.Reconnecting)
- return;
- HTTPManager.Logger.Information("SignalR Connection", "Transport Reconnected");
- InitOnStart();
- if (OnReconnected != null)
- {
- try
- {
- OnReconnected(this);
- }
- catch (Exception ex)
- {
- HTTPManager.Logger.Exception("SignalR Connection", "OnReconnected", ex);
- }
- }
- }
-
-
-
- void IConnection.TransportAborted()
- {
- Close();
- }
-
-
-
- void IConnection.Error(string reason)
- {
-
- if (this.State == ConnectionStates.Closed)
- return;
-
- if (HTTPManager.IsQuitting)
- {
- Close();
- return;
- }
- HTTPManager.Logger.Error("SignalR Connection", reason);
- ReconnectStarted = false;
- if (OnError != null)
- OnError(this, reason);
- if (this.State == ConnectionStates.Connected || this.State == ConnectionStates.Reconnecting)
- {
- this.ReconnectDelayStartedAt = DateTime.UtcNow;
- if (this.State != ConnectionStates.Reconnecting)
- this.ReconnectStartedAt = DateTime.UtcNow;
-
- }
- else
- {
-
- if (this.State != ConnectionStates.Connecting || !TryFallbackTransport())
- Close();
- }
- }
-
-
-
- Uri IConnection.BuildUri(RequestTypes type)
- {
- return (this as IConnection).BuildUri(type, null);
- }
-
-
-
- Uri IConnection.BuildUri(RequestTypes type, TransportBase transport)
- {
- lock (SyncRoot)
- {
-
- queryBuilder.Length = 0;
- UriBuilder uriBuilder = new UriBuilder(Uri);
- if (!uriBuilder.Path.EndsWith("/"))
- uriBuilder.Path += "/";
- this.RequestCounter %= UInt64.MaxValue;
- switch (type)
- {
- case RequestTypes.Negotiate:
- uriBuilder.Path += "negotiate";
- goto default;
- case RequestTypes.Connect:
- #if !BESTHTTP_DISABLE_WEBSOCKET
- if (transport != null && transport.Type == TransportTypes.WebSocket)
- uriBuilder.Scheme = HTTPProtocolFactory.IsSecureProtocol(Uri) ? "wss" : "ws";
- #endif
- uriBuilder.Path += "connect";
- goto default;
- case RequestTypes.Start:
- uriBuilder.Path += "start";
- goto default;
- case RequestTypes.Poll:
- uriBuilder.Path += "poll";
- if (this.LastReceivedMessage != null)
- {
- queryBuilder.Append("messageId=");
- queryBuilder.Append(this.LastReceivedMessage.MessageId);
- }
- if (!string.IsNullOrEmpty(GroupsToken))
- {
- if (queryBuilder.Length > 0)
- queryBuilder.Append("&");
- queryBuilder.Append("groupsToken=");
- queryBuilder.Append(GroupsToken);
- }
- goto default;
- case RequestTypes.Send:
- uriBuilder.Path += "send";
- goto default;
- case RequestTypes.Reconnect:
- #if !BESTHTTP_DISABLE_WEBSOCKET
- if (transport != null && transport.Type == TransportTypes.WebSocket)
- uriBuilder.Scheme = HTTPProtocolFactory.IsSecureProtocol(Uri) ? "wss" : "ws";
- #endif
- uriBuilder.Path += "reconnect";
- if (this.LastReceivedMessage != null)
- {
- queryBuilder.Append("messageId=");
- queryBuilder.Append(this.LastReceivedMessage.MessageId);
- }
- if (!string.IsNullOrEmpty(GroupsToken))
- {
- if (queryBuilder.Length > 0)
- queryBuilder.Append("&");
- queryBuilder.Append("groupsToken=");
- queryBuilder.Append(GroupsToken);
- }
- goto default;
- case RequestTypes.Abort:
- uriBuilder.Path += "abort";
- goto default;
- case RequestTypes.Ping:
- uriBuilder.Path += "ping";
- queryBuilder.Append("&tid=");
- queryBuilder.Append(this.RequestCounter++.ToString());
- queryBuilder.Append("&_=");
- queryBuilder.Append(Timestamp.ToString());
- break;
- default:
- if (queryBuilder.Length > 0)
- queryBuilder.Append("&");
- queryBuilder.Append("tid=");
- queryBuilder.Append(this.RequestCounter++.ToString());
- queryBuilder.Append("&_=");
- queryBuilder.Append(Timestamp.ToString());
- if (transport != null)
- {
- queryBuilder.Append("&transport=");
- queryBuilder.Append(transport.Name);
- }
- queryBuilder.Append("&clientProtocol=");
- queryBuilder.Append(ClientProtocols[(byte)Protocol]);
- if (NegotiationResult != null && !string.IsNullOrEmpty(this.NegotiationResult.ConnectionToken))
- {
- queryBuilder.Append("&connectionToken=");
- queryBuilder.Append(this.NegotiationResult.ConnectionToken);
- }
- if (this.Hubs != null && this.Hubs.Length > 0)
- {
- queryBuilder.Append("&connectionData=");
- queryBuilder.Append(this.ConnectionData);
- }
- break;
- }
-
- if (this.AdditionalQueryParams != null && this.AdditionalQueryParams.Count > 0)
- queryBuilder.Append(this.QueryParams);
- uriBuilder.Query = queryBuilder.ToString();
-
- queryBuilder.Length = 0;
- return uriBuilder.Uri;
- }
- }
-
-
-
- HTTPRequest IConnection.PrepareRequest(HTTPRequest req, RequestTypes type)
- {
- if (req != null && AuthenticationProvider != null)
- AuthenticationProvider.PrepareRequest(req, type);
- if (RequestPreparator != null)
- RequestPreparator(this, req, type);
- return req;
- }
-
-
-
- string IConnection.ParseResponse(string responseStr)
- {
- Dictionary<string, object> dic = JSON.Json.Decode(responseStr) as Dictionary<string, object>;
- if (dic == null)
- {
- (this as IConnection).Error("Failed to parse Start response: " + responseStr);
- return string.Empty;
- }
- object value;
- if (!dic.TryGetValue("Response", out value) || value == null)
- {
- (this as IConnection).Error("No 'Response' key found in response: " + responseStr);
- return string.Empty;
- }
- return value.ToString();
- }
- #endregion
- #region IHeartbeat Implementation
-
-
-
- void IHeartbeat.OnHeartbeatUpdate(TimeSpan dif)
- {
- switch(this.State)
- {
- case ConnectionStates.Connected:
- if (Transport.SupportsKeepAlive && NegotiationResult.KeepAliveTimeout != null && DateTime.UtcNow - LastMessageReceivedAt >= NegotiationResult.KeepAliveTimeout)
- Reconnect();
- if (PingRequest == null && DateTime.UtcNow - LastPingSentAt >= PingInterval)
- Ping();
- break;
- case ConnectionStates.Reconnecting:
- if ( DateTime.UtcNow - ReconnectStartedAt >= NegotiationResult.DisconnectTimeout)
- {
- HTTPManager.Logger.Warning("SignalR Connection", "OnHeartbeatUpdate - Failed to reconnect in the given time!");
- Close();
- }
- else if (DateTime.UtcNow - ReconnectDelayStartedAt >= ReconnectDelay)
- {
- if (HTTPManager.Logger.Level <= Logger.Loglevels.Warning)
- HTTPManager.Logger.Warning("SignalR Connection", this.ReconnectStarted.ToString() + " " + this.ReconnectStartedAt.ToString() + " " + NegotiationResult.DisconnectTimeout.ToString());
- Reconnect();
- }
- break;
- default:
- if (TransportConnectionStartedAt != null && DateTime.UtcNow - TransportConnectionStartedAt >= NegotiationResult.TransportConnectTimeout)
- {
- HTTPManager.Logger.Warning("SignalR Connection", "OnHeartbeatUpdate - Transport failed to connect in the given time!");
-
- (this as IConnection).Error("Transport failed to connect in the given time!");
- }
- break;
- }
- }
- #endregion
- #region Private Helper Functions
-
-
-
- private void InitOnStart()
- {
- this.State = ConnectionStates.Connected;
-
- ReconnectStarted = false;
- TransportConnectionStartedAt = null;
- LastPingSentAt = DateTime.UtcNow;
- LastMessageReceivedAt = DateTime.UtcNow;
- HTTPManager.Heartbeats.Subscribe(this);
- }
-
-
-
- private Hub FindHub(UInt64 msgId)
- {
- if (Hubs != null)
- for (int i = 0; i < Hubs.Length; ++i)
- if ((Hubs[i] as IHub).HasSentMessageId(msgId))
- return Hubs[i];
- return null;
- }
-
-
-
- private bool TryFallbackTransport()
- {
- if (this.State == ConnectionStates.Connecting)
- {
- if (BufferedMessages != null)
- BufferedMessages.Clear();
-
- Transport.Stop();
- Transport = null;
- switch(NextProtocolToTry)
- {
- #if !BESTHTTP_DISABLE_WEBSOCKET
- case SupportedProtocols.WebSocket:
- Transport = new WebSocketTransport(this);
- break;
- #endif
- #if !BESTHTTP_DISABLE_SERVERSENT_EVENTS
- case SupportedProtocols.ServerSentEvents:
- Transport = new ServerSentEventsTransport(this);
- NextProtocolToTry = SupportedProtocols.HTTP;
- break;
- #endif
- case SupportedProtocols.HTTP:
- Transport = new PollingTransport(this);
- NextProtocolToTry = SupportedProtocols.Unknown;
- break;
- case SupportedProtocols.Unknown:
- return false;
- }
- TransportConnectionStartedAt = DateTime.UtcNow;
- Transport.Connect();
- if (PingRequest != null)
- PingRequest.Abort();
- return true;
- }
- return false;
- }
-
-
-
- private void AdditionalQueryParams_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
- {
- BuiltQueryParams = null;
- }
- #endregion
- #region Ping Implementation
-
-
-
- private void Ping()
- {
- HTTPManager.Logger.Information("SignalR Connection", "Sending Ping request.");
- PingRequest = new HTTPRequest((this as IConnection).BuildUri(RequestTypes.Ping), OnPingRequestFinished);
- PingRequest.ConnectTimeout = PingInterval;
- (this as IConnection).PrepareRequest(PingRequest, RequestTypes.Ping);
- PingRequest.Send();
- LastPingSentAt = DateTime.UtcNow;
- }
-
-
-
- void OnPingRequestFinished(HTTPRequest req, HTTPResponse resp)
- {
- PingRequest = null;
- string reason = string.Empty;
- switch (req.State)
- {
-
- case HTTPRequestStates.Finished:
- if (resp.IsSuccess)
- {
-
- string response = (this as IConnection).ParseResponse(resp.DataAsText);
- if (response != "pong")
- reason = "Wrong answer for ping request: " + response;
- else
- HTTPManager.Logger.Information("SignalR Connection", "Pong received.");
- }
- else
- reason = string.Format("Ping - Request Finished Successfully, but the server sent an error. Status Code: {0}-{1} Message: {2}",
- resp.StatusCode,
- resp.Message,
- resp.DataAsText);
- break;
-
- case HTTPRequestStates.Error:
- reason = "Ping - Request Finished with Error! " + (req.Exception != null ? (req.Exception.Message + "\n" + req.Exception.StackTrace) : "No Exception");
- break;
-
- case HTTPRequestStates.ConnectionTimedOut:
- reason = "Ping - Connection Timed Out!";
- break;
-
- case HTTPRequestStates.TimedOut:
- reason = "Ping - Processing the request Timed Out!";
- break;
- }
- if (!string.IsNullOrEmpty(reason))
- (this as IConnection).Error(reason);
- }
- #endregion
- }
- }
- #endif
|