imported signalr 1.1.3 into NzbDrone.

This commit is contained in:
kayone
2013-11-21 21:26:57 -08:00
parent 891443e05d
commit 0e623e7ce4
236 changed files with 20490 additions and 35 deletions
@@ -0,0 +1,96 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNet.SignalR.Json;
using Newtonsoft.Json.Linq;
namespace Microsoft.AspNet.SignalR.Hubs
{
public class DefaultHubManager : IHubManager
{
private readonly IEnumerable<IMethodDescriptorProvider> _methodProviders;
private readonly IHubActivator _activator;
private readonly IEnumerable<IHubDescriptorProvider> _hubProviders;
public DefaultHubManager(IDependencyResolver resolver)
{
_hubProviders = resolver.ResolveAll<IHubDescriptorProvider>();
_methodProviders = resolver.ResolveAll<IMethodDescriptorProvider>();
_activator = resolver.Resolve<IHubActivator>();
}
public HubDescriptor GetHub(string hubName)
{
HubDescriptor descriptor = null;
if (_hubProviders.FirstOrDefault(p => p.TryGetHub(hubName, out descriptor)) != null)
{
return descriptor;
}
return null;
}
public IEnumerable<HubDescriptor> GetHubs(Func<HubDescriptor, bool> predicate)
{
var hubs = _hubProviders.SelectMany(p => p.GetHubs());
if (predicate != null)
{
return hubs.Where(predicate);
}
return hubs;
}
public MethodDescriptor GetHubMethod(string hubName, string method, IList<IJsonValue> parameters)
{
HubDescriptor hub = GetHub(hubName);
if (hub == null)
{
return null;
}
MethodDescriptor descriptor = null;
if (_methodProviders.FirstOrDefault(p => p.TryGetMethod(hub, method, out descriptor, parameters)) != null)
{
return descriptor;
}
return null;
}
public IEnumerable<MethodDescriptor> GetHubMethods(string hubName, Func<MethodDescriptor, bool> predicate)
{
HubDescriptor hub = GetHub(hubName);
if (hub == null)
{
return null;
}
var methods = _methodProviders.SelectMany(p => p.GetMethods(hub));
if (predicate != null)
{
return methods.Where(predicate);
}
return methods;
}
public IHub ResolveHub(string hubName)
{
HubDescriptor hub = GetHub(hubName);
return hub == null ? null : _activator.Create(hub);
}
public IEnumerable<IHub> ResolveHubs()
{
return GetHubs(predicate: null).Select(hub => _activator.Create(hub));
}
}
}
@@ -0,0 +1,54 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNet.SignalR.Json;
namespace Microsoft.AspNet.SignalR.Hubs
{
public class DefaultParameterResolver : IParameterResolver
{
/// <summary>
/// Resolves a parameter value based on the provided object.
/// </summary>
/// <param name="descriptor">Parameter descriptor.</param>
/// <param name="value">Value to resolve the parameter value from.</param>
/// <returns>The parameter value.</returns>
public virtual object ResolveParameter(ParameterDescriptor descriptor, IJsonValue value)
{
if (descriptor == null)
{
throw new ArgumentNullException("descriptor");
}
if (value == null)
{
throw new ArgumentNullException("value");
}
if (value.GetType() == descriptor.ParameterType)
{
return value;
}
return value.ConvertTo(descriptor.ParameterType);
}
/// <summary>
/// Resolves method parameter values based on provided objects.
/// </summary>
/// <param name="method">Method descriptor.</param>
/// <param name="values">List of values to resolve parameter values from.</param>
/// <returns>Array of parameter values.</returns>
public virtual IList<object> ResolveMethodParameters(MethodDescriptor method, IList<IJsonValue> values)
{
if (method == null)
{
throw new ArgumentNullException("method");
}
return method.Parameters.Zip(values, ResolveParameter).ToArray();
}
}
}
@@ -0,0 +1,17 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.
namespace Microsoft.AspNet.SignalR.Hubs
{
public abstract class Descriptor
{
/// <summary>
/// Name of Descriptor.
/// </summary>
public virtual string Name { get; set; }
/// <summary>
/// Flags whether the name was specified.
/// </summary>
public virtual bool NameSpecified { get; set; }
}
}
@@ -0,0 +1,22 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.
using System;
namespace Microsoft.AspNet.SignalR.Hubs
{
/// <summary>
/// Holds information about a single hub.
/// </summary>
public class HubDescriptor : Descriptor
{
/// <summary>
/// Hub type.
/// </summary>
public virtual Type HubType { get; set; }
public string CreateQualifiedName(string unqualifiedName)
{
return Name + "." + unqualifiedName;
}
}
}
@@ -0,0 +1,42 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
namespace Microsoft.AspNet.SignalR.Hubs
{
/// <summary>
/// Holds information about a single hub method.
/// </summary>
public class MethodDescriptor : Descriptor
{
/// <summary>
/// The return type of this method.
/// </summary>
public virtual Type ReturnType { get; set; }
/// <summary>
/// Hub descriptor object, target to this method.
/// </summary>
public virtual HubDescriptor Hub { get; set; }
/// <summary>
/// Available method parameters.
/// </summary>
[SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly", Justification = "This is supposed to be mutable")]
public virtual IList<ParameterDescriptor> Parameters { get; set; }
/// <summary>
/// Method invocation delegate.
/// Takes a target hub and an array of invocation arguments as it's arguments.
/// </summary>
public virtual Func<IHub, object[], object> Invoker { get; set; }
/// <summary>
/// Attributes attached to this method.
/// </summary>
public virtual IEnumerable<Attribute> Attributes { get; set; }
}
}
@@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Globalization;
namespace Microsoft.AspNet.SignalR.Hubs
{
public class NullMethodDescriptor : MethodDescriptor
{
private static readonly IEnumerable<Attribute> _attributes = new List<Attribute>();
private static readonly IList<ParameterDescriptor> _parameters = new List<ParameterDescriptor>();
private string _methodName;
public NullMethodDescriptor(string methodName)
{
_methodName = methodName;
}
public override Func<IHub, object[], object> Invoker
{
get
{
return (emptyHub, emptyParameters) =>
{
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, Resources.Error_MethodCouldNotBeResolved, _methodName));
};
}
}
public override IList<ParameterDescriptor> Parameters
{
get { return _parameters; }
}
public override IEnumerable<Attribute> Attributes
{
get { return _attributes; }
}
}
}
@@ -0,0 +1,23 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.
using System;
namespace Microsoft.AspNet.SignalR.Hubs
{
/// <summary>
/// Holds information about a single hub method parameter.
/// </summary>
public class ParameterDescriptor
{
/// <summary>
/// Parameter name.
/// </summary>
public virtual string Name { get; set; }
/// <summary>
/// Parameter type.
/// </summary>
public virtual Type ParameterType { get; set; }
}
}
@@ -0,0 +1,79 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
namespace Microsoft.AspNet.SignalR.Hubs
{
internal class HubMethodDispatcher
{
private HubMethodExecutor _executor;
public HubMethodDispatcher(MethodInfo methodInfo)
{
_executor = GetExecutor(methodInfo);
MethodInfo = methodInfo;
}
private delegate object HubMethodExecutor(IHub hub, object[] parameters);
private delegate void VoidHubMethodExecutor(IHub hub, object[] parameters);
public MethodInfo MethodInfo { get; private set; }
public object Execute(IHub hub, object[] parameters)
{
return _executor(hub, parameters);
}
private static HubMethodExecutor GetExecutor(MethodInfo methodInfo)
{
// Parameters to executor
ParameterExpression hubParameter = Expression.Parameter(typeof(IHub), "hub");
ParameterExpression parametersParameter = Expression.Parameter(typeof(object[]), "parameters");
// Build parameter list
List<Expression> parameters = new List<Expression>();
ParameterInfo[] paramInfos = methodInfo.GetParameters();
for (int i = 0; i < paramInfos.Length; i++)
{
ParameterInfo paramInfo = paramInfos[i];
BinaryExpression valueObj = Expression.ArrayIndex(parametersParameter, Expression.Constant(i));
UnaryExpression valueCast = Expression.Convert(valueObj, paramInfo.ParameterType);
// valueCast is "(Ti) parameters[i]"
parameters.Add(valueCast);
}
// Call method
UnaryExpression instanceCast = (!methodInfo.IsStatic) ? Expression.Convert(hubParameter, methodInfo.ReflectedType) : null;
MethodCallExpression methodCall = Expression.Call(instanceCast, methodInfo, parameters);
// methodCall is "((TController) hub) method((T0) parameters[0], (T1) parameters[1], ...)"
// Create function
if (methodCall.Type == typeof(void))
{
Expression<VoidHubMethodExecutor> lambda = Expression.Lambda<VoidHubMethodExecutor>(methodCall, hubParameter, parametersParameter);
VoidHubMethodExecutor voidExecutor = lambda.Compile();
return WrapVoidAction(voidExecutor);
}
else
{
// must coerce methodCall to match HubMethodExecutor signature
UnaryExpression castMethodCall = Expression.Convert(methodCall, typeof(object));
Expression<HubMethodExecutor> lambda = Expression.Lambda<HubMethodExecutor>(castMethodCall, hubParameter, parametersParameter);
return lambda.Compile();
}
}
private static HubMethodExecutor WrapVoidAction(VoidHubMethodExecutor executor)
{
return delegate(IHub hub, object[] parameters)
{
executor(hub, parameters);
return null;
};
}
}
}
@@ -0,0 +1,28 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
namespace Microsoft.AspNet.SignalR.Hubs
{
/// <summary>
/// Describes hub descriptor provider, which provides information about available hubs.
/// </summary>
public interface IHubDescriptorProvider
{
/// <summary>
/// Retrieve all avaiable hubs.
/// </summary>
/// <returns>Collection of hub descriptors.</returns>
[SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "This call might be expensive")]
IList<HubDescriptor> GetHubs();
/// <summary>
/// Tries to retrieve hub with a given name.
/// </summary>
/// <param name="hubName">Name of the hub.</param>
/// <param name="descriptor">Retrieved descriptor object.</param>
/// <returns>True, if hub has been found</returns>
bool TryGetHub(string hubName, out HubDescriptor descriptor);
}
}
@@ -0,0 +1,58 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.
using System;
using System.Collections.Generic;
using Microsoft.AspNet.SignalR.Json;
using Newtonsoft.Json.Linq;
namespace Microsoft.AspNet.SignalR.Hubs
{
/// <summary>
/// Describes a hub manager - main point in the whole hub and method lookup process.
/// </summary>
public interface IHubManager
{
/// <summary>
/// Retrieves a single hub descriptor.
/// </summary>
/// <param name="hubName">Name of the hub.</param>
/// <returns>Hub descriptor, if found. Null, otherwise.</returns>
HubDescriptor GetHub(string hubName);
/// <summary>
/// Retrieves all available hubs matching the given predicate.
/// </summary>
/// <returns>List of hub descriptors.</returns>
IEnumerable<HubDescriptor> GetHubs(Func<HubDescriptor, bool> predicate);
/// <summary>
/// Resolves a given hub name to a concrete object.
/// </summary>
/// <param name="hubName">Name of the hub.</param>
/// <returns>Hub implementation instance, if found. Null otherwise.</returns>
IHub ResolveHub(string hubName);
/// <summary>
/// Resolves all available hubs to their concrete objects.
/// </summary>
/// <returns>List of hub instances.</returns>
IEnumerable<IHub> ResolveHubs();
/// <summary>
/// Retrieves a method with a given name on a given hub.
/// </summary>
/// <param name="hubName">Name of the hub.</param>
/// <param name="method">Name of the method to find.</param>
/// <param name="parameters">Method parameters to match.</param>
/// <returns>Descriptor of the method, if found. Null otherwise.</returns>
MethodDescriptor GetHubMethod(string hubName, string method, IList<IJsonValue> parameters);
/// <summary>
/// Gets all methods available to call on a given hub.
/// </summary>
/// <param name="hubName">Name of the hub,</param>
/// <param name="predicate">Optional predicate for filtering results.</param>
/// <returns>List of available methods.</returns>
IEnumerable<MethodDescriptor> GetHubMethods(string hubName, Func<MethodDescriptor, bool> predicate);
}
}
@@ -0,0 +1,33 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Microsoft.AspNet.SignalR.Json;
using Newtonsoft.Json.Linq;
namespace Microsoft.AspNet.SignalR.Hubs
{
/// <summary>
/// Describes a hub method provider that builds a collection of available methods on a given hub.
/// </summary>
public interface IMethodDescriptorProvider
{
/// <summary>
/// Retrieve all methods on a given hub.
/// </summary>
/// <param name="hub">Hub descriptor object.</param>
/// <returns>Available methods.</returns>
IEnumerable<MethodDescriptor> GetMethods(HubDescriptor hub);
/// <summary>
/// Tries to retrieve a method.
/// </summary>
/// <param name="hub">Hub descriptor object</param>
/// <param name="method">Name of the method.</param>
/// <param name="descriptor">Descriptor of the method, if found. Null otherwise.</param>
/// <param name="parameters">Method parameters to match.</param>
/// <returns>True, if a method has been found.</returns>
[SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "2#", Justification = "This is a well known pattern for efficient lookup")]
bool TryGetMethod(HubDescriptor hub, string method, out MethodDescriptor descriptor, IList<IJsonValue> parameters);
}
}
@@ -0,0 +1,22 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.
using System.Collections.Generic;
using Microsoft.AspNet.SignalR.Json;
using Newtonsoft.Json.Linq;
namespace Microsoft.AspNet.SignalR.Hubs
{
/// <summary>
/// Describes a parameter resolver for resolving parameter-matching values based on provided information.
/// </summary>
public interface IParameterResolver
{
/// <summary>
/// Resolves method parameter values based on provided objects.
/// </summary>
/// <param name="method">Method descriptor.</param>
/// <param name="values">List of values to resolve parameter values from.</param>
/// <returns>Array of parameter values.</returns>
IList<object> ResolveMethodParameters(MethodDescriptor method, IList<IJsonValue> values);
}
}
@@ -0,0 +1,87 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Microsoft.AspNet.SignalR.Hubs
{
public class ReflectedHubDescriptorProvider : IHubDescriptorProvider
{
private readonly Lazy<IDictionary<string, HubDescriptor>> _hubs;
private readonly Lazy<IAssemblyLocator> _locator;
public ReflectedHubDescriptorProvider(IDependencyResolver resolver)
{
_locator = new Lazy<IAssemblyLocator>(resolver.Resolve<IAssemblyLocator>);
_hubs = new Lazy<IDictionary<string, HubDescriptor>>(BuildHubsCache);
}
public IList<HubDescriptor> GetHubs()
{
return _hubs.Value
.Select(kv => kv.Value)
.Distinct()
.ToList();
}
public bool TryGetHub(string hubName, out HubDescriptor descriptor)
{
return _hubs.Value.TryGetValue(hubName, out descriptor);
}
protected IDictionary<string, HubDescriptor> BuildHubsCache()
{
// Getting all IHub-implementing types that apply
var types = _locator.Value.GetAssemblies()
.SelectMany(GetTypesSafe)
.Where(IsHubType);
// Building cache entries for each descriptor
// Each descriptor is stored in dictionary under a key
// that is it's name or the name provided by an attribute
var cacheEntries = types
.Select(type => new HubDescriptor
{
NameSpecified = (type.GetHubAttributeName() != null),
Name = type.GetHubName(),
HubType = type
})
.ToDictionary(hub => hub.Name,
hub => hub,
StringComparer.OrdinalIgnoreCase);
return cacheEntries;
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "If we throw then it's not a hub type")]
private static bool IsHubType(Type type)
{
try
{
return typeof(IHub).IsAssignableFrom(type) &&
!type.IsAbstract &&
(type.Attributes.HasFlag(TypeAttributes.Public) ||
type.Attributes.HasFlag(TypeAttributes.NestedPublic));
}
catch
{
return false;
}
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "If we throw then we have an empty type")]
private static IEnumerable<Type> GetTypesSafe(Assembly a)
{
try
{
return a.GetTypes();
}
catch
{
return Enumerable.Empty<Type>();
}
}
}
}
@@ -0,0 +1,150 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using Microsoft.AspNet.SignalR.Json;
namespace Microsoft.AspNet.SignalR.Hubs
{
public class ReflectedMethodDescriptorProvider : IMethodDescriptorProvider
{
private readonly ConcurrentDictionary<string, IDictionary<string, IEnumerable<MethodDescriptor>>> _methods;
private readonly ConcurrentDictionary<string, MethodDescriptor> _executableMethods;
public ReflectedMethodDescriptorProvider()
{
_methods = new ConcurrentDictionary<string, IDictionary<string, IEnumerable<MethodDescriptor>>>(StringComparer.OrdinalIgnoreCase);
_executableMethods = new ConcurrentDictionary<string, MethodDescriptor>(StringComparer.OrdinalIgnoreCase);
}
public IEnumerable<MethodDescriptor> GetMethods(HubDescriptor hub)
{
return FetchMethodsFor(hub)
.SelectMany(kv => kv.Value)
.ToList();
}
/// <summary>
/// Retrieves an existing dictionary of all available methods for a given hub from cache.
/// If cache entry does not exist - it is created automatically by BuildMethodCacheFor.
/// </summary>
/// <param name="hub"></param>
/// <returns></returns>
private IDictionary<string, IEnumerable<MethodDescriptor>> FetchMethodsFor(HubDescriptor hub)
{
return _methods.GetOrAdd(
hub.Name,
key => BuildMethodCacheFor(hub));
}
/// <summary>
/// Builds a dictionary of all possible methods on a given hub.
/// Single entry contains a collection of available overloads for a given method name (key).
/// This dictionary is being cached afterwards.
/// </summary>
/// <param name="hub">Hub to build cache for</param>
/// <returns>Dictionary of available methods</returns>
private static IDictionary<string, IEnumerable<MethodDescriptor>> BuildMethodCacheFor(HubDescriptor hub)
{
return ReflectionHelper.GetExportedHubMethods(hub.HubType)
.GroupBy(GetMethodName, StringComparer.OrdinalIgnoreCase)
.ToDictionary(group => group.Key,
group => group.Select(oload =>
new MethodDescriptor
{
ReturnType = oload.ReturnType,
Name = group.Key,
NameSpecified = (GetMethodAttributeName(oload) != null),
Invoker = new HubMethodDispatcher(oload).Execute,
Hub = hub,
Attributes = oload.GetCustomAttributes(typeof(Attribute), inherit: true).Cast<Attribute>(),
Parameters = oload.GetParameters()
.Select(p => new ParameterDescriptor
{
Name = p.Name,
ParameterType = p.ParameterType,
})
.ToList()
}),
StringComparer.OrdinalIgnoreCase);
}
/// <summary>
/// Searches the specified <paramref name="hub">Hub</paramref> for the specified <paramref name="method"/>.
/// </summary>
/// <remarks>
/// In the case that there are multiple overloads of the specified <paramref name="method"/>, the <paramref name="parameters">parameter set</paramref> helps determine exactly which instance of the overload should be resolved.
/// If there are multiple overloads found with the same number of matching parameters, none of the methods will be returned because it is not possible to determine which overload of the method was intended to be resolved.
/// </remarks>
/// <param name="hub">Hub to search for the specified <paramref name="method"/> on.</param>
/// <param name="method">The method name to search for.</param>
/// <param name="descriptor">If successful, the <see cref="MethodDescriptor"/> that was resolved.</param>
/// <param name="parameters">The set of parameters that will be used to help locate a specific overload of the specified <paramref name="method"/>.</param>
/// <returns>True if the method matching the name/parameter set is found on the hub, otherwise false.</returns>
public bool TryGetMethod(HubDescriptor hub, string method, out MethodDescriptor descriptor, IList<IJsonValue> parameters)
{
string hubMethodKey = BuildHubExecutableMethodCacheKey(hub, method, parameters);
if (!_executableMethods.TryGetValue(hubMethodKey, out descriptor))
{
IEnumerable<MethodDescriptor> overloads;
if (FetchMethodsFor(hub).TryGetValue(method, out overloads))
{
var matches = overloads.Where(o => o.Matches(parameters)).ToList();
// If only one match is found, that is the "executable" version, otherwise none of the methods can be returned because we don't know which one was actually being targeted
descriptor = matches.Count == 1 ? matches[0] : null;
}
else
{
descriptor = null;
}
// If an executable method was found, cache it for future lookups (NOTE: we don't cache null instances because it could be a surface area for DoS attack by supplying random method names to flood the cache)
if (descriptor != null)
{
_executableMethods.TryAdd(hubMethodKey, descriptor);
}
}
return descriptor != null;
}
private static string BuildHubExecutableMethodCacheKey(HubDescriptor hub, string method, IList<IJsonValue> parameters)
{
string normalizedParameterCountKeyPart;
if (parameters != null)
{
normalizedParameterCountKeyPart = parameters.Count.ToString(CultureInfo.InvariantCulture);
}
else
{
// NOTE: we normalize a null parameter array to be the same as an empty (i.e. Length == 0) parameter array
normalizedParameterCountKeyPart = "0";
}
// NOTE: we always normalize to all uppercase since method names are case insensitive and could theoretically come in diff. variations per call
string normalizedMethodName = method.ToUpperInvariant();
string methodKey = hub.Name + "::" + normalizedMethodName + "(" + normalizedParameterCountKeyPart + ")";
return methodKey;
}
private static string GetMethodName(MethodInfo method)
{
return GetMethodAttributeName(method) ?? method.Name;
}
private static string GetMethodAttributeName(MethodInfo method)
{
return ReflectionHelper.GetAttributeValue<HubMethodNameAttribute, string>(method, a => a.MethodName);
}
}
}