/// <summary> /// Sends asynchronously long-polling request again. /// </summary> protected void ReconnectLongPollingConnection(bool resetFailures) { if (resetFailures) { _longPollingConnecFailures = 0; } else { _longPollingConnecFailures++; } // try to reconnect, if possible: if (IsLongPolling && State == BayeuxConnectionState.Connected) { BayeuxRequest message = LongPollingRequest; string dataToSend; string requestMethod; lock (_syncObject) { requestMethod = message.RequestMethod; dataToSend = SerializeRequest(message); } _httpLongPollingConnection.SendRequestAsync(null, dataToSend, requestMethod, HttpDataSourceResponseType.AsString); } }
/// <summary> /// Init constructor. /// </summary> public BayeuxException(string message, BayeuxRequest request, BayeuxResponse response, IJSonObject responseObject) : base(message) { Request = request; Response = response; JSonResponse = responseObject; }
/// <summary> /// Converts <see cref="BayeuxRequest"/> to string containing its JSON representation. /// </summary> protected string SerializeRequest(BayeuxRequest request) { _writerCache.Remove(0, _writerCache.Length); _jsonWriter.WriteArrayBegin(); request.Write(_jsonWriter); _jsonWriter.WriteArrayEnd(); return(_jsonWriter.ToString()); }
private void DataSource_OnDataReceived(object sender, HttpDataSourceEventArgs e) { // say, there the current request is no more needed: BayeuxRequest r = _request; _request = null; ProcessReceivedData(r, e); }
/// <summary> /// Stops listening for asynchronous data. /// </summary> public void StopLongPolling() { if (IsLongPolling) { _longPollingRequest = null; _longPolling = false; _httpLongPollingConnection.Cancel(); } }
/// <summary> /// Process given response. Request is also provided. /// The default behavior is that it only passes response to request, however there might be /// a situation, when no request was given (when a 'text' message has been sent). /// Returning 'true' as a result will filter out the ResponseReceived event. /// </summary> protected virtual bool ProcessResponse(BayeuxRequest request, BayeuxResponse response) { if (request != null) { request.ProcessResponse(response); } else { DebugLog.WriteBayeuxLine("BayeuxConnection: Processing response ignored for null request!"); } return(false); }
/// <summary> /// Sends a bayeux message to the server. /// Connection must be established first otherwise the exception will be thrown. /// </summary> public void Send(BayeuxRequest message, bool asynchronous) { if (_state != BayeuxConnectionState.Connected) { throw new InvalidOperationException("Not connected"); } if (message == null) { throw new ArgumentNullException("message"); } Send(message, null, asynchronous); }
private void DataSource_OnDataReceiveFailed(object sender, HttpDataSourceEventArgs e) { // say, there the current request is no more needed: BayeuxRequest r = _request; _request = null; if (r != null) { r.ProcessFailed(e); } OnDataFailed(new BayeuxConnectionEventArgs(this, e.StatusCode, e.StatusDescription)); }
/// <summary> /// Sends a bayeux message to the server with the ability to override the JSON returned by request object itself /// with the one specified as raw JSON data. /// </summary> public void Send(BayeuxRequest message, string overrideWithJSonData, bool asynchronous) { if (message == null) { throw new ArgumentNullException("message"); } string dataToSend = overrideWithJSonData; lock (_syncObject) { if (_request != null) { if (_httpConnection.IsActive) { _httpConnection.Cancel(); // this is a sync operation, which should cause the _request to be nulled ... } _request = null; } if (_request != null) { throw new InvalidOperationException("Can't start new request, when current has not been finished/cancelled"); } if (string.IsNullOrEmpty(message.ClientID)) { message.ClientID = ClientID; } _request = message; // serialize JSON data as text message if not provided as parameter: if (string.IsNullOrEmpty(overrideWithJSonData)) { dataToSend = SerializeRequest(message); } } if (asynchronous) { _httpConnection.SendRequestAsync(null, dataToSend, message.RequestMethod, HttpDataSourceResponseType.AsString); } else { _httpConnection.SendRequest(null, dataToSend, message.RequestMethod, HttpDataSourceResponseType.AsString); } }
/// <summary> /// Starts another long-polling HTTP connection to asynchronously receive events from Bayeux server. /// </summary> public void StartLongPolling(BayeuxRequest request) { if (request == null) { throw new ArgumentNullException("request"); } if (_httpLongPollingConnection == null) { throw new InvalidOperationException("Long-polling connection not specified during BayeuxConnection object creation"); } if (State != BayeuxConnectionState.Connected) { throw new InvalidOperationException("Not connected"); } if (IsLongPolling) { throw new InvalidOperationException("Connection is already polling"); } _longPollingRequest = request; _longPolling = true; ReconnectLongPollingConnection(true); }
private void ProcessReceivedData(BayeuxRequest request, HttpDataSourceEventArgs e) { IJSonObject jsonData = null; try { // read JSON data: jsonData = _jsonReader.ReadAsJSonObject(e.StringData); OnDataReceived(new BayeuxConnectionEventArgs(this, e.StatusCode, e.StatusDescription, e.StringData, jsonData, null)); } catch (JSonReaderException ex) { OnDataFailed(new BayeuxConnectionEventArgs(this, e.StatusCode, e.StatusDescription, e.StringData, ex)); } if (jsonData != null) { // process JSON response, in case it is an array of responses: if (jsonData.IsArray) { foreach (IJSonObject message in jsonData.ArrayItems) { ProcessResponseMessage(request, e.StatusCode, e.StatusDescription, message, e.StringData); } } else { ProcessResponseMessage(request, e.StatusCode, e.StatusDescription, jsonData, e.StringData); } } else { DebugLog.WriteBayeuxLine("--- No JSON data received from server ---"); OnDataFailed(new BayeuxConnectionEventArgs(this, HttpStatusCode.NoContent, "No JSON data received")); } }
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> /// Sends bayeux message. /// </summary> protected void SendRequest(BayeuxRequest message, bool asynchronous) { Send(message, null, asynchronous); }