protected void Gated(bool writerTerminated, bool earlyUngateRequested)
{
Receive<Terminated>(terminated =>
{
if (!writerTerminated)
{
if (earlyUngateRequested)
Self.Tell(new Ungate());
}
else
Context.System.Scheduler.ScheduleTellOnce(_settings.RetryGateClosedFor, Self, new Ungate(), Self);
Become(() => Gated(true, earlyUngateRequested));
});
Receive<IsIdle>(idle => Sender.Tell(Idle.Instance));
Receive<Ungate>(ungate =>
{
if (!writerTerminated)
{
// Ungate was sent from EndpointManager, but we must wait for Terminated first.
Become(() => Gated(false, true));
}
else if (_resendBuffer.NonAcked.Any() || _resendBuffer.Nacked.Any())
{
// If we talk to a system we have not talked to before (or has given up talking to in the past) stop
// system delivery attempts after the specified time. This act will drop the pending system messages and gate the
// remote address at the EndpointManager level stopping this actor. In case the remote system becomes reachable
// again it will be immediately quarantined due to out-of-sync system message buffer and becomes quarantined.
// In other words, this action is safe.
if (_bailoutAt != null && _bailoutAt.IsOverdue)
{
throw new HopelessAssociation(_localAddress, _remoteAddress, Uid,
new TimeoutException("Delivery of system messages timed out and they were dropped"));
}
_writer = CreateWriter();
//Resending will be triggered by the incoming GotUid message after the connection finished
GoToActive();
}
else
{
GoToIdle();
}
});
Receive<AttemptSysMsgRedelivery>(redelivery => { }); // Ignore
Receive<EndpointManager.Send>(send => send.Message is ISystemMessage, send => TryBuffer(send.Copy(NextSeq())));
Receive<EndpointManager.Send>(send => Context.System.DeadLetters.Tell(send));
Receive<EndpointWriter.FlushAndStop>(flush => Context.Stop(Self));
Receive<EndpointWriter.StopReading>(stop =>
{
stop.ReplyTo.Tell(new EndpointWriter.StoppedReading(stop.Writer));
Sender.Tell(new EndpointWriter.StoppedReading(stop.Writer));
});
}