Exemple #1
0
        /// <summary>
        /// <para>
        /// Complete the stream. After that you are not allowed to
        /// call <see cref="OnNext"/>, <see cref="OnError"/> and <see cref="OnComplete"/>.
        /// </para>
        /// <para>
        /// After signalling completion the Actor will then stop itself as it has completed the protocol.
        /// When <see cref="OnComplete"/> is called before any <see cref="ISubscriber{T}"/> has had the chance to subscribe
        /// to this <see cref="ActorPublisher{T}"/> the completion signal (and therefore stopping of the Actor as well)
        /// will be delayed until such <see cref="ISubscriber{T}"/> arrives.
        /// </para>
        /// </summary>
        public void OnCompleteThenStop()
        {
            switch (_lifecycleState)
            {
            case LifecycleState.Active:
            case LifecycleState.PreSubscriber:
                _lifecycleState = LifecycleState.CompleteThenStop;
                _onError        = null;
                if (_subscriber != null)
                {
                    // otherwise onComplete will be called when the subscription arrives
                    try
                    {
                        ReactiveStreamsCompliance.TryOnComplete(_subscriber);
                    }
                    finally
                    {
                        Context.Stop(Self);
                    }
                }
                break;

            default: OnComplete(); break;
            }
        }
Exemple #2
0
        /// <summary>
        /// Complete the stream. After that you are not allowed to
        /// call <see cref="OnNext"/>, <see cref="OnError"/> and <see cref="OnComplete"/>.
        /// </summary>
        /// <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 OnComplete()
        {
            switch (_lifecycleState)
            {
            case LifecycleState.Active:
            case LifecycleState.PreSubscriber:
                _lifecycleState = LifecycleState.Completed;
                _onError        = null;
                if (_subscriber != null)
                {
                    // otherwise onComplete will be called when the subscription arrives
                    try
                    {
                        ReactiveStreamsCompliance.TryOnComplete(_subscriber);
                    }
                    finally
                    {
                        _subscriber = null;
                    }
                }
                break;

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

            case LifecycleState.Completed:
            case LifecycleState.CompleteThenStop: throw new IllegalStateException("OnComplete must only be called once");

            case LifecycleState.Canceled: break;
            }
        }
Exemple #3
0
 /// <summary>
 /// TBD
 /// </summary>
 public override void AroundPostStop()
 {
     _state.Remove(Self);
     try
     {
         if (_lifecycleState == LifecycleState.Active)
             ReactiveStreamsCompliance.TryOnComplete(_subscriber);
     }
     finally
     {
         base.AroundPostStop();
     }
 }
Exemple #4
0
 private void Complete()
 {
     // No need to complete if had already been cancelled, or we closed earlier
     if (!(_upstreamCompleted || _downstreamCompleted))
     {
         _upstreamCompleted = true;
         if (!ReferenceEquals(_exposedPublisher, null))
         {
             _exposedPublisher.Shutdown(null);
         }
         if (!ReferenceEquals(_subscriber, null))
         {
             ReactiveStreamsCompliance.TryOnComplete(_subscriber);
         }
     }
 }
Exemple #5
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);
        }
Exemple #6
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);
        }