/// <summary> /// Init constructor. /// </summary> public BayeuxConnection(IHttpDataSource connection, IHttpDataSource longPollingConnection) { if (connection == null) { throw new ArgumentNullException("connection"); } _syncObject = new object(); _writerCache = new StringBuilder(); _jsonWriter = new JSonWriter(_writerCache, false); _jsonWriter.CompactEnumerables = true; _jsonReader = new JSonReader(); _state = BayeuxConnectionState.Disconnected; _subscribedChannels = new List <string>(); LongPollingRetryDelay = DefaultRetryDelay; LongPollingConnectRetries = DefaultNumberOfConnectRetries; _httpConnection = connection; _httpConnection.DataReceived += DataSource_OnDataReceived; _httpConnection.DataReceiveFailed += DataSource_OnDataReceiveFailed; if (longPollingConnection != null) { _httpLongPollingConnection = longPollingConnection; _httpLongPollingConnection.DataReceived += LongPollingDataSource_OnDataReceived; _httpLongPollingConnection.DataReceiveFailed += LongPollingDataSource_OnDataReceiveFailed; } }
/// <summary> /// Cancels the currently executed asynchronous server request. /// </summary> public void Cancel() { if (_httpConnection.IsActive) { _httpConnection.Cancel(); } // check if cancelled the handshake request: if (_state == BayeuxConnectionState.Connecting) { _state = BayeuxConnectionState.Disconnected; } }
/// <summary> /// Sends handshake request to the server. /// </summary> public void Handshake(BayeuxConnectionTypes supportedConnectionTypes, IJSonWritable data, IJSonWritable ext, bool asynchronous) { // if there is another Handshake request executed in background, try to cancel it first: if (_state == BayeuxConnectionState.Connecting) { Cancel(); // <-- this should reset the state to Disconnected! } if (_state != BayeuxConnectionState.Disconnected) { throw new InvalidOperationException("Connecting or already connected to bayeux server! Disconnect first"); } _state = BayeuxConnectionState.Connecting; SendRequest(new HandshakeRequest(supportedConnectionTypes, data, ext), asynchronous); }
private void ProcessResponseMessage(BayeuxRequest request, HttpStatusCode httpStatusCode, string httpStatusDescription, IJSonObject message, string rawMessage) { try { string channel = message["channel"].StringValue; // each Bayuex message must have a channel associated! BayeuxResponse response = null; if (string.IsNullOrEmpty(channel)) throw new BayeuxException("Unexpected message with empty channel!"); if (request != null && (channel.StartsWith("/meta", StringComparison.Ordinal) && channel != request.Channel)) throw new BayeuxException(string.Format(CultureInfo.InvariantCulture, "Unexpected response with channel: '{0}'", channel), request, null, message); if (request != null && channel.StartsWith("/meta", StringComparison.Ordinal) && request.ID != message["id"].StringValue) throw new BayeuxException(string.Format(CultureInfo.InvariantCulture, "Invalid response ID, current: '{0}', expected: '{1}'", request.ID, message["id"].StringValue), request, null, message); /////////////////////////////////////////////////////////////////////////////////////////// // identify meta messages: if (channel == HandshakeRequest.MetaChannel) { var handshakeResponse = new HandshakeResponse(message); response = handshakeResponse; // inform, that connection succeeded: if (handshakeResponse.Successful) { ClientID = response.ClientID; if (string.IsNullOrEmpty(ClientID)) { throw new BayeuxException("Invalid ClientID received from server", request, handshakeResponse, message); } OnConnected(new BayeuxConnectionEventArgs(this, httpStatusCode, httpStatusDescription, rawMessage, message, handshakeResponse)); } else { // inform that Handshake failed, via dedicated event: ClientID = null; OnConnectionFailed(new BayeuxConnectionEventArgs(this, response.Successful ? HttpStatusCode.OK : HttpStatusCode.BadRequest, null, rawMessage, message, response)); } } if (channel == DisconnectRequest.MetaChannel) { response = new BayeuxResponse(message); // inform that disconnection succeeded: _state = BayeuxConnectionState.Disconnected; ClientID = null; OnDisconnected(new BayeuxConnectionEventArgs(this, response.Successful ? HttpStatusCode.OK : HttpStatusCode.BadRequest, null, rawMessage, message, response)); } if (channel == SubscribeRequest.MetaChannel) { var subscribeResponse = new SubscribeResponse(message); response = subscribeResponse; if (subscribeResponse.Successful) _subscribedChannels.Add(subscribeResponse.SubscriptionChannel); } if (channel == UnsubscribeRequest.MetaChannel) { var unsubscribeResponse = new UnsubscribeResponse(message); response = unsubscribeResponse; if (unsubscribeResponse.Successful) _subscribedChannels.Remove(unsubscribeResponse.SubscriptionChannel); } if (_subscribedChannels.Contains(channel)) { response = new BayeuxResponse(message); // event from server: OnEventReceived(new BayeuxConnectionEventArgs(this, httpStatusCode, httpStatusDescription, rawMessage, message, response)); } // process generic response: if (response == null) response = ProvideResponse(message); // allow filtering of ResponseReceived event: if (ProcessResponse(request, response)) return; // one place to process all responses: OnResponseReceived(new BayeuxConnectionEventArgs(this, httpStatusCode, httpStatusDescription, rawMessage, message, response)); } catch (Exception ex) { DebugLog.WriteBayeuxException(ex); string statusDescription = string.Concat(httpStatusDescription, "; unexpected exception: \"", ex.Message, "\""); OnDataFailed(new BayeuxConnectionEventArgs(this, httpStatusCode, statusDescription, rawMessage, message)); } }
/// <summary> /// Cancels the currently executed asynchronous server request. /// </summary> public void Cancel() { if (_httpConnection.IsActive) _httpConnection.Cancel(); // check if cancelled the handshake request: if (_state == BayeuxConnectionState.Connecting) _state = BayeuxConnectionState.Disconnected; }
/// <summary> /// Sends handshake request to the server. /// </summary> public void Handshake(BayeuxConnectionTypes supportedConnectionTypes, IJSonWritable data, IJSonWritable ext, bool asynchronous) { // if there is another Handshake request executed in background, try to cancel it first: if (_state == BayeuxConnectionState.Connecting) Cancel(); // <-- this should reset the state to Disconnected! if (_state != BayeuxConnectionState.Disconnected) throw new InvalidOperationException("Connecting or already connected to bayeux server! Disconnect first"); _state = BayeuxConnectionState.Connecting; SendRequest(new HandshakeRequest(supportedConnectionTypes, data, ext), asynchronous); }
/// <summary> /// Init constructor. /// </summary> public BayeuxConnection(IHttpDataSource connection, IHttpDataSource longPollingConnection) { if (connection == null) throw new ArgumentNullException("connection"); _syncObject = new object(); _writerCache = new StringBuilder(); _jsonWriter = new JSonWriter(_writerCache, false); _jsonWriter.CompactEnumerables = true; _jsonReader = new JSonReader(); _state = BayeuxConnectionState.Disconnected; _subscribedChannels = new List<string>(); LongPollingRetryDelay = DefaultRetryDelay; LongPollingConnectRetries = DefaultNumberOfConnectRetries; _httpConnection = connection; _httpConnection.DataReceived += DataSource_OnDataReceived; _httpConnection.DataReceiveFailed += DataSource_OnDataReceiveFailed; if (longPollingConnection != null) { _httpLongPollingConnection = longPollingConnection; _httpLongPollingConnection.DataReceived += LongPollingDataSource_OnDataReceived; _httpLongPollingConnection.DataReceiveFailed += LongPollingDataSource_OnDataReceiveFailed; } }
private void ProcessResponseMessage(BayeuxRequest request, HttpStatusCode httpStatusCode, string httpStatusDescription, IJSonObject message, string rawMessage) { try { string channel = message["channel"].StringValue; // each Bayuex message must have a channel associated! BayeuxResponse response = null; if (string.IsNullOrEmpty(channel)) { throw new BayeuxException("Unexpected message with empty channel!"); } if (request != null && (channel.StartsWith("/meta", StringComparison.Ordinal) && channel != request.Channel)) { throw new BayeuxException(string.Format(CultureInfo.InvariantCulture, "Unexpected response with channel: '{0}'", channel), request, null, message); } if (request != null && channel.StartsWith("/meta", StringComparison.Ordinal) && request.ID != message["id"].StringValue) { throw new BayeuxException(string.Format(CultureInfo.InvariantCulture, "Invalid response ID, current: '{0}', expected: '{1}'", request.ID, message["id"].StringValue), request, null, message); } /////////////////////////////////////////////////////////////////////////////////////////// // identify meta messages: if (channel == HandshakeRequest.MetaChannel) { var handshakeResponse = new HandshakeResponse(message); response = handshakeResponse; // inform, that connection succeeded: if (handshakeResponse.Successful) { ClientID = response.ClientID; if (string.IsNullOrEmpty(ClientID)) { throw new BayeuxException("Invalid ClientID received from server", request, handshakeResponse, message); } OnConnected(new BayeuxConnectionEventArgs(this, httpStatusCode, httpStatusDescription, rawMessage, message, handshakeResponse)); } else { // inform that Handshake failed, via dedicated event: ClientID = null; OnConnectionFailed(new BayeuxConnectionEventArgs(this, response.Successful ? HttpStatusCode.OK : HttpStatusCode.BadRequest, null, rawMessage, message, response)); } } if (channel == DisconnectRequest.MetaChannel) { response = new BayeuxResponse(message); // inform that disconnection succeeded: _state = BayeuxConnectionState.Disconnected; ClientID = null; OnDisconnected(new BayeuxConnectionEventArgs(this, response.Successful ? HttpStatusCode.OK : HttpStatusCode.BadRequest, null, rawMessage, message, response)); } if (channel == SubscribeRequest.MetaChannel) { var subscribeResponse = new SubscribeResponse(message); response = subscribeResponse; if (subscribeResponse.Successful) { _subscribedChannels.Add(subscribeResponse.SubscriptionChannel); } } if (channel == UnsubscribeRequest.MetaChannel) { var unsubscribeResponse = new UnsubscribeResponse(message); response = unsubscribeResponse; if (unsubscribeResponse.Successful) { _subscribedChannels.Remove(unsubscribeResponse.SubscriptionChannel); } } if (_subscribedChannels.Contains(channel)) { response = new BayeuxResponse(message); // event from server: OnEventReceived(new BayeuxConnectionEventArgs(this, httpStatusCode, httpStatusDescription, rawMessage, message, response)); } // process generic response: if (response == null) { response = ProvideResponse(message); } // allow filtering of ResponseReceived event: if (ProcessResponse(request, response)) { return; } // one place to process all responses: OnResponseReceived(new BayeuxConnectionEventArgs(this, httpStatusCode, httpStatusDescription, rawMessage, message, response)); } catch (Exception ex) { DebugLog.WriteBayeuxException(ex); string statusDescription = string.Concat(httpStatusDescription, "; unexpected exception: \"", ex.Message, "\""); OnDataFailed(new BayeuxConnectionEventArgs(this, httpStatusCode, statusDescription, rawMessage, message)); } }