private RequestHandle <TResult> RequestAsyncCore <TParams, TResult>(EscapedUTF8String methodName, TParams parameters, IJsonFormatterResolver formatterResolver, IErrorHandler errorHandler, CancellationToken cancellationToken = default) { var idNum = Interlocked.Increment(ref this.id); var id = new ID(idNum); if (cancellationToken.CanBeCanceled) { RegisterCancellation(id, cancellationToken);//ラムダ式のクロージャ生成を遅延 } var request = new Request <TParams>() { ID = id, Method = methodName, Params = parameters }; var serializedRequest = JsonSerializer.SerializeUnsafe(request, formatterResolver).CopyToPooled(); var handle = RequestHandle <TResult> .Create(serializedRequest, errorHandler); if (!UnResponsedRequests.TryAdd(idNum, handle)) { Debug.Fail("ID conflicted."); } _ = MessageChannel.Writer.WriteAsync(handle); return(handle); }
public RpcMethodHandle(RpcDomain domain, string name, IJsonFormatterResolver jsonFormatterResolver, IErrorHandler errorHandler) { Name = name; EscapedUTF8Name = EscapedUTF8String.FromUnEscaped(name); Domain = domain; JsonFormatterResolver = jsonFormatterResolver; ErrorHandler = errorHandler; }
internal ValueTask NotifyAsync <TParams>(EscapedUTF8String methodName, TParams parameters, IJsonFormatterResolver formatterResolver) { var serializedNotification = JsonSerializer.SerializeUnsafe(new Notification <TParams>() { Method = methodName, Params = parameters }, formatterResolver).CopyToPooled(); var handle = SendMessageHandle.Create(serializedNotification); _ = MessageChannel.Writer.WriteAsync(handle); return(handle.Task); }
private static UTF8String UnEscape(EscapedUTF8String escaped) { bool shouldReturn = UnEscapeUnsafe(escaped, out var str); UTF8String ret = str.Clone(); if (shouldReturn) { ArrayPool <byte> .Shared.Return(str.bytes.Array !); } return(ret); }
/// <summary> /// trueを返した場合、<see cref="ArrayPool{byte}.Shared"/>に内部バッファを返還する必要があり、また返還するまでは永久に使用可能です。 /// falseを返した場合、<see cref="ArrayPool{byte}.Shared"/>に内部バッファを返還する必要はありませんが、ヒープに保存することができません。 /// </summary> /// <param name="escaped"></param> /// <param name="str"></param> /// <returns></returns> public static bool UnEscapeUnsafe(EscapedUTF8String escaped, out UTF8String str) { var quoted = escaped.GetQuoted(); var reader = new JsonReader(quoted.Array, quoted.Offset); var segment = reader.ReadStringSegmentUnsafe(); str = new UTF8String(segment); if (quoted.Array == segment.Array) { return(true); } else { ArrayPool <byte> .Shared.Return(quoted.Array !); return(false); } }
public bool RemoveMethod(string name, [NotNullWhen(true)] out RpcAsyncMethodEntry?methodEntry) { return(MethodEntries.TryRemove(EscapedUTF8String.FromUnEscaped(name), out methodEntry)); }
public bool AddMethod(string name, RpcAsyncMethodEntry methodEntry) { return(MethodEntries.TryAdd(EscapedUTF8String.FromUnEscaped(name), methodEntry)); }
internal ValueTask <TResult> RequestAsync <TParams, TResult>(EscapedUTF8String methodName, TParams parameters, IJsonFormatterResolver formatterResolver, IErrorHandler errorHandler, CancellationToken cancellationToken = default) { var handle = RequestAsyncCore <TParams, TResult>(methodName, parameters, formatterResolver, errorHandler, cancellationToken); return(handle.Task); }
public static MessageParseResult ParseDuplexMessage(ArraySegment <byte> message) { var parseResult = new MessageParseResult(); var reader = new JsonReader(message.Array !, message.Offset); if (reader.ReadIsBeginObject()) { try { while (true) { reader.SkipWhiteSpace(); var buffer = reader.GetBufferUnsafe().AsSpan(reader.GetCurrentOffsetUnsafe()); ref var bufferRef = ref MemoryMarshal.GetReference(buffer); const uint id = (('"') | ('i' << 8) | ('d' << 16) | ('"' << 24)); const ulong method = ((ulong)'"') | ((ulong)'m' << 8) | ((ulong)'e' << 16) | ((ulong)'t' << 24) | ((ulong)'h' << 32) | ((ulong)'o' << 40) | ((ulong)'d' << 48) | ((ulong)'"' << 56); const ulong @params = ((ulong)'"') | ((ulong)'p' << 8) | ((ulong)'a' << 16) | ((ulong)'r' << 24) | ((ulong)'a' << 32) | ((ulong)'m' << 40) | ((ulong)'s' << 48) | ((ulong)'"' << 56); const ulong jsonrpc = (((ulong)'"') | ((ulong)'j' << 8) | ((ulong)'s' << 16) | ((ulong)'o' << 24) | ((ulong)'n' << 32) | ((ulong)'r' << 40) | ((ulong)'p' << 48) | ((ulong)'c' << 56)); const ulong ___2_0 = (((ulong)'"') | ((ulong)'2' << 8) | ((ulong)'.' << 16) | ((ulong)'0' << 24) | ((ulong)'"' << 32)) << 24; const ulong result = (((ulong)'"') | ((ulong)'r' << 8) | ((ulong)'e' << 16) | ((ulong)'s' << 24) | ((ulong)'u' << 32) | ((ulong)'l' << 40) | ((ulong)'t' << 48) | ((ulong)'"' << 56)); const ulong error = (((ulong)'"') | ((ulong)'e' << 8) | ((ulong)'r' << 16) | ((ulong)'r' << 24) | ((ulong)'o' << 32) | ((ulong)'r' << 40) | ((ulong)'"' << 48)); switch (buffer.Length) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: goto UnknownProperty; //最短の正常な文字列パターンは"id":1}で7byteある case 7: case 8: case 9: case 10: { if (Unsafe.ReadUnaligned <uint>(ref bufferRef) == id) { goto ID; } else { goto UnknownProperty; } } case 11: { var chars8 = Unsafe.ReadUnaligned <ulong>(ref bufferRef); if ((uint)chars8 == id) { goto ID; } else if ((chars8 & (ulong)0x00FFFFFFFFFFFFFF) == error) { goto Error; } else { goto UnknownProperty; } } //その次に短いのは"params":[]}または"params":{}}または"method":""または"result":1} case 12: case 13: case 14: case 15: { var chars8 = Unsafe.ReadUnaligned <ulong>(ref bufferRef); switch (chars8) { case result: { goto Result; } case method: { goto Method; } case @params: { goto Params; } default: { if ((uint)chars8 == id) { goto ID; } else if ((chars8 & (ulong)0x00FFFFFFFFFFFFFF) == error) { goto Error; } else { goto UnknownProperty; } } } } //その次が"jsonrpc":"2.0"} default: { var chars8 = Unsafe.ReadUnaligned <ulong>(ref bufferRef); switch (chars8) { case jsonrpc: { goto JsonRpc; } case result: { goto Result; } case method: { goto Method; } case @params: { goto Params; } default: { if ((uint)chars8 == id) { goto ID; } else if ((chars8 & (ulong)0x00FFFFFFFFFFFFFF) == error) { goto Error; } else { goto UnknownProperty; } } } } JsonRpc: { if (Unsafe.AddByteOffset(ref bufferRef, (IntPtr)(8)) == (byte)'"') { reader.AdvanceOffset(9); if (reader.ReadIsNameSeparator()) { reader.SkipWhiteSpace(); buffer = reader.GetBufferUnsafe().AsSpan(reader.GetCurrentOffsetUnsafe()); bufferRef = ref MemoryMarshal.GetReference(buffer); if ((Unsafe.ReadUnaligned <ulong>(ref Unsafe.AddByteOffset(ref bufferRef, (IntPtr)(-3))) & 0xFFFFFFFFFF000000) == ___2_0) { reader.AdvanceOffset(5); parseResult[MessagePropertyKind.JsonRpcVersion] = PropertyState.Valid; break; } else { goto UnExpectedFormatProperty; } } else { goto InvalidJson; } } else { goto UnknownProperty; } } Method: { reader.AdvanceOffset(8); if (reader.ReadIsNameSeparator()) { try { parseResult.Method = EscapedUTF8String.FromEscapedNonQuoted(reader.ReadStringSegmentRaw()); } catch (JsonParsingException) { parseResult[MessagePropertyKind.Method] = PropertyState.Invalid; goto UnExpectedFormatProperty; } parseResult[MessagePropertyKind.Method] = PropertyState.Valid; break; } else { goto InvalidJson; } } Params: { reader.AdvanceOffset(8); if (reader.ReadIsNameSeparator()) { try { parseResult.Params = reader.ReadNextBlockSegment(); } catch (JsonParsingException) { parseResult[MessagePropertyKind.Params] = PropertyState.Invalid; goto UnExpectedFormatProperty; } parseResult[MessagePropertyKind.Params] = PropertyState.Valid; break; } else { goto InvalidJson; } } ID: { reader.AdvanceOffset(4); if (reader.ReadIsNameSeparator()) { try { parseResult.id = ID.Formatter.DeserializeNullableSafe(ref reader); } catch (JsonParsingException) { parseResult[MessagePropertyKind.ID] = PropertyState.Invalid; goto UnExpectedFormatProperty; } parseResult[MessagePropertyKind.ID] = PropertyState.Valid; break; } else { goto InvalidJson; } } Result: { reader.AdvanceOffset(8); if (reader.ReadIsNameSeparator()) { try { parseResult.Result = reader.ReadNextBlockSegment(); } catch (JsonParsingException) { parseResult[MessagePropertyKind.Result] = PropertyState.Invalid; goto UnExpectedFormatProperty; } parseResult[MessagePropertyKind.Result] = PropertyState.Valid; break; } else { goto InvalidJson; } } Error: { reader.AdvanceOffset(7); if (reader.ReadIsNameSeparator()) { try { parseResult.Error = reader.ReadNextBlockSegment(); //Client.JsonResolver.GetFormatterWithVerify<Client.ResponseError<object?>>().Deserialize(ref reader, Client.JsonResolver); } catch (JsonParsingException) { parseResult[MessagePropertyKind.Error] = PropertyState.Invalid; goto UnExpectedFormatProperty; } parseResult[MessagePropertyKind.Error] = PropertyState.Valid; break; } else { goto InvalidJson; } } UnknownProperty: { parseResult.ParseErrors |= MessageParseErrors.HasUnknownProperty; try { reader.ReadStringSegmentRaw(); } catch (JsonParsingException) { goto InvalidJson; } if (reader.ReadIsValueSeparator()) { try { reader.ReadNextBlock(); } catch (JsonParsingException) { goto InvalidJson; } break; } else { goto InvalidJson; } } UnExpectedFormatProperty: { parseResult.ParseErrors = MessageParseErrors.HasInvalidProperty; try { reader.ReadNextBlock(); } catch (JsonParsingException) { goto InvalidJson; } break; } } switch (reader.GetCurrentJsonToken()) { case JsonToken.ValueSeparator: { reader.AdvanceOffset(1); continue; } case JsonToken.EndObject: { return(parseResult); } default: goto InvalidJson; } } }
public ID(EscapedUTF8String id) { String = id; numberValue = default; }