3.2.30.3
This commit is contained in:
parent
8de80d43ba
commit
0f23c7cfc1
|
@ -1614,7 +1614,7 @@ namespace Emby.Server.Implementations
|
|||
{
|
||||
try
|
||||
{
|
||||
ServerManager.Start(GetUrlPrefixes());
|
||||
ServerManager.Start(GetUrlPrefixes().ToArray());
|
||||
return;
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -1631,7 +1631,7 @@ namespace Emby.Server.Implementations
|
|||
|
||||
try
|
||||
{
|
||||
ServerManager.Start(GetUrlPrefixes());
|
||||
ServerManager.Start(GetUrlPrefixes().ToArray());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
|
@ -10,7 +10,6 @@ using System.Reflection;
|
|||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Emby.Server.Implementations.HttpServer;
|
||||
using Emby.Server.Implementations.HttpServer.SocketSharp;
|
||||
using Emby.Server.Implementations.Services;
|
||||
using MediaBrowser.Common.Net;
|
||||
|
@ -34,7 +33,7 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
private string DefaultRedirectPath { get; set; }
|
||||
|
||||
private readonly ILogger _logger;
|
||||
public IEnumerable<string> UrlPrefixes { get; private set; }
|
||||
public string[] UrlPrefixes { get; private set; }
|
||||
|
||||
private readonly List<IService> _restServices = new List<IService>();
|
||||
|
||||
|
@ -62,8 +61,8 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
private readonly Func<Type, Func<string, object>> _funcParseFn;
|
||||
private readonly bool _enableDualModeSockets;
|
||||
|
||||
public List<Action<IRequest, IResponse, object>> RequestFilters { get; set; }
|
||||
public List<Action<IRequest, IResponse, object>> ResponseFilters { get; set; }
|
||||
public Action<IRequest, IResponse, object>[] RequestFilters { get; set; }
|
||||
public Action<IRequest, IResponse, object>[] ResponseFilters { get; set; }
|
||||
|
||||
private readonly Dictionary<Type, Type> ServiceOperationsMap = new Dictionary<Type, Type>();
|
||||
public static HttpListenerHost Instance { get; protected set; }
|
||||
|
@ -95,8 +94,8 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
|
||||
_logger = logger;
|
||||
|
||||
RequestFilters = new List<Action<IRequest, IResponse, object>>();
|
||||
ResponseFilters = new List<Action<IRequest, IResponse, object>>();
|
||||
RequestFilters = new Action<IRequest, IResponse, object>[] { };
|
||||
ResponseFilters = new Action<IRequest, IResponse, object>[] { };
|
||||
}
|
||||
|
||||
public string GlobalResponse { get; set; }
|
||||
|
@ -135,7 +134,9 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
//Exec all RequestFilter attributes with Priority < 0
|
||||
var attributes = GetRequestFilterAttributes(requestDto.GetType());
|
||||
var i = 0;
|
||||
for (; i < attributes.Length && attributes[i].Priority < 0; i++)
|
||||
var count = attributes.Count;
|
||||
|
||||
for (; i < count && attributes[i].Priority < 0; i++)
|
||||
{
|
||||
var attribute = attributes[i];
|
||||
attribute.RequestFilter(req, res, requestDto);
|
||||
|
@ -148,7 +149,7 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
}
|
||||
|
||||
//Exec remaining RequestFilter attributes with Priority >= 0
|
||||
for (; i < attributes.Length && attributes[i].Priority >= 0; i++)
|
||||
for (; i < count && attributes[i].Priority >= 0; i++)
|
||||
{
|
||||
var attribute = attributes[i];
|
||||
attribute.RequestFilter(req, res, requestDto);
|
||||
|
@ -167,7 +168,7 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
ServiceOperationsMap[requestType] = serviceType;
|
||||
}
|
||||
|
||||
private IHasRequestFilter[] GetRequestFilterAttributes(Type requestDtoType)
|
||||
private List<IHasRequestFilter> GetRequestFilterAttributes(Type requestDtoType)
|
||||
{
|
||||
var attributes = requestDtoType.GetTypeInfo().GetCustomAttributes(true).OfType<IHasRequestFilter>().ToList();
|
||||
|
||||
|
@ -179,24 +180,7 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
|
||||
attributes.Sort((x, y) => x.Priority - y.Priority);
|
||||
|
||||
return attributes.ToArray(attributes.Count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts the Web Service
|
||||
/// </summary>
|
||||
private void StartListener()
|
||||
{
|
||||
WebSocketSharpRequest.HandlerFactoryPath = GetHandlerPathIfAny(UrlPrefixes.First());
|
||||
|
||||
_listener = GetListener();
|
||||
|
||||
_listener.WebSocketConnected = OnWebSocketConnected;
|
||||
_listener.WebSocketConnecting = OnWebSocketConnecting;
|
||||
_listener.ErrorHandler = ErrorHandler;
|
||||
_listener.RequestHandler = RequestHandler;
|
||||
|
||||
_listener.Start(UrlPrefixes);
|
||||
return attributes;
|
||||
}
|
||||
|
||||
public static string GetHandlerPathIfAny(string listenerUrl)
|
||||
|
@ -698,13 +682,18 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
|
||||
ServiceController.Init(this, types);
|
||||
|
||||
var requestFilters = _appHost.GetExports<IRequestFilter>().ToList();
|
||||
foreach (var filter in requestFilters)
|
||||
var list = new List<Action<IRequest, IResponse, object>>();
|
||||
foreach (var filter in _appHost.GetExports<IRequestFilter>())
|
||||
{
|
||||
RequestFilters.Add(filter.Filter);
|
||||
list.Add(filter.Filter);
|
||||
}
|
||||
|
||||
ResponseFilters.Add(new ResponseFilter(_logger).FilterResponse);
|
||||
RequestFilters = list.ToArray();
|
||||
|
||||
ResponseFilters = new Action<IRequest, IResponse, object>[]
|
||||
{
|
||||
new ResponseFilter(_logger).FilterResponse
|
||||
};
|
||||
}
|
||||
|
||||
public RouteAttribute[] GetRouteAttributes(Type requestType)
|
||||
|
@ -819,10 +808,20 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public void StartServer(IEnumerable<string> urlPrefixes)
|
||||
public void StartServer(string[] urlPrefixes)
|
||||
{
|
||||
UrlPrefixes = urlPrefixes.ToList();
|
||||
StartListener();
|
||||
UrlPrefixes = urlPrefixes;
|
||||
|
||||
WebSocketSharpRequest.HandlerFactoryPath = GetHandlerPathIfAny(UrlPrefixes[0]);
|
||||
|
||||
_listener = GetListener();
|
||||
|
||||
_listener.WebSocketConnected = OnWebSocketConnected;
|
||||
_listener.WebSocketConnecting = OnWebSocketConnecting;
|
||||
_listener.ErrorHandler = ErrorHandler;
|
||||
_listener.RequestHandler = RequestHandler;
|
||||
|
||||
_listener.Start(UrlPrefixes);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +1,8 @@
|
|||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using MediaBrowser.Model.Services;
|
||||
using SocketHttpListener.Net;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
|
||||
namespace Emby.Server.Implementations.HttpServer
|
||||
{
|
||||
|
@ -30,7 +28,20 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
}
|
||||
else
|
||||
{
|
||||
var headerText = string.Join(", ", headers.Select(i => i.Name + "=" + i.Value).ToArray(headers.Count));
|
||||
var headerText = string.Empty;
|
||||
var index = 0;
|
||||
|
||||
foreach (var i in headers)
|
||||
{
|
||||
if (index > 0)
|
||||
{
|
||||
headerText += ", ";
|
||||
}
|
||||
|
||||
headerText += i.Name + "=" + i.Value;
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
logger.Info("HTTP {0} {1}. {2}", method, url, headerText);
|
||||
}
|
||||
|
@ -49,7 +60,8 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
var durationMs = duration.TotalMilliseconds;
|
||||
var logSuffix = durationMs >= 1000 && durationMs < 60000 ? "ms (slow)" : "ms";
|
||||
|
||||
var headerText = headers == null ? string.Empty : "Headers: " + string.Join(", ", headers.Where(i => i.Name.IndexOf("Access-", StringComparison.OrdinalIgnoreCase) == -1).Select(i => i.Name + "=" + i.Value).ToArray());
|
||||
//var headerText = headers == null ? string.Empty : "Headers: " + string.Join(", ", headers.Where(i => i.Name.IndexOf("Access-", StringComparison.OrdinalIgnoreCase) == -1).Select(i => i.Name + "=" + i.Value).ToArray());
|
||||
var headerText = string.Empty;
|
||||
logger.Info("HTTP Response {0} to {1}. Time: {2}{3}. {4} {5}", statusCode, endPoint, Convert.ToInt32(durationMs).ToString(CultureInfo.InvariantCulture), logSuffix, url, headerText);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ using MediaBrowser.Controller.Net;
|
|||
using MediaBrowser.Controller.Security;
|
||||
using MediaBrowser.Controller.Session;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Emby.Server.Implementations.HttpServer.Security
|
||||
|
@ -78,7 +77,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
|
|||
|
||||
if (!IsExemptFromRoles(auth, authAttribtues, info))
|
||||
{
|
||||
var roles = authAttribtues.GetRoles().ToList();
|
||||
var roles = authAttribtues.GetRoles();
|
||||
|
||||
ValidateRoles(roles, user);
|
||||
}
|
||||
|
@ -162,7 +161,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
|
|||
return false;
|
||||
}
|
||||
|
||||
private void ValidateRoles(List<string> roles, User user)
|
||||
private void ValidateRoles(string[] roles, User user)
|
||||
{
|
||||
if (roles.Contains("admin", StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
|
|
|
@ -3,8 +3,8 @@ using MediaBrowser.Controller.Net;
|
|||
using MediaBrowser.Controller.Security;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MediaBrowser.Model.Services;
|
||||
using System.Linq;
|
||||
|
||||
namespace Emby.Server.Implementations.HttpServer.Security
|
||||
{
|
||||
|
@ -90,7 +90,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
|
|||
AccessToken = token
|
||||
});
|
||||
|
||||
var tokenInfo = result.Items.FirstOrDefault();
|
||||
var tokenInfo = result.Items.Length > 0 ? result.Items[0] : null;
|
||||
|
||||
if (tokenInfo != null)
|
||||
{
|
||||
|
@ -161,7 +161,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
|
|||
// There should be at least to parts
|
||||
if (parts.Length != 2) return null;
|
||||
|
||||
var acceptedNames = new[] { "MediaBrowser", "Emby"};
|
||||
var acceptedNames = new[] { "MediaBrowser", "Emby" };
|
||||
|
||||
// It has to be a digest request
|
||||
if (!acceptedNames.Contains(parts[0] ?? string.Empty, StringComparer.OrdinalIgnoreCase))
|
||||
|
|
|
@ -112,7 +112,7 @@ namespace Emby.Server.Implementations.ServerManager
|
|||
/// <summary>
|
||||
/// Starts this instance.
|
||||
/// </summary>
|
||||
public void Start(IEnumerable<string> urlPrefixes)
|
||||
public void Start(string[] urlPrefixes)
|
||||
{
|
||||
ReloadHttpServer(urlPrefixes);
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ namespace Emby.Server.Implementations.ServerManager
|
|||
/// <summary>
|
||||
/// Restarts the Http Server, or starts it if not currently running
|
||||
/// </summary>
|
||||
private void ReloadHttpServer(IEnumerable<string> urlPrefixes)
|
||||
private void ReloadHttpServer(string[] urlPrefixes)
|
||||
{
|
||||
_logger.Info("Loading Http Server");
|
||||
|
||||
|
|
|
@ -24,19 +24,33 @@ namespace Emby.Server.Implementations.Services
|
|||
"POLL", "SUBSCRIBE", "UNSUBSCRIBE"
|
||||
});
|
||||
|
||||
public static IEnumerable<MethodInfo> GetActions(this Type serviceType)
|
||||
public static List<MethodInfo> GetActions(this Type serviceType)
|
||||
{
|
||||
foreach (var mi in serviceType.GetRuntimeMethods().Where(i => i.IsPublic && !i.IsStatic))
|
||||
var list = new List<MethodInfo>();
|
||||
|
||||
foreach (var mi in serviceType.GetRuntimeMethods())
|
||||
{
|
||||
if (!mi.IsPublic)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mi.IsStatic)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mi.GetParameters().Length != 1)
|
||||
continue;
|
||||
|
||||
var actionName = mi.Name;
|
||||
if (!AllVerbs.Contains(actionName, StringComparer.OrdinalIgnoreCase) && !string.Equals(actionName, ServiceMethod.AnyAction, StringComparison.OrdinalIgnoreCase))
|
||||
if (!AllVerbs.Contains(actionName, StringComparer.OrdinalIgnoreCase))
|
||||
continue;
|
||||
|
||||
yield return mi;
|
||||
list.Add(mi);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,8 +73,7 @@ namespace Emby.Server.Implementations.Services
|
|||
var actionName = request.Verb ?? "POST";
|
||||
|
||||
ServiceMethod actionContext;
|
||||
if (ServiceExecGeneral.execMap.TryGetValue(ServiceMethod.Key(serviceType, actionName, requestName), out actionContext)
|
||||
|| ServiceExecGeneral.execMap.TryGetValue(ServiceMethod.AnyKey(serviceType, requestName), out actionContext))
|
||||
if (ServiceExecGeneral.execMap.TryGetValue(ServiceMethod.Key(serviceType, actionName, requestName), out actionContext))
|
||||
{
|
||||
if (actionContext.RequestFilters != null)
|
||||
{
|
||||
|
|
|
@ -4,8 +4,6 @@ namespace Emby.Server.Implementations.Services
|
|||
{
|
||||
public class ServiceMethod
|
||||
{
|
||||
public const string AnyAction = "ANY";
|
||||
|
||||
public string Id { get; set; }
|
||||
|
||||
public ActionInvokerFn ServiceAction { get; set; }
|
||||
|
@ -15,10 +13,5 @@ namespace Emby.Server.Implementations.Services
|
|||
{
|
||||
return serviceType.FullName + " " + method.ToUpper() + " " + requestDtoName;
|
||||
}
|
||||
|
||||
public static string AnyKey(Type serviceType, string requestDtoName)
|
||||
{
|
||||
return Key(serviceType, AnyAction, requestDtoName);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Emby.Server.Implementations.Services
|
||||
|
@ -64,11 +63,16 @@ namespace Emby.Server.Implementations.Services
|
|||
if (instance == null)
|
||||
instance = _CreateInstanceFn(type);
|
||||
|
||||
foreach (var pair in keyValuePairs.Where(x => !string.IsNullOrEmpty(x.Value)))
|
||||
foreach (var pair in keyValuePairs)
|
||||
{
|
||||
propertyName = pair.Key;
|
||||
propertyTextValue = pair.Value;
|
||||
|
||||
if (string.IsNullOrEmpty(propertyTextValue))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!propertySetterMap.TryGetValue(propertyName, out propertySerializerEntry))
|
||||
{
|
||||
if (propertyName == "v")
|
||||
|
@ -115,7 +119,7 @@ namespace Emby.Server.Implementations.Services
|
|||
{
|
||||
public static Action<object, object> GetSetPropertyMethod(Type type, PropertyInfo propertyInfo)
|
||||
{
|
||||
if (!propertyInfo.CanWrite || propertyInfo.GetIndexParameters().Any()) return null;
|
||||
if (!propertyInfo.CanWrite || propertyInfo.GetIndexParameters().Length > 0) return null;
|
||||
|
||||
var setMethodInfo = propertyInfo.SetMethod;
|
||||
return (instance, value) => setMethodInfo.Invoke(instance, new[] { value });
|
||||
|
|
|
@ -70,24 +70,27 @@ namespace MediaBrowser.Api.Dlna
|
|||
public Stream RequestStream { get; set; }
|
||||
}
|
||||
|
||||
[Route("/Dlna/{UuId}/mediareceiverregistrar/events", Summary = "Processes an event subscription request")]
|
||||
[Route("/Dlna/{UuId}/mediareceiverregistrar/events", "SUBSCRIBE", Summary = "Processes an event subscription request")]
|
||||
[Route("/Dlna/{UuId}/mediareceiverregistrar/events", "UNSUBSCRIBE", Summary = "Processes an event subscription request")]
|
||||
public class ProcessMediaReceiverRegistrarEventRequest
|
||||
{
|
||||
[ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "SUBSCRIBE,POST")]
|
||||
[ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "SUBSCRIBE,UNSUBSCRIBE")]
|
||||
public string UuId { get; set; }
|
||||
}
|
||||
|
||||
[Route("/Dlna/{UuId}/contentdirectory/events", Summary = "Processes an event subscription request")]
|
||||
[Route("/Dlna/{UuId}/contentdirectory/events", "SUBSCRIBE", Summary = "Processes an event subscription request")]
|
||||
[Route("/Dlna/{UuId}/contentdirectory/events", "UNSUBSCRIBE", Summary = "Processes an event subscription request")]
|
||||
public class ProcessContentDirectoryEventRequest
|
||||
{
|
||||
[ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "SUBSCRIBE,POST")]
|
||||
[ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "SUBSCRIBE,UNSUBSCRIBE")]
|
||||
public string UuId { get; set; }
|
||||
}
|
||||
|
||||
[Route("/Dlna/{UuId}/connectionmanager/events", Summary = "Processes an event subscription request")]
|
||||
[Route("/Dlna/{UuId}/connectionmanager/events", "SUBSCRIBE", Summary = "Processes an event subscription request")]
|
||||
[Route("/Dlna/{UuId}/connectionmanager/events", "UNSUBSCRIBE", Summary = "Processes an event subscription request")]
|
||||
public class ProcessConnectionManagerEventRequest
|
||||
{
|
||||
[ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "SUBSCRIBE,POST")]
|
||||
[ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "SUBSCRIBE,UNSUBSCRIBE")]
|
||||
public string UuId { get; set; }
|
||||
}
|
||||
|
||||
|
@ -200,17 +203,32 @@ namespace MediaBrowser.Api.Dlna
|
|||
}
|
||||
}
|
||||
|
||||
public object Any(ProcessContentDirectoryEventRequest request)
|
||||
public object Subscribe(ProcessContentDirectoryEventRequest request)
|
||||
{
|
||||
return ProcessEventRequest(_contentDirectory);
|
||||
}
|
||||
|
||||
public object Any(ProcessConnectionManagerEventRequest request)
|
||||
public object Subscribe(ProcessConnectionManagerEventRequest request)
|
||||
{
|
||||
return ProcessEventRequest(_connectionManager);
|
||||
}
|
||||
|
||||
public object Any(ProcessMediaReceiverRegistrarEventRequest request)
|
||||
public object Subscribe(ProcessMediaReceiverRegistrarEventRequest request)
|
||||
{
|
||||
return ProcessEventRequest(_mediaReceiverRegistrar);
|
||||
}
|
||||
|
||||
public object Unsubscribe(ProcessContentDirectoryEventRequest request)
|
||||
{
|
||||
return ProcessEventRequest(_contentDirectory);
|
||||
}
|
||||
|
||||
public object Unsubscribe(ProcessConnectionManagerEventRequest request)
|
||||
{
|
||||
return ProcessEventRequest(_connectionManager);
|
||||
}
|
||||
|
||||
public object Unsubscribe(ProcessMediaReceiverRegistrarEventRequest request)
|
||||
{
|
||||
return ProcessEventRequest(_mediaReceiverRegistrar);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MediaBrowser.Model.Services;
|
||||
|
||||
namespace MediaBrowser.Controller.Net
|
||||
|
@ -50,7 +49,7 @@ namespace MediaBrowser.Controller.Net
|
|||
get { return 0; }
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetRoles()
|
||||
public string[] GetRoles()
|
||||
{
|
||||
return (Roles ?? string.Empty).Split(new []{ ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
@ -61,6 +60,6 @@ namespace MediaBrowser.Controller.Net
|
|||
bool EscapeParentalControl { get; }
|
||||
bool AllowBeforeStartupWizard { get; }
|
||||
|
||||
IEnumerable<string> GetRoles();
|
||||
string[] GetRoles();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,13 +13,13 @@ namespace MediaBrowser.Controller.Net
|
|||
/// Gets the URL prefix.
|
||||
/// </summary>
|
||||
/// <value>The URL prefix.</value>
|
||||
IEnumerable<string> UrlPrefixes { get; }
|
||||
string[] UrlPrefixes { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Starts the specified server name.
|
||||
/// </summary>
|
||||
/// <param name="urlPrefixes">The URL prefixes.</param>
|
||||
void StartServer(IEnumerable<string> urlPrefixes);
|
||||
void StartServer(string[] urlPrefixes);
|
||||
|
||||
/// <summary>
|
||||
/// Stops this instance.
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace MediaBrowser.Controller.Net
|
|||
/// Starts this instance.
|
||||
/// </summary>
|
||||
/// <param name="urlPrefixes">The URL prefixes.</param>
|
||||
void Start(IEnumerable<string> urlPrefixes);
|
||||
void Start(string[] urlPrefixes);
|
||||
|
||||
/// <summary>
|
||||
/// Sends a message to all clients currently connected via a web socket
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
using System.Reflection;
|
||||
|
||||
[assembly: AssemblyVersion("3.2.30.2")]
|
||||
[assembly: AssemblyVersion("3.2.30.3")]
|
||||
|
|
Loading…
Reference in New Issue
Block a user