} /* PlayFile() */ /// <summary> /// This is an example of how to populate and call a more complicated /// RESTapi structure. We play an audio/video file from here... /// </summary> /// <param name="audioUri"></param> /// <param name="videoUri"></param> /// protected virtual void PlayFile(String audioUri, RESTapi.audio_type_option audioType = RESTapi.audio_type_option.audioxwav, String videoUri = "", RESTapi.video_type_option videoType = RESTapi.video_type_option.videoxvid) { bool hasAudio = !String.IsNullOrWhiteSpace(audioUri); bool hasVideo = !String.IsNullOrWhiteSpace(videoUri); RESTapi.web_service ws = new RESTapi.web_service() { Item = new RESTapi.call() { call_action = new RESTapi.call_action() { Item = new RESTapi.play() { offset = "0s", repeat = "0", delay = "0s", play_source = new RESTapi.play_source() { audio_uri = hasAudio ? audioUri : String.Empty, audio_type = audioType, audio_typeSpecified = hasAudio, video_uri = hasVideo ? videoUri : String.Empty, video_type = videoType, video_typeSpecified = hasVideo, } } } } }; if (hasAudio) { LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Debug1, "Call::PlayFile : Playing audio \"{0}\"...", audioUri); } if (hasVideo) { LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Debug1, "Call::PlayFile : Playing video \"{0}\"...", videoUri); } String responseString = String.Empty; if (RestHelpers.SendHttpRequest(out responseString, CallURI, "PUT", ws)) { LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Debug1, "Call::PlayFile : Play file OK"); LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Debug1, responseString); } else { LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Error, "Call::PlayFile : Play file failed!"); PutEvent(RESTapi.event_type.end_play); } } /* PlayFile() */
protected virtual void AnswerCall(RESTapi.media_type MediaType = RESTapi.media_type.audiovideo, bool AsyncCompletion = true) { /// <call answer="yes" media="audiovideo" signaling="yes" dtmf_mode="rfc2833" async_completion="yes" /// async_dtmf="yes" async_tone="yes" rx_delta="+0dB" tx_delta="+0dB" cpa="no" info_ack_mode="automatic"/> /// RESTapi.web_service ws = new RESTapi.web_service() { Item = new RESTapi.call() { answer = RESTapi.boolean_type.yes, answerSpecified = true, async_completion = AsyncCompletion ? RESTapi.boolean_type.yes : RESTapi.boolean_type.no, async_completionSpecified = true, media = MediaType, mediaSpecified = true, dtmf_mode = RESTapi.dtmf_mode_option.rfc2833, async_dtmf = RESTapi.boolean_type.yes, async_dtmfSpecified = true, async_tone = RESTapi.boolean_type.yes, async_toneSpecified = true, info_ack_mode = RESTapi.ack_mode_option.automatic, info_ack_modeSpecified = true, } }; String responseString = String.Empty; if (RestHelpers.SendHttpRequest(out responseString, CallURI, "PUT", ws)) { LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Debug1, "Call::AnswerCall : AnswerCall OK"); LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Debug1, responseString); // Note: If we use async_completion, we DON'T have to put the event // manually as it will (or rather... should) appear as a separate // event from the XMS server... // if (!AsyncCompletion) { PutEvent(RESTapi.event_type.answered); } } else { LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Error, "Call::AnswerCall : AnswerCall failed!"); Hangup(); } }
} /* DeleteCall() */ public void Hangup(string ResourceID) { String requestUri = String.Format("http://{0}:{1}/default/calls/{2}?appid={3}", RestSettings.Instance.ServerIP, RestSettings.Instance.ServerPort, ResourceID, RestSettings.Instance.AppID); T currentCall = GetCallByResourceID(ResourceID); if (currentCall != null) { RESTapi.web_service ws = new RESTapi.web_service() { Item = new RESTapi.call() { call_action = new RESTapi.call_action() { Item = new RESTapi.hangup() { content_type = "text/plain", content = "data", } } } }; LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Debug1, "CallDispatcher::Hangup : Hanging up call with ID \"{0}\"...", ResourceID); String responseString = String.Empty; /// Send the hangup request... /// if (RestHelpers.SendHttpRequest(out responseString, requestUri, "PUT", ws)) { LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Debug1, "CallDispatcher::Hangup : Hangup OK"); LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Debug1, responseString); } else { LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Error, "CallDispatcher::Hangup : Hangup failed!"); } /// Remember to delete the call resource... /// DeleteCall(ResourceID); } } /* Hangup() */
private void PutEvent(RESTapi.event_type type) { RESTapi.web_service ws = new RESTapi.web_service() { Item = new RESTapi.@event() { type = type, resource_type = ResourceType, resource_id = ResourceID, } }; /// IMPORTANT: Call the dispatcher IN A NEW THREAD or stuff will just /// randomly lock up / fail for no apparent reason! /// ThreadPool.QueueUserWorkItem(x => { this.Dispatcher.ProcessRequest(ws); }); } /* PutEvent() */
protected virtual void AcceptCall(bool EarlyMedia = true, RESTapi.media_type MediaType = RESTapi.media_type.audiovideo) { /// <call accept="yes" early_media="yes" media="audiovideo" signaling="yes" dtmf_mode="rfc2833" /// async_dtmf="yes" async_tone="yes" rx_delta="+0dB" tx_delta="+0dB" cpa="no" info_ack_mode="automatic"/> /// RESTapi.web_service ws = new RESTapi.web_service() { Item = new RESTapi.call() { accept = RESTapi.boolean_type.yes, acceptSpecified = true, early_media = EarlyMedia ? RESTapi.boolean_type.yes : RESTapi.boolean_type.no, early_mediaSpecified = true, media = MediaType, mediaSpecified = true, dtmf_mode = RESTapi.dtmf_mode_option.rfc2833, async_dtmf = RESTapi.boolean_type.yes, async_dtmfSpecified = true, async_tone = RESTapi.boolean_type.yes, async_toneSpecified = true, info_ack_mode = RESTapi.ack_mode_option.automatic, info_ack_modeSpecified = true, } }; String responseString = String.Empty; if (RestHelpers.SendHttpRequest(out responseString, CallURI, "PUT", ws)) { LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Debug1, "Call::AcceptCall : Accept call OK"); LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Debug1, responseString); PutEvent(RESTapi.event_type.ringing); } else { LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Error, "Call::AcceptCall : Accept call failed!"); Hangup(); } }
/// <summary> /// Ok - if we get here (!) then we have a valid event associated with a /// specific call. We should handle the event (obviously!) appropriately. /// </summary> /// <param name="ws">The web_service request to process</param> /// protected virtual void HandleEvent(RESTapi.web_service ws) { RESTapi.@event @event = ws.Item as RESTapi.@event; LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Event, "Call::HandleEvent : Processing event \"{0}\"", @event.type.ToString()); this._LastEvent = ws.Item as RESTapi.@event; this._LastEventData = null; if (this._LastEvent.event_data != null) { this._LastEventData = this._LastEvent.event_data.ToDictionary(x => x.name, x => x.value); /*string _Buf = ""; * * foreach (KeyValuePair<string, string> kv in this._LastEventData) * { * _Buf += string.Format(" => {0}->{1}\n", kv.Key, kv.Value); * } * * Logger.LogMessage("Call::HandleEvent : Event has associated event data:\n{0}", _Buf);*/ } switch (@event.type) { case RESTapi.event_type.incoming: this.CallState = CallStateType.Ringing; OnIncoming(); break; case RESTapi.event_type.ringing: this.CallState = CallStateType.Ringing; OnRinging(); break; case RESTapi.event_type.accepted: this.CallState = CallStateType.Ringing; OnAccepted(); break; case RESTapi.event_type.answered: case RESTapi.event_type.connected: this.CallState = CallStateType.Connected; OnConnected(); break; case RESTapi.event_type.alarm: OnAlarm(); break; case RESTapi.event_type.dtmf: OnDtmf(); break; case RESTapi.event_type.end_play: OnEndPlay(); break; case RESTapi.event_type.hangup: this.CallState = CallStateType.Hangup; OnHangup(); break; default: LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Error, "Call::HandleEvent : Unhandled event \"{0}\"", @event.type.ToString()); break; } }
/// <summary> /// We received a web_service object to process... this function will /// determine if the request is for a new call or an existing call. /// Additionally, if the request is a hangup, we should delete the call /// from our list. /// </summary> /// <param name="ws"> The web_service request to process</param> /// public void ProcessRequest(RESTapi.web_service ws) { T currentCall = null; RESTapi.@event @event = ws.Item as RESTapi.@event; if (@event.type == RESTapi.event_type.keepalive) { LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Debug1, "CallDispatcher::ProcessRequest : Keepalive received"); return; } String response = RestHelpers.RESTapiToXML(ws, typeof(RESTapi.web_service)); LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Debug1, "CallDispatcher::ProcessRequest : Received web service request :\n{0}", response); if (@event.type == RESTapi.event_type.incoming) { /// Note that we probably should check that this is not an existing /// call / resource id rather than assuming... /// currentCall = new T() { Dispatcher = this as ICallDispatcher <CallBase>, Direction = "inbound", ResourceID = @event.resource_id, ResourceType = @event.resource_type, CallState = CallBase.CallStateType.Ringing, }; foreach (RESTapi.event_data data in @event.event_data) { switch (data.name.ToLower()) { case "caller_uri": currentCall.CallerUri = data.value; break; case "called_uri": currentCall.CalledUri = data.value; break; case "uri": currentCall.Uri = data.value; break; case "name": currentCall.Name = data.value; break; } } } else { foreach (T call in Calls) { if (call.ResourceID == @event.resource_id) { currentCall = call; break; } } } if (currentCall != null) { /// The following is a way of calling a protected / private member /// of a class - kind of like using "friend class" in C++. It uses /// reflection. /// MethodInfo handleEventMethod = currentCall.GetType().GetMethod("HandleEvent", BindingFlags.Instance | BindingFlags.NonPublic); switch (@event.type) { case RESTapi.event_type.incoming: Calls.Add(currentCall); handleEventMethod.Invoke(currentCall, new object[] { ws }); break; case RESTapi.event_type.hangup: handleEventMethod.Invoke(currentCall, new object[] { ws }); Calls.Remove(currentCall); break; default: handleEventMethod.Invoke(currentCall, new object[] { ws }); break; } } } /* ProcessRequest() */
} /* ProcessRequest() */ /// <summary> /// Gets a list of any calls that are already in progress on the XMS server. We can /// use this to populate our calls list and potentially do "stuff" with them... /// </summary> /// public void GetCalls() { String uri = String.Format("http://{0}:{1}/default/calls?appid={2}", RestSettings.Instance.ServerIP, RestSettings.Instance.ServerPort, RestSettings.Instance.AppID); String responseString = String.Empty; if (RestHelpers.SendHttpRequest(out responseString, uri, "GET")) { LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Debug1, "CallDispatcher::GetCalls : Received web service request :\n{0}", responseString); RESTapi.web_service ws = (RESTapi.web_service)RestHelpers.XMLToRESTapi(responseString, typeof(RESTapi.web_service)); RESTapi.calls_response Responses = (RESTapi.calls_response)ws.Item; int numCalls = 0; if (!int.TryParse(Responses.size, out numCalls)) { LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Error, "CallDispatcher::GetCalls : Oops... RESTapi.calls_response.size is not a number!"); return; } LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Info, "CallDispatcher::GetCalls : Found {0} RESTapi calls", numCalls); if (numCalls > 0 && Responses.call_response != null) { /// Each "call_response" object corresponds to a single call in progress. /// foreach (RESTapi.call_response Response in Responses.call_response) { bool Exists = false; foreach (T call in Calls) { if (call.ResourceID == Response.identifier) { Exists = true; break; } } if (!Exists) { this.Calls.Add(new T() { Dispatcher = this as ICallDispatcher <CallBase>, ResourceID = Response.identifier, CalledUri = Response.destination_uri, CallerUri = Response.source_uri, Direction = Response.call_type.ToString(), Uri = Response.destination_uri, Name = Response.appid, CallState = Response.connected == RESTapi.boolean_type.yes ? CallBase.CallStateType.Connected : CallBase.CallStateType.Unknown, }); } } } } } /* GetCalls() */
} /* DisconnectFromEventHandler() */ static public EventDispatcherList <T> GetEventHandlers() { EventDispatcherList <T> retval = new EventDispatcherList <T>(); String uri = String.Format("http://{0}:{1}/default/eventhandlers?appid={2}", RestSettings.Instance.ServerIP, RestSettings.Instance.ServerPort, RestSettings.Instance.AppID); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri); request.Method = "GET"; request.ProtocolVersion = HttpVersion.Version11; try { LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Debug2, "EventDispatcher::GetEventHandlers : Sent GET {0}", uri); /// This waits for a response from the far end... /// using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) { using (StreamReader stream = new StreamReader(response.GetResponseStream())) { /// Read the result from the far end... /// String result = stream.ReadToEnd(); LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Debug2, "EventDispatcher::GetEventHandlers : Received {0:D} {1}", response.StatusCode, response.StatusDescription); LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Debug3, "EventDispatcher::GetEventHandlers : {0}", result); RESTapi.web_service evresponse = RestHelpers.XMLToRESTapi(result, typeof(RESTapi.web_service)) as RESTapi.web_service; if (evresponse != null) { /// We know that the actual object type is "eventhandlers_response" /// in this case so we go ahead and cast it... /// RESTapi.eventhandlers_response evhandlers = evresponse.Item as RESTapi.eventhandlers_response; if (evhandlers != null) { LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Info, "EventDispatcher::GetEventHandlers : Found {0} existing event handlers", evhandlers.size); if (evhandlers.eventhandler_response != null) { foreach (RESTapi.eventhandler_response ev in evhandlers.eventhandler_response) { LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Debug3, "EventDispatcher::GetEventHandlers : Event handler :\n" + " => identifier = {0}\n" + " => href = {1}\n" + " => appid = {2}\n", ev.identifier, ev.href, ev.appid); retval.Add(new EventDispatcher <T>() { _OID = ev.identifier, _EventHandlerURI = ev.href.Contains("http://") ? String.Format("{0}?appid={1}", ev.href, ev.appid) : String.Format("http://{0}:{1}{2}?appid={3}", RestSettings.Instance.ServerIP, RestSettings.Instance.ServerPort, ev.href, ev.appid), _ConnectionState = ConnectionStateEnum.Connected, }); } } } } } } } catch (WebException ex) { if (ex.Status == WebExceptionStatus.ProtocolError) { HttpWebResponse response = ex.Response as HttpWebResponse; if (response != null) { LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Warning, "EventDispatcher::GetEventHandlers : Received HTTP failure response {0} {1}", (int)response.StatusCode, response.StatusDescription); } } else { LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Warning, "EventDispatcher::GetEventHandlers : {0}\n{1}", ex.Message.ToString(), ex.StackTrace.ToString()); } return(retval); } catch (Exception ex) { LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Warning, "EventDispatcher::GetEventHandlers : {0}\n{1}", ex.Message.ToString(), ex.StackTrace.ToString()); return(retval); } return(retval); } /* GetEventHandlers() */
/// <summary> /// Connect to the XMS server's event handler. This demonstrates how to /// use the web service API that was generated from the XSD. /// </summary> /// <returns>true = success, false = failure</returns> /// private bool ConnectToEventHandler() { /// This is the URI we are sending the request to... /// String uri = String.Format("http://{0}:{1}/default/eventhandlers?appid={2}", RestSettings.Instance.ServerIP, RestSettings.Instance.ServerPort, RestSettings.Instance.AppID); /// Here we create the actual HTTP request. We set the method to one /// of "POST" or "GET". Note that we do have to explicitly set the /// protocol version as XMS doesn't like the .NET default... /// HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri); request.Method = "POST"; request.ProtocolVersion = HttpVersion.Version11; /// This creates a RESTapi.web_service object which is the actual /// payload of the request... in this case, it's an event subscribe /// type request. /// RESTapi.web_service service = new RESTapi.web_service() { Item = new RESTapi.eventhandler() { eventsubscribe = new RESTapi.eventsubscribe[] { new RESTapi.eventsubscribe() } } }; /// The RestHelpers class contains various functions for converting /// between RESTapi objects and XML / text. In this case, we need to /// convert from RESTapi -> an XML string. /// String requestContent = RestHelpers.RESTapiToXML(service, typeof(RESTapi.web_service)); if (String.IsNullOrWhiteSpace(requestContent)) { /// The conversion failed as the string is empty... /// return(false); } /// Set the content type and length appropriately... /// request.ContentType = "application/xml"; request.ContentLength = requestContent.Length; try { /// The following code sends the request. The "using" makes sure /// that if the request fails, the stream gets closed properly (ie. /// it cleans up stream exceptions correctly!) /// using (StreamWriter stream = new StreamWriter(request.GetRequestStream())) { stream.Write(requestContent); stream.Close(); } LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Debug2, "EventDispatcher::ConnectToEventHandler : Sent POST {0}", uri); /// This waits for the response from the XMS server... /// using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) { using (StreamReader stream = new StreamReader(response.GetResponseStream())) { String result = stream.ReadToEnd(); if (String.IsNullOrWhiteSpace(result)) { LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Warning, "EventDispatcher::ConnectToEventHandler : POST response contained no payload!"); return(false); } /// If all went well and fingers (and toes) crossed, we have /// a "payload" (ie. XML...) from the XMS server which contains /// "stuff" for us to do things with... /// LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Debug2, "EventDispatcher::ConnectToEventHandler : Received {0:D} {1}", response.StatusCode, response.StatusDescription); try { /// We first convert the XML/text response into a /// web_service object... /// RESTapi.web_service evresponse = RestHelpers.XMLToRESTapi(result, typeof(RESTapi.web_service)) as RESTapi.web_service; if (evresponse != null) { /// We know that the actual object type is "eventhandler_response" /// in this case so we go ahead and cast it... /// RESTapi.eventhandler_response item = evresponse.Item as RESTapi.eventhandler_response; /// We need to store the OID and EventHandler URI for later /// use (ie. when we disconnect / process events!) /// this._OID = item.identifier; this._EventHandlerURI = String.Format("{0}?appid={1}", item.href, RestSettings.Instance.AppID); if (!this._EventHandlerURI.Contains("http://")) { this._EventHandlerURI = String.Format("http://{0}:{1}{2}?appid={3}", RestSettings.Instance.ServerIP, RestSettings.Instance.ServerPort, item.href, RestSettings.Instance.AppID); } LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Debug2, "EventDispatcher::ConnectToEventHandler : EventHandler URI is \"{0}\", OID is \"{1}\"", this._EventHandlerURI, this._OID); } } catch (Exception ex) { LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Warning, "EventDispatcher::ConnectToEventHandler : {0}\n{1}", ex.Message, ex.StackTrace); return(false); } if (String.IsNullOrWhiteSpace(this._EventHandlerURI)) { LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Warning, "EventDispatcher::ConnectToEventHandler : EventHandler URI was null!"); return(false); } } } } catch (WebException ex) { /// Process any exceptions that we caught above... /// if (ex.Status == WebExceptionStatus.ProtocolError) { HttpWebResponse response = ex.Response as HttpWebResponse; if (response != null) { LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Warning, "EventDispatcher::ConnectToEventHandler : Received HTTP failure response {0} {1}", (int)response.StatusCode, response.StatusDescription); } } else { LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Warning, "EventDispatcher::ConnectToEventHandler : {0}\n{1}", ex.Message.ToString(), ex.StackTrace.ToString()); } return(false); } catch (Exception ex) { LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Warning, "EventDispatcher::ConnectToEventHandler : {0}\n{1}", ex.Message.ToString(), ex.StackTrace.ToString()); return(false); } LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Debug2, "EventDispatcher::ConnectToEventHandler : EventHandler connected"); return(true); } /* ConnectToEventHandler() */
/// <summary> /// This thread processes any events that occur whilst the connection to /// the XMS server is open. It sends a single "GET" request which then /// receives "chunks" of data. Ie. there is ONE request but MULTIPLE /// responses. We pass each of these "chunks" to the call dispatcher to /// work out what to do with them. /// </summary> /// public void InternalProcessEventsThread() { LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Debug2, "EventDispatcher::InternalProcessEventsThread : Entering InternalProcessEventsThread()"); String ServerUri = String.Format("http://{0}:{1}", RestSettings.Instance.ServerIP, RestSettings.Instance.ServerPort); try { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(this._EventHandlerURI); request.Accept = null; request.ContentType = null; request.KeepAlive = true; request.Method = "GET"; request.ProtocolVersion = HttpVersion.Version11; LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Debug2, "EventDispatcher::InternalProcessEventsThread : Sent GET {0}", this._EventHandlerURI); using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) { using (StreamReader stream = new StreamReader(response.GetResponseStream())) { LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Debug2, "EventDispatcher::InternalProcessEventsThread : Received {0:D} {1}", response.StatusCode, response.StatusDescription); LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Info, "EventDispatcher::InternalProcessEventsThread : Waiting for events..."); while (!stream.EndOfStream) { String line = stream.ReadLine(); if (String.IsNullOrWhiteSpace(line)) { continue; } int bufferLength = Int32.Parse(line, NumberStyles.AllowHexSpecifier); if (bufferLength > 0) { /// MC : Thu Feb 19 10:52:00 GMT 2015 /// /// Note that there was a pretty serious bug / omission in the following section whereby I had assumed that /// stream.Read(...) would always return the whole data chunk. This is not the case. Sometimes (seemingly /// when the data spans two TCP packets) stream.Read(...) returns LESS than "bufferLength" chars and we are /// required to keep calling the function until we have ALL of the data. Failure to do this will cause an /// exception when attempting to cast the data to a RESTapi.web_service object. /// char[] buffer = new char[bufferLength + 1]; int readLength = 0; int count = 0; while (readLength < bufferLength) { readLength += stream.Read(buffer, readLength, bufferLength - readLength); count++; } LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Debug2, "EventDispatcher::InternalProcessEventsThread : Read {0} bytes from stream [{1} read{2}]", readLength, count, count == 1 ? "" : "s"); /// Cast the data to a web service event... /// RESTapi.web_service ws = RestHelpers.XMLToRESTapi(new String(buffer), typeof(RESTapi.web_service)) as RESTapi.web_service; if (ws != null) { /// We have an event! We need to pass this to "something" /// that will determine which call etc. the request belongs /// to - ie. a call dispatcher. /// CallDispatcher <T> .Instance.ProcessRequest(ws); } } } } } } catch (WebException ex) { if (ex.Status == WebExceptionStatus.ProtocolError) { HttpWebResponse response = ex.Response as HttpWebResponse; if (response != null) { LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Warning, "EventDispatcher::InternalProcessEventsThread : Received HTTP failure response {0:D} {1}", (int)response.StatusCode, response.StatusDescription); } } else { LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Warning, "EventDispatcher::InternalProcessEventsThread : {0}\n{1}", ex.Message.ToString(), ex.StackTrace.ToString()); } } catch (ThreadInterruptedException ex) { LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Warning, "EventDispatcher::InternalProcessEventsThread : {0}\n{1}", ex.Message.ToString(), ex.StackTrace.ToString()); } catch (Exception ex) { LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Warning, "EventDispatcher::InternalProcessEventsThread : {0}\n{1}", ex.Message.ToString(), ex.StackTrace.ToString()); } LoggingSingleton.Instance.Message(LogType.Library, LogLevel.Debug2, "EventDispatcher::InternalProcessEventsThread : Leaving InternalProcessEventsThread()"); }