Added some functions (e.g. CloseSession method) to WebSocketServiceHost<T> and other classes

This commit is contained in:
sta 2013-09-05 14:16:33 +09:00
parent c464cf8f52
commit d98aad51e6
9 changed files with 1113 additions and 604 deletions

View File

@ -164,6 +164,59 @@ namespace WebSocketSharp
}
}
internal static string CheckIfValidCloseData (this byte [] data)
{
return data.Length > 125
? "The payload length of a Close frame must be 125 bytes or less."
: null;
}
internal static string CheckIfValidCloseStatusCode (this ushort code)
{
return !code.IsCloseStatusCode ()
? "Invalid close status code."
: null;
}
internal static string CheckIfValidPingMessage (this string message)
{
return message != null && message.Length > 0 && Encoding.UTF8.GetBytes (message).Length > 125
? "The payload length of a Ping frame must be 125 bytes or less."
: null;
}
internal static string CheckIfValidSendData (this byte [] data)
{
return data == null
? "'data' must not be null."
: null;
}
internal static string CheckIfValidSendData (this string data)
{
return data == null
? "'data' must not be null."
: null;
}
internal static string CheckIfValidServicePath (this string servicePath)
{
return servicePath == null || servicePath.Length == 0
? "'servicePath' must not be null or empty."
: servicePath [0] != '/'
? "'servicePath' not absolute path."
: servicePath.IndexOfAny (new [] {'?', '#'}) != -1
? "'servicePath' must not contain either or both query and fragment components."
: null;
}
internal static string CheckIfValidSessionID (this string id)
{
return id == null || id.Length == 0
? "'id' must not be null or empty."
: null;
}
internal static byte [] Compress (this byte [] value, CompressionMethod method)
{
return method == CompressionMethod.DEFLATE
@ -230,26 +283,26 @@ namespace WebSocketSharp
return value == method.ToCompressionExtension ();
}
// <summary>
// Determines whether the specified <see cref="int"/> equals the specified <see cref="char"/>,
// and invokes the specified Action&lt;int&gt; delegate at the same time.
// </summary>
// <returns>
// <c>true</c> if <paramref name="value"/> equals <paramref name="c"/>; otherwise, <c>false</c>.
// </returns>
// <param name="value">
// An <see cref="int"/> to compare.
// </param>
// <param name="c">
// A <see cref="char"/> to compare.
// </param>
// <param name="action">
// An Action&lt;int&gt; delegate that references the method(s) called at the same time as when comparing.
// An <see cref="int"/> parameter to pass to the method(s) is <paramref name="value"/>.
// </param>
// <exception cref="ArgumentOutOfRangeException">
// <paramref name="value"/> is less than 0, or greater than 255.
// </exception>
/// <summary>
/// Determines whether the specified <see cref="int"/> equals the specified <see cref="char"/>,
/// and invokes the specified Action&lt;int&gt; delegate at the same time.
/// </summary>
/// <returns>
/// <c>true</c> if <paramref name="value"/> equals <paramref name="c"/>; otherwise, <c>false</c>.
/// </returns>
/// <param name="value">
/// An <see cref="int"/> to compare.
/// </param>
/// <param name="c">
/// A <see cref="char"/> to compare.
/// </param>
/// <param name="action">
/// An Action&lt;int&gt; delegate that references the method(s) called at the same time as when comparing.
/// An <see cref="int"/> parameter to pass to the method(s) is <paramref name="value"/>.
/// </param>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="value"/> is less than 0, or greater than 255.
/// </exception>
internal static bool EqualsWith (this int value, char c, Action<int> action)
{
if (value < 0 || value > 255)
@ -259,6 +312,31 @@ namespace WebSocketSharp
return value == c - 0;
}
/// <summary>
/// Gets the absolute path from the specified <see cref="Uri"/>.
/// </summary>
/// <returns>
/// A <see cref="string"/> that contains the absolute path if it is successfully found;
/// otherwise, <see langword="null"/>.
/// </returns>
/// <param name="uri">
/// A <see cref="Uri"/> that contains a URI to get the absolute path from.
/// </param>
internal static string GetAbsolutePath (this Uri uri)
{
if (uri.IsAbsoluteUri)
return uri.AbsolutePath;
var original = uri.OriginalString;
if (original [0] != '/')
return null;
var i = original.IndexOfAny (new [] {'?', '#'});
return i > 0
? original.Substring (0, i)
: original;
}
internal static string GetNameInternal (this string nameAndValue, string separator)
{
int i = nameAndValue.IndexOf (separator);
@ -498,6 +576,14 @@ namespace WebSocketSharp
return CompressionMethod.NONE;
}
internal static string TrimEndSlash (this string value)
{
value = value.TrimEnd ('/');
return value.Length > 0
? value
: "/";
}
internal static string Unquote (this string value)
{
var start = value.IndexOf ('\"');
@ -536,7 +622,7 @@ namespace WebSocketSharp
/// </param>
public static bool Contains (this string value, params char [] chars)
{
return chars.Length == 0
return chars == null || chars.Length == 0
? true
: value == null || value.Length == 0
? false
@ -639,35 +725,6 @@ namespace WebSocketSharp
eventHandler (sender, e);
}
/// <summary>
/// Gets the absolute path from the specified <see cref="Uri"/>.
/// </summary>
/// <returns>
/// A <see cref="string"/> that contains the absolute path if gets successfully;
/// otherwise, <see langword="null"/>.
/// </returns>
/// <param name="uri">
/// A <see cref="Uri"/> that contains a URI to get the absolute path from.
/// </param>
public static string GetAbsolutePath (this Uri uri)
{
if (uri == null)
return null;
if (uri.IsAbsoluteUri)
return uri.AbsolutePath;
var uriString = uri.OriginalString;
var i = uriString.IndexOf ('/');
if (i != 0)
return null;
i = uriString.IndexOfAny (new [] {'?', '#'});
return i > 0
? uriString.Substring (0, i)
: uriString;
}
/// <summary>
/// Gets the collection of cookies from the specified <see cref="NameValueCollection"/>.
/// </summary>
@ -851,25 +908,23 @@ namespace WebSocketSharp
/// </list>
/// </remarks>
/// <returns>
/// <c>true</c> if <paramref name="code"/> is in the allowable range of the WebSocket close status code; otherwise, <c>false</c>.
/// <c>true</c> if <paramref name="value"/> is in the allowable range of the WebSocket close status code;
/// otherwise, <c>false</c>.
/// </returns>
/// <param name="code">
/// <param name="value">
/// A <see cref="ushort"/> to test.
/// </param>
public static bool IsCloseStatusCode (this ushort code)
public static bool IsCloseStatusCode (this ushort value)
{
return code < 1000
? false
: code > 4999
? false
: true;
return value > 999 && value < 5000;
}
/// <summary>
/// Determines whether the specified <see cref="string"/> is enclosed in the specified <see cref="char"/>.
/// </summary>
/// <returns>
/// <c>true</c> if <paramref name="value"/> is enclosed in <paramref name="c"/>; otherwise, <c>false</c>.
/// <c>true</c> if <paramref name="value"/> is enclosed in <paramref name="c"/>;
/// otherwise, <c>false</c>.
/// </returns>
/// <param name="value">
/// A <see cref="string"/> to test.
@ -879,9 +934,10 @@ namespace WebSocketSharp
/// </param>
public static bool IsEnclosedIn (this string value, char c)
{
return value == null || value.Length == 0
? false
: value [0] == c && value [value.Length - 1] == c;
return value != null &&
value.Length > 1 &&
value [0] == c &&
value [value.Length - 1] == c;
}
/// <summary>
@ -1021,44 +1077,6 @@ namespace WebSocketSharp
request.Headers.Contains ("Connection", "Upgrade");
}
/// <summary>
/// Determines whether the specified <see cref="string"/> is valid absolute path.
/// </summary>
/// <returns>
/// <c>true</c> if <paramref name="absPath"/> is valid absolute path; otherwise, <c>false</c>.
/// </returns>
/// <param name="absPath">
/// A <see cref="string"/> to test.
/// </param>
/// <param name="message">
/// A <see cref="string"/> that receives a message if <paramref name="absPath"/> is invalid.
/// </param>
public static bool IsValidAbsolutePath (this string absPath, out string message)
{
if (absPath == null || absPath.Length == 0)
{
message = "Must not be null or empty.";
return false;
}
var i = absPath.IndexOf ('/');
if (i != 0)
{
message = "Not absolute path: " + absPath;
return false;
}
i = absPath.IndexOfAny (new [] {'?', '#'});
if (i != -1)
{
message = "Must not contain either or both query and fragment components: " + absPath;
return false;
}
message = String.Empty;
return true;
}
/// <summary>
/// Determines whether the specified <see cref="string"/> is a URI string.
/// </summary>

View File

