protected override void Ready(object message)
{
if (message is InboundAssociation)
{
var ia = message as InboundAssociation;
var wrappedHandle = WrapHandle(ia.Association, associationListener, true);
wrappedHandle.ThrottlerActor.Tell(new Handle(wrappedHandle));
}
else if (message is AssociateUnderlying)
{
var ua = message as AssociateUnderlying;
// Slight modification of PipeTo, only success is sent, failure is propagated to a separate Task
var associateTask = WrappedTransport.Associate(ua.RemoteAddress);
var self = Self;
associateTask.ContinueWith(tr =>
{
if (tr.IsFaulted)
{
ua.StatusPromise.SetException(tr.Exception ?? new Exception("association failed"));
}
else
{
self.Tell(new AssociateResult(tr.Result, ua.StatusPromise));
}
}, TaskContinuationOptions.AttachedToParent
& TaskContinuationOptions.ExecuteSynchronously);
}
else if (message is AssociateResult) // Finished outbound association and got back the handle
{
var ar = message as AssociateResult;
var wrappedHandle = WrapHandle(ar.AssociationHandle, associationListener, false);
var naked = NakedAddress(ar.AssociationHandle.RemoteAddress);
var inMode = GetInboundMode(naked);
wrappedHandle.OutboundThrottleMode.Value = GetOutboundMode(naked);
wrappedHandle.ReadHandlerSource.Task.ContinueWith(tr => new ListenerAndMode(tr.Result, inMode), TaskContinuationOptions.AttachedToParent & TaskContinuationOptions.ExecuteSynchronously)
.PipeTo(wrappedHandle.ThrottlerActor);
_handleTable.Add(Tuple.Create(naked, wrappedHandle));
ar.StatusPromise.SetResult(wrappedHandle);
}
else if (message is SetThrottle)
{
var st = message as SetThrottle;
var naked = NakedAddress(st.Address);
_throttlingModes[naked] = new Tuple <ThrottleMode, ThrottleTransportAdapter.Direction>(st.Mode, st.Direction);
var ok = Task.FromResult(SetThrottleAck.Instance);
var modes = new List <Task <SetThrottleAck> >()
{
ok
};
foreach (var handle in _handleTable)
{
if (handle.Item1 == naked)
{
modes.Add(SetMode(handle.Item2, st.Mode, st.Direction));
}
}
var sender = Sender;
Task.WhenAll(modes).ContinueWith(tr =>
{
return(SetThrottleAck.Instance);
},
TaskContinuationOptions.AttachedToParent & TaskContinuationOptions.ExecuteSynchronously)
.PipeTo(sender);
}
else if (message is ForceDisassociate)
{
var fd = message as ForceDisassociate;
var naked = NakedAddress(fd.Address);
foreach (var handle in _handleTable)
{
if (handle.Item1 == naked)
{
handle.Item2.Disassociate();
}
}
/*
* NOTE: Important difference between Akka.NET and Akka here.
* In canonical Akka, ThrottleHandlers are never removed from
* the _handleTable. The reason is because Ask-ing a terminated ActorRef
* doesn't cause any exceptions to be thrown upstream - it just times out
* and propagates a failed Future.
*
* In the CLR, a CancellationException gets thrown and causes all
* parent tasks chaining back to the EndPointManager to fail due
* to an Ask timeout.
*
* So in order to avoid this problem, we remove any disassociated handles
* from the _handleTable.
*
* Questions? Ask @Aaronontheweb
*/
_handleTable.RemoveAll(tuple => tuple.Item1 == naked);
Sender.Tell(ForceDisassociateAck.Instance);
}
else if (message is ForceDisassociateExplicitly)
{
var fde = message as ForceDisassociateExplicitly;
var naked = NakedAddress(fde.Address);
foreach (var handle in _handleTable)
{
if (handle.Item1 == naked)
{
handle.Item2.DisassociateWithFailure(fde.Reason);
}
}
/*
* NOTE: Important difference between Akka.NET and Akka here.
* In canonical Akka, ThrottleHandlers are never removed from
* the _handleTable. The reason is because Ask-ing a terminated ActorRef
* doesn't cause any exceptions to be thrown upstream - it just times out
* and propagates a failed Future.
*
* In the CLR, a CancellationException gets thrown and causes all
* parent tasks chaining back to the EndPointManager to fail due
* to an Ask timeout.
*
* So in order to avoid this problem, we remove any disassociated handles
* from the _handleTable.
*
* Questions? Ask @Aaronontheweb
*/
_handleTable.RemoveAll(tuple => tuple.Item1 == naked);
Sender.Tell(ForceDisassociateAck.Instance);
}
else if (message is Checkin)
{
var chkin = message as Checkin;
var naked = NakedAddress(chkin.Origin);
_handleTable.Add(new Tuple <Address, ThrottlerHandle>(naked, chkin.ThrottlerHandle));
SetMode(naked, chkin.ThrottlerHandle);
}
}