public static ReadOnlyMemory <byte> Decode(string words, out bool parityError) { var split = words.Split(" ", StringSplitOptions.RemoveEmptyEntries); if (split.Length % 6 != 0) { throw new ArgumentException("RFC1751 works in 6 word blocks", "words"); } parityError = false; if (split.Length == 0) { return(new byte[0]); } var builder = new System.Buffers.ArrayBufferWriter <byte>(8); for (int i = 0; i < split.Length; i += 6) { var bits = Decode(split[i], split[i + 1], split[i + 2], split[i + 3], split[i + 4], split[i + 5], out var parity); parityError |= parity; var span = builder.GetSpan(8); BinaryPrimitives.WriteUInt64LittleEndian(span, bits); builder.Advance(8); } return(builder.WrittenMemory); }
public static async Task <Message> Deserialize(Stream stream, CancellationToken cancellationToken) { // TypeModel.DeserializeWithLengthPrefix does not work. We'll do it ourselves. const int BufferCapacity = 256; // This is arbitrary. var bufferWriter = new System.Buffers.ArrayBufferWriter <byte>(); var expectedLength = await GetMessageLength(stream, cancellationToken).ConfigureAwait(false); while (bufferWriter.WrittenCount < expectedLength) { var buffer = bufferWriter.GetMemory(BufferCapacity); var byteCount = await stream.ReadAsync(buffer, cancellationToken).ConfigureAwait(false); bufferWriter.Advance(byteCount); } Debug.Assert(bufferWriter.WrittenCount == expectedLength, $"Expected {expectedLength}, but got {bufferWriter.WrittenCount}"); return(TypeModel.Deserialize <Message>(bufferWriter.WrittenMemory)); }
private async Task ReceiveLoop() { var response = new System.Buffers.ArrayBufferWriter <byte>(); while (!cancellationTokenSource.IsCancellationRequested) { var buffer = response.GetMemory(); try { var result = await socket.ReceiveAsync(buffer, cancellationTokenSource.Token); response.Advance(result.Count); if (result.EndOfMessage) { var json = System.Text.Json.JsonDocument.Parse(response.WrittenMemory); var type = json.RootElement.GetProperty("type").GetString(); if (type == "response") { var id = json.RootElement.GetProperty("id").GetUInt32(); var status = json.RootElement.GetProperty("status").GetString(); if (status == "success") { lock (responses) { if (responses.TryGetValue(id, out var task)) { responses.Remove(id); task.SetResult(json.RootElement.GetProperty("result").Clone()); } } } else if (status == "error") { var error = json.RootElement.GetProperty("error").GetString(); var request = json.RootElement.GetProperty("request").Clone(); RippleException exception; if (json.RootElement.TryGetProperty("error_exception", out var element)) { exception = new RippleSubmitRequestException(error, element.GetString(), request); } else { exception = new RippleRequestException(error, request); } lock (responses) { if (responses.TryGetValue(id, out var task)) { responses.Remove(id); task.SetException(exception); } } } else { lock (responses) { if (responses.TryGetValue(id, out var task)) { responses.Remove(id); task.SetException(new NotSupportedException(string.Format("{0} not a supported status", status))); } } } } else if (type == "path_find") { var id = json.RootElement.GetProperty("id").GetUInt32(); var pathFindResponse = new PathFindResponse(json.RootElement); try { OnPathFind?.Invoke(this, id, pathFindResponse); } catch (Exception exc) { // TODO: We don't want user exceptions from the OnPathFind event to tear down this thread but we should bubble them up somehow. } } response.Clear(); } } catch (TaskCanceledException taskCanceledException) { if (taskCanceledException.CancellationToken == cancellationTokenSource.Token) { // We canceled the receive, while loop will now terminate and task completes successfully } else { // Something else unexpected was cancelled, rethrow throw; } } } socket.Dispose(); }