public async Task WriteAsync(CapnpNet.Message msg) { await _semaphore.WaitAsync(); try { await msg.SerializeAsync(_writeStream); } finally { _semaphore.Release(); } msg.Dispose(); }
public async Task <CapnpNet.Message> ReceiveAsync() { var msg = new CapnpNet.Message().Init(null, false); var intBuf = ArrayPool <byte> .Shared.Rent(16); var bytesRead = await _readStream.ReadAsync(intBuf, 0, 4); if (bytesRead < intBuf.Length) { throw new InvalidOperationException("Expected more data"); } var segmentCount = BitConverter.ToInt32(intBuf, 0) + 1; var readLen = segmentCount * 4 + (segmentCount % 2 == 0 ? 4 : 0); if (intBuf.Length < readLen) { ArrayPool <byte> .Shared.Return(intBuf); intBuf = ArrayPool <byte> .Shared.Rent(segmentCount * 4 + 4); } bytesRead = await _readStream.ReadAsync(intBuf, 0, readLen); if (bytesRead < intBuf.Length) { throw new InvalidOperationException("Expected more data"); } for (int i = 0; i < segmentCount; i++) { var len = BitConverter.ToInt32(intBuf, i * 4) * 8; var seg = await _segFactory.CreateAsync(msg, len); seg.Is(out ArraySegment <byte> arrSeg); bytesRead = await _readStream.ReadAsync(arrSeg.Array, arrSeg.Offset, len); if (bytesRead < len) { throw new InvalidOperationException("Expected more data"); } } ArrayPool <byte> .Shared.Return(intBuf); return(msg); }
internal void Process(CapnpNet.Message rpcMessage) { try { var message = rpcMessage.GetRoot <Message>(); if (message.Is(out Message unimplemented)) { // TODO: release resources throw new NotImplementedException(); } else if (message.Is(out Exception abort)) { throw new InvalidOperationException($"Connection aborted by remote: {abort.type.ToString()}: {abort.reason.ToString()}"); } else if (message.Is(out Bootstrap bootstrap)) { var reply = new CapnpNet.Message().Init(_segFactory, true); //await reply.PreAllocateAsync(senderMsg.CalculateSize() + 3); reply.SetRoot(new Return(reply) { answerId = bootstrap.questionId, which = Return.Union.results, results = new Payload { content = new OtherPointer { Type = PointerType.Other, OtherPointerType = OtherPointerType.Capability, CapabilityId = 0 }, capTable = new FlatArray <CapDescriptor>(reply, 1, out AllocationContext allocContext) { new CapDescriptor(ref allocContext) { which = CapDescriptor.Union.senderHosted, senderHosted = this.ExportCap(_bootstrapCap) } } } }); rpcMessage.Dispose(); rpcMessage = null; this.Consume((msgStream: _msgStream, reply: reply), async state => { await state.msgStream.WriteAsync(state.reply); state.reply.Dispose(); }); } else if (message.Is(out Call call)) { bool valid; ref Answer ans = ref _answers.TryGet(call.questionId, out valid); if (!valid) { // TODO: return exception message } if (call.target.which == MessageTarget.Union.importedCap) { ref Export export = ref _exports.TryGet(call.target.importedCap, out valid); if (!valid) { // TODO: return exception message } // TODO: read cap descriptors, look up corresponding imports, await any still pending if ([email protected](out var @struct) == false) { // TODO: return exception } switch (call.sendResultsTo.which) { case Call.sendResultsToGroup.Union.caller: // set up return message break; case Call.sendResultsToGroup.Union.yourself: // set aside memory to hold result break; case Call.sendResultsToGroup.Union.thirdParty: default: throw new NotImplementedException(); } //ans.task = export.capability.DispatchCall( // call.interfaceId, // call.methodId, // new CallContext(call, this), // CancellationToken.None); var callTask = ans.task; this.Consume(async() => { await callTask; if (call.sendResultsTo.which == Call.sendResultsToGroup.Union.caller) { } }); }