From f6517fa567be49e382ebbaf0fc8cd2b4186f169e Mon Sep 17 00:00:00 2001 From: sta Date: Thu, 10 Oct 2013 16:38:41 +0900 Subject: [PATCH] Modified WebSocketSessionManager.cs and WebSocketServiceHostManager.cs (Modified parameter order of some methods. e.g. SendTo (data, id) -> SendTo (id, data)) --- websocket-sharp/Server/HttpServer.cs | 3 +- websocket-sharp/Server/WebSocketServer.cs | 2 +- .../Server/WebSocketServiceHostManager.cs | 891 +++++++++++------- .../Server/WebSocketSessionManager.cs | 685 +++++++++----- websocket-sharp/WebSocket.cs | 5 +- websocket-sharp/WsFrame.cs | 15 + 6 files changed, 1019 insertions(+), 582 deletions(-) diff --git a/websocket-sharp/Server/HttpServer.cs b/websocket-sharp/Server/HttpServer.cs index 706b08fc..41ba66a4 100644 --- a/websocket-sharp/Server/HttpServer.cs +++ b/websocket-sharp/Server/HttpServer.cs @@ -429,8 +429,9 @@ namespace WebSocketSharp.Server { var wsContext = context.AcceptWebSocket (); + var path = wsContext.Path; IWebSocketServiceHost host; - if (!_serviceHosts.TryGetServiceHostInternally (wsContext.Path, out host)) + if (path == null || !_serviceHosts.TryGetServiceHostInternally (path, out host)) { context.Response.StatusCode = (int) HttpStatusCode.NotImplemented; return false; diff --git a/websocket-sharp/Server/WebSocketServer.cs b/websocket-sharp/Server/WebSocketServer.cs index e39dbca9..4c72ef4f 100644 --- a/websocket-sharp/Server/WebSocketServer.cs +++ b/websocket-sharp/Server/WebSocketServer.cs @@ -227,7 +227,7 @@ namespace WebSocketSharp.Server var path = context.Path; IWebSocketServiceHost host; - if (!_serviceHosts.TryGetServiceHostInternally (path, out host)) + if (path == null || !_serviceHosts.TryGetServiceHostInternally (path, out host)) { websocket.Close (HttpStatusCode.NotImplemented); return; diff --git a/websocket-sharp/Server/WebSocketServiceHostManager.cs b/websocket-sharp/Server/WebSocketServiceHostManager.cs index 922b1526..f5958d46 100644 --- a/websocket-sharp/Server/WebSocketServiceHostManager.cs +++ b/websocket-sharp/Server/WebSocketServiceHostManager.cs @@ -109,28 +109,19 @@ namespace WebSocketSharp.Server } /// - /// Gets the WebSocket service host with the specified . + /// Gets a WebSocket service host with the specified . /// /// - /// A instance that represents the WebSocket service host - /// if it is successfully found; otherwise, . + /// A instance that represents the service host + /// if the service is successfully found; otherwise, . /// /// - /// A that contains an absolute path to the WebSocket service managed by - /// the WebSocket service host to get. + /// A that contains an absolute path to the service to find. /// public IWebSocketServiceHost this [string servicePath] { get { - var msg = servicePath.CheckIfValidServicePath (); - if (msg != null) - { - _logger.Error (msg); - return null; - } - IWebSocketServiceHost host; - if (!TryGetServiceHostInternally (servicePath, out host)) - _logger.Error ("The WebSocket service with the specified path not found.\npath: " + servicePath); + TryGetServiceHost (servicePath, out host); return host; } @@ -197,54 +188,70 @@ namespace WebSocketSharp.Server #region Private Methods - private void broadcast (Opcode opcode, byte [] data) + private void broadcast (Opcode opcode, byte [] data, Action completed) + { + var cache = new Dictionary (); + try { + foreach (var host in ServiceHosts) + { + if (_state != ServerState.START) + break; + + host.Sessions.Broadcast (opcode, data, cache); + } + + if (completed != null) + completed (); + } + catch (Exception ex) { + _logger.Fatal (ex.ToString ()); + } + finally { + cache.Clear (); + } + } + + private void broadcast (Opcode opcode, Stream stream, Action completed) + { + var cache = new Dictionary (); + try { + foreach (var host in ServiceHosts) + { + if (_state != ServerState.START) + break; + + host.Sessions.Broadcast (opcode, stream, cache); + } + + if (completed != null) + completed (); + } + catch (Exception ex) { + _logger.Fatal (ex.ToString ()); + } + finally { + foreach (var cached in cache.Values) + cached.Dispose (); + + cache.Clear (); + } + } + + private void broadcastAsync (Opcode opcode, byte [] data, Action completed) { WaitCallback callback = state => { - var cache = new Dictionary (); - try { - foreach (var host in ServiceHosts) - { - if (_state != ServerState.START) - break; - - host.Sessions.BroadcastInternally (opcode, data, cache); - } - } - catch (Exception ex) { - _logger.Fatal (ex.ToString ()); - } - finally { - cache.Clear (); - } + broadcast (opcode, data, completed); }; ThreadPool.QueueUserWorkItem (callback); } - private void broadcast (Opcode opcode, Stream stream) + private void broadcastAsync (Opcode opcode, Stream stream, Action completed) { WaitCallback callback = state => { - var cache = new Dictionary (); - try { - foreach (var host in ServiceHosts) - { - if (_state != ServerState.START) - break; - - host.Sessions.BroadcastInternally (opcode, stream, cache); - } - } - catch (Exception ex) { - _logger.Fatal (ex.ToString ()); - } - finally { - foreach (var cached in cache.Values) - cached.Dispose (); - - cache.Clear (); - } + broadcast (opcode, stream, completed); }; ThreadPool.QueueUserWorkItem (callback); @@ -258,7 +265,7 @@ namespace WebSocketSharp.Server if (_state != ServerState.START) break; - result.Add (host.ServicePath, host.Sessions.BroadpingInternally (frameAsBytes, timeOut)); + result.Add (host.ServicePath, host.Sessions.Broadping (frameAsBytes, timeOut)); } return result; @@ -277,7 +284,7 @@ namespace WebSocketSharp.Server if (_serviceHosts.TryGetValue (servicePath, out host)) { _logger.Error ( - "The WebSocket service with the specified path already exists.\npath: " + servicePath); + "A WebSocket service with the specified path already exists.\npath: " + servicePath); return; } @@ -297,7 +304,7 @@ namespace WebSocketSharp.Server if (!_serviceHosts.TryGetValue (servicePath, out host)) { _logger.Error ( - "The WebSocket service with the specified path not found.\npath: " + servicePath); + "A WebSocket service with the specified path not found.\npath: " + servicePath); return false; } @@ -345,10 +352,16 @@ namespace WebSocketSharp.Server internal bool TryGetServiceHostInternally (string servicePath, out IWebSocketServiceHost serviceHost) { servicePath = HttpUtility.UrlDecode (servicePath).TrimEndSlash (); + bool result; lock (_sync) { - return _serviceHosts.TryGetValue (servicePath, out serviceHost); + result = _serviceHosts.TryGetValue (servicePath, out serviceHost); } + + if (!result) + _logger.Error ("A WebSocket service with the specified path not found.\npath: " + servicePath); + + return result; } #endregion @@ -356,13 +369,50 @@ namespace WebSocketSharp.Server #region Public Methods /// - /// Broadcasts the specified array of to all clients of the WebSocket services - /// provided by the WebSocket server. + /// Broadcasts a binary to all clients of the WebSocket services + /// provided by a WebSocket server. /// + /// + /// This method does not wait for the broadcast to be complete. + /// /// - /// An array of to broadcast. + /// An array of that contains a binary data to broadcast. /// public void Broadcast (byte [] data) + { + Broadcast (data, null); + } + + /// + /// Broadcasts a text to all clients of the WebSocket services + /// provided by a WebSocket server. + /// + /// + /// This method does not wait for the broadcast to be complete. + /// + /// + /// A that contains a text data to broadcast. + /// + public void Broadcast (string data) + { + Broadcast (data, null); + } + + /// + /// Broadcasts a binary to all clients of the WebSocket services + /// provided by a WebSocket server. + /// + /// + /// This method does not wait for the broadcast to be complete. + /// + /// + /// An array of that contains a binary data to broadcast. + /// + /// + /// A delegate that references the method(s) called when + /// the broadcast is complete. + /// + public void Broadcast (byte [] data, Action completed) { var msg = _state.CheckIfStarted () ?? data.CheckIfValidSendData (); if (msg != null) @@ -372,19 +422,26 @@ namespace WebSocketSharp.Server } if (data.LongLength <= WebSocket.FragmentLength) - broadcast (Opcode.BINARY, data); + broadcastAsync (Opcode.BINARY, data, completed); else - broadcast (Opcode.BINARY, new MemoryStream (data)); + broadcastAsync (Opcode.BINARY, new MemoryStream (data), completed); } /// - /// Broadcasts the specified to all clients of the WebSocket services - /// provided by the WebSocket server. + /// Broadcasts a text to all clients of the WebSocket services + /// provided by a WebSocket server. /// + /// + /// This method does not wait for the broadcast to be complete. + /// /// - /// A to broadcast. + /// A that contains a text data to broadcast. /// - public void Broadcast (string data) + /// + /// A delegate that references the method(s) called when + /// the broadcast is complete. + /// + public void Broadcast (string data, Action completed) { var msg = _state.CheckIfStarted () ?? data.CheckIfValidSendData (); if (msg != null) @@ -395,71 +452,241 @@ namespace WebSocketSharp.Server var rawData = Encoding.UTF8.GetBytes (data); if (rawData.LongLength <= WebSocket.FragmentLength) - broadcast (Opcode.TEXT, rawData); + broadcastAsync (Opcode.TEXT, rawData, completed); else - broadcast (Opcode.TEXT, new MemoryStream (rawData)); + broadcastAsync (Opcode.TEXT, new MemoryStream (rawData), completed); } /// - /// Broadcasts the specified array of to all clients of the WebSocket service - /// with the specified . + /// Broadcasts a binary data from the specified to all clients + /// of the WebSocket services provided by a WebSocket server. /// - /// - /// An array of to broadcast. + /// + /// This method does not wait for the broadcast to be complete. + /// + /// + /// A object from which contains a binary data to broadcast. /// - /// - /// A that contains an absolute path to the WebSocket service to find. + /// + /// An that contains the number of bytes to broadcast. /// - public void BroadcastTo (byte [] data, string servicePath) + /// + /// true if is disposed after a binary data broadcasted; + /// otherwise, false. + /// + public void Broadcast (Stream stream, int length, bool dispose) { - var msg = _state.CheckIfStarted () ?? servicePath.CheckIfValidServicePath (); + Broadcast (stream, length, dispose, null); + } + + /// + /// Broadcasts a binary data from the specified to all clients + /// of the WebSocket services provided by a WebSocket server. + /// + /// + /// This method does not wait for the broadcast to be complete. + /// + /// + /// A object from which contains a binary data to broadcast. + /// + /// + /// An that contains the number of bytes to broadcast. + /// + /// + /// true if is disposed after a binary data broadcasted; + /// otherwise, false. + /// + /// + /// A delegate that references the method(s) called when + /// the broadcast is complete. + /// + public void Broadcast (Stream stream, int length, bool dispose, Action completed) + { + var msg = _state.CheckIfStarted () ?? + stream.CheckIfCanRead () ?? + (length < 1 ? "'length' must be greater than 0." : null); + if (msg != null) { _logger.Error (msg); return; } - IWebSocketServiceHost host; - if (!TryGetServiceHostInternally (servicePath, out host)) + Action result = data => { - _logger.Error ("The WebSocket service with the specified path not found.\npath: " + servicePath); - return; - } + var readLen = data.Length; + if (readLen == 0) + { + _logger.Error ("A data cannot be read from 'stream'."); + return; + } - host.Sessions.Broadcast (data); + if (readLen != length) + _logger.Warn (String.Format ( + "A data with 'length' cannot be read from 'stream'.\nexpected: {0} actual: {1}", + length, + readLen)); + + if (dispose) + stream.Dispose (); + + if (readLen <= WebSocket.FragmentLength) + broadcast (Opcode.BINARY, data, completed); + else + broadcast (Opcode.BINARY, new MemoryStream (data), completed); + }; + + Action exception = ex => + { + _logger.Fatal (ex.ToString ()); + }; + + stream.ReadBytesAsync (length, result, exception); } /// - /// Broadcasts the specified to all clients of the WebSocket service + /// Broadcasts a binary to all clients of a WebSocket service /// with the specified . /// - /// - /// A to broadcast. - /// + /// + /// This method does not wait for the broadcast to be complete. + /// /// /// A that contains an absolute path to the WebSocket service to find. /// - public void BroadcastTo (string data, string servicePath) + /// + /// An array of that contains a binary data to broadcast. + /// + public void BroadcastTo (string servicePath, byte [] data) { - var msg = _state.CheckIfStarted () ?? servicePath.CheckIfValidServicePath (); - if (msg != null) - { - _logger.Error (msg); - return; - } - - IWebSocketServiceHost host; - if (!TryGetServiceHostInternally (servicePath, out host)) - { - _logger.Error ("The WebSocket service with the specified path not found.\npath: " + servicePath); - return; - } - - host.Sessions.Broadcast (data); + BroadcastTo (servicePath, data, null); } /// - /// Sends Pings to all clients of the WebSocket services provided by the WebSocket server. + /// Broadcasts a text to all clients of a WebSocket service + /// with the specified . + /// + /// + /// This method does not wait for the broadcast to be complete. + /// + /// + /// A that contains an absolute path to the WebSocket service to find. + /// + /// + /// A that contains a text data to broadcast. + /// + public void BroadcastTo (string servicePath, string data) + { + BroadcastTo (servicePath, data, null); + } + + /// + /// Broadcasts a binary to all clients of a WebSocket service + /// with the specified . + /// + /// + /// This method does not wait for the broadcast to be complete. + /// + /// + /// A that contains an absolute path to the WebSocket service to find. + /// + /// + /// An array of that contains a binary data to broadcast. + /// + /// + /// A delegate that references the method(s) called when + /// the broadcast is complete. + /// + public void BroadcastTo (string servicePath, byte [] data, Action completed) + { + IWebSocketServiceHost host; + if (TryGetServiceHost (servicePath, out host)) + host.Sessions.Broadcast (data, completed); + } + + /// + /// Broadcasts a text to all clients of a WebSocket service + /// with the specified . + /// + /// + /// This method does not wait for the broadcast to be complete. + /// + /// + /// A that contains an absolute path to the WebSocket service to find. + /// + /// + /// A that contains a text data to broadcast. + /// + /// + /// A delegate that references the method(s) called when + /// the broadcast is complete. + /// + public void BroadcastTo (string servicePath, string data, Action completed) + { + IWebSocketServiceHost host; + if (TryGetServiceHost (servicePath, out host)) + host.Sessions.Broadcast (data, completed); + } + + /// + /// Broadcasts a binary data from the specified to all clients + /// of a WebSocket service with the specified . + /// + /// + /// This method does not wait for the broadcast to be complete. + /// + /// + /// A that contains an absolute path to the WebSocket service to find. + /// + /// + /// A object from which contains a binary data to broadcast. + /// + /// + /// An that contains the number of bytes to broadcast. + /// + /// + /// true if is disposed after a binary data broadcasted; + /// otherwise, false. + /// + public void BroadcastTo (string servicePath, Stream stream, int length, bool dispose) + { + BroadcastTo (servicePath, stream, length, dispose, null); + } + + /// + /// Broadcasts a binary data from the specified to all clients + /// of a WebSocket service with the specified . + /// + /// + /// This method does not wait for the broadcast to be complete. + /// + /// + /// A that contains an absolute path to the WebSocket service to find. + /// + /// + /// A object from which contains a binary data to broadcast. + /// + /// + /// An that contains the number of bytes to broadcast. + /// + /// + /// true if is disposed after a binary data broadcasted; + /// otherwise, false. + /// + /// + /// A delegate that references the method(s) called when + /// the broadcast is complete. + /// + public void BroadcastTo ( + string servicePath, Stream stream, int length, bool dispose, Action completed) + { + IWebSocketServiceHost host; + if (TryGetServiceHost (servicePath, out host)) + host.Sessions.Broadcast (stream, length, dispose, completed); + } + + /// + /// Sends Pings to all clients of the WebSocket services provided by a WebSocket server. /// /// /// A Dictionary<string, Dictionary<string, bool>> that contains the collection of @@ -475,12 +702,12 @@ namespace WebSocketSharp.Server return null; } - return broadping (WsFrame.CreatePingFrame (Mask.UNMASK).ToByteArray (), 1000); + return broadping (WsFrame.EmptyUnmaskPingData, 1000); } /// - /// Sends Pings with the specified to all clients of the WebSocket services - /// provided by the WebSocket server. + /// Sends Pings with the specified to all clients of the WebSocket + /// services provided by a WebSocket server. /// /// /// A Dictionary<string, Dictionary<string, bool>> that contains the collection of @@ -489,15 +716,17 @@ namespace WebSocketSharp.Server /// If is invalid, returns . /// /// - /// A that contains a message to send. + /// A that contains a message to broadcast. /// public Dictionary> Broadping (string message) { if (message == null || message.Length == 0) return Broadping (); - var data = Encoding.UTF8.GetBytes (message); - var msg = _state.CheckIfStarted () ?? data.CheckIfValidPingData (); + byte [] data; + var msg = _state.CheckIfStarted () ?? + (data = Encoding.UTF8.GetBytes (message)).CheckIfValidPingData (); + if (msg != null) { _logger.Error (msg); @@ -508,319 +737,339 @@ namespace WebSocketSharp.Server } /// - /// Sends Pings to all clients of the WebSocket service with the specified . + /// Sends Pings to all clients of a WebSocket service with + /// the specified . /// /// - /// A Dictionary<string, bool> that contains the collection of pairs of session ID and value - /// indicating whether the WebSocket service received a Pong from each client in a time. - /// If the WebSocket service is not found, returns . + /// A Dictionary<string, bool> that contains the collection of pairs of session ID and + /// value indicating whether the WebSocket service received a Pong from each client in a time. + /// If the WebSocket service not found, returns . /// /// /// A that contains an absolute path to the WebSocket service to find. /// public Dictionary BroadpingTo (string servicePath) { - var msg = _state.CheckIfStarted () ?? servicePath.CheckIfValidServicePath (); - if (msg != null) - { - _logger.Error (msg); - return null; - } - IWebSocketServiceHost host; - if (!TryGetServiceHostInternally (servicePath, out host)) - { - _logger.Error ("The WebSocket service with the specified path not found.\npath: " + servicePath); - return null; - } - - return host.Sessions.BroadpingInternally (); + return TryGetServiceHost (servicePath, out host) + ? host.Sessions.Broadping () + : null; } /// - /// Sends Pings with the specified to all clients of the WebSocket service - /// with the specified . + /// Sends Pings with the specified to all clients + /// of a WebSocket service with the specified . /// /// - /// A Dictionary<string, bool> that contains the collection of pairs of session ID and value - /// indicating whether the WebSocket service received a Pong from each client in a time. - /// If the WebSocket service is not found, returns . + /// A Dictionary<string, bool> that contains the collection of pairs of session ID and + /// value indicating whether the WebSocket service received a Pong from each client in a time. + /// If the WebSocket service not found, returns . /// + /// + /// A that contains an absolute path to the WebSocket service to find. + /// /// /// A that contains a message to send. /// - /// - /// A that contains an absolute path to the WebSocket service to find. - /// - public Dictionary BroadpingTo (string message, string servicePath) + public Dictionary BroadpingTo (string servicePath, string message) { - if (message == null || message.Length == 0) - return BroadpingTo (servicePath); - - var data = Encoding.UTF8.GetBytes (message); - var msg = _state.CheckIfStarted () ?? data.CheckIfValidPingData () ?? servicePath.CheckIfValidServicePath (); - if (msg != null) - { - _logger.Error (msg); - return null; - } - IWebSocketServiceHost host; - if (!TryGetServiceHostInternally (servicePath, out host)) - { - _logger.Error ("The WebSocket service with the specified path not found.\npath: " + servicePath); - return null; - } - - return host.Sessions.BroadpingInternally ( - WsFrame.CreatePingFrame (Mask.UNMASK, data).ToByteArray (), 1000); + return TryGetServiceHost (servicePath, out host) + ? host.Sessions.Broadping (message) + : null; } /// - /// Closes the session with the specified and - /// . + /// Closes the session with the specified and + /// . /// + /// + /// A that contains an absolute path to a WebSocket service to find. + /// /// /// A that contains a session ID to find. /// - /// - /// A that contains an absolute path to the WebSocket service to find. - /// - public void CloseSession (string id, string servicePath) + public void CloseSession (string servicePath, string id) { - var msg = _state.CheckIfStarted () ?? servicePath.CheckIfValidServicePath (); - if (msg != null) - { - _logger.Error (msg); - return; - } - IWebSocketServiceHost host; - if (!TryGetServiceHostInternally (servicePath, out host)) - { - _logger.Error ("The WebSocket service with the specified path not found.\npath: " + servicePath); - return; - } - - host.Sessions.CloseSession (id); + if (TryGetServiceHost (servicePath, out host)) + host.Sessions.CloseSession (id); } /// - /// Closes the session with the specified , , - /// and . + /// Closes the session with the specified , , + /// and . /// + /// + /// A that contains an absolute path to a WebSocket service to find. + /// + /// + /// A that contains a session ID to find. + /// /// /// A that contains a status code indicating the reason for closure. /// /// /// A that contains the reason for closure. /// - /// - /// A that contains a session ID to find. - /// - /// - /// A that contains an absolute path to the WebSocket service to find. - /// - public void CloseSession (ushort code, string reason, string id, string servicePath) + public void CloseSession (string servicePath, string id, ushort code, string reason) { - var msg = _state.CheckIfStarted () ?? servicePath.CheckIfValidServicePath (); - if (msg != null) - { - _logger.Error (msg); - return; - } - IWebSocketServiceHost host; - if (!TryGetServiceHostInternally (servicePath, out host)) - { - _logger.Error ("The WebSocket service with the specified path not found.\npath: " + servicePath); - return; - } - - host.Sessions.CloseSession (code, reason, id); + if (TryGetServiceHost (servicePath, out host)) + host.Sessions.CloseSession (id, code, reason); } /// - /// Closes the session with the specified , , - /// and . + /// Closes the session with the specified , , + /// and . /// + /// + /// A that contains an absolute path to a WebSocket service to find. + /// + /// + /// A that contains a session ID to find. + /// /// - /// A that contains a status code indicating the reason for closure. + /// One of the values that indicate the status codes for closure. /// /// /// A that contains the reason for closure. /// - /// - /// A that contains a session ID to find. - /// - /// - /// A that contains an absolute path to the WebSocket service to find. - /// - public void CloseSession (CloseStatusCode code, string reason, string id, string servicePath) + public void CloseSession (string servicePath, string id, CloseStatusCode code, string reason) { - var msg = _state.CheckIfStarted () ?? servicePath.CheckIfValidServicePath (); - if (msg != null) - { - _logger.Error (msg); - return; - } - IWebSocketServiceHost host; - if (!TryGetServiceHostInternally (servicePath, out host)) - { - _logger.Error ("The WebSocket service with the specified path not found.\npath: " + servicePath); - return; - } - - host.Sessions.CloseSession (code, reason, id); + if (TryGetServiceHost (servicePath, out host)) + host.Sessions.CloseSession (id, code, reason); } /// - /// Sends a Ping to the client associated with the specified and - /// . + /// Sends a Ping to the client associated with the specified + /// and . /// /// - /// true if the WebSocket service with receives a Pong - /// from the client in a time; otherwise, false. + /// true if the WebSocket service with receives + /// a Pong from the client in a time; otherwise, false. /// - /// - /// A that contains a session ID that represents the destination for the Ping. - /// /// /// A that contains an absolute path to the WebSocket service to find. /// - public bool PingTo (string id, string servicePath) + /// + /// A that contains a session ID that represents the destination + /// for the Ping. + /// + public bool PingTo (string servicePath, string id) { - var msg = _state.CheckIfStarted () ?? servicePath.CheckIfValidServicePath (); - if (msg != null) - { - _logger.Error (msg); - return false; - } - IWebSocketServiceHost host; - if (!TryGetServiceHostInternally (servicePath, out host)) - { - _logger.Error ("The WebSocket service with the specified path not found.\npath: " + servicePath); - return false; - } - - return host.Sessions.PingTo (id); + return TryGetServiceHost (servicePath, out host) && host.Sessions.PingTo (id); } /// - /// Sends a Ping with the specified to the client associated with - /// the specified and . + /// Sends a Ping with the specified to the client associated + /// with the specified and . /// /// - /// true if the WebSocket service with receives a Pong - /// from the client in a time; otherwise, false. + /// true if the WebSocket service with receives + /// a Pong from the client in a time; otherwise, false. /// + /// + /// A that contains an absolute path to the WebSocket service to find. + /// + /// + /// A that contains a session ID that represents the destination + /// for the Ping. + /// /// /// A that contains a message to send. /// - /// - /// A that contains a session ID that represents the destination for the Ping. - /// - /// - /// A that contains an absolute path to the WebSocket service to find. - /// - public bool PingTo (string message, string id, string servicePath) + public bool PingTo (string servicePath, string id, string message) { - var msg = _state.CheckIfStarted () ?? servicePath.CheckIfValidServicePath (); - if (msg != null) - { - _logger.Error (msg); - return false; - } - IWebSocketServiceHost host; - if (!TryGetServiceHostInternally (servicePath, out host)) - { - _logger.Error ("The WebSocket service with the specified path not found.\npath: " + servicePath); - return false; - } - - return host.Sessions.PingTo (message, id); + return TryGetServiceHost (servicePath, out host) && host.Sessions.PingTo (id, message); } /// /// Sends a binary to the client associated with the specified - /// and . + /// and . /// - /// - /// An array of that contains a binary data to send. - /// - /// - /// A that contains a session ID that represents the destination for the data. - /// + /// + /// This method does not wait for the send to be complete. + /// /// /// A that contains an absolute path to the WebSocket service to find. /// - public void SendTo (byte [] data, string id, string servicePath) + /// + /// A that contains a session ID that represents the destination + /// for the data. + /// + /// + /// An array of that contains a binary data to send. + /// + public void SendTo (string servicePath, string id, byte [] data) { - var msg = _state.CheckIfStarted () ?? servicePath.CheckIfValidServicePath (); - if (msg != null) - { - _logger.Error (msg); - return; - } - - IWebSocketServiceHost host; - if (!TryGetServiceHostInternally (servicePath, out host)) - { - _logger.Error ("The WebSocket service with the specified path not found.\npath: " + servicePath); - return; - } - - host.Sessions.SendTo (data, id); + SendTo (servicePath, id, data, null); } /// /// Sends a text to the client associated with the specified - /// and . + /// and . /// - /// - /// A that contains a text data to send. - /// - /// - /// A that contains a session ID that represents the destination for the data. - /// + /// + /// This method does not wait for the send to be complete. + /// /// /// A that contains an absolute path to the WebSocket service to find. /// - public void SendTo (string data, string id, string servicePath) + /// + /// A that contains a session ID that represents the destination + /// for the data. + /// + /// + /// A that contains a text data to send. + /// + public void SendTo (string servicePath, string id, string data) { - var msg = _state.CheckIfStarted () ?? servicePath.CheckIfValidServicePath (); - if (msg != null) - { - _logger.Error (msg); - return; - } - - IWebSocketServiceHost host; - if (!TryGetServiceHostInternally (servicePath, out host)) - { - _logger.Error ("The WebSocket service with the specified path not found.\npath: " + servicePath); - return; - } - - host.Sessions.SendTo (data, id); + SendTo (servicePath, id, data, null); } /// - /// Tries to get the WebSocket service host with the specified . + /// Sends a binary to the client associated with the specified + /// and . + /// + /// + /// This method does not wait for the send to be complete. + /// + /// + /// A that contains an absolute path to the WebSocket service to find. + /// + /// + /// A that contains a session ID that represents the destination + /// for the data. + /// + /// + /// An array of that contains a binary data to send. + /// + /// + /// An Action<bool> delegate that references the method(s) called when + /// the send is complete. + /// A passed to this delegate is true if the send is complete + /// successfully; otherwise, false. + /// + public void SendTo (string servicePath, string id, byte [] data, Action completed) + { + IWebSocketServiceHost host; + if (TryGetServiceHost (servicePath, out host)) + host.Sessions.SendTo (id, data, completed); + } + + /// + /// Sends a text to the client associated with the specified + /// and . + /// + /// + /// This method does not wait for the send to be complete. + /// + /// + /// A that contains an absolute path to the WebSocket service to find. + /// + /// + /// A that contains a session ID that represents the destination + /// for the data. + /// + /// + /// A that contains a text data to send. + /// + /// + /// An Action<bool> delegate that references the method(s) called when + /// the send is complete. + /// A passed to this delegate is true if the send is complete + /// successfully; otherwise, false. + /// + public void SendTo (string servicePath, string id, string data, Action completed) + { + IWebSocketServiceHost host; + if (TryGetServiceHost (servicePath, out host)) + host.Sessions.SendTo (id, data, completed); + } + + /// + /// Sends a binary data from the specified to the client associated with + /// the specified and . + /// + /// + /// This method does not wait for the send to be complete. + /// + /// + /// A that contains an absolute path to the WebSocket service to find. + /// + /// + /// A that contains a session ID that represents the destination + /// for the data. + /// + /// + /// A object from which contains a binary data to send. + /// + /// + /// An that contains the number of bytes to send. + /// + /// + /// true if is disposed after a binary data read; + /// otherwise, false. + /// + public void SendTo (string servicePath, string id, Stream stream, int length, bool dispose) + { + SendTo (servicePath, id, stream, length, dispose, null); + } + + /// + /// Sends a binary data from the specified to the client associated with + /// the specified and . + /// + /// + /// This method does not wait for the send to be complete. + /// + /// + /// A that contains an absolute path to the WebSocket service to find. + /// + /// + /// A that contains a session ID that represents the destination + /// for the data. + /// + /// + /// A object from which contains a binary data to send. + /// + /// + /// An that contains the number of bytes to send. + /// + /// + /// true if is disposed after a binary data read; + /// otherwise, false. + /// + /// + /// An Action<bool> delegate that references the method(s) called when + /// the send is complete. + /// A passed to this delegate is true if the send is complete + /// successfully; otherwise, false. + /// + public void SendTo ( + string servicePath, string id, Stream stream, int length, bool dispose, Action completed) + { + IWebSocketServiceHost host; + if (TryGetServiceHost (servicePath, out host)) + host.Sessions.SendTo (id, stream, length, dispose, completed); + } + + /// + /// Tries to get a WebSocket service host with the specified . /// /// - /// true if the WebSocket service host is successfully found; otherwise, false. + /// true if the service is successfully found; otherwise, false. /// /// - /// A that contains an absolute path to the WebSocket service managed by - /// the WebSocket service host to get. + /// A that contains an absolute path to the service to find. /// /// /// When this method returns, a instance that represents - /// the WebSocket service host if it is successfully found; otherwise, . + /// the service host if the service is successfully found; otherwise, . /// This parameter is passed uninitialized. /// public bool TryGetServiceHost (string servicePath, out IWebSocketServiceHost serviceHost) @@ -834,11 +1083,7 @@ namespace WebSocketSharp.Server return false; } - var result = TryGetServiceHostInternally (servicePath, out serviceHost); - if (!result) - _logger.Error ("The WebSocket service with the specified path not found.\npath: " + servicePath); - - return result; + return TryGetServiceHostInternally (servicePath, out serviceHost); } #endregion diff --git a/websocket-sharp/Server/WebSocketSessionManager.cs b/websocket-sharp/Server/WebSocketSessionManager.cs index d8273d80..831364ca 100644 --- a/websocket-sharp/Server/WebSocketSessionManager.cs +++ b/websocket-sharp/Server/WebSocketSessionManager.cs @@ -37,20 +37,35 @@ using System.Timers; namespace WebSocketSharp.Server { /// - /// Manages the sessions to the Websocket service. + /// Manages the sessions to a Websocket service. /// public class WebSocketSessionManager { + #region Private Static Fields + + private static readonly List _emptySessions; + + #endregion + #region Private Fields - private object _forSweep; - private volatile bool _keepClean; - private Logger _logger; - private Dictionary _sessions; - private volatile ServerState _state; - private volatile bool _sweeping; - private System.Timers.Timer _sweepTimer; - private object _sync; + private object _forSweep; + private volatile bool _keepClean; + private Logger _logger; + private Dictionary _sessions; + private volatile ServerState _state; + private volatile bool _sweeping; + private System.Timers.Timer _sweepTimer; + private object _sync; + + #endregion + + #region Static Constructor + + static WebSocketSessionManager () + { + _emptySessions = new List (); + } #endregion @@ -66,7 +81,7 @@ namespace WebSocketSharp.Server _logger = logger; _forSweep = new object (); _keepClean = true; - _sessions = new Dictionary (); + _sessions = new Dictionary (); _state = ServerState.READY; _sweeping = false; _sync = new object (); @@ -84,18 +99,6 @@ namespace WebSocketSharp.Server } } - internal IEnumerable ServiceInstances { - get { - if (_state != ServerState.START) - return new List (); - - lock (_sync) - { - return _sessions.Values.ToList (); - } - } - } - #endregion #region Public Properties @@ -108,7 +111,7 @@ namespace WebSocketSharp.Server /// public IEnumerable ActiveIDs { get { - return from result in BroadpingInternally () + return from result in Broadping (WsFrame.EmptyUnmaskPingData, 1000) where result.Value select result.Key; } @@ -152,34 +155,26 @@ namespace WebSocketSharp.Server /// public IEnumerable InactiveIDs { get { - return from result in BroadpingInternally () + return from result in Broadping (WsFrame.EmptyUnmaskPingData, 1000) where !result.Value select result.Key; } } /// - /// Gets the session information with the specified . + /// Gets a WebSocket session information with the specified . /// /// - /// A instance with if it is successfully found; - /// otherwise, . + /// A instance that contains the session information + /// if the session is successfully found; otherwise, . /// /// - /// A that contains the ID of the session information to get. + /// A that contains an ID of the session to find. /// public IWebSocketSession this [string id] { get { - var msg = _state.CheckIfStarted () ?? id.CheckIfValidSessionID (); - if (msg != null) - { - _logger.Error (msg); - return null; - } - - WebSocketService session; - if (!TryGetServiceInstance (id, out session)) - _logger.Error ("The WebSocket session with the specified ID not found.\nID: " + id); + IWebSocketSession session; + TryGetSession (id, out session); return session; } @@ -215,8 +210,13 @@ namespace WebSocketSharp.Server /// public IEnumerable Sessions { get { - return from IWebSocketSession session in ServiceInstances - select session; + if (_state == ServerState.SHUTDOWN) + return _emptySessions; + + lock (_sync) + { + return _sessions.Values.ToList (); + } } } @@ -238,11 +238,25 @@ namespace WebSocketSharp.Server }; } + private bool tryGetSession (string id, out IWebSocketSession session) + { + bool result; + lock (_sync) + { + result = _sessions.TryGetValue (id, out session); + } + + if (!result) + _logger.Error ("A WebSocket session with the specified ID not found.\nID: " + id); + + return result; + } + #endregion #region Internal Methods - internal string Add (WebSocketService session) + internal string Add (IWebSocketSession session) { lock (_sync) { @@ -256,51 +270,45 @@ namespace WebSocketSharp.Server } } - internal void BroadcastInternally (Opcode opcode, byte [] data) + internal void Broadcast (Opcode opcode, byte [] data, Action completed) { - WaitCallback callback = state => - { - var cache = new Dictionary (); - try { - BroadcastInternally (opcode, data, cache); - } - catch (Exception ex) { - _logger.Fatal (ex.ToString ()); - } - finally { - cache.Clear (); - } - }; - - ThreadPool.QueueUserWorkItem (callback); + var cache = new Dictionary (); + try { + Broadcast (opcode, data, cache); + if (completed != null) + completed (); + } + catch (Exception ex) { + _logger.Fatal (ex.ToString ()); + } + finally { + cache.Clear (); + } } - internal void BroadcastInternally (Opcode opcode, Stream stream) + internal void Broadcast (Opcode opcode, Stream stream, Action completed) { - WaitCallback callback = state => - { - var cache = new Dictionary (); - try { - BroadcastInternally (opcode, stream, cache); - } - catch (Exception ex) { - _logger.Fatal (ex.ToString ()); - } - finally { - foreach (var cached in cache.Values) - cached.Dispose (); + var cache = new Dictionary (); + try { + Broadcast (opcode, stream, cache); + if (completed != null) + completed (); + } + catch (Exception ex) { + _logger.Fatal (ex.ToString ()); + } + finally { + foreach (var cached in cache.Values) + cached.Dispose (); - cache.Clear (); - } - }; - - ThreadPool.QueueUserWorkItem (callback); + cache.Clear (); + } } - internal void BroadcastInternally ( + internal void Broadcast ( Opcode opcode, byte [] data, Dictionary cache) { - foreach (var session in ServiceInstances) + foreach (var session in Sessions) { if (_state != ServerState.START) break; @@ -309,10 +317,10 @@ namespace WebSocketSharp.Server } } - internal void BroadcastInternally ( + internal void Broadcast ( Opcode opcode, Stream stream, Dictionary cache) { - foreach (var session in ServiceInstances) + foreach (var session in Sessions) { if (_state != ServerState.START) break; @@ -321,15 +329,30 @@ namespace WebSocketSharp.Server } } - internal Dictionary BroadpingInternally () + internal void BroadcastAsync (Opcode opcode, byte [] data, Action completed) { - return BroadpingInternally (WsFrame.CreatePingFrame (Mask.UNMASK).ToByteArray (), 1000); + WaitCallback callback = state => + { + Broadcast (opcode, data, completed); + }; + + ThreadPool.QueueUserWorkItem (callback); } - internal Dictionary BroadpingInternally (byte [] frameAsBytes, int timeOut) + internal void BroadcastAsync (Opcode opcode, Stream stream, Action completed) + { + WaitCallback callback = state => + { + Broadcast (opcode, stream, completed); + }; + + ThreadPool.QueueUserWorkItem (callback); + } + + internal Dictionary Broadping (byte [] frameAsBytes, int timeOut) { var result = new Dictionary (); - foreach (var session in ServiceInstances) + foreach (var session in Sessions) { if (_state != ServerState.START) break; @@ -379,25 +402,52 @@ namespace WebSocketSharp.Server } } - internal bool TryGetServiceInstance (string id, out WebSocketService service) - { - lock (_sync) - { - return _sessions.TryGetValue (id, out service); - } - } - #endregion #region Public Methods /// - /// Broadcasts the specified array of to all clients of the WebSocket service. + /// Broadcasts a binary to all clients of a WebSocket service. /// + /// + /// This method does not wait for the broadcast to be complete. + /// /// - /// An array of to broadcast. + /// An array of that contains a binary data to broadcast. /// public void Broadcast (byte [] data) + { + Broadcast (data, null); + } + + /// + /// Broadcasts a text to all clients of a WebSocket service. + /// + /// + /// This method does not wait for the broadcast to be complete. + /// + /// + /// A that contains a text data to broadcast. + /// + public void Broadcast (string data) + { + Broadcast (data, null); + } + + /// + /// Broadcasts a binary to all clients of a WebSocket service. + /// + /// + /// This method does not wait for the broadcast to be complete. + /// + /// + /// An array of that contains a binary data to broadcast. + /// + /// + /// A delegate that references the method(s) called when + /// the broadcast is complete. + /// + public void Broadcast (byte [] data, Action completed) { var msg = _state.CheckIfStarted () ?? data.CheckIfValidSendData (); if (msg != null) @@ -407,18 +457,25 @@ namespace WebSocketSharp.Server } if (data.LongLength <= WebSocket.FragmentLength) - BroadcastInternally (Opcode.BINARY, data); + BroadcastAsync (Opcode.BINARY, data, completed); else - BroadcastInternally (Opcode.BINARY, new MemoryStream (data)); + BroadcastAsync (Opcode.BINARY, new MemoryStream (data), completed); } /// - /// Broadcasts the specified to all clients of the WebSocket service. + /// Broadcasts a text to all clients of a WebSocket service. /// + /// + /// This method does not wait for the broadcast to be complete. + /// /// - /// A to broadcast. + /// A that contains a text data to broadcast. /// - public void Broadcast (string data) + /// + /// A delegate that references the method(s) called when + /// the broadcast is complete. + /// + public void Broadcast (string data, Action completed) { var msg = _state.CheckIfStarted () ?? data.CheckIfValidSendData (); if (msg != null) @@ -429,17 +486,104 @@ namespace WebSocketSharp.Server var rawData = Encoding.UTF8.GetBytes (data); if (rawData.LongLength <= WebSocket.FragmentLength) - BroadcastInternally (Opcode.TEXT, rawData); + BroadcastAsync (Opcode.TEXT, rawData, completed); else - BroadcastInternally (Opcode.TEXT, new MemoryStream (rawData)); + BroadcastAsync (Opcode.TEXT, new MemoryStream (rawData), completed); } /// - /// Sends Pings to all clients of the WebSocket service. + /// Broadcasts a binary data from the specified + /// to all clients of a WebSocket service. + /// + /// + /// This method does not wait for the broadcast to be complete. + /// + /// + /// A object from which contains a binary data to broadcast. + /// + /// + /// An that contains the number of bytes to broadcast. + /// + /// + /// true if is disposed after a binary data broadcasted; + /// otherwise, false. + /// + public void Broadcast (Stream stream, int length, bool dispose) + { + Broadcast (stream, length, dispose, null); + } + + /// + /// Broadcasts a binary data from the specified + /// to all clients of a WebSocket service. + /// + /// + /// This method does not wait for the broadcast to be complete. + /// + /// + /// A object from which contains a binary data to broadcast. + /// + /// + /// An that contains the number of bytes to broadcast. + /// + /// + /// true if is disposed after a binary data broadcasted; + /// otherwise, false. + /// + /// + /// A delegate that references the method(s) called when + /// the broadcast is complete. + /// + public void Broadcast (Stream stream, int length, bool dispose, Action completed) + { + var msg = _state.CheckIfStarted () ?? + stream.CheckIfCanRead () ?? + (length < 1 ? "'length' must be greater than 0." : null); + + if (msg != null) + { + _logger.Error (msg); + return; + } + + Action result = data => + { + var readLen = data.Length; + if (readLen == 0) + { + _logger.Error ("A data cannot be read from 'stream'."); + return; + } + + if (readLen != length) + _logger.Warn (String.Format ( + "A data with 'length' cannot be read from 'stream'.\nexpected: {0} actual: {1}", + length, + readLen)); + + if (dispose) + stream.Dispose (); + + if (readLen <= WebSocket.FragmentLength) + Broadcast (Opcode.BINARY, data, completed); + else + Broadcast (Opcode.BINARY, new MemoryStream (data), completed); + }; + + Action exception = ex => + { + _logger.Fatal (ex.ToString ()); + }; + + stream.ReadBytesAsync (length, result, exception); + } + + /// + /// Sends Pings to all clients of a WebSocket service. /// /// - /// A Dictionary<string, bool> that contains the collection of pairs of session ID and value - /// indicating whether the WebSocket service received a Pong from each client in a time. + /// A Dictionary<string, bool> that contains the collection of pairs of session ID and + /// value indicating whether the WebSocket service received a Pong from each client in a time. /// public Dictionary Broadping () { @@ -450,15 +594,16 @@ namespace WebSocketSharp.Server return null; } - return BroadpingInternally (); + return Broadping (WsFrame.EmptyUnmaskPingData, 1000); } /// - /// Sends Pings with the specified to all clients of the WebSocket service. + /// Sends Pings with the specified to all clients + /// of a WebSocket service. /// /// - /// A Dictionary<string, bool> that contains the collection of pairs of session ID and value - /// indicating whether the WebSocket service received a Pong from each client in a time. + /// A Dictionary<string, bool> that contains the collection of pairs of session ID and + /// value indicating whether the WebSocket service received a Pong from each client in a time. /// /// /// A that contains a message to send. @@ -468,15 +613,17 @@ namespace WebSocketSharp.Server if (message == null || message.Length == 0) return Broadping (); - var data = Encoding.UTF8.GetBytes (message); - var msg = _state.CheckIfStarted () ?? data.CheckIfValidPingData (); + byte [] data; + var msg = _state.CheckIfStarted () ?? + (data = Encoding.UTF8.GetBytes (message)).CheckIfValidPingData (); + if (msg != null) { _logger.Error (msg); return null; } - return BroadpingInternally (WsFrame.CreatePingFrame (Mask.UNMASK, data).ToByteArray (), 1000); + return Broadping (WsFrame.CreatePingFrame (Mask.UNMASK, data).ToByteArray (), 1000); } /// @@ -487,85 +634,49 @@ namespace WebSocketSharp.Server /// public void CloseSession (string id) { - var msg = _state.CheckIfStarted () ?? id.CheckIfValidSessionID (); - if (msg != null) - { - _logger.Error (msg); - return; - } - - WebSocketService session; - if (!TryGetServiceInstance (id, out session)) - { - _logger.Error ("The WebSocket session with the specified ID not found.\nID: " + id); - return; - } - - session.Context.WebSocket.Close (); + IWebSocketSession session; + if (TryGetSession (id, out session)) + session.Context.WebSocket.Close (); } /// - /// Closes the session with the specified , - /// and . + /// Closes the session with the specified , + /// and . /// + /// + /// A that contains a session ID to find. + /// /// /// A that contains a status code indicating the reason for closure. /// /// /// A that contains the reason for closure. /// - /// - /// A that contains a session ID to find. - /// - public void CloseSession (ushort code, string reason, string id) + public void CloseSession (string id, ushort code, string reason) { - var msg = _state.CheckIfStarted () ?? id.CheckIfValidSessionID (); - if (msg != null) - { - _logger.Error (msg); - return; - } - - WebSocketService session; - if (!TryGetServiceInstance (id, out session)) - { - _logger.Error ("The WebSocket session with the specified ID not found.\nID: " + id); - return; - } - - session.Context.WebSocket.Close (code, reason); + IWebSocketSession session; + if (TryGetSession (id, out session)) + session.Context.WebSocket.Close (code, reason); } /// - /// Closes the session with the specified , - /// and . + /// Closes the session with the specified , + /// and . /// + /// + /// A that contains a session ID to find. + /// /// - /// A that contains a status code indicating the reason for closure. + /// One of the values that indicate the status codes for closure. /// /// /// A that contains the reason for closure. /// - /// - /// A that contains a session ID to find. - /// - public void CloseSession (CloseStatusCode code, string reason, string id) + public void CloseSession (string id, CloseStatusCode code, string reason) { - var msg = _state.CheckIfStarted () ?? id.CheckIfValidSessionID (); - if (msg != null) - { - _logger.Error (msg); - return; - } - - WebSocketService session; - if (!TryGetServiceInstance (id, out session)) - { - _logger.Error ("The WebSocket session with the specified ID not found.\nID: " + id); - return; - } - - session.Context.WebSocket.Close (code, reason); + IWebSocketSession session; + if (TryGetSession (id, out session)) + session.Context.WebSocket.Close (code, reason); } /// @@ -576,116 +687,187 @@ namespace WebSocketSharp.Server /// otherwise, false. /// /// - /// A that contains a session ID that represents the destination for the Ping. + /// A that contains a session ID that represents the destination + /// for the Ping. /// public bool PingTo (string id) { - var msg = _state.CheckIfStarted () ?? id.CheckIfValidSessionID (); - if (msg != null) - { - _logger.Error (msg); - return false; - } - - WebSocketService session; - if (!TryGetServiceInstance (id, out session)) - { - _logger.Error ("The WebSocket session with the specified ID not found.\nID: " + id); - return false; - } - - return session.Context.WebSocket.Ping (); + IWebSocketSession session; + return TryGetSession (id, out session) && session.Context.WebSocket.Ping (); } /// - /// Sends a Ping with the specified to the client associated with - /// the specified . + /// Sends a Ping with the specified to the client + /// associated with the specified . /// /// /// true if the WebSocket service receives a Pong from the client in a time; /// otherwise, false. /// + /// + /// A that contains a session ID that represents the destination + /// for the Ping. + /// /// /// A that contains a message to send. /// - /// - /// A that contains a session ID that represents the destination for the Ping. - /// - public bool PingTo (string message, string id) + public bool PingTo (string id, string message) { - var msg = _state.CheckIfStarted () ?? id.CheckIfValidSessionID (); - if (msg != null) - { - _logger.Error (msg); - return false; - } - - WebSocketService session; - if (!TryGetServiceInstance (id, out session)) - { - _logger.Error ("The WebSocket session with the specified ID not found.\nID: " + id); - return false; - } - - return session.Context.WebSocket.Ping (message); + IWebSocketSession session; + return TryGetSession (id, out session) && session.Context.WebSocket.Ping (message); } /// /// Sends a binary to the client associated with the specified /// . /// + /// + /// This method does not wait for the send to be complete. + /// + /// + /// A that contains a session ID that represents the destination + /// for the data. + /// /// /// An array of that contains a binary data to send. /// - /// - /// A that contains a session ID that represents the destination for the data. - /// - public void SendTo (byte [] data, string id) + public void SendTo (string id, byte [] data) { - var msg = _state.CheckIfStarted () ?? id.CheckIfValidSessionID (); - if (msg != null) - { - _logger.Error (msg); - return; - } - - WebSocketService session; - if (!TryGetServiceInstance (id, out session)) - { - _logger.Error ("The WebSocket session with the specified ID not found.\nID: " + id); - return; - } - - session.Context.WebSocket.Send (data, null); + SendTo (id, data, null); } /// /// Sends a text to the client associated with the specified /// . /// + /// + /// This method does not wait for the send to be complete. + /// + /// + /// A that contains a session ID that represents the destination + /// for the data. + /// /// /// A that contains a text data to send. /// - /// - /// A that contains a session ID that represents the destination for the data. - /// - public void SendTo (string data, string id) + public void SendTo (string id, string data) { - var msg = _state.CheckIfStarted () ?? id.CheckIfValidSessionID (); - if (msg != null) - { - _logger.Error (msg); - return; - } + SendTo (id, data, null); + } - WebSocketService session; - if (!TryGetServiceInstance (id, out session)) - { - _logger.Error ("The WebSocket session with the specified ID not found.\nID: " + id); - return; - } + /// + /// Sends a binary to the client associated with the specified + /// . + /// + /// + /// This method does not wait for the send to be complete. + /// + /// + /// A that contains a session ID that represents the destination + /// for the data. + /// + /// + /// An array of that contains a binary data to send. + /// + /// + /// An Action<bool> delegate that references the method(s) called when + /// the send is complete. + /// A passed to this delegate is true if the send is complete + /// successfully; otherwise, false. + /// + public void SendTo (string id, byte [] data, Action completed) + { + IWebSocketSession session; + if (TryGetSession (id, out session)) + session.Context.WebSocket.Send (data, completed); + } - session.Context.WebSocket.Send (data, null); + /// + /// Sends a text to the client associated with the specified + /// . + /// + /// + /// This method does not wait for the send to be complete. + /// + /// + /// A that contains a session ID that represents the destination + /// for the data. + /// + /// + /// A that contains a text data to send. + /// + /// + /// An Action<bool> delegate that references the method(s) called when + /// the send is complete. + /// A passed to this delegate is true if the send is complete + /// successfully; otherwise, false. + /// + public void SendTo (string id, string data, Action completed) + { + IWebSocketSession session; + if (TryGetSession (id, out session)) + session.Context.WebSocket.Send (data, completed); + } + + /// + /// Sends a binary data from the specified to the client + /// associated with the specified . + /// + /// + /// This method does not wait for the send to be complete. + /// + /// + /// A that contains a session ID that represents the destination + /// for the data. + /// + /// + /// A object from which contains a binary data to send. + /// + /// + /// An that contains the number of bytes to send. + /// + /// + /// true if is disposed after a binary data read; + /// otherwise, false. + /// + public void SendTo (string id, Stream stream, int length, bool dispose) + { + SendTo (id, stream, length, dispose, null); + } + + /// + /// Sends a binary data from the specified to the client + /// associated with the specified . + /// + /// + /// This method does not wait for the send to be complete. + /// + /// + /// A that contains a session ID that represents the destination + /// for the data. + /// + /// + /// A object from which contains a binary data to send. + /// + /// + /// An that contains the number of bytes to send. + /// + /// + /// true if is disposed after a binary data read; + /// otherwise, false. + /// + /// + /// An Action<bool> delegate that references the method(s) called when + /// the send is complete. + /// A passed to this delegate is true if the send is complete + /// successfully; otherwise, false. + /// + public void SendTo ( + string id, Stream stream, int length, bool dispose, Action completed) + { + IWebSocketSession session; + if (TryGetSession (id, out session)) + session.Context.WebSocket.Send (stream, length, dispose, completed); } /// @@ -706,7 +888,7 @@ namespace WebSocketSharp.Server lock (_sync) { - WebSocketService session; + IWebSocketSession session; if (_sessions.TryGetValue (id, out session)) { var state = session.State; @@ -725,18 +907,17 @@ namespace WebSocketSharp.Server } /// - /// Tries to get the session information with the specified . + /// Tries to get a WebSocket session information with the specified . /// /// - /// true if the session information is successfully found; - /// otherwise, false. + /// true if the session is successfully found; otherwise, false. /// /// - /// A that contains the ID of the session information to get. + /// A that contains an ID of the session to find. /// /// - /// When this method returns, a instance that contains the session - /// information if it is successfully found; otherwise, . + /// When this method returns, a instance that contains + /// the session information if the session is successfully found; otherwise, . /// This parameter is passed uninitialized. /// public bool TryGetSession (string id, out IWebSocketSession session) @@ -750,13 +931,7 @@ namespace WebSocketSharp.Server return false; } - WebSocketService service; - var result = TryGetServiceInstance (id, out service); - if (!result) - _logger.Error ("The WebSocket session with the specified ID not found.\nID: " + id); - - session = service; - return result; + return tryGetSession (id, out session); } #endregion diff --git a/websocket-sharp/WebSocket.cs b/websocket-sharp/WebSocket.cs index d0765bd4..a143b3d7 100644 --- a/websocket-sharp/WebSocket.cs +++ b/websocket-sharp/WebSocket.cs @@ -1381,8 +1381,9 @@ namespace WebSocketSharp cached = stream.Compress (_compression); cache.Add (_compression, cached); } + else + cached.Position = 0; - cached.Position = 0; sendFragmented (opcode, cached, Mask.UNMASK, _compression != CompressionMethod.NONE); } catch (Exception ex) { @@ -1556,7 +1557,7 @@ namespace WebSocketSharp { return _client ? Ping (WsFrame.CreatePingFrame (Mask.MASK).ToByteArray (), 5000) - : Ping (WsFrame.CreatePingFrame (Mask.UNMASK).ToByteArray (), 1000); + : Ping (WsFrame.EmptyUnmaskPingData, 1000); } /// diff --git a/websocket-sharp/WsFrame.cs b/websocket-sharp/WsFrame.cs index c91f184a..3fae6501 100644 --- a/websocket-sharp/WsFrame.cs +++ b/websocket-sharp/WsFrame.cs @@ -36,6 +36,21 @@ namespace WebSocketSharp { internal class WsFrame : IEnumerable { + #region Internal Static Fields + + internal static readonly byte [] EmptyUnmaskPingData; + + #endregion + + #region Static Constructor + + static WsFrame () + { + EmptyUnmaskPingData = CreatePingFrame (Mask.UNMASK).ToByteArray (); + } + + #endregion + #region Private Constructors private WsFrame ()