public Endpoint(Lifetime bindLifetime, RdCall <TReq, TRes> call, RdId rdId, IScheduler wireScheduler) : base(call, rdId, wireScheduler) { myDef = bindLifetime.CreateNested(); myCall.Wire.Advise(Lifetime, this); Lifetime.TryOnTermination(() => ResultInternal.SetIfEmpty(RdTaskResult <TRes> .Cancelled())); Result.AdviseOnce(Lifetime.Eternal, taskResult => { var potentiallyBindable = taskResult.Result; if (potentiallyBindable.IsBindable()) { potentiallyBindable.IdentifyPolymorphic(myCall.Proto.Identities, myCall.RdId.Mix(RdId.ToString())); potentiallyBindable.BindPolymorphic(Lifetime, myCall, RdId.ToString()); } else { myDef.Terminate(); } Trace(RdReactiveBase.ourLogSend, "send response", taskResult); myWire.Send(RdId, writer => { RdTaskResult <TRes> .Write(myCall.WriteResponseDelegate, myCall.SerializationContext, writer, taskResult); }); }); }
//received response from wire public void OnWireReceived(UnsafeReader reader) { var resultFromWire = RdTaskResult <TRes> .Read(myCall.ReadResponseDelegate, myCall.SerializationContext, reader); if (RdReactiveBase.LogReceived.IsTraceEnabled()) { RdReactiveBase.LogReceived.Trace($"call {myCall.Location} ({myCall.RdId}) received response for task '{RdId}' : {resultFromWire.PrintToString()}"); } Scheduler.Queue(() => { using (myCall.UsingDebugInfo()) { if (ResultInternal.SetIfEmpty(resultFromWire)) { return; } } //trace if (RdReactiveBase.LogReceived.IsTraceEnabled()) { RdReactiveBase.LogReceived.Trace($"call {myCall.Location} ({myCall.RdId}) response for task '{RdId}' was dropped, because task already has result: {Result.Value}"); } myLifetimeDef.Terminate(); //todo not true in case of bindable entities }); }
private static RdTask <T> FromResult(RdTaskResult <T> result) { var res = new RdTask <T>(); res.ResultInternal.Value = result; return(res); }
public override void OnWireReceived(UnsafeReader reader) { using (myCall.UsingDebugInfo()) { //we are on endpoint side, so listening for cancellation Trace(RdReactiveBase.ourLogReceived, "received cancellation"); reader.ReadVoid(); //nothing just a void value ResultInternal.SetIfEmpty(RdTaskResult <TRes> .Cancelled()); myDef.Terminate(); } }
internal Lifetime Subscribe(Lifetime outerLifetime) { var taskWireSubscriptionDefinition = outerLifetime.CreateNested(); var externalCancellation = outerLifetime.CreateNested(); myCall.Wire.Advise(taskWireSubscriptionDefinition.Lifetime, this); //this lifetimeDef listen only one value taskWireSubscriptionDefinition.Lifetime.TryOnTermination(() => ResultInternal.SetIfEmpty(RdTaskResult <TRes> .Cancelled())); Result.AdviseOnce(Lifetime.Eternal, taskResult => { try { var potentiallyBindable = taskResult.Result; if (potentiallyBindable.IsBindable()) { if (myIsEndpoint) { potentiallyBindable.IdentifyPolymorphic(myCall.Proto.Identities, myCall.RdId.Mix(RdId.ToString())); } potentiallyBindable.BindPolymorphic(externalCancellation.Lifetime, myCall, RdId.ToString()); } else { externalCancellation.Terminate(); } if (myIsEndpoint) { Trace(RdReactiveBase.ourLogSend, "send response", taskResult); myWire.Send(RdId, writer => { RdTaskResult <TRes> .Write(myCall.WriteResponseDelegate, myCall.SerializationContext, writer, taskResult); }); } else if (taskResult.Status == RdTaskStatus.Canceled) //we need to transfer cancellation to the other side { Trace(RdReactiveBase.ourLogSend, "send cancellation"); myWire.Send(RdId, writer => { writer.Write(Unit.Instance); }); //send cancellation to the other side } } finally { taskWireSubscriptionDefinition.Terminate(); //no need to listen result or cancellation from wire } }); return(externalCancellation.Lifetime); }
public override void OnWireReceived(UnsafeReader reader) { using (myCall.UsingDebugInfo()) { // we are at call side, so listening no response and bind it if it's bindable var resultFromWire = RdTaskResult <TRes> .Read(myCall.ReadResponseDelegate, myCall.SerializationContext, reader); Trace(RdReactiveBase.ourLogReceived, "received response", resultFromWire); if (!ResultInternal.SetIfEmpty(resultFromWire)) { Trace(RdReactiveBase.ourLogReceived, "response from wire was rejected because task already has result"); } } }
public WiredRdTask(LifetimeDefinition lifetimeDef, RdCall <TReq, TRes> call, RdId rdId, IScheduler scheduler) { myLifetimeDef = lifetimeDef; myCall = call; RdId = rdId; Scheduler = scheduler; myWire = call.Wire; call.Wire.Advise(lifetimeDef.Lifetime, this); lifetimeDef.Lifetime.TryOnTermination(() => { //otherwise it could be successful continuation from Queue if (ResultInternal.SetIfEmpty(RdTaskResult <TRes> .Cancelled())) { RdReactiveBase.LogSend.Trace($"call {myCall.Location} ({myCall.RdId}) send cancellation for task '{RdId}'"); myWire.Send(rdId, writer => { writer.Write(Unit.Instance); }); //send cancellation to the other side } }); }
//received response from wire public void OnWireReceived(UnsafeReader reader) { using (myCall.UsingDebugInfo()) { if (myIsEndpoint) //we are on endpoint side, so listening for cancellation { Trace(RdReactiveBase.ourLogReceived, "received cancellation"); reader.ReadVoid(); //nothing just a void value ResultInternal.SetIfEmpty(RdTaskResult <TRes> .Cancelled()); } else // we are at call side, so listening no response and bind it if it's bindable { var resultFromWire = RdTaskResult <TRes> .Read(myCall.ReadResponseDelegate, myCall.SerializationContext, reader); Trace(RdReactiveBase.ourLogReceived, "received response", resultFromWire); if (!ResultInternal.SetIfEmpty(resultFromWire)) { Trace(RdReactiveBase.ourLogReceived, "response from wire was rejected because task already has result"); } } } }
public static RdTask <T> Cancelled() { return(FromResult(RdTaskResult <T> .Cancelled())); }
public void Set(T value) => ResultInternal.Value = RdTaskResult <T> .Success(value);
public override void OnWireReceived(UnsafeReader reader) { var taskId = RdId.Read(reader); var value = ReadRequestDelegate(SerializationContext, reader); if (LogReceived.IsTraceEnabled()) { LogReceived.Trace("endpoint `{0}`::({1}), taskId={2}, request = {3}", Location, RdId, taskId, value.PrintToString()); } var taskLifetimeDef = myBindLifetime.CreateNested(); //subscribe for lifetime cancellation new WiredLifetime(taskLifetimeDef, taskId, this, Wire); RdTask <TRes> rdTask; using (UsingDebugInfo()) //now supports only sync handlers { try { rdTask = Handler(taskLifetimeDef.Lifetime, value); } catch (Exception e) { rdTask = RdTask <TRes> .Faulted(e); } } rdTask.Result.Advise(taskLifetimeDef.Lifetime, result => { if (LogSend.IsTraceEnabled()) { LogSend.Trace("endpoint `{0}`::({1}), taskId={2}, response = {3}", Location, RdId, taskId, result.PrintToString()); } RdTaskResult <TRes> validatedResult; try { if (result.Status == RdTaskStatus.Success) { AssertNullability(result.Result); } validatedResult = result; } catch (Exception e) { LogSend.Error(e); validatedResult = RdTaskResult <TRes> .Faulted(e); } Wire.Send(taskId, writer => { RdTaskResult <TRes> .Write(WriteResponseDelegate, SerializationContext, writer, validatedResult); }); taskLifetimeDef.Terminate(); //need to terminate to unsubscribe lifetime listener - not for bindable entries }); }
public static void Write(CtxWriteDelegate <T> writeDelegate, SerializationCtx ctx, UnsafeWriter writer, RdTaskResult <T> value) { writer.Write((int)value.Status); switch (value.Status) { case RdTaskStatus.Success: writeDelegate(ctx, writer, value.Result); break; case RdTaskStatus.Canceled: break; case RdTaskStatus.Faulted: RdFault.Write(ctx, writer, value.Error); break; default: throw new ArgumentOutOfRangeException(); } }
public void SetCancelled() => ResultInternal.Value = RdTaskResult <T> .Cancelled();
public void Set(Exception e) => ResultInternal.Value = RdTaskResult <T> .Faulted(e);
public static RdTask <T> Faulted(Exception exception) => FromResult(RdTaskResult <T> .Faulted(exception));
public static RdTask <T> Successful(T result) => FromResult(RdTaskResult <T> .Success(result));
public static RdTask <T> Faulted(Exception exception) { return(FromResult(RdTaskResult <T> .Faulted(exception))); }
public void Set(Exception e) => ResultInternal.SetIfEmpty(RdTaskResult <T> .Faulted(e));
public void SetCancelled() => ResultInternal.SetIfEmpty(RdTaskResult <T> .Cancelled());
public void Set(T value) => ResultInternal.SetIfEmpty(RdTaskResult <T> .Success(value));
public CallSite(Lifetime outerLifetime, RdCall <TReq, TRes> call, RdId rdId, IScheduler wireScheduler) : base(call, rdId, wireScheduler) { var taskWireSubscriptionDefinition = outerLifetime.CreateNested(); myCall.Wire.Advise(taskWireSubscriptionDefinition.Lifetime, this); //this lifetimeDef listen only one value taskWireSubscriptionDefinition.Lifetime.TryOnTermination(() => ResultInternal.SetIfEmpty(RdTaskResult <TRes> .Cancelled())); Result.AdviseOnce(Lifetime.Eternal, taskResult => { taskWireSubscriptionDefinition.Terminate(); //no need to listen result or cancellation from wire var potentiallyBindable = taskResult.Result; if (potentiallyBindable.IsBindable()) { potentiallyBindable.BindPolymorphic(outerLifetime, myCall, RdId.ToString()); if (!outerLifetime.TryOnTermination(SendCancellation)) { SendCancellation(); } } else if (taskResult.Status == RdTaskStatus.Canceled) //we need to transfer cancellation to the other side { SendCancellation(); } }); }
public static RdTask <T> Successful(T result) { return(FromResult(RdTaskResult <T> .Success(result))); }
public static RdTask <T> Cancelled() => FromResult(RdTaskResult <T> .Cancelled());