123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473 |
- using JsonRPC4.Common;
- using JsonRPC4.Router.Abstractions;
- using JsonRPC4.Router.Utilities;
- using Microsoft.Extensions.Logging;
- using Microsoft.Extensions.Options;
- using System;
- using System.Buffers;
- using System.Collections.Concurrent;
- using System.Collections.Generic;
- using System.Linq;
- using System.Reflection;
- using System.Threading.Tasks;
- namespace JsonRPC4.Router.Defaults
- {
- public class DefaultRequestMatcher : IRpcRequestMatcher
- {
- private class CompiledMethodInfo
- {
- public MethodInfo MethodInfo
- {
- get;
- }
- public CompiledParameterInfo[] Parameters
- {
- get;
- }
- public CompiledMethodInfo(MethodInfo methodInfo, CompiledParameterInfo[] parameters)
- {
- MethodInfo = methodInfo;
- Parameters = parameters;
- }
- }
- private class CompiledParameterInfo
- {
- public string Name
- {
- get;
- }
- public RpcParameterType Type
- {
- get;
- }
- public Type RawType
- {
- get;
- }
- public bool IsOptional
- {
- get;
- }
- public CompiledParameterInfo(string name, RpcParameterType type, Type rawType, bool isOptional)
- {
- Name = name;
- Type = type;
- RawType = rawType;
- IsOptional = isOptional;
- }
- }
- private static ConcurrentDictionary<MethodInfo, CompiledMethodInfo> compiledMethodCache
- {
- get;
- } = new ConcurrentDictionary<MethodInfo, CompiledMethodInfo>();
- private static ConcurrentDictionary<string, RpcMethodInfo[]> requestToMethodCache
- {
- get;
- } = new ConcurrentDictionary<string, RpcMethodInfo[]>();
- private ILogger<DefaultRequestMatcher> logger
- {
- get;
- }
- private IOptions<RpcServerConfiguration> serverConfig
- {
- get;
- }
- public DefaultRequestMatcher(ILogger<DefaultRequestMatcher> logger, IOptions<RpcServerConfiguration> serverConfig)
- {
- this.logger = logger;
- this.serverConfig = serverConfig;
- }
- public RpcMethodInfo GetMatchingMethod(RpcRequest request, IReadOnlyList<MethodInfo> methods)
- {
- //IL_0041: Unknown result type (might be due to invalid IL or missing references)
- //IL_0046: Unknown result type (might be due to invalid IL or missing references)
- //IL_0051: Unknown result type (might be due to invalid IL or missing references)
- //IL_0056: Unknown result type (might be due to invalid IL or missing references)
- //IL_0098: Unknown result type (might be due to invalid IL or missing references)
- //IL_0099: Unknown result type (might be due to invalid IL or missing references)
- if (request == null)
- {
- throw new ArgumentNullException("request");
- }
- logger.AttemptingToMatchMethod(request.Method);
- CompiledMethodInfo[] array = ArrayPool<CompiledMethodInfo>.Shared.Rent(methods.Count);
- Span<RpcMethodInfo> val;
- try
- {
- FillCompiledMethodInfos(methods, array);
- val = FilterAndBuildMethodInfoByRequest(MemoryExtensions.AsSpan<CompiledMethodInfo>(array, 0, methods.Count), request);
- }
- finally
- {
- ArrayPool<CompiledMethodInfo>.Shared.Return(array, true);
- }
- if (val.Length == 1)
- {
- logger.RequestMatchedMethod();
- return val[0];
- }
- string message;
- if (val.Length > 1)
- {
- List<string> list = new List<string>();
- Span<RpcMethodInfo> val2 = val;
- for (int i = 0; i < val2.Length; i++)
- {
- RpcMethodInfo rpcMethodInfo = val2[i];
- List<string> list2 = new List<string>();
- ParameterInfo[] parameters = rpcMethodInfo.Method.GetParameters();
- foreach (ParameterInfo parameterInfo in parameters)
- {
- string text = parameterInfo.Name + ": " + parameterInfo.ParameterType.Name;
- if (parameterInfo.IsOptional)
- {
- text += "(Optional)";
- }
- list2.Add(text);
- }
- string text2 = string.Join(", ", list2);
- list.Add("{Name: '" + rpcMethodInfo.Method.Name + "', Parameters: [" + text2 + "]}");
- }
- message = "More than one method matched the rpc request. Unable to invoke due to ambiguity. Methods that matched the same name: " + string.Join(", ", list);
- }
- else
- {
- logger.MethodsInRoute(methods);
- message = "No methods matched request.";
- }
- throw new RpcException(RpcErrorCode.MethodNotFound, message);
- }
- private void FillCompiledMethodInfos(IReadOnlyList<MethodInfo> methods, CompiledMethodInfo[] compiledMethods)
- {
- for (int i = 0; i < methods.Count; i++)
- {
- MethodInfo methodInfo = methods[i];
- if (!compiledMethodCache.TryGetValue(methodInfo, out CompiledMethodInfo value))
- {
- CompiledParameterInfo[] parameters = methodInfo.GetParameters().Select(ExtractParam).ToArray();
- value = new CompiledMethodInfo(methodInfo, parameters);
- }
- compiledMethods[i] = value;
- }
- CompiledParameterInfo ExtractParam(ParameterInfo parameterInfo)
- {
- Type type = parameterInfo.ParameterType;
- if (type.IsGenericType)
- {
- Type underlyingType = Nullable.GetUnderlyingType(type);
- if (underlyingType != null)
- {
- type = underlyingType;
- }
- }
- return new CompiledParameterInfo(type: (type == typeof(short) || type == typeof(ushort) || type == typeof(int) || type == typeof(uint) || type == typeof(long) || type == typeof(ulong) || type == typeof(float) || type == typeof(double) || type == typeof(decimal)) ? RpcParameterType.Number : ((!(type == typeof(string))) ? RpcParameterType.Object : RpcParameterType.String), name: parameterInfo.Name, rawType: parameterInfo.ParameterType, isOptional: parameterInfo.IsOptional);
- }
- }
- private RpcMethodInfo[] FilterAndBuildMethodInfoByRequest(ReadOnlySpan<CompiledMethodInfo> methods, RpcRequest request)
- {
- int num = 0;
- int num2 = 200;
- int num3 = request.Method.Length;
- if (request.Parameters != null)
- {
- num3 += 3 + num2;
- }
- char[] array = ArrayPool<char>.Shared.Rent(num3);
- RpcMethodInfo[] result;
- try
- {
- for (int i = 0; i < request.Method.Length; i++)
- {
- array[num++] = request.Method[i];
- }
- if (request.Parameters != null)
- {
- array[num++] = ' ';
- array[num++] = (request.Parameters.IsDictionary ? 'd' : 'a');
- array[num++] = ' ';
- if (request.Parameters.IsDictionary)
- {
- using (Dictionary<string, IRpcParameter>.Enumerator enumerator = request.Parameters.AsDictionary.GetEnumerator())
- {
- while (enumerator.MoveNext())
- {
- KeyValuePair<string, IRpcParameter> keyValuePair = enumerator.Current;
- if (num + keyValuePair.Key.Length + 1 >= keyValuePair.Key.Length)
- {
- ArrayPool<char>.Shared.Return(array, false);
- array = ArrayPool<char>.Shared.Rent(array.Length + 30);
- }
- array[num++] = ' ';
- for (int j = 0; j < keyValuePair.Key.Length; j++)
- {
- array[num++] = keyValuePair.Key[j];
- }
- }
- goto IL_1E3;
- }
- }
- List<IRpcParameter> asList = request.Parameters.AsList;
- for (int k = 0; k < asList.Count; k++)
- {
- char c;
- switch (asList[k].Type)
- {
- case RpcParameterType.Null:
- c = '-';
- break;
- case RpcParameterType.Number:
- c = 'n';
- break;
- case RpcParameterType.String:
- c = 's';
- break;
- case RpcParameterType.Object:
- c = 'o';
- break;
- default:
- throw new InvalidOperationException(string.Format("Unimplemented parameter type '{0}'", asList[k].Type));
- }
- array[num++] = c;
- }
- }
- IL_1E3:
- string text = new string(array, 0, num);
- RpcMethodInfo[] array2;
- if (DefaultRequestMatcher.requestToMethodCache.TryGetValue(text, out array2))
- {
- result = array2;
- }
- else
- {
- DefaultRequestMatcher.CompiledMethodInfo[] array3 = ArrayPool<DefaultRequestMatcher.CompiledMethodInfo>.Shared.Rent(methods.Length);
- try
- {
- int num4 = 0;
- for (int l = 0; l < methods.Length; l++)
- {
- DefaultRequestMatcher.CompiledMethodInfo compiledMethodInfo = methods[l];
- if (RpcUtil.NamesMatch(MemoryExtensions.AsSpan(compiledMethodInfo.MethodInfo.Name), MemoryExtensions.AsSpan(request.Method)))
- {
- array3[num4++] = compiledMethodInfo;
- }
- }
- Span<RpcMethodInfo> span;
- if (num4 < 1)
- {
- span = Span<RpcMethodInfo>.Empty;
- }
- else
- {
- RpcMethodInfo[] array4 = ArrayPool<RpcMethodInfo>.Shared.Rent(num4);
- try
- {
- int num5 = 0;
- for (int m = 0; m < num4; m++)
- {
- DefaultRequestMatcher.CompiledMethodInfo method = array3[m];
- ValueTuple<bool, RpcMethodInfo> valueTuple = this.HasParameterSignature(method, request);
- bool item = valueTuple.Item1;
- RpcMethodInfo item2 = valueTuple.Item2;
- if (item)
- {
- array4[num5++] = item2;
- }
- }
- if (num5 <= 1)
- {
- span = MemoryExtensions.AsSpan<RpcMethodInfo>(array4, 0, num5);
- }
- else
- {
- RpcMethodInfo[] array5 = ArrayPool<RpcMethodInfo>.Shared.Rent(num5);
- try
- {
- int num6 = 0;
- for (int n = 0; n < num5; n++)
- {
- bool flag = true;
- RpcMethodInfo rpcMethodInfo = array4[n];
- ParameterInfo[] parameters = rpcMethodInfo.Method.GetParameters();
- if (rpcMethodInfo.Parameters.Length == parameters.Length)
- {
- for (int num7 = 0; num7 < rpcMethodInfo.Parameters.Length; num7++)
- {
- object value = rpcMethodInfo.Parameters[num7];
- ParameterInfo parameterInfo = parameters[num7];
- if (!RpcUtil.TypesMatch(value, parameterInfo.ParameterType))
- {
- flag = false;
- break;
- }
- }
- }
- else
- {
- flag = false;
- }
- if (flag)
- {
- array5[num6++] = array4[n];
- }
- }
- RpcMethodInfo[] array7;
- int num9;
- if (num6 <= 0)
- {
- RpcMethodInfo[] array6 = array4;
- int num8 = num5;
- array7 = array6;
- num9 = num8;
- }
- else
- {
- RpcMethodInfo[] array8 = array5;
- int num8 = num6;
- array7 = array8;
- num9 = num8;
- }
- if (num9 <= 1)
- {
- span = MemoryExtensions.AsSpan<RpcMethodInfo>(array4, 0, num9);
- }
- else
- {
- RpcMethodInfo[] array9 = ArrayPool<RpcMethodInfo>.Shared.Rent(num9);
- try
- {
- int num10 = 0;
- for (int num11 = 0; num11 < num9; num11++)
- {
- RpcMethodInfo rpcMethodInfo2 = array7[num11];
- if (string.Equals(rpcMethodInfo2.Method.Name, request.Method, StringComparison.Ordinal))
- {
- array9[num10++] = rpcMethodInfo2;
- }
- }
- span = MemoryExtensions.AsSpan<RpcMethodInfo>(array9, 0, num10);
- }
- finally
- {
- ArrayPool<RpcMethodInfo>.Shared.Return(array9, false);
- }
- }
- }
- finally
- {
- ArrayPool<RpcMethodInfo>.Shared.Return(array5, false);
- }
- }
- }
- finally
- {
- ArrayPool<RpcMethodInfo>.Shared.Return(array4, false);
- }
- }
- RpcMethodInfo[] array10 = span.ToArray();
- DefaultRequestMatcher.requestToMethodCache.TryAdd(text, array10);
- result = array10;
- }
- finally
- {
- ArrayPool<DefaultRequestMatcher.CompiledMethodInfo>.Shared.Return(array3, false);
- }
- }
- }
- finally
- {
- ArrayPool<char>.Shared.Return(array, false);
- }
- return result;
- }
- private (bool Matches, RpcMethodInfo MethodInfo) HasParameterSignature(CompiledMethodInfo method, RpcRequest rpcRequest)
- {
- IList<IRpcParameter> parameterList;
- if (rpcRequest.Parameters == null)
- {
- parameterList = new IRpcParameter[0];
- }
- else if (rpcRequest.Parameters.IsDictionary)
- {
- Dictionary<string, IRpcParameter> asDictionary = rpcRequest.Parameters.AsDictionary;
- if (!TryParseParameterList(method, asDictionary, out parameterList))
- {
- return (false, null);
- }
- }
- else
- {
- parameterList = rpcRequest.Parameters.AsList;
- }
- if (parameterList.Count() > method.Parameters.Length)
- {
- return (false, null);
- }
- for (int i = 0; i < parameterList.Count(); i++)
- {
- CompiledParameterInfo compiledParameterInfo = method.Parameters[i];
- IRpcParameter rpcParameter = parameterList[i];
- if (rpcParameter.Type != compiledParameterInfo.Type && compiledParameterInfo.Type != RpcParameterType.Object && (rpcParameter.Type != 0 || !compiledParameterInfo.RawType.IsNullableType()))
- {
- return (false, null);
- }
- }
- object[] array = new object[method.Parameters.Length];
- for (int j = 0; j < parameterList.Count(); j++)
- {
- CompiledParameterInfo compiledParameterInfo2 = method.Parameters[j];
- if (!parameterList[j].TryGetValue(compiledParameterInfo2.RawType, out object value))
- {
- return (false, null);
- }
- array[j] = value;
- }
- RpcMethodInfo item = new RpcMethodInfo(method.MethodInfo, array);
- return (true, item);
- }
- private bool TryParseParameterList(CompiledMethodInfo method, Dictionary<string, IRpcParameter> requestParameters, out IList<IRpcParameter> parameterList)
- {
- //IL_0036: Unknown result type (might be due to invalid IL or missing references)
- //IL_0042: Unknown result type (might be due to invalid IL or missing references)
- parameterList = new IRpcParameter[method.Parameters.Count()];
- for (int i = 0; i < method.Parameters.Length; i++)
- {
- CompiledParameterInfo compiledParameterInfo = method.Parameters[i];
- foreach (KeyValuePair<string, IRpcParameter> requestParameter in requestParameters)
- {
- if (RpcUtil.NamesMatch(MemoryExtensions.AsSpan(compiledParameterInfo.Name), MemoryExtensions.AsSpan(requestParameter.Key)))
- {
- parameterList[i] = requestParameter.Value;
- }
- }
- if (!compiledParameterInfo.IsOptional)
- {
- parameterList = null;
- return false;
- }
- }
- return true;
- }
- }
- }
|