2020-04-11 21:21:17 +02:00
|
|
|
|
using Capnp.Util;
|
|
|
|
|
using System;
|
2020-03-10 21:55:34 +01:00
|
|
|
|
using System.Collections.Generic;
|
2019-06-12 21:56:55 +02:00
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
|
|
|
|
namespace Capnp.Rpc
|
|
|
|
|
{
|
|
|
|
|
class PendingAnswer: IDisposable
|
|
|
|
|
{
|
2020-01-11 17:21:31 +01:00
|
|
|
|
readonly CancellationTokenSource? _cts;
|
2020-02-22 13:46:03 +01:00
|
|
|
|
readonly TaskCompletionSource<AnswerOrCounterquestion> _cancelCompleter;
|
2020-04-11 21:21:17 +02:00
|
|
|
|
readonly StrictlyOrderedAwaitTask<AnswerOrCounterquestion> _answerTask;
|
2019-06-12 21:56:55 +02:00
|
|
|
|
|
2020-01-11 17:21:31 +01:00
|
|
|
|
public PendingAnswer(Task<AnswerOrCounterquestion> callTask, CancellationTokenSource? cts)
|
2019-06-12 21:56:55 +02:00
|
|
|
|
{
|
2020-02-22 13:46:03 +01:00
|
|
|
|
async Task<AnswerOrCounterquestion> CancelableAwaitWhenReady()
|
2019-06-12 21:56:55 +02:00
|
|
|
|
{
|
2020-02-22 13:46:03 +01:00
|
|
|
|
return await await Task.WhenAny(callTask, _cancelCompleter.Task);
|
2019-06-12 21:56:55 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-02-22 13:46:03 +01:00
|
|
|
|
if (callTask == null)
|
|
|
|
|
throw new ArgumentNullException(nameof(callTask));
|
2019-06-12 21:56:55 +02:00
|
|
|
|
|
2020-02-22 13:46:03 +01:00
|
|
|
|
_cts = cts;
|
|
|
|
|
_cancelCompleter = new TaskCompletionSource<AnswerOrCounterquestion>();
|
2020-04-11 21:21:17 +02:00
|
|
|
|
_answerTask = CancelableAwaitWhenReady().EnforceAwaitOrder();
|
2020-03-21 13:27:46 +01:00
|
|
|
|
|
2020-04-11 21:21:17 +02:00
|
|
|
|
TakeCapTableOwnership();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async void TakeCapTableOwnership()
|
|
|
|
|
{
|
|
|
|
|
try
|
2020-03-21 13:27:46 +01:00
|
|
|
|
{
|
2020-04-11 21:21:17 +02:00
|
|
|
|
var aorcq = await _answerTask;
|
2020-03-21 13:27:46 +01:00
|
|
|
|
|
2020-04-11 21:21:17 +02:00
|
|
|
|
if (aorcq.Answer != null)
|
2020-03-21 13:27:46 +01:00
|
|
|
|
{
|
2020-04-11 21:21:17 +02:00
|
|
|
|
if (aorcq.Answer.Caps != null)
|
|
|
|
|
{
|
|
|
|
|
foreach (var cap in aorcq.Answer.Caps)
|
|
|
|
|
{
|
|
|
|
|
cap.AddRef();
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-03-21 13:27:46 +01:00
|
|
|
|
}
|
2020-04-11 21:21:17 +02:00
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-03-21 13:27:46 +01:00
|
|
|
|
|
2020-04-11 21:21:17 +02:00
|
|
|
|
async void ReleaseCapTableOwnership()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var aorcq = await _answerTask;
|
2020-03-21 13:27:46 +01:00
|
|
|
|
if (aorcq.Answer != null)
|
|
|
|
|
{
|
|
|
|
|
if (aorcq.Answer.Caps != null)
|
|
|
|
|
{
|
|
|
|
|
foreach (var cap in aorcq.Answer.Caps)
|
|
|
|
|
{
|
2020-04-11 21:21:17 +02:00
|
|
|
|
cap?.Release();
|
2020-03-21 13:27:46 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-04-11 21:21:17 +02:00
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
}
|
2019-06-12 21:56:55 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-02-22 13:46:03 +01:00
|
|
|
|
public CancellationToken CancellationToken => _cts?.Token ?? CancellationToken.None;
|
|
|
|
|
|
2020-03-21 13:27:46 +01:00
|
|
|
|
public IReadOnlyList<CapDescriptor.WRITER>? CapTable { get; set; }
|
2020-03-10 21:55:34 +01:00
|
|
|
|
|
2020-02-22 13:46:03 +01:00
|
|
|
|
public void Cancel()
|
2019-06-12 21:56:55 +02:00
|
|
|
|
{
|
2020-02-22 13:46:03 +01:00
|
|
|
|
_cts?.Cancel();
|
|
|
|
|
_cancelCompleter.SetCanceled();
|
2019-06-12 21:56:55 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-04-11 21:21:17 +02:00
|
|
|
|
public void Chain(Action<StrictlyOrderedAwaitTask<AnswerOrCounterquestion>> func)
|
2019-06-12 21:56:55 +02:00
|
|
|
|
{
|
2020-02-22 13:46:03 +01:00
|
|
|
|
func(_answerTask);
|
2019-06-12 21:56:55 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-02-22 13:46:03 +01:00
|
|
|
|
public void Chain(PromisedAnswer.READER rd, Action<Task<Proxy>> func)
|
2019-06-12 21:56:55 +02:00
|
|
|
|
{
|
2020-04-11 21:21:17 +02:00
|
|
|
|
async Task<Proxy> EvaluateProxy()
|
2019-06-12 21:56:55 +02:00
|
|
|
|
{
|
2020-04-11 21:21:17 +02:00
|
|
|
|
var aorcq = await _answerTask;
|
|
|
|
|
|
|
|
|
|
if (aorcq.Answer != null)
|
2019-06-12 21:56:55 +02:00
|
|
|
|
{
|
2020-04-11 21:21:17 +02:00
|
|
|
|
DeserializerState cur = aorcq.Answer;
|
2019-06-12 21:56:55 +02:00
|
|
|
|
|
2020-04-11 21:21:17 +02:00
|
|
|
|
foreach (var op in rd.Transform)
|
2019-06-12 21:56:55 +02:00
|
|
|
|
{
|
2020-04-11 21:21:17 +02:00
|
|
|
|
switch (op.which)
|
2019-06-12 21:56:55 +02:00
|
|
|
|
{
|
2020-04-11 21:21:17 +02:00
|
|
|
|
case PromisedAnswer.Op.WHICH.GetPointerField:
|
2019-06-12 21:56:55 +02:00
|
|
|
|
try
|
|
|
|
|
{
|
2020-04-11 21:21:17 +02:00
|
|
|
|
cur = cur.StructReadPointer(op.GetPointerField);
|
2019-06-12 21:56:55 +02:00
|
|
|
|
}
|
2020-04-11 21:21:17 +02:00
|
|
|
|
catch (System.Exception)
|
2019-06-12 21:56:55 +02:00
|
|
|
|
{
|
2020-04-11 21:21:17 +02:00
|
|
|
|
throw new RpcException("Illegal pointer field in transformation operation");
|
2019-06-12 21:56:55 +02:00
|
|
|
|
}
|
2020-04-11 21:21:17 +02:00
|
|
|
|
break;
|
2020-04-10 18:29:06 +02:00
|
|
|
|
|
2020-04-11 21:21:17 +02:00
|
|
|
|
case PromisedAnswer.Op.WHICH.Noop:
|
|
|
|
|
break;
|
2019-06-12 21:56:55 +02:00
|
|
|
|
|
|
|
|
|
default:
|
2020-04-11 21:21:17 +02:00
|
|
|
|
throw new ArgumentOutOfRangeException("Unknown transformation operation");
|
2019-06-12 21:56:55 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2020-04-11 21:21:17 +02:00
|
|
|
|
|
|
|
|
|
switch (cur.Kind)
|
2019-06-12 21:56:55 +02:00
|
|
|
|
{
|
2020-04-11 21:21:17 +02:00
|
|
|
|
case ObjectKind.Capability:
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
return new Proxy(aorcq.Answer.Caps![(int)cur.CapabilityIndex]);
|
|
|
|
|
}
|
|
|
|
|
catch (ArgumentOutOfRangeException)
|
|
|
|
|
{
|
|
|
|
|
throw new RpcException("Capability index out of range");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case ObjectKind.Nil:
|
|
|
|
|
return new Proxy(NullCapability.Instance);
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
throw new ArgumentOutOfRangeException("Transformation did not result in a capability");
|
2019-06-12 21:56:55 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2020-04-11 21:21:17 +02:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
var path = MemberAccessPath.Deserialize(rd);
|
|
|
|
|
var cap = new RemoteAnswerCapability(aorcq.Counterquestion!, path);
|
|
|
|
|
return new Proxy(cap);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-06-12 21:56:55 +02:00
|
|
|
|
|
2020-04-11 21:21:17 +02:00
|
|
|
|
func(EvaluateProxy());
|
2019-06-12 21:56:55 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-02-22 13:46:03 +01:00
|
|
|
|
public void Dispose()
|
2019-06-12 21:56:55 +02:00
|
|
|
|
{
|
2020-02-22 13:46:03 +01:00
|
|
|
|
_cts?.Dispose();
|
2020-04-11 21:21:17 +02:00
|
|
|
|
ReleaseCapTableOwnership();
|
2019-06-12 21:56:55 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2020-01-11 17:56:12 +01:00
|
|
|
|
}
|