Ejemplo n.º 1
0
        /// <summary>
        /// Terminate the stream with failure. After that you are not allowed to
        /// call <see cref="OnNext"/>, <see cref="OnError"/> and <see cref="OnComplete"/>.
        /// </summary>
        /// <param name="cause">TBD</param>
        /// <exception cref="IllegalStateException">
        /// This exception is thrown for a number of reasons. These include:
        /// <dl>
        ///   <dt>when in the <see cref="LifecycleState.ErrorEmitted"/> state</dt>
        ///   <dd>This exception is thrown when this <see cref="ActorPublisher{T}"/> has already terminated due to an error.</dd>
        ///   <dt>when in the <see cref="LifecycleState.Completed"/> or <see cref="LifecycleState.CompleteThenStop"/> state</dt>
        ///   <dd>This exception is thrown when this <see cref="ActorPublisher{T}"/> has already completed.</dd>
        /// </dl>
        /// </exception>
        public void OnError(Exception cause)
        {
            switch (_lifecycleState)
            {
            case LifecycleState.Active:
            case LifecycleState.PreSubscriber:
                _lifecycleState = LifecycleState.ErrorEmitted;
                _onError        = new OnErrorBlock(cause, false);
                if (_subscriber != null)
                {
                    // otherwise onError will be called when the subscription arrives
                    try
                    {
                        ReactiveStreamsCompliance.TryOnError(_subscriber, cause);
                    }
                    finally
                    {
                        _subscriber = null;
                    }
                }
                break;

            case LifecycleState.ErrorEmitted: throw new IllegalStateException("OnError must only be called once");

            case LifecycleState.Completed:
            case LifecycleState.CompleteThenStop: throw new IllegalStateException("OnError must not be called after OnComplete");

            case LifecycleState.Canceled: break;
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// <para>
        /// Terminate the stream with failure. After that you are not allowed to
        /// call <see cref="OnNext"/>, <see cref="OnError"/> and <see cref="OnComplete"/>.
        /// </para>
        /// <para>
        /// After signalling the Error the Actor will then stop itself as it has completed the protocol.
        /// When <see cref="OnError"/> is called before any <see cref="ISubscriber{T}"/> has had the chance to subscribe
        /// to this <see cref="ActorPublisher{T}"/> the error signal (and therefore stopping of the Actor as well)
        /// will be delayed until such <see cref="ISubscriber{T}"/> arrives.
        /// </para>
        /// </summary>
        /// <param name="cause">TBD</param>
        public void OnErrorThenStop(Exception cause)
        {
            switch (_lifecycleState)
            {
            case LifecycleState.Active:
            case LifecycleState.PreSubscriber:
                _lifecycleState = LifecycleState.ErrorEmitted;
                _onError        = new OnErrorBlock(cause, stop: true);
                if (_subscriber != null)
                {
                    // otherwise onError will be called when the subscription arrives
                    try
                    {
                        ReactiveStreamsCompliance.TryOnError(_subscriber, cause);
                    }
                    finally
                    {
                        Context.Stop(Self);
                    }
                }
                break;

            default: OnError(cause); break;
            }
        }
Ejemplo n.º 3
0
            public void Fail(Exception reason)
            {
                // No need to fail if had already been cancelled, or we closed earlier
                if (!(_downstreamCompleted || _upstreamCompleted))
                {
                    _upstreamCompleted = true;
                    _upstreamFailed    = reason;

                    if (!ReferenceEquals(_exposedPublisher, null))
                    {
                        _exposedPublisher.Shutdown(reason);
                    }
                    if (!ReferenceEquals(_subscriber, null) && !(reason is ISpecViolation))
                    {
                        ReactiveStreamsCompliance.TryOnError(_subscriber, reason);
                    }
                }
            }
Ejemplo n.º 4
0
        /// <summary>
        /// TBD
        /// </summary>
        /// <param name="receive">TBD</param>
        /// <param name="message">TBD</param>
        /// <returns>TBD</returns>
        protected internal override bool AroundReceive(Receive receive, object message)
        {
            if (message is Request)
            {
                var req = (Request)message;
                if (req.IsProcessed)
                {
                    // it's an unstashed Request, demand is already handled
                    base.AroundReceive(receive, req);
                }
                else
                {
                    if (req.Count < 1)
                    {
                        if (_lifecycleState == LifecycleState.Active)
                        {
                            OnError(new ArgumentException("Number of requested elements must be positive. Rule 3.9"));
                        }
                    }
                    else
                    {
                        _demand += req.Count;
                        if (_demand < 0)
                        {
                            _demand = long.MaxValue; // long overflow: effectively unbounded
                        }
                        req.MarkProcessed();
                        base.AroundReceive(receive, message);
                    }
                }
            }
            else if (message is Subscribe <T> )
            {
                var sub        = (Subscribe <T>)message;
                var subscriber = sub.Subscriber;
                switch (_lifecycleState)
                {
                case LifecycleState.PreSubscriber:
                    _scheduledSubscriptionTimeout.Cancel();
                    _subscriber     = subscriber;
                    _lifecycleState = LifecycleState.Active;
                    ReactiveStreamsCompliance.TryOnSubscribe(subscriber, new ActorPublisherSubscription(Self));
                    break;

                case LifecycleState.ErrorEmitted:
                    if (_onError.Stop)
                    {
                        Context.Stop(Self);
                    }
                    ReactiveStreamsCompliance.TryOnSubscribe(subscriber, CancelledSubscription.Instance);
                    ReactiveStreamsCompliance.TryOnError(subscriber, _onError.Cause);
                    break;

                case LifecycleState.Completed:
                    ReactiveStreamsCompliance.TryOnSubscribe(subscriber, CancelledSubscription.Instance);
                    ReactiveStreamsCompliance.TryOnComplete(subscriber);
                    break;

                case LifecycleState.CompleteThenStop:
                    Context.Stop(Self);
                    ReactiveStreamsCompliance.TryOnSubscribe(subscriber, CancelledSubscription.Instance);
                    ReactiveStreamsCompliance.TryOnComplete(subscriber);
                    break;

                case LifecycleState.Active:
                case LifecycleState.Canceled:
                    if (_subscriber == subscriber)
                    {
                        ReactiveStreamsCompliance.RejectDuplicateSubscriber(subscriber);
                    }
                    else
                    {
                        ReactiveStreamsCompliance.RejectAdditionalSubscriber(subscriber, "ActorPublisher");
                    }
                    break;
                }
            }
            else if (message is Cancel)
            {
                if (_lifecycleState != LifecycleState.Canceled)
                {
                    // possible to receive again in case of stash
                    CancelSelf();
                    base.AroundReceive(receive, message);
                }
            }
            else if (message is SubscriptionTimeoutExceeded)
            {
                if (!_scheduledSubscriptionTimeout.IsCancellationRequested)
                {
                    CancelSelf();
                    base.AroundReceive(receive, message);
                }
            }
            else
            {
                return(base.AroundReceive(receive, message));
            }
            return(true);
        }
Ejemplo n.º 5
0
        protected override bool AroundReceive(Receive receive, object message)
        {
            if (message is Request)
            {
                var req = (Request)message;
                if (req.Count < 1)
                {
                    if (_lifecycleState == LifecycleState.Active)
                    {
                        OnError(new ArgumentException("Number of requested elements must be positive. Rule 3.9"));
                    }
                    else
                    {
                        base.AroundReceive(receive, message);
                    }
                }
                else
                {
                    _demand += req.Count;
                    if (_demand < 0)
                    {
                        _demand = long.MaxValue;              // long overflow: effectively unbounded
                    }
                    base.AroundReceive(receive, message);
                }
            }
            else if (message is Subscribe <T> )
            {
                var sub        = (Subscribe <T>)message;
                var subscriber = sub.Subscriber;
                switch (_lifecycleState)
                {
                case LifecycleState.PreSubscriber:
                    _scheduledSubscriptionTimeout.Cancel();
                    _subscriber     = subscriber;
                    _lifecycleState = LifecycleState.Active;
                    ReactiveStreamsCompliance.TryOnSubscribe(subscriber, new ActorPublisherSubscription(Self));
                    break;

                case LifecycleState.ErrorEmitted:
                    if (_onError.Stop)
                    {
                        Context.Stop(Self);
                    }
                    ReactiveStreamsCompliance.TryOnSubscribe(subscriber, CancelledSubscription.Instance);
                    ReactiveStreamsCompliance.TryOnError(subscriber, _onError.Cause);
                    break;

                case LifecycleState.Completed:
                    ReactiveStreamsCompliance.TryOnSubscribe(subscriber, CancelledSubscription.Instance);
                    ReactiveStreamsCompliance.TryOnComplete(subscriber);
                    break;

                case LifecycleState.CompleteThenStop:
                    Context.Stop(Self);
                    ReactiveStreamsCompliance.TryOnSubscribe(subscriber, CancelledSubscription.Instance);
                    ReactiveStreamsCompliance.TryOnComplete(subscriber);
                    break;

                case LifecycleState.Active:
                case LifecycleState.Canceled:
                    ReactiveStreamsCompliance.TryOnSubscribe(subscriber, CancelledSubscription.Instance);
                    ReactiveStreamsCompliance.TryOnError(subscriber, _subscriber == subscriber
                            ? new IllegalStateException("Cannot subscribe the same subscriber multiple times")
                            : new IllegalStateException("Only supports one subscriber"));
                    break;
                }
            }
            else if (message is Cancel)
            {
                CancelSelf();
                base.AroundReceive(receive, message);
            }
            else if (message is SubscriptionTimeoutExceeded)
            {
                if (!_scheduledSubscriptionTimeout.IsCancellationRequested)
                {
                    CancelSelf();
                    base.AroundReceive(receive, message);
                }
            }
            else
            {
                return(base.AroundReceive(receive, message));
            }
            return(true);
        }