Modified the Sweep method of WebSocketServiceManager class
This commit is contained in:
parent
03e95638e3
commit
ef17cabdd3
@ -64,6 +64,16 @@ namespace WebSocketSharp.Server {
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Internal Properties
|
||||||
|
|
||||||
|
internal WebSocket WebSocket {
|
||||||
|
get {
|
||||||
|
return _websocket;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region Protected Properties
|
#region Protected Properties
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -31,36 +31,36 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Timers;
|
using System.Timers;
|
||||||
|
|
||||||
namespace WebSocketSharp.Server {
|
namespace WebSocketSharp.Server
|
||||||
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Manages the collection of <see cref="WebSocketService"/> objects.
|
/// Manages the collection of <see cref="WebSocketService"/> instances.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class WebSocketServiceManager {
|
public class WebSocketServiceManager
|
||||||
|
{
|
||||||
#region Private Fields
|
#region Private Fields
|
||||||
|
|
||||||
private object _forSweep;
|
private object _forSweep;
|
||||||
private volatile bool _isStopped;
|
|
||||||
private volatile bool _isSweeping;
|
|
||||||
private Dictionary<string, WebSocketService> _services;
|
private Dictionary<string, WebSocketService> _services;
|
||||||
|
private volatile bool _stopped;
|
||||||
|
private volatile bool _sweeping;
|
||||||
private Timer _sweepTimer;
|
private Timer _sweepTimer;
|
||||||
private object _syncRoot;
|
private object _sync;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Internal Constructors
|
#region Internal Constructors
|
||||||
|
|
||||||
internal WebSocketServiceManager()
|
internal WebSocketServiceManager ()
|
||||||
{
|
{
|
||||||
_forSweep = new object();
|
_forSweep = new object ();
|
||||||
_isStopped = false;
|
_services = new Dictionary<string, WebSocketService> ();
|
||||||
_isSweeping = false;
|
_stopped = false;
|
||||||
_services = new Dictionary<string, WebSocketService>();
|
_sweeping = false;
|
||||||
_syncRoot = new object();
|
_sync = new object ();
|
||||||
|
|
||||||
setSweepTimer();
|
setSweepTimer ();
|
||||||
startSweepTimer();
|
startSweepTimer ();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -68,62 +68,49 @@ namespace WebSocketSharp.Server {
|
|||||||
#region Public Properties
|
#region Public Properties
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the collection of IDs of active <see cref="WebSocketService"/> objects
|
/// Gets the collection of IDs of active <see cref="WebSocketService"/> instances
|
||||||
/// managed by the <see cref="WebSocketServiceManager"/>.
|
/// managed by the <see cref="WebSocketServiceManager"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>
|
/// <value>
|
||||||
/// An IEnumerable<string> that contains the collection of IDs of active <see cref="WebSocketService"/> objects.
|
/// An IEnumerable<string> that contains the collection of IDs
|
||||||
|
/// of active <see cref="WebSocketService"/> instances.
|
||||||
/// </value>
|
/// </value>
|
||||||
public IEnumerable<string> ActiveIDs {
|
public IEnumerable<string> ActiveIDs {
|
||||||
get {
|
get {
|
||||||
return from result in Broadping(String.Empty)
|
return from result in Broadping (String.Empty)
|
||||||
where result.Value
|
where result.Value
|
||||||
select result.Key;
|
select result.Key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the number of <see cref="WebSocketService"/> objects
|
/// Gets the number of <see cref="WebSocketService"/> instances
|
||||||
/// managed by the <see cref="WebSocketServiceManager"/>.
|
/// managed by the <see cref="WebSocketServiceManager"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>
|
/// <value>
|
||||||
/// An <see cref="int"/> that contains the number of <see cref="WebSocketService"/> objects
|
/// An <see cref="int"/> that contains the number of <see cref="WebSocketService"/> instances
|
||||||
/// managed by the <see cref="WebSocketServiceManager"/>.
|
/// managed by the <see cref="WebSocketServiceManager"/>.
|
||||||
/// </value>
|
/// </value>
|
||||||
public int Count {
|
public int Count {
|
||||||
get {
|
get {
|
||||||
lock (_syncRoot)
|
lock (_sync)
|
||||||
{
|
{
|
||||||
return _services.Count;
|
return _services.Count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the collection of IDs of inactive <see cref="WebSocketService"/> objects
|
|
||||||
/// managed by the <see cref="WebSocketServiceManager"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>
|
|
||||||
/// An IEnumerable<string> that contains the collection of IDs of inactive <see cref="WebSocketService"/> objects.
|
|
||||||
/// </value>
|
|
||||||
public IEnumerable<string> InactiveIDs {
|
|
||||||
get {
|
|
||||||
return from result in Broadping(String.Empty)
|
|
||||||
where !result.Value
|
|
||||||
select result.Key;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the collection of IDs of <see cref="WebSocketService"/> objects
|
/// Gets the collection of IDs of <see cref="WebSocketService"/> instances
|
||||||
/// managed by the <see cref="WebSocketServiceManager"/>.
|
/// managed by the <see cref="WebSocketServiceManager"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>
|
/// <value>
|
||||||
/// An IEnumerable<string> that contains the collection of IDs of <see cref="WebSocketService"/> objects.
|
/// An IEnumerable<string> that contains the collection of IDs
|
||||||
|
/// of <see cref="WebSocketService"/> instances.
|
||||||
/// </value>
|
/// </value>
|
||||||
public IEnumerable<string> IDs {
|
public IEnumerable<string> IDs {
|
||||||
get {
|
get {
|
||||||
lock (_syncRoot)
|
lock (_sync)
|
||||||
{
|
{
|
||||||
return _services.Keys;
|
return _services.Keys;
|
||||||
}
|
}
|
||||||
@ -131,12 +118,28 @@ namespace WebSocketSharp.Server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether the <see cref="WebSocketServiceManager"/> cleans up
|
/// Gets the collection of IDs of inactive <see cref="WebSocketService"/> instances
|
||||||
/// the inactive <see cref="WebSocketService"/> objects periodically.
|
/// managed by the <see cref="WebSocketServiceManager"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>
|
/// <value>
|
||||||
/// <c>true</c> if the <see cref="WebSocketServiceManager"/> cleans up the inactive <see cref="WebSocketService"/> objects
|
/// An IEnumerable<string> that contains the collection of IDs
|
||||||
/// every 60 seconds; otherwise, <c>false</c>.
|
/// of inactive <see cref="WebSocketService"/> instances.
|
||||||
|
/// </value>
|
||||||
|
public IEnumerable<string> InactiveIDs {
|
||||||
|
get {
|
||||||
|
return from result in Broadping (String.Empty)
|
||||||
|
where !result.Value
|
||||||
|
select result.Key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether the <see cref="WebSocketServiceManager"/> cleans up
|
||||||
|
/// the inactive <see cref="WebSocketService"/> instances periodically.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// <c>true</c> if the <see cref="WebSocketServiceManager"/> cleans up
|
||||||
|
/// the inactive <see cref="WebSocketService"/> instances every 60 seconds; otherwise, <c>false</c>.
|
||||||
/// </value>
|
/// </value>
|
||||||
public bool Sweeping {
|
public bool Sweeping {
|
||||||
get {
|
get {
|
||||||
@ -144,11 +147,13 @@ namespace WebSocketSharp.Server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal set {
|
internal set {
|
||||||
if (value && !_isStopped)
|
if (value)
|
||||||
startSweepTimer();
|
{
|
||||||
|
if (!_stopped)
|
||||||
if (!value)
|
startSweepTimer ();
|
||||||
stopSweepTimer();
|
}
|
||||||
|
else
|
||||||
|
stopSweepTimer ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,146 +161,146 @@ namespace WebSocketSharp.Server {
|
|||||||
|
|
||||||
#region Private Methods
|
#region Private Methods
|
||||||
|
|
||||||
private void broadcast(byte[] data)
|
private void broadcast (byte [] data)
|
||||||
{
|
{
|
||||||
lock (_syncRoot)
|
lock (_sync)
|
||||||
{
|
{
|
||||||
foreach (var service in _services.Values)
|
foreach (var service in _services.Values)
|
||||||
service.Send(data);
|
service.Send (data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void broadcast(string data)
|
private void broadcast (string data)
|
||||||
{
|
{
|
||||||
lock (_syncRoot)
|
lock (_sync)
|
||||||
{
|
{
|
||||||
foreach (var service in _services.Values)
|
foreach (var service in _services.Values)
|
||||||
service.Send(data);
|
service.Send (data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void broadcastAsync(byte[] data)
|
private void broadcastAsync (byte [] data)
|
||||||
{
|
{
|
||||||
var copied = copy();
|
var copied = copy ();
|
||||||
var services = copied.Values.GetEnumerator();
|
var services = copied.Values.GetEnumerator ();
|
||||||
|
|
||||||
Action completed = null;
|
Action completed = null;
|
||||||
completed = () =>
|
completed = () =>
|
||||||
{
|
{
|
||||||
if (services.MoveNext())
|
if (services.MoveNext ())
|
||||||
services.Current.SendAsync(data, completed);
|
services.Current.SendAsync (data, completed);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (services.MoveNext())
|
if (services.MoveNext ())
|
||||||
services.Current.SendAsync(data, completed);
|
services.Current.SendAsync (data, completed);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void broadcastAsync(string data)
|
private void broadcastAsync (string data)
|
||||||
{
|
{
|
||||||
var copied = copy();
|
var copied = copy ();
|
||||||
var services = copied.Values.GetEnumerator();
|
var services = copied.Values.GetEnumerator ();
|
||||||
|
|
||||||
Action completed = null;
|
Action completed = null;
|
||||||
completed = () =>
|
completed = () =>
|
||||||
{
|
{
|
||||||
if (services.MoveNext())
|
if (services.MoveNext ())
|
||||||
services.Current.SendAsync(data, completed);
|
services.Current.SendAsync (data, completed);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (services.MoveNext())
|
if (services.MoveNext ())
|
||||||
services.Current.SendAsync(data, completed);
|
services.Current.SendAsync (data, completed);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Dictionary<string, WebSocketService> copy()
|
private Dictionary<string, WebSocketService> copy ()
|
||||||
{
|
{
|
||||||
lock (_syncRoot)
|
lock (_sync)
|
||||||
{
|
{
|
||||||
return new Dictionary<string, WebSocketService>(_services);
|
return new Dictionary<string, WebSocketService> (_services);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string createID()
|
private static string createID ()
|
||||||
{
|
{
|
||||||
return Guid.NewGuid().ToString("N");
|
return Guid.NewGuid ().ToString ("N");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setSweepTimer()
|
private void setSweepTimer ()
|
||||||
{
|
{
|
||||||
_sweepTimer = new Timer(60 * 1000);
|
_sweepTimer = new Timer (60 * 1000);
|
||||||
_sweepTimer.Elapsed += (sender, e) =>
|
_sweepTimer.Elapsed += (sender, e) =>
|
||||||
{
|
{
|
||||||
Sweep();
|
Sweep ();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startSweepTimer()
|
private void startSweepTimer ()
|
||||||
{
|
{
|
||||||
if (!_sweepTimer.Enabled)
|
if (!_sweepTimer.Enabled)
|
||||||
_sweepTimer.Start();
|
_sweepTimer.Start ();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void stop(ushort code, string reason, bool ignoreArgs)
|
private void stop (ushort code, string reason, bool ignoreArgs)
|
||||||
{
|
{
|
||||||
stopSweepTimer();
|
stopSweepTimer ();
|
||||||
lock (_syncRoot)
|
lock (_sync)
|
||||||
{
|
{
|
||||||
if (_isStopped)
|
if (_stopped)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_isStopped = true;
|
_stopped = true;
|
||||||
foreach (var service in copy().Values)
|
foreach (var service in copy ().Values)
|
||||||
if (ignoreArgs)
|
if (ignoreArgs)
|
||||||
service.Stop();
|
service.Stop ();
|
||||||
else
|
else
|
||||||
service.Stop(code, reason);
|
service.Stop (code, reason);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void stopSweepTimer()
|
private void stopSweepTimer ()
|
||||||
{
|
{
|
||||||
if (_sweepTimer.Enabled)
|
if (_sweepTimer.Enabled)
|
||||||
_sweepTimer.Stop();
|
_sweepTimer.Stop ();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Internal Methods
|
#region Internal Methods
|
||||||
|
|
||||||
internal string Add(WebSocketService service)
|
internal string Add (WebSocketService service)
|
||||||
{
|
{
|
||||||
lock (_syncRoot)
|
lock (_sync)
|
||||||
{
|
{
|
||||||
if (_isStopped)
|
if (_stopped)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var id = createID();
|
var id = createID ();
|
||||||
_services.Add(id, service);
|
_services.Add (id, service);
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal bool Remove(string id)
|
internal bool Remove (string id)
|
||||||
{
|
{
|
||||||
lock (_syncRoot)
|
lock (_sync)
|
||||||
{
|
{
|
||||||
return _services.Remove(id);
|
return _services.Remove (id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Stop()
|
internal void Stop ()
|
||||||
{
|
{
|
||||||
stop(0, null, true);
|
stop (0, null, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Stop(ushort code, string reason)
|
internal void Stop (ushort code, string reason)
|
||||||
{
|
{
|
||||||
stop(code, reason, false);
|
stop (code, reason, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Stop(CloseStatusCode code, string reason)
|
internal void Stop (CloseStatusCode code, string reason)
|
||||||
{
|
{
|
||||||
Stop((ushort)code, reason);
|
Stop ((ushort) code, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -303,103 +308,113 @@ namespace WebSocketSharp.Server {
|
|||||||
#region Public Methods
|
#region Public Methods
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Broadcasts the specified array of <see cref="byte"/> to the clients of every <see cref="WebSocketService"/>
|
/// Broadcasts the specified array of <see cref="byte"/> to the clients of every
|
||||||
/// managed by the <see cref="WebSocketServiceManager"/>.
|
/// <see cref="WebSocketService"/> instances managed by the <see cref="WebSocketServiceManager"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="data">
|
/// <param name="data">
|
||||||
/// An array of <see cref="byte"/> to broadcast.
|
/// An array of <see cref="byte"/> to broadcast.
|
||||||
/// </param>
|
/// </param>
|
||||||
public void Broadcast(byte[] data)
|
public void Broadcast (byte [] data)
|
||||||
{
|
{
|
||||||
if (_isStopped)
|
if (_stopped)
|
||||||
broadcast(data);
|
broadcast (data);
|
||||||
else
|
else
|
||||||
broadcastAsync(data);
|
broadcastAsync (data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Broadcasts the specified <see cref="string"/> to the clients of every <see cref="WebSocketService"/>
|
/// Broadcasts the specified <see cref="string"/> to the clients of every
|
||||||
/// managed by the <see cref="WebSocketServiceManager"/>.
|
/// <see cref="WebSocketService"/> instances managed by the <see cref="WebSocketServiceManager"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="data">
|
/// <param name="data">
|
||||||
/// A <see cref="string"/> to broadcast.
|
/// A <see cref="string"/> to broadcast.
|
||||||
/// </param>
|
/// </param>
|
||||||
public void Broadcast(string data)
|
public void Broadcast (string data)
|
||||||
{
|
{
|
||||||
if (_isStopped)
|
if (_stopped)
|
||||||
broadcast(data);
|
broadcast (data);
|
||||||
else
|
else
|
||||||
broadcastAsync(data);
|
broadcastAsync (data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Pings with the specified <see cref="string"/> to the clients of every <see cref="WebSocketService"/>
|
/// Sends Pings with the specified <see cref="string"/> to the clients of every
|
||||||
/// managed by the <see cref="WebSocketServiceManager"/>.
|
/// <see cref="WebSocketService"/> instances managed by the <see cref="WebSocketServiceManager"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>
|
/// <returns>
|
||||||
/// A Dictionary<string, bool> that contains the collection of IDs and values
|
/// A Dictionary<string, bool> that contains the collection of IDs and values indicating
|
||||||
/// indicating whether each <see cref="WebSocketService"/> received a Pong in a time.
|
/// whether each <see cref="WebSocketService"/> instances received a Pong in a time.
|
||||||
/// </returns>
|
/// </returns>
|
||||||
/// <param name="message">
|
/// <param name="message">
|
||||||
/// A <see cref="string"/> that contains a message.
|
/// A <see cref="string"/> that contains a message to send.
|
||||||
/// </param>
|
/// </param>
|
||||||
public Dictionary<string, bool> Broadping(string message)
|
public Dictionary<string, bool> Broadping (string message)
|
||||||
{
|
{
|
||||||
var result = new Dictionary<string, bool>();
|
var result = new Dictionary<string, bool> ();
|
||||||
foreach (var session in copy())
|
foreach (var session in copy ())
|
||||||
result.Add(session.Key, session.Value.Ping(message));
|
result.Add (session.Key, session.Value.Ping (message));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Cleans up the inactive <see cref="WebSocketService"/> objects.
|
/// Cleans up the inactive <see cref="WebSocketService"/> instances.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Sweep()
|
public void Sweep ()
|
||||||
{
|
{
|
||||||
if (_isStopped || _isSweeping || Count == 0)
|
if (_stopped || _sweeping || Count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
lock (_forSweep)
|
lock (_forSweep)
|
||||||
{
|
{
|
||||||
_isSweeping = true;
|
_sweeping = true;
|
||||||
foreach (var id in InactiveIDs)
|
foreach (var id in InactiveIDs)
|
||||||
{
|
{
|
||||||
lock (_syncRoot)
|
lock (_sync)
|
||||||
{
|
{
|
||||||
if (_isStopped)
|
if (_stopped)
|
||||||
{
|
{
|
||||||
_isSweeping = false;
|
_sweeping = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
WebSocketService service;
|
WebSocketService service;
|
||||||
if (TryGetWebSocketService(id, out service))
|
if (_services.TryGetValue (id, out service))
|
||||||
service.Stop(CloseStatusCode.ABNORMAL, String.Empty);
|
{
|
||||||
|
var state = service.WebSocket.ReadyState;
|
||||||
|
if (state == WsState.OPEN)
|
||||||
|
service.Stop (CloseStatusCode.ABNORMAL, String.Empty);
|
||||||
|
else if (state == WsState.CLOSING)
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
_services.Remove (id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_isSweeping = false;
|
_sweeping = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tries to get the <see cref="WebSocketService"/> associated with the specified <paramref name="id"/>.
|
/// Tries to get the <see cref="WebSocketService"/> associated with the specified ID.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>
|
/// <returns>
|
||||||
/// <c>true</c> if the <see cref="WebSocketServiceManager"/> manages the <see cref="WebSocketService"/> with the specified <paramref name="id"/>; otherwise, <c>false</c>.
|
/// <c>true</c> if the <see cref="WebSocketServiceManager"/> manages the <see cref="WebSocketService"/>
|
||||||
|
/// with <paramref name="id"/>; otherwise, <c>false</c>.
|
||||||
/// </returns>
|
/// </returns>
|
||||||
/// <param name="id">
|
/// <param name="id">
|
||||||
/// A <see cref="string"/> that contains the ID to find.
|
/// A <see cref="string"/> that contains an ID to find.
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <param name="service">
|
/// <param name="service">
|
||||||
/// When this method returns, contains the <see cref="WebSocketService"/> with the specified <paramref name="id"/>, if the <paramref name="id"/> is found; otherwise, <see langword="null"/>.
|
/// When this method returns, contains a <see cref="WebSocketService"/> with <paramref name="id"/>
|
||||||
|
/// if it is found; otherwise, <see langword="null"/>.
|
||||||
/// </param>
|
/// </param>
|
||||||
public bool TryGetWebSocketService(string id, out WebSocketService service)
|
public bool TryGetWebSocketService (string id, out WebSocketService service)
|
||||||
{
|
{
|
||||||
lock (_syncRoot)
|
lock (_sync)
|
||||||
{
|
{
|
||||||
return _services.TryGetValue(id, out service);
|
return _services.TryGetValue (id, out service);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user