@ -134,7 +134,8 @@ namespace WebSocketSharp.Server
set {
if (_listening)
{
_logger.Error ("The value of Certificate property cannot be changed because the server has already been started.");
_logger.Error (
"The value of Certificate property cannot be changed because the server has already been started.");
return;
}
@ -233,7 +234,8 @@ namespace WebSocketSharp.Server
set {
if (_listening)
{
_logger.Error ("The value of RootPath property cannot be changed because the server has already been started.");
_logger.Error (
"The value of RootPath property cannot be changed because the server has already been started.");
return;
}
@ -386,10 +388,9 @@ namespace WebSocketSharp.Server
private bool processWebSocketRequest (HttpListenerContext context)
{
var wsContext = context.AcceptWebSocket ();
var path = wsContext.Path.UrlDecode ();
IWebSocketServiceHost host;
if (!_serviceHosts.TryGetServiceHost (path, out host))
if (!_serviceHosts.TryGetServiceHost (wsContext.Path, out host))
{
context.Response.StatusCode = (int) HttpStatusCode.NotImplemented;
return false;
@ -451,26 +452,19 @@ namespace WebSocketSharp.Server
_receiveRequestThread.Start ();
}
private void stop (ushort code, string reason, bool ignoreArgs)
private void stop (ushort code, string reason)
{
if (!ignoreArgs)
var data = code.Append (reason);
var msg = data.CheckIfValidCloseData ();
if (msg != null)
{
var data = code.Append (reason);
if (data.Length > 125)
{
_logger.Error (
String.Format ("The payload length of a Close frame must be 125 bytes or less.\ncode: {0}\nreason: {1}", code, reason));
return;
}
_logger.Error (String.Format ("{0}\ncode: {1}\nreason: {2}", msg, code, reason));
return;
}
_listener.Close ();
_receiveRequestThread.Join (5 * 1000);
if (ignoreArgs)
_serviceHosts.Stop ();
else
_serviceHosts.Stop (code, reason);
_serviceHosts.Stop (code, reason);
_listening = false;
}
@ -481,6 +475,10 @@ namespace WebSocketSharp.Server
/// <summary>
/// Adds the specified typed WebSocket service with the specified <paramref name="servicePath"/>.
/// </summary>
/// <remarks>
/// This method converts <paramref name="servicePath"/> to URL-decoded string and
/// removes <c>'/'</c> from tail end of <paramref name="servicePath"/>.
/// </remarks>
/// <param name="servicePath">
/// A <see cref="string"/> that contains an absolute path to the WebSocket service.
/// </param>
@ -490,10 +488,10 @@ namespace WebSocketSharp.Server
public void AddWebSocketService<T> (string servicePath)
where T : WebSocketService, new ()
{
string msg;
if (!servicePath.IsValidAbsolutePath (out msg))
var msg = servicePath.CheckIfValidServicePath ();
if (msg != null)
{
_logger.Error (msg);
_logger.Error (String.Format ("{0}\nservice path: {1}", msg, servicePath ?? ""));
return;
}
@ -529,6 +527,10 @@ namespace WebSocketSharp.Server
/// <summary>
/// Removes the WebSocket service with the specified <paramref name="servicePath"/>.
/// </summary>
/// <remarks>
/// This method converts <paramref name="servicePath"/> to URL-decoded string and
/// removes <c>'/'</c> from tail end of <paramref name="servicePath"/>.
/// </remarks>
/// <returns>
/// <c>true</c> if the WebSocket service is successfully found and removed; otherwise, <c>false</c>.
/// </returns>
@ -537,9 +539,10 @@ namespace WebSocketSharp.Server
/// </param>
public bool RemoveWebSocketService (string servicePath)
{
if (servicePath.IsNullOrEmpty ())
var msg = servicePath.CheckIfValidServicePath ();
if (msg != null)
{
_logger.Error ("'servicePath' must not be null or empty.");
_logger.Error (String.Format ("{0}\nservice path: {1}", msg, servicePath ?? ""));
return false;
}
@ -576,7 +579,10 @@ namespace WebSocketSharp.Server
if (!_listening)
return;
stop (0, null, true);
_listener.Close ();
_receiveRequestThread.Join (5 * 1000);
_serviceHosts.Stop ();
_listening = false;
}
/// <summary>
@ -594,13 +600,14 @@ namespace WebSocketSharp.Server
if (!_listening)
return;
if (!code.IsCloseStatusCode ())
var msg = code.CheckIfValidCloseStatusCode ();
if (msg != null)
{
_logger.Error ("Invalid status code for stop.\ncode: " + code);
_logger.Error (String.Format ("{0}\ncode: {1}", msg, code));
return;
}
stop (code, reason, false);
stop (code, reason);
}
/// <summary>
@ -618,7 +625,7 @@ namespace WebSocketSharp.Server
if (!_listening)
return;
stop ((ushort) code, reason, false);
stop ((ushort) code, reason);
}
#endregion

View File

@ -79,22 +79,81 @@ namespace WebSocketSharp.Server
/// </param>
void Broadcast (string data);
/// <summary>
/// Sends Pings to all clients of the WebSocket service host.
/// </summary>
/// <returns>
/// A Dictionary&lt;string, bool&gt; that contains the collection of pairs of session ID and value
/// indicating whether the WebSocket service host received a Pong from each client in a time.
/// </returns>
Dictionary<string, bool> Broadping ();
/// <summary>
/// Sends Pings with the specified <paramref name="message"/> to all clients of
/// the WebSocket service host.
/// </summary>
/// <returns>
/// A Dictionary&lt;string, bool&gt; that contains the collection of pairs of session ID and value
/// indicating whether the WebSocket service host received the Pong from each client in a time.
/// indicating whether the WebSocket service host received a Pong from each client in a time.
/// </returns>
/// <param name="message">
/// A <see cref="string"/> that contains a message to send.
/// </param>
Dictionary<string, bool> Broadping (string message);
/// <summary>
/// Close the WebSocket session with the specified <paramref name="id"/>.
/// </summary>
/// <param name="id">
/// A <see cref="string"/> that contains a session ID to find.
/// </param>
void CloseSession (string id);
/// <summary>
/// Close the WebSocket session with the specified <paramref name="code"/>, <paramref name="reason"/>
/// and <paramref name="id"/>.
/// </summary>
/// <param name="code">
/// A <see cref="ushort"/> that contains a status code indicating the reason for closure.
/// </param>
/// <param name="reason">
/// A <see cref="string"/> that contains the reason for closure.
/// </param>
/// <param name="id">
/// A <see cref="string"/> that contains a session ID to find.
/// </param>
void CloseSession (ushort code, string reason, string id);
/// <summary>
/// Close the WebSocket session with the specified <paramref name="code"/>, <paramref name="reason"/>
/// and <paramref name="id"/>.
/// </summary>
/// <param name="code">
/// A <see cref="CloseStatusCode"/> that contains a status code indicating the reason for closure.
/// </param>
/// <param name="reason">
/// A <see cref="string"/> that contains the reason for closure.
/// </param>
/// <param name="id">
/// A <see cref="string"/> that contains a session ID to find.
/// </param>
void CloseSession (CloseStatusCode code, string reason, string id);
/// <summary>
/// Sends a Ping to the client associated with the specified <paramref name="id"/>.
/// </summary>
/// <returns>
/// <c>true</c> if the WebSocket service host receives a Pong from the client in a time;
/// otherwise, <c>false</c>.
/// </returns>
/// <param name="id">
/// A <see cref="string"/> that contains a session ID that represents the destination for the Ping.
/// </param>
bool PingTo (string id);
/// <summary>
/// Sends a Ping with the specified <paramref name="message"/> to the client associated with
/// the specified ID.
/// the specified <paramref name="id"/>.
/// </summary>
/// <returns>
/// <c>true</c> if the WebSocket service host receives a Pong from the client in a time;
@ -104,12 +163,12 @@ namespace WebSocketSharp.Server
/// A <see cref="string"/> that contains a message to send.
/// </param>
/// <param name="id">
/// A <see cref="string"/> that contains an ID that represents the destination for the Ping.
/// A <see cref="string"/> that contains a session ID that represents the destination for the Ping.
/// </param>
bool PingTo (string message, string id);
/// <summary>
/// Sends a binary data to the client associated with the specified ID.
/// Sends a binary data to the client associated with the specified <paramref name="id"/>.
/// </summary>
/// <returns>
/// <c>true</c> if <paramref name="data"/> is successfully sent; otherwise, <c>false</c>.
@ -118,12 +177,12 @@ namespace WebSocketSharp.Server
/// An array of <see cref="byte"/> that contains a binary data to send.
/// </param>
/// <param name="id">
/// A <see cref="string"/> that contains an ID that represents the destination for the data.
/// A <see cref="string"/> that contains a session ID that represents the destination for the data.
/// </param>
bool SendTo (byte [] data, string id);
/// <summary>
/// Sends a text data to the client associated with the specified ID.
/// Sends a text data to the client associated with the specified <paramref name="id"/>.
/// </summary>
/// <returns>
/// <c>true</c> if <paramref name="data"/> is successfully sent; otherwise, <c>false</c>.
@ -132,15 +191,10 @@ namespace WebSocketSharp.Server
/// A <see cref="string"/> that contains a text data to send.
/// </param>
/// <param name="id">
/// A <see cref="string"/> that contains an ID that represents the destination for the data.
/// A <see cref="string"/> that contains a session ID that represents the destination for the data.
/// </param>
bool SendTo (string data, string id);
/// <summary>
/// Starts the WebSocket service host.
/// </summary>
void Start ();
/// <summary>
/// Stops the WebSocket service host.
/// </summary>

View File

@ -199,10 +199,10 @@ namespace WebSocketSharp.Server
private void stop (ushort code, string reason)
{
var data = code.Append (reason);
if (data.Length > 125)
var msg = data.CheckIfValidCloseData ();
if (msg != null)
{
Log.Error (String.Format (
"The payload length of a Close frame must be 125 bytes or less.\ncode: {0}\nreason: {1}", code, reason));
Log.Error (String.Format ("{0}\ncode: {1}\nreason: {2}", msg, code, reason));
return;
}
@ -223,9 +223,9 @@ namespace WebSocketSharp.Server
protected override void AcceptWebSocket (TcpListenerWebSocketContext context)
{
var websocket = context.WebSocket;
var path = context.Path.UrlDecode ();
websocket.Log = Log;
var path = context.Path;
IWebSocketServiceHost host;
if (!_serviceHosts.TryGetServiceHost (path, out host))
{
@ -246,6 +246,10 @@ namespace WebSocketSharp.Server
/// <summary>
/// Adds the specified typed WebSocket service with the specified <paramref name="servicePath"/>.
/// </summary>
/// <remarks>
/// This method converts <paramref name="servicePath"/> to URL-decoded string and
/// removes <c>'/'</c> from tail end of <paramref name="servicePath"/>.
/// </remarks>
/// <param name="servicePath">
/// A <see cref="string"/> that contains an absolute path to the WebSocket service.
/// </param>
@ -255,10 +259,10 @@ namespace WebSocketSharp.Server
public void AddWebSocketService<T> (string servicePath)
where T : WebSocketService, new ()
{
string msg;
if (!servicePath.IsValidAbsolutePath (out msg))
var msg = servicePath.CheckIfValidServicePath ();
if (msg != null)
{
Log.Error (msg);
Log.Error (String.Format ("{0}\nservice path: {1}", msg, servicePath ?? ""));
return;
}
@ -276,6 +280,10 @@ namespace WebSocketSharp.Server
/// <summary>
/// Removes the WebSocket service with the specified <paramref name="servicePath"/>.
/// </summary>
/// <remarks>
/// This method converts <paramref name="servicePath"/> to URL-decoded string and
/// removes <c>'/'</c> from tail end of <paramref name="servicePath"/>.
/// </remarks>
/// <returns>
/// <c>true</c> if the WebSocket service is successfully found and removed; otherwise, <c>false</c>.
/// </returns>
@ -284,9 +292,10 @@ namespace WebSocketSharp.Server
/// </param>
public bool RemoveWebSocketService (string servicePath)
{
if (servicePath.IsNullOrEmpty ())
var msg = servicePath.CheckIfValidServicePath ();
if (msg != null)
{
Log.Error ("'servicePath' must not be null or empty.");
Log.Error (String.Format ("{0}\nservice path: {1}", msg, servicePath ?? ""));
return false;
}
@ -314,9 +323,10 @@ namespace WebSocketSharp.Server
/// </param>
public void Stop (ushort code, string reason)
{
if (!code.IsCloseStatusCode ())
var msg = code.CheckIfValidCloseStatusCode ();
if (msg != null)
{
Log.Error ("Invalid status code for stop.\ncode: " + code);
Log.Error (String.Format ("{0}\ncode: {1}", msg, code));
return;
}

View File

@ -117,7 +117,7 @@ namespace WebSocketSharp.Server
/// <summary>
/// Initializes a new instance of the <see cref="WebSocketServerBase"/> class
/// that listens for incoming connection attempts on the specified <paramref name="address"/>,
/// <paramref name="port"/>, <paramref name="absPath"/> and <paramref name="secure"/>.
/// <paramref name="port"/>, <paramref name="servicePath"/> and <paramref name="secure"/>.
/// </summary>
/// <param name="address">
/// A <see cref="IPAddress"/> that contains a local IP address.
@ -125,7 +125,7 @@ namespace WebSocketSharp.Server
/// <param name="port">
/// An <see cref="int"/> that contains a port number.
/// </param>
/// <param name="absPath">
/// <param name="servicePath">
/// A <see cref="string"/> that contains an absolute path.
/// </param>
/// <param name="secure">
@ -133,14 +133,14 @@ namespace WebSocketSharp.Server
/// (<c>true</c> indicates providing a secure connection.)
/// </param>
/// <exception cref="ArgumentNullException">
/// Either <paramref name="address"/> or <paramref name="absPath"/> is <see langword="null"/>.
/// Either <paramref name="address"/> or <paramref name="servicePath"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="port"/> is 0 or less, or 65536 or greater.
/// </exception>
/// <exception cref="ArgumentException">
/// <para>
/// <paramref name="absPath"/> is invalid.
/// <paramref name="servicePath"/> is invalid.
/// </para>
/// <para>
/// -or-
@ -149,20 +149,20 @@ namespace WebSocketSharp.Server
/// Pair of <paramref name="port"/> and <paramref name="secure"/> is invalid.
/// </para>
/// </exception>
protected WebSocketServerBase (IPAddress address, int port, string absPath, bool secure)
protected WebSocketServerBase (IPAddress address, int port, string servicePath, bool secure)
{
if (address == null)
throw new ArgumentNullException ("address");
if (absPath == null)
throw new ArgumentNullException ("absPath");
if (servicePath == null)
throw new ArgumentNullException ("servicePath");
if (!port.IsPortNumber ())
throw new ArgumentOutOfRangeException ("port", "Invalid port number: " + port);
string msg;
if (!absPath.IsValidAbsolutePath (out msg))
throw new ArgumentException (msg, "absPath");
var msg = servicePath.CheckIfValidServicePath ();
if (msg != null)
throw new ArgumentException (msg, "servicePath");
if ((port == 80 && secure) || (port == 443 && !secure))
throw new ArgumentException (String.Format (
@ -170,7 +170,7 @@ namespace WebSocketSharp.Server
_address = address;
_port = port;
_uri = absPath.ToUri ();
_uri = servicePath.ToUri ();
_secure = secure;
init ();

View File

@ -37,7 +37,7 @@ using WebSocketSharp.Net.WebSockets;
namespace WebSocketSharp.Server
{
/// <summary>
/// Provides the basic functions of the WebSocket service.
/// Provides the basic functions of the WebSocket service managed by the WebSocket service host.
/// </summary>
/// <remarks>
/// The WebSocketService class is an abstract class.
@ -46,9 +46,9 @@ namespace WebSocketSharp.Server
{
#region Private Fields
private WebSocket _websocket;
private WebSocketContext _context;
private WebSocketServiceManager _sessions;
private WebSocket _websocket;
#endregion
@ -115,11 +115,10 @@ namespace WebSocketSharp.Server
}
/// <summary>
/// Gets the sessions to the <see cref="WebSocketService"/> instances.
/// Gets the collection of the WebSocket sessions managed by the WebSocket service host.
/// </summary>
/// <value>
/// A <see cref="WebSocketServiceManager"/> that contains the sessions to
/// the <see cref="WebSocketService"/> instances.
/// A <see cref="WebSocketServiceManager"/> that contains a collection of the WebSocket sessions.
/// </value>
protected WebSocketServiceManager Sessions {
get {
@ -134,10 +133,10 @@ namespace WebSocketSharp.Server
#region Public Properties
/// <summary>
/// Gets the ID of the current <see cref="WebSocketService"/> instance.
/// Gets the session ID of the current <see cref="WebSocketService"/> instance.
/// </summary>
/// <value>
/// A <see cref="string"/> that contains an ID.
/// A <see cref="string"/> that contains a session ID.
/// </value>
public string ID {
get; private set;
@ -216,6 +215,97 @@ namespace WebSocketSharp.Server
#region Protected Methods
/// <summary>
/// Broadcasts the specified array of <see cref="byte"/> to the clients of every <see cref="WebSocketService"/>
/// instances in the <see cref="WebSocketService.Sessions"/>.
/// </summary>
/// <param name="data">
/// An array of <see cref="byte"/> to broadcast.
/// </param>
protected virtual void Broadcast (byte [] data)
{
if (!IsBound)
return;
var msg = data.CheckIfValidSendData ();
if (msg != null)
{
Log.Error (msg);
Error (msg);
return;
}
_sessions.Broadcast (data);
}
/// <summary>
/// Broadcasts the specified <see cref="string"/> to the clients of every <see cref="WebSocketService"/>
/// instances in the <see cref="WebSocketService.Sessions"/>.
/// </summary>
/// <param name="data">
/// A <see cref="string"/> to broadcast.
/// </param>
protected virtual void Broadcast (string data)
{
if (!IsBound)
return;
var msg = data.CheckIfValidSendData ();
if (msg != null)
{
Log.Error (msg);
Error (msg);
return;
}
_sessions.Broadcast (data);
}
/// <summary>
/// Sends Pings to the clients of every <see cref="WebSocketService"/> instances
/// in the <see cref="WebSocketService.Sessions"/>.
/// </summary>
/// <returns>
/// A Dictionary&lt;string, bool&gt; that contains the collection of pairs of session ID and value
/// indicating whether the each <see cref="WebSocketService"/> instance received a Pong in a time.
/// </returns>
protected virtual Dictionary<string, bool> Broadping ()
{
return IsBound
? _sessions.Broadping ()
: null;
}
/// <summary>
/// Sends Pings with the specified <paramref name="message"/> to the clients of every <see cref="WebSocketService"/>
/// instances in the <see cref="WebSocketService.Sessions"/>.
/// </summary>
/// <returns>
/// A Dictionary&lt;string, bool&gt; that contains the collection of pairs of session ID and value
/// indicating whether the each <see cref="WebSocketService"/> instance received a Pong in a time.
/// </returns>
/// <param name="message">
/// A <see cref="string"/> that contains a message to send.
/// </param>
protected virtual Dictionary<string, bool> Broadping (string message)
{
if (!IsBound)
return null;
var msg = message.CheckIfValidPingMessage ();
if (msg != null)
{
Log.Error (msg);
Error (msg);
return null;
}
return _sessions.Broadping (message);
}
/// <summary>
/// Calls the <see cref="OnError"/> method with the specified <paramref name="message"/>.
/// </summary>
@ -269,6 +359,125 @@ namespace WebSocketSharp.Server
{
}
/// <summary>
/// Sends a Ping to the client of the <see cref="WebSocketService"/> instance
/// with the specified <paramref name="id"/>.
/// </summary>
/// <returns>
/// <c>true</c> if the <see cref="WebSocketService"/> instance with <paramref name="id"/> receives
/// a Pong in a time; otherwise, <c>false</c>.
/// </returns>
/// <param name="id">
/// A <see cref="string"/> that contains a session ID that represents the destination for the Ping.
/// </param>
protected virtual bool PingTo (string id)
{
if (!IsBound)
return false;
var msg = id.CheckIfValidSessionID ();
if (msg != null)
{
Log.Error (msg);
Error (msg);
return false;
}
return _sessions.PingTo (id);
}
/// <summary>
/// Sends a Ping with the specified <paramref name="message"/> to the client of
/// the <see cref="WebSocketService"/> instance with the specified <paramref name="id"/>.
/// </summary>
/// <returns>
/// <c>true</c> if the <see cref="WebSocketService"/> instance with <paramref name="id"/> receives
/// a Pong in a time; otherwise, <c>false</c>.
/// </returns>
/// <param name="message">
/// A <see cref="string"/> that contains a message to send.
/// </param>
/// <param name="id">
/// A <see cref="string"/> that contains a session ID that represents the destination for the Ping.
/// </param>
protected virtual bool PingTo (string message, string id)
{
if (!IsBound)
return false;
var msg = id.CheckIfValidSessionID ();
if (msg != null)
{
Log.Error (msg);
Error (msg);
return false;
}
return _sessions.PingTo (message, id);
}
/// <summary>
/// Sends a binary data to the client of the <see cref="WebSocketService"/> instance
/// with the specified <paramref name="id"/>.
/// </summary>
/// <returns>
/// <c>true</c> if <paramref name="data"/> is successfully sent; otherwise, <c>false</c>.
/// </returns>
/// <param name="data">
/// An array of <see cref="byte"/> that contains a binary data to send.
/// </param>
/// <param name="id">
/// A <see cref="string"/> that contains a session ID that represents the destination for the data.
/// </param>
protected virtual bool SendTo (byte [] data, string id)
{
if (!IsBound)
return false;
var msg = id.CheckIfValidSessionID ();
if (msg != null)
{
Log.Error (msg);
Error (msg);
return false;
}
return _sessions.SendTo (data, id);
}
/// <summary>
/// Sends a text data to the client of the <see cref="WebSocketService"/> instance
/// with the specified <paramref name="id"/>.
/// </summary>
/// <returns>
/// <c>true</c> if <paramref name="data"/> is successfully sent; otherwise, <c>false</c>.
/// </returns>
/// <param name="data">
/// A <see cref="string"/> that contains a text data to send.
/// </param>
/// <param name="id">
/// A <see cref="string"/> that contains a session ID that represents the destination for the data.
/// </param>
protected virtual bool SendTo (string data, string id)
{
if (!IsBound)
return false;
var msg = id.CheckIfValidSessionID ();
if (msg != null)
{
Log.Error (msg);
Error (msg);
return false;
}
return _sessions.SendTo (data, id);
}
/// <summary>
/// Validates the cookies used in the WebSocket connection request.
/// </summary>
@ -296,101 +505,6 @@ namespace WebSocketSharp.Server
#region Public Methods
/// <summary>
/// Broadcasts the specified array of <see cref="byte"/> to the clients of every <see cref="WebSocketService"/>
/// instances in the <see cref="WebSocketService.Sessions"/>.
/// </summary>
/// <param name="data">
/// An array of <see cref="byte"/> to broadcast.
/// </param>
public virtual void Broadcast (byte [] data)
{
if (!IsBound)
return;
if (data == null)
{
var msg = "'data' must not be null.";
Log.Error (msg);
Error (msg);
return;
}
_sessions.Broadcast (data);
}
/// <summary>
/// Broadcasts the specified <see cref="string"/> to the clients of every <see cref="WebSocketService"/>
/// instances in the <see cref="WebSocketService.Sessions"/>.
/// </summary>
/// <param name="data">
/// A <see cref="string"/> to broadcast.
/// </param>
public virtual void Broadcast (string data)
{
if (!IsBound)
return;
if (data == null)
{
var msg = "'data' must not be null.";
Log.Error (msg);
Error (msg);
return;
}
_sessions.Broadcast (data);
}
/// <summary>
/// Sends Pings to the clients of every <see cref="WebSocketService"/> instances
/// in the <see cref="WebSocketService.Sessions"/>.
/// </summary>
/// <returns>
/// A Dictionary&lt;string, bool&gt; that contains the collection of pairs of session ID and value
/// indicating whether the each <see cref="WebSocketService"/> instance received a Pong in a time.
/// </returns>
public virtual Dictionary<string, bool> Broadping ()
{
return IsBound
? _sessions.Broadping (String.Empty)
: null;
}
/// <summary>
/// Sends Pings with the specified <paramref name="message"/> to the clients of every <see cref="WebSocketService"/>
/// instances in the <see cref="WebSocketService.Sessions"/>.
/// </summary>
/// <returns>
/// A Dictionary&lt;string, bool&gt; that contains the collection of pairs of session ID and value
/// indicating whether the each <see cref="WebSocketService"/> instance received a Pong in a time.
/// </returns>
/// <param name="message">
/// A <see cref="string"/> that contains a message to send.
/// </param>
public virtual Dictionary<string, bool> Broadping (string message)
{
if (!IsBound)
return null;
if (message.IsNullOrEmpty ())
return _sessions.Broadping (String.Empty);
var len = Encoding.UTF8.GetBytes (message).Length;
if (len > 125)
{
var msg = "The payload length of a Ping frame must be 125 bytes or less.";
Log.Error (msg);
Error (msg);
return null;
}
return _sessions.Broadping (message);
}
/// <summary>
/// Sends a Ping to the client of the current <see cref="WebSocketService"/> instance.
/// </summary>
@ -423,53 +537,6 @@ namespace WebSocketSharp.Server
: false;
}
/// <summary>
/// Sends a Ping to the client of the <see cref="WebSocketService"/> instance
/// with the specified ID.
/// </summary>
/// <returns>
/// <c>true</c> if the <see cref="WebSocketService"/> instance with <paramref name="id"/> receives
/// a Pong in a time; otherwise, <c>false</c>.
/// </returns>
/// <param name="id">
/// A <see cref="string"/> that contains an ID that represents the destination for the Ping.
/// </param>
public virtual bool PingTo (string id)
{
return PingTo (String.Empty, id);
}
/// <summary>
/// Sends a Ping with the specified <paramref name="message"/> to the client of
/// the <see cref="WebSocketService"/> instance with the specified ID.
/// </summary>
/// <returns>
/// <c>true</c> if the <see cref="WebSocketService"/> instance with <paramref name="id"/> receives
/// a Pong in a time; otherwise, <c>false</c>.
/// </returns>
/// <param name="message">
/// A <see cref="string"/> that contains a message to send.
/// </param>
/// <param name="id">
/// A <see cref="string"/> that contains an ID that represents the destination for the Ping.
/// </param>
public virtual bool PingTo (string message, string id)
{
if (!IsBound)
return false;
if (id.IsNullOrEmpty ())
{
var msg = "'id' must not be null or empty.";
Log.Error (msg);
Error (msg);
return false;
}
return _sessions.PingTo (message, id);
}
/// <summary>
/// Sends a binary data to the client of the current <see cref="WebSocketService"/> instance.
/// </summary>
@ -494,76 +561,6 @@ namespace WebSocketSharp.Server
_websocket.Send (data);
}
/// <summary>
/// Sends a binary data to the client of the <see cref="WebSocketService"/> instance
/// with the specified ID.
/// </summary>
/// <returns>
/// <c>true</c> if <paramref name="data"/> is successfully sent; otherwise, <c>false</c>.
/// </returns>
/// <param name="data">
/// An array of <see cref="byte"/> that contains a binary data to send.
/// </param>
/// <param name="id">
/// A <see cref="string"/> that contains an ID that represents the destination for the data.
/// </param>
public virtual bool SendTo (byte [] data, string id)
{
if (!IsBound)
return false;
var msg = data == null
? "'data' must not be null."
: id.IsNullOrEmpty ()
? "'id' must not be null or empty."
: null;
if (msg != null)
{
Log.Error (msg);
Error (msg);
return false;
}
return _sessions.SendTo (data, id);
}
/// <summary>
/// Sends a text data to the client of the <see cref="WebSocketService"/> instance
/// with the specified ID.
/// </summary>
/// <returns>
/// <c>true</c> if <paramref name="data"/> is successfully sent; otherwise, <c>false</c>.
/// </returns>
/// <param name="data">
/// A <see cref="string"/> that contains a text data to send.
/// </param>
/// <param name="id">
/// A <see cref="string"/> that contains an ID that represents the destination for the data.
/// </param>
public virtual bool SendTo (string data, string id)
{
if (!IsBound)
return false;
var msg = data == null
? "'data' must not be null."
: id.IsNullOrEmpty ()
? "'id' must not be null or empty."
: null;
if (msg != null)
{
Log.Error (msg);
Error (msg);
return false;
}
return _sessions.SendTo (data, id);
}
/// <summary>
/// Starts the current <see cref="WebSocketService"/> instance.
/// </summary>

View File

@ -52,6 +52,7 @@ namespace WebSocketSharp.Server
{
#region Private Fields
private string _servicePath;
private WebSocketServiceManager _sessions;
#endregion
@ -111,43 +112,43 @@ namespace WebSocketSharp.Server
/// <summary>
/// Initializes a new instance of the WebSocketServiceHost&lt;T&gt; class that listens for
/// incoming connection attempts on the specified <paramref name="port"/> and <paramref name="absPath"/>.
/// incoming connection attempts on the specified <paramref name="port"/> and <paramref name="servicePath"/>.
/// </summary>
/// <param name="port">
/// An <see cref="int"/> that contains a port number.
/// </param>
/// <param name="absPath">
/// <param name="servicePath">
/// A <see cref="string"/> that contains an absolute path.
/// </param>
public WebSocketServiceHost (int port, string absPath)
: this (System.Net.IPAddress.Any, port, absPath)
public WebSocketServiceHost (int port, string servicePath)
: this (System.Net.IPAddress.Any, port, servicePath)
{
}
/// <summary>
/// Initializes a new instance of the WebSocketServiceHost&lt;T&gt; class that listens for
/// incoming connection attempts on the specified <paramref name="port"/>, <paramref name="absPath"/>
/// incoming connection attempts on the specified <paramref name="port"/>, <paramref name="servicePath"/>
/// and <paramref name="secure"/>.
/// </summary>
/// <param name="port">
/// An <see cref="int"/> that contains a port number.
/// </param>
/// <param name="absPath">
/// <param name="servicePath">
/// A <see cref="string"/> that contains an absolute path.
/// </param>
/// <param name="secure">
/// A <see cref="bool"/> that indicates providing a secure connection or not.
/// (<c>true</c> indicates providing a secure connection.)
/// </param>
public WebSocketServiceHost (int port, string absPath, bool secure)
: this (System.Net.IPAddress.Any, port, absPath, secure)
public WebSocketServiceHost (int port, string servicePath, bool secure)
: this (System.Net.IPAddress.Any, port, servicePath, secure)
{
}
/// <summary>
/// Initializes a new instance of the WebSocketServiceHost&lt;T&gt; class that listens for
/// incoming connection attempts on the specified <paramref name="address"/>, <paramref name="port"/>
/// and <paramref name="absPath"/>.
/// and <paramref name="servicePath"/>.
/// </summary>
/// <param name="address">
/// A <see cref="System.Net.IPAddress"/> that contains a local IP address.
@ -155,18 +156,18 @@ namespace WebSocketSharp.Server
/// <param name="port">
/// An <see cref="int"/> that contains a port number.
/// </param>
/// <param name="absPath">
/// <param name="servicePath">
/// A <see cref="string"/> that contains an absolute path.
/// </param>
public WebSocketServiceHost (System.Net.IPAddress address, int port, string absPath)
: this (address, port, absPath, port == 443 ? true : false)
public WebSocketServiceHost (System.Net.IPAddress address, int port, string servicePath)
: this (address, port, servicePath, port == 443 ? true : false)
{
}
/// <summary>
/// Initializes a new instance of the WebSocketServiceHost&lt;T&gt; class that listens for
/// incoming connection attempts on the specified <paramref name="address"/>, <paramref name="port"/>,
/// <paramref name="absPath"/> and <paramref name="secure"/>.
/// <paramref name="servicePath"/> and <paramref name="secure"/>.
/// </summary>
/// <param name="address">
/// A <see cref="System.Net.IPAddress"/> that contains a local IP address.
@ -174,15 +175,15 @@ namespace WebSocketSharp.Server
/// <param name="port">
/// An <see cref="int"/> that contains a port number.
/// </param>
/// <param name="absPath">
/// <param name="servicePath">
/// A <see cref="string"/> that contains an absolute path.
/// </param>
/// <param name="secure">
/// A <see cref="bool"/> that indicates providing a secure connection or not.
/// (<c>true</c> indicates providing a secure connection.)
/// </param>
public WebSocketServiceHost (System.Net.IPAddress address, int port, string absPath, bool secure)
: base (address, port, absPath, secure)
public WebSocketServiceHost (System.Net.IPAddress address, int port, string servicePath, bool secure)
: base (address, port, servicePath, secure)
{
_sessions = new WebSocketServiceManager (Log);
}
@ -208,8 +209,8 @@ namespace WebSocketSharp.Server
/// the inactive <see cref="WebSocketService"/> instances periodically.
/// </summary>
/// <value>
/// <c>true</c> if the WebSocket service host cleans up the inactive WebSocket service instances every 60 seconds;
/// otherwise, <c>false</c>. The default value is <c>true</c>.
/// <c>true</c> if the WebSocket service host cleans up the inactive WebSocket service instances
/// every 60 seconds; otherwise, <c>false</c>. The default value is <c>true</c>.
/// </value>
public bool KeepClean {
get {
@ -221,6 +222,33 @@ namespace WebSocketSharp.Server
}
}
/// <summary>
/// Gets the collection of the WebSocket sessions managed by the WebSocket service host.
/// </summary>
/// <value>
/// A <see cref="WebSocketServiceManager"/> that contains a collection of the WebSocket sessions.
/// </value>
public WebSocketServiceManager Sessions {
get {
return _sessions;
}
}
/// <summary>
/// Gets the path to the WebSocket service that the WebSocket service host provides.
/// </summary>
/// <value>
/// A <see cref="string"/> that contains an absolute path to the WebSocket service.
/// </value>
public string ServicePath {
get {
if (_servicePath == null)
_servicePath = HttpUtility.UrlDecode (BaseUri.GetAbsolutePath ()).TrimEndSlash ();
return _servicePath;
}
}
/// <summary>
/// Gets the WebSocket URL on which to listen for incoming connection attempts.
/// </summary>
@ -244,10 +272,10 @@ namespace WebSocketSharp.Server
private void stop (ushort code, string reason)
{
var data = code.Append (reason);
if (data.Length > 125)
var msg = data.CheckIfValidCloseData ();
if (msg != null)
{
Log.Error (String.Format (
"The payload length of a Close frame must be 125 bytes or less.\ncode: {0}\nreason: {1}", code, reason));
Log.Error (String.Format ("{0}\ncode: {1}\nreason: {2}", msg, code, reason));
return;
}
@ -268,17 +296,17 @@ namespace WebSocketSharp.Server
protected override void AcceptWebSocket (TcpListenerWebSocketContext context)
{
var websocket = context.WebSocket;
var path = context.Path.UrlDecode ();
websocket.Log = Log;
if (path != Uri.GetAbsolutePath ().UrlDecode ())
var path = HttpUtility.UrlDecode (context.Path).TrimEndSlash ();
if (path != ServicePath)
{
websocket.Close (HttpStatusCode.NotImplemented);
return;
}
if (Uri.IsAbsoluteUri)
websocket.Url = Uri;
if (BaseUri.IsAbsoluteUri)
websocket.Url = BaseUri;
((IWebSocketServiceHost) this).BindWebSocket (context);
}
@ -295,9 +323,10 @@ namespace WebSocketSharp.Server
/// </param>
public void Broadcast (byte [] data)
{
if (data == null)
var msg = data.CheckIfValidSendData ();
if (msg != null)
{
Log.Error ("'data' must not be null.");
Log.Error (msg);
return;
}
@ -312,34 +341,44 @@ namespace WebSocketSharp.Server
/// </param>
public void Broadcast (string data)
{
if (data == null)
var msg = data.CheckIfValidSendData ();
if (msg != null)
{
Log.Error ("'data' must not be null.");
Log.Error (msg);
return;
}
_sessions.Broadcast (data);
}
/// <summary>
/// Sends Pings to all clients.
/// </summary>
/// <returns>
/// A Dictionary&lt;string, bool&gt; that contains the collection of pairs of session ID and value
/// indicating whether the WebSocket service host received a Pong from each client in a time.
/// </returns>
public Dictionary<string, bool> Broadping ()
{
return _sessions.Broadping ();
}
/// <summary>
/// Sends Pings with the specified <paramref name="message"/> to all clients.
/// </summary>
/// <returns>
/// A Dictionary&lt;string, bool&gt; that contains the collection of pairs of session ID and value
/// indicating whether the service host received the Pong from each client in a time.
/// indicating whether the WebSocket service host received a Pong from each client in a time.
/// </returns>
/// <param name="message">
/// A <see cref="string"/> that contains a message to send.
/// </param>
public Dictionary<string, bool> Broadping (string message)
{
if (message.IsNullOrEmpty ())
return _sessions.Broadping (String.Empty);
var len = Encoding.UTF8.GetBytes (message).Length;
if (len > 125)
var msg = message.CheckIfValidPingMessage ();
if (msg != null)
{
Log.Error ("The payload length of a Ping frame must be 125 bytes or less.");
Log.Error (msg);
return null;
}
@ -347,23 +386,115 @@ namespace WebSocketSharp.Server
}
/// <summary>
/// Sends a Ping with the specified <paramref name="message"/> to the client associated with
/// the specified ID.
/// Close the WebSocket session with the specified <paramref name="id"/>.
/// </summary>
/// <param name="id">
/// A <see cref="string"/> that contains a session ID to find.
/// </param>
public void CloseSession (string id)
{
var msg = id.CheckIfValidSessionID ();
if (msg != null)
{
Log.Error (msg);
return;
}
_sessions.StopServiceInstance (id);
}
/// <summary>
/// Close the WebSocket session with the specified <paramref name="code"/>, <paramref name="reason"/>
/// and <paramref name="id"/>.
/// </summary>
/// <param name="code">
/// A <see cref="ushort"/> that contains a status code indicating the reason for closure.
/// </param>
/// <param name="reason">
/// A <see cref="string"/> that contains the reason for closure.
/// </param>
/// <param name="id">
/// A <see cref="string"/> that contains a session ID to find.
/// </param>
public void CloseSession (ushort code, string reason, string id)
{
var msg = id.CheckIfValidSessionID ();
if (msg != null)
{
Log.Error (msg);
return;
}
_sessions.StopServiceInstance (code, reason, id);
}
/// <summary>
/// Close the WebSocket session with the specified <paramref name="code"/>, <paramref name="reason"/>
/// and <paramref name="id"/>.
/// </summary>
/// <param name="code">
/// A <see cref="CloseStatusCode"/> that contains a status code indicating the reason for closure.
/// </param>
/// <param name="reason">
/// A <see cref="string"/> that contains the reason for closure.
/// </param>
/// <param name="id">
/// A <see cref="string"/> that contains a session ID to find.
/// </param>
public void CloseSession (CloseStatusCode code, string reason, string id)
{
var msg = id.CheckIfValidSessionID ();
if (msg != null)
{
Log.Error (msg);
return;
}
_sessions.StopServiceInstance (code, reason, id);
}
/// <summary>
/// Sends a Ping to the client associated with the specified <paramref name="id"/>.
/// </summary>
/// <returns>
/// <c>true</c> if the service host receives a Pong from the client in a time; otherwise, <c>false</c>.
/// <c>true</c> if the WebSocket service host receives a Pong from the client in a time;
/// otherwise, <c>false</c>.
/// </returns>
/// <param name="id">
/// A <see cref="string"/> that contains a session ID that represents the destination for the Ping.
/// </param>
public bool PingTo (string id)
{
var msg = id.CheckIfValidSessionID ();
if (msg != null)
{
Log.Error (msg);
return false;
}
return _sessions.PingTo (id);
}
/// <summary>
/// Sends a Ping with the specified <paramref name="message"/> to the client associated with
/// the specified <paramref name="id"/>.
/// </summary>
/// <returns>
/// <c>true</c> if the WebSocket service host receives a Pong from the client in a time;
/// otherwise, <c>false</c>.
/// </returns>
/// <param name="message">
/// A <see cref="string"/> that contains a message to send.
/// </param>
/// <param name="id">
/// A <see cref="string"/> that contains an ID that represents the destination for the Ping.
/// A <see cref="string"/> that contains a session ID that represents the destination for the Ping.
/// </param>
public bool PingTo (string message, string id)
{
if (id.IsNullOrEmpty ())
var msg = id.CheckIfValidSessionID ();
if (msg != null)
{
Log.Error ("'id' must not be null or empty.");
Log.Error (msg);
return false;
}
@ -371,7 +502,7 @@ namespace WebSocketSharp.Server
}
/// <summary>
/// Sends a binary data to the client associated with the specified ID.
/// Sends a binary data to the client associated with the specified <paramref name="id"/>.
/// </summary>
/// <returns>
/// <c>true</c> if <paramref name="data"/> is successfully sent; otherwise, <c>false</c>.
@ -380,16 +511,11 @@ namespace WebSocketSharp.Server
/// An array of <see cref="byte"/> that contains a binary data to send.
/// </param>
/// <param name="id">
/// A <see cref="string"/> that contains an ID that represents the destination for the data.
/// A <see cref="string"/> that contains a session ID that represents the destination for the data.
/// </param>
public bool SendTo (byte [] data, string id)
{
var msg = data == null
? "'data' must not be null."
: id.IsNullOrEmpty ()
? "'id' must not be null or empty."
: null;
var msg = id.CheckIfValidSessionID ();
if (msg != null)
{
Log.Error (msg);
@ -400,7 +526,7 @@ namespace WebSocketSharp.Server
}
/// <summary>
/// Sends a text data to the client associated with the specified ID.
/// Sends a text data to the client associated with the specified <paramref name="id"/>.
/// </summary>
/// <returns>
/// <c>true</c> if <paramref name="data"/> is successfully sent; otherwise, <c>false</c>.
@ -409,16 +535,11 @@ namespace WebSocketSharp.Server
/// A <see cref="string"/> that contains a text data to send.
/// </param>
/// <param name="id">
/// A <see cref="string"/> that contains an ID that represents the destination for the data.
/// A <see cref="string"/> that contains a session ID that represents the destination for the data.
/// </param>
public bool SendTo (string data, string id)
{
var msg = data == null
? "'data' must not be null."
: id.IsNullOrEmpty ()
? "'id' must not be null or empty."
: null;
var msg = id.CheckIfValidSessionID ();
if (msg != null)
{
Log.Error (msg);
@ -449,9 +570,10 @@ namespace WebSocketSharp.Server
/// </param>
public void Stop (ushort code, string reason)
{
if (!code.IsCloseStatusCode ())
var msg = code.CheckIfValidCloseStatusCode ();
if (msg != null)
{
Log.Error ("Invalid status code for stop.\ncode: " + code);
Log.Error (String.Format ("{0}\ncode: {1}", msg, code));
return;
}
@ -528,17 +650,80 @@ namespace WebSocketSharp.Server
}
/// <summary>
/// Sends a Ping with the specified <paramref name="message"/> to the client associated with
/// the specified ID.
/// Close the WebSocket session with the specified <paramref name="id"/>.
/// </summary>
/// <param name="id">
/// A <see cref="string"/> that contains a session ID to find.
/// </param>
void IWebSocketServiceHost.CloseSession (string id)
{
_sessions.StopServiceInstance (id);
}
/// <summary>
/// Close the WebSocket session with the specified <paramref name="code"/>, <paramref name="reason"/>
/// and <paramref name="id"/>.
/// </summary>
/// <param name="code">
/// A <see cref="ushort"/> that contains a status code indicating the reason for closure.
/// </param>
/// <param name="reason">
/// A <see cref="string"/> that contains the reason for closure.
/// </param>
/// <param name="id">
/// A <see cref="string"/> that contains a session ID to find.
/// </param>
void IWebSocketServiceHost.CloseSession (ushort code, string reason, string id)
{
_sessions.StopServiceInstance (code, reason, id);
}
/// <summary>
/// Close the WebSocket session with the specified <paramref name="code"/>, <paramref name="reason"/>
/// and <paramref name="id"/>.
/// </summary>
/// <param name="code">
/// A <see cref="CloseStatusCode"/> that contains a status code indicating the reason for closure.
/// </param>
/// <param name="reason">
/// A <see cref="string"/> that contains the reason for closure.
/// </param>
/// <param name="id">
/// A <see cref="string"/> that contains a session ID to find.
/// </param>
void IWebSocketServiceHost.CloseSession (CloseStatusCode code, string reason, string id)
{
_sessions.StopServiceInstance (code, reason, id);
}
/// <summary>
/// Sends a Ping to the client associated with the specified <paramref name="id"/>.
/// </summary>
/// <returns>
/// <c>true</c> if the service host receives a Pong from the client in a time; otherwise, <c>false</c>.
/// <c>true</c> if the WebSocket service host receives a Pong from the client in a time;
/// otherwise, <c>false</c>.
/// </returns>
/// <param name="id">
/// A <see cref="string"/> that contains a session ID that represents the destination for the Ping.
/// </param>
bool IWebSocketServiceHost.PingTo (string id)
{
return _sessions.PingTo (id);
}
/// <summary>
/// Sends a Ping with the specified <paramref name="message"/> to the client associated with
/// the specified <paramref name="id"/>.
/// </summary>
/// <returns>
/// <c>true</c> if the WebSocket service host receives a Pong from the client in a time;
/// otherwise, <c>false</c>.
/// </returns>
/// <param name="message">
/// A <see cref="string"/> that contains a message to send.
/// </param>
/// <param name="id">
/// A <see cref="string"/> that contains an ID that represents the destination for the Ping.
/// A <see cref="string"/> that contains a session ID that represents the destination for the Ping.
/// </param>
bool IWebSocketServiceHost.PingTo (string message, string id)
{
@ -546,7 +731,7 @@ namespace WebSocketSharp.Server
}
/// <summary>
/// Sends a binary data to the client associated with the specified ID.
/// Sends a binary data to the client associated with the specified <paramref name="id"/>.
/// </summary>
/// <returns>
/// <c>true</c> if <paramref name="data"/> is successfully sent; otherwise, <c>false</c>.
@ -555,7 +740,7 @@ namespace WebSocketSharp.Server
/// An array of <see cref="byte"/> that contains a binary data to send.
/// </param>
/// <param name="id">
/// A <see cref="string"/> that contains an ID that represents the destination for the data.
/// A <see cref="string"/> that contains a session ID that represents the destination for the data.
/// </param>
bool IWebSocketServiceHost.SendTo (byte [] data, string id)
{
@ -563,7 +748,7 @@ namespace WebSocketSharp.Server
}
/// <summary>
/// Sends a text data to the client associated with the specified ID.
/// Sends a text data to the client associated with the specified <paramref name="id"/>.
/// </summary>
/// <returns>
/// <c>true</c> if <paramref name="data"/> is successfully sent; otherwise, <c>false</c>.
@ -572,7 +757,7 @@ namespace WebSocketSharp.Server
/// A <see cref="string"/> that contains a text data to send.
/// </param>
/// <param name="id">
/// A <see cref="string"/> that contains an ID that represents the destination for the data.
/// A <see cref="string"/> that contains a session ID that represents the destination for the data.
/// </param>
bool IWebSocketServiceHost.SendTo (string data, string id)
{

View File

@ -29,6 +29,7 @@
using System;
using System.Collections.Generic;
using System.Text;
using WebSocketSharp.Net;
namespace WebSocketSharp.Server
{
@ -63,56 +64,6 @@ namespace WebSocketSharp.Server
#endregion
#region Public Properties
/// <summary>
/// Gets the connection count to the WebSocket services managed by the <see cref="WebSocketServiceHostManager"/>.
/// </summary>
/// <value>
/// An <see cref="int"/> that contains the connection count.
/// </value>
public int ConnectionCount {
get {
var count = 0;
foreach (var host in ServiceHosts)
count += host.ConnectionCount;
return count;
}
}
/// <summary>
/// Gets the number of the WebSocket services managed by the <see cref="WebSocketServiceHostManager"/>.
/// </summary>
/// <value>
/// An <see cref="int"/> that contains the number of the WebSocket services.
/// </value>
public int ServiceCount {
get {
lock (_sync)
{
return _serviceHosts.Count;
}
}
}
/// <summary>
/// Gets the collection of paths to the WebSocket services managed by the <see cref="WebSocketServiceHostManager"/>.
/// </summary>
/// <value>
/// An IEnumerable&lt;string&gt; that contains the collection of paths.
/// </value>
public IEnumerable<string> ServicePaths {
get {
lock (_sync)
{
return _serviceHosts.Keys;
}
}
}
#endregion
#region Internal Properties
internal bool KeepClean {
@ -144,6 +95,56 @@ namespace WebSocketSharp.Server
#endregion
#region Public Properties
/// <summary>
/// Gets the connection count to the WebSocket services managed by the <see cref="WebSocketServiceHostManager"/>.
/// </summary>
/// <value>
/// An <see cref="int"/> that contains the connection count.
/// </value>
public int ConnectionCount {
get {
var count = 0;
foreach (var host in ServiceHosts)
count += host.ConnectionCount;
return count;
}
}
/// <summary>
/// Gets the number of the WebSocket services managed by the <see cref="WebSocketServiceHostManager"/>.
/// </summary>
/// <value>
/// An <see cref="int"/> that contains the number of the WebSocket services.
/// </value>
public int Count {
get {
lock (_sync)
{
return _serviceHosts.Count;
}
}
}
/// <summary>
/// Gets the collection of paths to the WebSocket services managed by the <see cref="WebSocketServiceHostManager"/>.
/// </summary>
/// <value>
/// An IEnumerable&lt;string&gt; that contains the collection of paths.
/// </value>
public IEnumerable<string> ServicePaths {
get {
lock (_sync)
{
return _serviceHosts.Keys;
}
}
}
#endregion
#region Private Methods
private Dictionary<string, IWebSocketServiceHost> copy ()
@ -160,6 +161,7 @@ namespace WebSocketSharp.Server
internal void Add (string servicePath, IWebSocketServiceHost serviceHost)
{
servicePath = HttpUtility.UrlDecode (servicePath).TrimEndSlash ();
lock (_sync)
{
IWebSocketServiceHost host;
@ -170,12 +172,14 @@ namespace WebSocketSharp.Server
return;
}
_serviceHosts.Add (servicePath.UrlDecode (), serviceHost);
_serviceHosts.Add (servicePath, serviceHost);
}
}
internal bool Remove (string servicePath)
{
servicePath = HttpUtility.UrlDecode (servicePath).TrimEndSlash ();
IWebSocketServiceHost host;
lock (_sync)
{
@ -217,6 +221,7 @@ namespace WebSocketSharp.Server
internal bool TryGetServiceHost (string servicePath, out IWebSocketServiceHost serviceHost)
{
servicePath = HttpUtility.UrlDecode (servicePath).TrimEndSlash ();
lock (_sync)
{
return _serviceHosts.TryGetValue (servicePath, out serviceHost);
@ -228,16 +233,18 @@ namespace WebSocketSharp.Server
#region Public Methods
/// <summary>
/// Broadcasts the specified array of <see cref="byte"/> to all clients of the WebSocket services.
/// Broadcasts the specified array of <see cref="byte"/> to all clients of the WebSocket services
/// managed by the <see cref="WebSocketServiceHostManager"/>.
/// </summary>
/// <param name="data">
/// An array of <see cref="byte"/> to broadcast.
/// </param>
public void Broadcast (byte [] data)
{
if (data == null)
var msg = data.CheckIfValidSendData ();
if (msg != null)
{
_logger.Error ("'data' must not be null.");
_logger.Error (msg);
return;
}
@ -246,16 +253,18 @@ namespace WebSocketSharp.Server
}
/// <summary>
/// Broadcasts the specified <see cref="string"/> to all clients of the WebSocket services.
/// Broadcasts the specified <see cref="string"/> to all clients of the WebSocket services
/// managed by the <see cref="WebSocketServiceHostManager"/>.
/// </summary>
/// <param name="data">
/// A <see cref="string"/> to broadcast.
/// </param>
public void Broadcast (string data)
{
if (data == null)
var msg = data.CheckIfValidSendData ();
if (msg != null)
{
_logger.Error ("'data' must not be null.");
_logger.Error (msg);
return;
}
@ -278,12 +287,7 @@ namespace WebSocketSharp.Server
/// </param>
public bool BroadcastTo (byte [] data, string servicePath)
{
var msg = data == null
? "'data' must not be null."
: servicePath.IsNullOrEmpty ()
? "'servicePath' must not be null or empty."
: null;
var msg = data.CheckIfValidSendData () ?? servicePath.CheckIfValidServicePath ();
if (msg != null)
{
_logger.Error (msg);
@ -316,12 +320,7 @@ namespace WebSocketSharp.Server
/// </param>
public bool BroadcastTo (string data, string servicePath)
{
var msg = data == null
? "'data' must not be null."
: servicePath.IsNullOrEmpty ()
? "'servicePath' must not be null or empty."
: null;
var msg = data.CheckIfValidSendData () ?? servicePath.CheckIfValidServicePath ();
if (msg != null)
{
_logger.Error (msg);
@ -340,26 +339,41 @@ namespace WebSocketSharp.Server
}
/// <summary>
/// Sends Pings with the specified <paramref name="message"/> to all clients of the WebSocket services.
/// Sends Pings to all clients of the WebSocket services managed by the <see cref="WebSocketServiceHostManager"/>.
/// </summary>
/// <returns>
/// A Dictionary&lt;string, Dictionary&lt;string, bool&gt;&gt; that contains the collection of
/// service paths and pairs of session ID and value indicating whether each WebSocket service
/// received the Pong from each client in a time.
/// received a Pong from each client in a time.
/// </returns>
public Dictionary<string, Dictionary<string, bool>> Broadping ()
{
var result = new Dictionary<string, Dictionary<string, bool>> ();
foreach (var service in copy ())
result.Add (service.Key, service.Value.Broadping ());
return result;
}
/// <summary>
/// Sends Pings with the specified <paramref name="message"/> to all clients of the WebSocket services
/// managed by the <see cref="WebSocketServiceHostManager"/>.
/// </summary>
/// <returns>
/// A Dictionary&lt;string, Dictionary&lt;string, bool&gt;&gt; that contains the collection of
/// service paths and pairs of session ID and value indicating whether each WebSocket service
/// received a Pong from each client in a time.
/// </returns>
/// <param name="message">
/// A <see cref="string"/> that contains a message to send.
/// </param>
public Dictionary<string, Dictionary<string, bool>> Broadping (string message)
{
if (!message.IsNullOrEmpty ())
var msg = message.CheckIfValidPingMessage ();
if (msg != null)
{
var len = Encoding.UTF8.GetBytes (message).Length;
if (len > 125)
{
_logger.Error ("The payload length of a Ping frame must be 125 bytes or less.");
return null;
}
_logger.Error (msg);
return null;
}
var result = new Dictionary<string, Dictionary<string, bool>> ();
@ -369,13 +383,43 @@ namespace WebSocketSharp.Server
return result;
}
/// <summary>
/// Sends Pings to all clients of the WebSocket service with the specified <paramref name="servicePath"/>.
/// </summary>
/// <returns>
/// A Dictionary&lt;string, bool&gt; 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 <see langword="null"/>.
/// </returns>
/// <param name="servicePath">
/// A <see cref="string"/> that contains an absolute path to the WebSocket service to find.
/// </param>
public Dictionary<string, bool> BroadpingTo (string servicePath)
{
var msg = servicePath.CheckIfValidServicePath ();
if (msg != null)
{
_logger.Error (msg);
return null;
}
IWebSocketServiceHost host;
if (!TryGetServiceHost (servicePath, out host))
{
_logger.Error ("The WebSocket service with the specified path not found.\npath: " + servicePath);
return null;
}
return host.Broadping ();
}
/// <summary>
/// Sends Pings with the specified <paramref name="message"/> to all clients of the WebSocket service
/// with the specified <paramref name="servicePath"/>.
/// </summary>
/// <returns>
/// A Dictionary&lt;string, bool&gt; that contains the collection of pairs of session ID and value
/// indicating whether the WebSocket service received the Pong from each client in a time.
/// indicating whether the WebSocket service received a Pong from each client in a time.
/// If the WebSocket service is not found, returns <see langword="null"/>.
/// </returns>
/// <param name="message">
@ -386,15 +430,7 @@ namespace WebSocketSharp.Server
/// </param>
public Dictionary<string, bool> BroadpingTo (string message, string servicePath)
{
if (message == null)
message = String.Empty;
var msg = Encoding.UTF8.GetBytes (message).Length > 125
? "The payload length of a Ping frame must be 125 bytes or less."
: servicePath.IsNullOrEmpty ()
? "'servicePath' must not be null or empty."
: null;
var msg = message.CheckIfValidPingMessage () ?? servicePath.CheckIfValidServicePath ();
if (msg != null)
{
_logger.Error (msg);
@ -411,21 +447,121 @@ namespace WebSocketSharp.Server
return host.Broadping (message);
}
/// <summary>
/// Close the WebSocket session with the specified <paramref name="id"/> and
/// <paramref name="servicePath"/>.
/// </summary>
/// <param name="id">
/// A <see cref="string"/> that contains a session ID to find.
/// </param>
/// <param name="servicePath">
/// A <see cref="string"/> that contains an absolute path to the WebSocket service to find.
/// </param>
public void CloseSession (string id, string servicePath)
{
var msg = id.CheckIfValidSessionID () ?? servicePath.CheckIfValidServicePath ();
if (msg != null)
{
_logger.Error (msg);
return;
}
IWebSocketServiceHost host;
if (!TryGetServiceHost (servicePath, out host))
{
_logger.Error ("The WebSocket service with the specified path not found.\npath: " + servicePath);
return;
}
host.CloseSession (id);
}
/// <summary>
/// Close the WebSocket session with the specified <paramref name="code"/>, <paramref name="reason"/>,
/// <paramref name="id"/> and <paramref name="servicePath"/>.
/// </summary>
/// <param name="code">
/// A <see cref="ushort"/> that contains a status code indicating the reason for closure.
/// </param>
/// <param name="reason">
/// A <see cref="string"/> that contains the reason for closure.
/// </param>
/// <param name="id">
/// A <see cref="string"/> that contains a session ID to find.
/// </param>
/// <param name="servicePath">
/// A <see cref="string"/> that contains an absolute path to the WebSocket service to find.
/// </param>
public void CloseSession (ushort code, string reason, string id, string servicePath)
{
var msg = id.CheckIfValidSessionID () ?? servicePath.CheckIfValidServicePath ();
if (msg != null)
{
_logger.Error (msg);
return;
}
IWebSocketServiceHost host;
if (!TryGetServiceHost (servicePath, out host))
{
_logger.Error ("The WebSocket service with the specified path not found.\npath: " + servicePath);
return;
}
host.CloseSession (code, reason, id);
}
/// <summary>
/// Close the WebSocket session with the specified <paramref name="code"/>, <paramref name="reason"/>,
/// <paramref name="id"/> and <paramref name="servicePath"/>.
/// </summary>
/// <param name="code">
/// A <see cref="CloseStatusCode"/> that contains a status code indicating the reason for closure.
/// </param>
/// <param name="reason">
/// A <see cref="string"/> that contains the reason for closure.
/// </param>
/// <param name="id">
/// A <see cref="string"/> that contains a session ID to find.
/// </param>
/// <param name="servicePath">
/// A <see cref="string"/> that contains an absolute path to the WebSocket service to find.
/// </param>
public void CloseSession (CloseStatusCode code, string reason, string id, string servicePath)
{
var msg = id.CheckIfValidSessionID () ?? servicePath.CheckIfValidServicePath ();
if (msg != null)
{
_logger.Error (msg);
return;
}
IWebSocketServiceHost host;
if (!TryGetServiceHost (servicePath, out host))
{
_logger.Error ("The WebSocket service with the specified path not found.\npath: " + servicePath);
return;
}
host.CloseSession (code, reason, id);
}
/// <summary>
/// Gets the connection count to the WebSocket service with the specified <paramref name="servicePath"/>.
/// </summary>
/// <returns>
/// An <see cref="int"/> that contains the connection count if the WebSocket service is successfully found;
/// otherwise, <c>-1</c>.
/// An <see cref="int"/> that contains the connection count if the WebSocket service is successfully
/// found; otherwise, <c>-1</c>.
/// </returns>
/// <param name="servicePath">
/// A <see cref="string"/> that contains an absolute path to the WebSocket service to find.
/// </param>
public int GetConnectionCount (string servicePath)
{
if (servicePath.IsNullOrEmpty ())
var msg = servicePath.CheckIfValidServicePath ();
if (msg != null)
{
_logger.Error ("'servicePath' must not be null or empty.");
_logger.Error (msg);
return -1;
}
@ -439,6 +575,39 @@ namespace WebSocketSharp.Server
return host.ConnectionCount;
}
/// <summary>
/// Sends a Ping to the client associated with the specified <paramref name="id"/> and
/// <paramref name="servicePath"/>.
/// </summary>
/// <returns>
/// <c>true</c> if the WebSocket service with <paramref name="servicePath"/> receives a Pong
/// from the client in a time; otherwise, <c>false</c>.
/// </returns>
/// <param name="id">
/// A <see cref="string"/> that contains a session ID that represents the destination for the Ping.
/// </param>
/// <param name="servicePath">
/// A <see cref="string"/> that contains an absolute path to the WebSocket service to find.
/// </param>
public bool PingTo (string id, string servicePath)
{
var msg = id.CheckIfValidSessionID () ?? servicePath.CheckIfValidServicePath ();
if (msg != null)
{
_logger.Error (msg);
return false;
}
IWebSocketServiceHost host;
if (!TryGetServiceHost (servicePath, out host))
{
_logger.Error ("The WebSocket service with the specified path not found.\npath: " + servicePath);
return false;
}
return host.PingTo (id);
}
/// <summary>
/// Sends a Ping with the specified <paramref name="message"/> to the client associated with
/// the specified <paramref name="id"/> and <paramref name="servicePath"/>.
@ -451,18 +620,15 @@ namespace WebSocketSharp.Server
/// A <see cref="string"/> that contains a message to send.
/// </param>
/// <param name="id">
/// A <see cref="string"/> that contains an ID that represents the destination for the Ping.
/// A <see cref="string"/> that contains a session ID that represents the destination for the Ping.
/// </param>
/// <param name="servicePath">
/// A <see cref="string"/> that contains an absolute path to the WebSocket service to find.
/// </param>
public bool PingTo (string message, string id, string servicePath)
{
var msg = id.IsNullOrEmpty ()
? "'id' must not be null or empty."
: servicePath.IsNullOrEmpty ()
? "'servicePath' must not be null or empty."
: null;
var msg = (message.CheckIfValidPingMessage () ?? id.CheckIfValidSessionID ()) ??
servicePath.CheckIfValidServicePath ();
if (msg != null)
{
@ -491,20 +657,15 @@ namespace WebSocketSharp.Server
/// An array of <see cref="byte"/> that contains a binary data to send.
/// </param>
/// <param name="id">
/// A <see cref="string"/> that contains an ID that represents the destination for the data.
/// A <see cref="string"/> that contains a session ID that represents the destination for the data.
/// </param>
/// <param name="servicePath">
/// A <see cref="string"/> that contains an absolute path to the WebSocket service to find.
/// </param>
public bool SendTo (byte [] data, string id, string servicePath)
{
var msg = data == null
? "'data' must not be null."
: id.IsNullOrEmpty ()
? "'id' must not be null or empty."
: servicePath.IsNullOrEmpty ()
? "'servicePath' must not be null or empty."
: null;
var msg = (data.CheckIfValidSendData () ?? id.CheckIfValidSessionID ()) ??
servicePath.CheckIfValidServicePath ();
if (msg != null)
{
@ -533,20 +694,15 @@ namespace WebSocketSharp.Server
/// A <see cref="string"/> that contains a text data to send.
/// </param>
/// <param name="id">
/// A <see cref="string"/> that contains an ID that represents the destination for the data.
/// A <see cref="string"/> that contains a session ID that represents the destination for the data.
/// </param>
/// <param name="servicePath">
/// A <see cref="string"/> that contains an absolute path to the WebSocket service to find.
/// </param>
public bool SendTo (string data, string id, string servicePath)
{
var msg = data == null
? "'data' must not be null."
: id.IsNullOrEmpty ()
? "'id' must not be null or empty."
: servicePath.IsNullOrEmpty ()
? "'servicePath' must not be null or empty."
: null;
var msg = (data.CheckIfValidSendData () ?? id.CheckIfValidSessionID ()) ??
servicePath.CheckIfValidServicePath ();
if (msg != null)
{

View File

@ -84,7 +84,7 @@ namespace WebSocketSharp.Server
/// </value>
public IEnumerable<string> ActiveIDs {
get {
return from result in Broadping (String.Empty)
return from result in Broadping ()
where result.Value
select result.Key;
}
@ -134,14 +134,14 @@ namespace WebSocketSharp.Server
/// </value>
public IEnumerable<string> InactiveIDs {
get {
return from result in Broadping (String.Empty)
return from result in Broadping ()
where !result.Value
select result.Key;
}
}
/// <summary>
/// Gets the <see cref="WebSocketService"/> instance with the specified ID
/// Gets the <see cref="WebSocketService"/> instance with the specified <paramref name="id"/>
/// from the <see cref="WebSocketServiceManager"/>.
/// </summary>
/// <value>
@ -153,9 +153,10 @@ namespace WebSocketSharp.Server
/// </param>
public WebSocketService this [string id] {
get {
if (id.IsNullOrEmpty ())
var msg = id.CheckIfValidSessionID ();
if (msg != null)
{
_logger.Error ("'id' must not be null or empty.");
_logger.Error (msg);
return null;
}
@ -289,23 +290,6 @@ namespace WebSocketSharp.Server
_sweepTimer.Start ();
}
private void stop (ushort code, string reason, bool ignoreArgs)
{
stopSweepTimer ();
lock (_sync)
{
if (_stopped)
return;
_stopped = true;
foreach (var service in copy ().Values)
if (ignoreArgs)
service.Stop ();
else
service.Stop (code, reason);
}
}
private void stopSweepTimer ()
{
if (_sweepTimer.Enabled)
@ -331,8 +315,8 @@ namespace WebSocketSharp.Server
}
/// <summary>
/// Broadcasts the specified array of <see cref="byte"/> to the clients of every
/// <see cref="WebSocketService"/> instances managed by the <see cref="WebSocketServiceManager"/>.
/// Broadcasts the specified array of <see cref="byte"/> to the clients of every <see cref="WebSocketService"/>
/// instances managed by the <see cref="WebSocketServiceManager"/>.
/// </summary>
/// <param name="data">
/// An array of <see cref="byte"/> to broadcast.
@ -346,8 +330,8 @@ namespace WebSocketSharp.Server
}
/// <summary>
/// Broadcasts the specified <see cref="string"/> to the clients of every
/// <see cref="WebSocketService"/> instances managed by the <see cref="WebSocketServiceManager"/>.
/// Broadcasts the specified <see cref="string"/> to the clients of every <see cref="WebSocketService"/>
/// instances managed by the <see cref="WebSocketServiceManager"/>.
/// </summary>
/// <param name="data">
/// A <see cref="string"/> to broadcast.
@ -361,12 +345,29 @@ namespace WebSocketSharp.Server
}
/// <summary>
/// Sends Pings with the specified <paramref name="message"/> to the clients of every
/// <see cref="WebSocketService"/> instances managed by the <see cref="WebSocketServiceManager"/>.
/// Sends Pings to the clients of every <see cref="WebSocketService"/> instances managed by
/// the <see cref="WebSocketServiceManager"/>.
/// </summary>
/// <returns>
/// A Dictionary&lt;string, bool&gt; that contains the collection of pairs of session ID and value
/// indicating whether the each <see cref="WebSocketService"/> instance received a Pong in a time.
/// A Dictionary&lt;string, bool&gt; that contains the collection of pairs of ID and value indicating
/// whether each <see cref="WebSocketService"/> instance received a Pong from the client in a time.
/// </returns>
internal Dictionary<string, bool> Broadping ()
{
var result = new Dictionary<string, bool> ();
foreach (var session in copy ())
result.Add (session.Key, session.Value.Ping ());
return result;
}
/// <summary>
/// Sends Pings with the specified <paramref name="message"/> to the clients of every <see cref="WebSocketService"/>
/// instances managed by the <see cref="WebSocketServiceManager"/>.
/// </summary>
/// <returns>
/// A Dictionary&lt;string, bool&gt; that contains the collection of pairs of ID and value indicating
/// whether each <see cref="WebSocketService"/> instance received a Pong from the client in a time.
/// </returns>
/// <param name="message">
/// A <see cref="string"/> that contains a message to send.
@ -381,12 +382,36 @@ namespace WebSocketSharp.Server
}
/// <summary>
/// Sends a Ping with the specified <paramref name="message"/> to the client of
/// the <see cref="WebSocketService"/> instance with the specified ID.
/// Sends a Ping to the client of the <see cref="WebSocketService"/> instance
/// with the specified <paramref name="id"/>.
/// </summary>
/// <returns>
/// <c>true</c> if the <see cref="WebSocketService"/> instance with <paramref name="id"/> receives
/// a Pong in a time; otherwise, <c>false</c>.
/// <c>true</c> if the <see cref="WebSocketService"/> instance receives a Pong from the client
/// in a time; otherwise, <c>false</c>.
/// </returns>
/// <param name="id">
/// A <see cref="string"/> that contains an ID that represents the destination for the Ping.
/// </param>
internal bool PingTo (string id)
{
WebSocketService service;
if (!TryGetServiceInstance (id, out service))
{
_logger.Error (
"The WebSocket service instance with the specified ID not found.\nID: " + id);
return false;
}
return service.Ping ();
}
/// <summary>
/// Sends a Ping with the specified <paramref name="message"/> to the client of the <see cref="WebSocketService"/>
/// instance with the specified <paramref name="id"/>.
/// </summary>
/// <returns>
/// <c>true</c> if the <see cref="WebSocketService"/> instance receives a Pong from the client
/// in a time; otherwise, <c>false</c>.
/// </returns>
/// <param name="message">
/// A <see cref="string"/> that contains a message to send.
@ -417,7 +442,7 @@ namespace WebSocketSharp.Server
/// <summary>
/// Sends a binary data to the client of the <see cref="WebSocketService"/> instance
/// with the specified ID.
/// with the specified <paramref name="id"/>.
/// </summary>
/// <returns>
/// <c>true</c> if <paramref name="data"/> is successfully sent; otherwise, <c>false</c>.
@ -444,7 +469,7 @@ namespace WebSocketSharp.Server
/// <summary>
/// Sends a text data to the client of the <see cref="WebSocketService"/> instance
/// with the specified ID.
/// with the specified <paramref name="id"/>.
/// </summary>
/// <returns>
/// <c>true</c> if <paramref name="data"/> is successfully sent; otherwise, <c>false</c>.
@ -471,12 +496,69 @@ namespace WebSocketSharp.Server
internal void Stop ()
{
stop (0, null, true);
stopSweepTimer ();
lock (_sync)
{
if (_stopped)
return;
_stopped = true;
foreach (var service in copy ().Values)
service.Stop ();
}
}
internal void Stop (ushort code, string reason)
{
stop (code, reason, false);
stopSweepTimer ();
lock (_sync)
{
if (_stopped)
return;
_stopped = true;
foreach (var service in copy ().Values)
service.Stop (code, reason);
}
}
internal void StopServiceInstance (string id)
{
WebSocketService service;
if (!TryGetServiceInstance (id, out service))
{
_logger.Error (
"The WebSocket service instance with the specified ID not found.\nID: " + id);
return;
}
service.Stop ();
}
internal void StopServiceInstance (ushort code, string reason, string id)
{
WebSocketService service;
if (!TryGetServiceInstance (id, out service))
{
_logger.Error (
"The WebSocket service instance with the specified ID not found.\nID: " + id);
return;
}
service.Stop (code, reason);
}
internal void StopServiceInstance (CloseStatusCode code, string reason, string id)
{
WebSocketService service;
if (!TryGetServiceInstance (id, out service))
{
_logger.Error (
"The WebSocket service instance with the specified ID not found.\nID: " + id);
return;
}
service.Stop (code, reason);
}
#endregion
@ -520,7 +602,7 @@ namespace WebSocketSharp.Server
}
/// <summary>
/// Tries to get the <see cref="WebSocketService"/> instance with the specified ID.
/// Tries to get the <see cref="WebSocketService"/> instance with the specified <paramref name="id"/>.
/// </summary>
/// <returns>
/// <c>true</c> if the <see cref="WebSocketService"/> instance with <paramref name="id"/>