示例#1
0
		public void OnCompleted ()
		{
			CheckDisposed ();
			if (!done) {
				done = true;
				if (n != null)
					observers.ForEach ((o) => n.Accept (o));
				var cmp = Notification.CreateOnCompleted<T> ();
				observers.ForEach ((o) => cmp.Accept (o));
			}
		}
        protected override void ProcessNotification(Notification notification)
        {
            var clone = Factory.GetDatabase(notification.Uri.DatabaseName).GetItem(notification.Uri.ToDataUri());

            if (ShouldProcess(clone.GetProviderPath(), $"{Action} changes on clone that were introduced on original item"))
            {
                switch (Action)
                {
                case (NotificationAction.Accept):
                    notification.Accept(clone);
                    break;

                case (NotificationAction.Reject):
                    notification.Reject(clone);
                    break;

                case (NotificationAction.Dismiss):
                    try
                    {
                        // dismiss does not seem to be universally supported by all Sitecore versions
                        // wrapper introduced no avoid late method binding error
                        DismissNotification(notification, clone);
                    }
                    catch (Exception ex)
                    {
                        WriteError(ex, ErrorIds.MethodNotFound, ErrorCategory.NotImplemented, notification);
                    }
                    break;
                }
            }
        }
示例#3
0
        public void OnCompleted_AcceptActionWithResult()
        {
            var n1 = new Notification <int> .OnCompleted();

            var res = n1.Accept(x => { Assert.Fail(); return(null); }, _ => { Assert.Fail(); return(null); }, () => "OK");

            Assert.AreEqual("OK", res);
        }
示例#4
0
        public void OnNext_AcceptObserverWithResult()
        {
            var n1 = new Notification <int> .OnNext(42);

            var res = n1.Accept(new AcceptObserver(x => "OK", _ => { Assert.Fail(); return(null); }, () => { Assert.Fail(); return(null); }));

            Assert.AreEqual("OK", res);
        }
示例#5
0
        public void OnNext_AcceptObserver()
        {
            var con = new CheckOnNextObserver();
            var n1  = new Notification <int> .OnNext(42);

            n1.Accept(con);

            Assert.AreEqual(42, con.Value);
        }
示例#6
0
		public void OnError (Exception error)
		{
			CheckDisposed ();
			if (!done) {
				done = true;
				n = Notification.CreateOnError<T> (error);
				observers.ForEach ((o) => n.Accept (o));
			}
		}
示例#7
0
        public void OnCompleted_AcceptAction()
        {
            var obs = false;

            var n1 = new Notification <int> .OnCompleted();

            n1.Accept(x => { Assert.Fail(); }, _ => { Assert.Fail(); }, () => { obs = true; });

            Assert.IsTrue(obs);
        }
示例#8
0
        public void OnCompleted_AcceptObserver()
        {
            var obs = new CheckOnCompletedObserver();

            var n1 = new Notification <int> .OnCompleted();

            n1.Accept(obs);

            Assert.IsTrue(obs.Completed);
        }
示例#9
0
        public void OnError_AcceptActionWithResult()
        {
            var ex = new Exception();

            var n1 = new Notification <int> .OnError(ex);

            var res = n1.Accept(x => { Assert.Fail(); return(null); }, x => "OK", () => { Assert.Fail(); return(null); });

            Assert.AreEqual("OK", res);
        }
 public void AcceptNotification(Notification notification)
 {
     notification.Accept();
     Notifications.Remove(notification);
     RaisePropertyChanged("Notifications");
     if (notification.Type == NotificationType.REQUEST_FOR_ACCESS)
     {
         GrantAccess(notification);
     }
 }
示例#11
0
        public void OnError_AcceptAction()
        {
            var ex = new Exception();

            var obs = false;

            var n1 = new Notification <int> .OnError(ex);

            n1.Accept(x => { Assert.Fail(); }, _ => { obs = true; }, () => { Assert.Fail(); });

            Assert.IsTrue(obs);
        }
示例#12
0
        public void OnError_AcceptObserver()
        {
            var ex = new Exception();

            var obs = new CheckOnErrorObserver();

            var n1 = new Notification <int> .OnError(ex);

            n1.Accept(obs);

            Assert.AreSame(ex, obs.Error);
        }
 private void LoopRec(Notification notification, Action <Notification> self)
 {
     notification.Accept(_observer);
     if (notification.Kind != NotificationKind.OnNext)
     {
         return;
     }
     notification = notification.Acknowldge();
     if (notification == null || notification.Kind == null)
     {
         return;
     }
     self(notification);
 }
示例#14
0
        public static IObservable <List <T> > ObserveWithBuffer <T>(this IObservable <T> source, IScheduler scheduler)
        {
            return(Observable.Create <List <T> >(observer =>
            {
                Notification <List <T> > outsideNotification = null;
                var gate = new object();
                bool active = false;
                var cancelable = new MultipleAssignmentDisposable();
                var disposable = source.Materialize().Subscribe(thisNotification =>
                {
                    bool wasNotAlreadyActive;
                    lock (gate)
                    {
                        wasNotAlreadyActive = !active;
                        active = true;
                        if (outsideNotification == null)
                        {
                            outsideNotification = Notification.CreateOnNext(new List <T>());
                        }
                        outsideNotification.Value.Add(thisNotification.Value);
                    }

                    if (wasNotAlreadyActive)
                    {
                        cancelable.Disposable = scheduler.Schedule(self =>
                        {
                            Notification <List <T> > localNotification = null;
                            lock (gate)
                            {
                                localNotification = outsideNotification;
                                outsideNotification = null;
                            }
                            localNotification.Accept(observer);
                            bool hasPendingNotification = false;
                            lock (gate)
                            {
                                hasPendingNotification = active = (outsideNotification != null);
                            }
                            if (hasPendingNotification)
                            {
                                self();
                            }
                        });
                    }
                });
                return new CompositeDisposable(disposable, cancelable);
            }));
        }
示例#15
0
        public static IObservable <T> ThrottleResponsive <T>(this IObservable <T> source, TimeSpan minInterval)
        {
            return(Observable.Create <T>(o =>
            {
                object gate = new Object();
                Notification <T> last = null, lastNonTerminal = null;
                DateTime referenceTime = DateTime.UtcNow - minInterval;

                var delayedReplay = new SerialDisposable();
                return new CompositeDisposable(source.Materialize().Subscribe(x =>
                {
                    lock (gate)
                    {
                        var elapsed = DateTime.UtcNow - referenceTime;
                        if (elapsed >= minInterval && delayedReplay.Disposable == null)
                        {
                            referenceTime = DateTime.UtcNow;
                            x.Accept(o);
                        }
                        else
                        {
                            if (x.Kind == NotificationKind.OnNext)
                            {
                                lastNonTerminal = x;
                            }
                            last = x;
                            if (delayedReplay.Disposable == null)
                            {
                                delayedReplay.Disposable = Scheduler.Default.Schedule(minInterval - elapsed, () =>
                                {
                                    lock (gate)
                                    {
                                        referenceTime = DateTime.UtcNow;
                                        if (lastNonTerminal != null && lastNonTerminal != last)
                                        {
                                            lastNonTerminal.Accept(o);
                                        }
                                        last.Accept(o);
                                        last = lastNonTerminal = null;
                                        delayedReplay.Disposable = null;
                                    }
                                });
                            }
                        }
                    }
                }), delayedReplay);
            }));
        }
        /// <summary>
        ///     Throttle a stream of notifications, only taking the last that occurs during a subscription.
        ///		Extension from Lee Campbell on MSDN.
        /// </summary>
        public static IObservable <T> ObserveLatestOn <T>(this IObservable <T> source, IScheduler scheduler)
        {
            return(Observable.Create <T>(observer =>
            {
                Notification <T> outsideNotification = null;
                var gate = new object();
                var active = false;
                var cancelable = new MultipleAssignmentDisposable();
                var disposable = source.Materialize()
                                 .Subscribe(thisNotification =>
                {
                    bool alreadyActive;
                    lock (gate)
                    {
                        alreadyActive = active;
                        active = true;
                        outsideNotification = thisNotification;
                    }

                    if (!alreadyActive)
                    {
                        cancelable.Disposable = scheduler
                                                .Schedule(self =>
                        {
                            Notification <T> localNotification = null;
                            lock (gate)
                            {
                                localNotification = outsideNotification;
                                outsideNotification = null;
                            }
                            localNotification.Accept(observer);
                            var hasPendingNotification = false;
                            lock (gate)
                            {
                                hasPendingNotification = active = (outsideNotification != null);
                            }
                            if (hasPendingNotification)
                            {
                                self();
                            }
                        });
                    }
                });
                return new CompositeDisposable(disposable, cancelable);
            }));
        }
        /// <summary>
        /// Returns an observable sequence with a single notification.
        /// </summary>
        public static IObservable <T> ToObservable <T>(this Notification <T> notification, IScheduler scheduler)
        {
            if (notification == null)
            {
                throw new ArgumentNullException("notification");
            }
            if (scheduler == null)
            {
                throw new ArgumentNullException("scheduler");
            }

            return(new AnonymousObservable <T>(observer => scheduler.Schedule(() =>
            {
                notification.Accept(observer);
                if (notification.Kind == NotificationKind.OnNext)
                {
                    observer.OnCompleted();
                }
            })));
        }
示例#18
0
 private void EmitCompletion(Notification <TSource> completion)
 {
     try { completion.Accept(_observer); }
     finally { Dispose(); }
 }
示例#19
0
        /// <summary>
        /// Limit the # of items that move through the second sequence. This limits only in a subscription, not globally!
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <param name="maxCount"></param>
        /// <returns></returns>
        /// <remarks>
        /// Copied from here:
        ///     https://social.msdn.microsoft.com/Forums/en-US/379a027d-4a06-4abd-9255-d54c3807b50c/parallel-processing-of-incoming-events-observablesemaphoreobserveparallel-?forum=rx
        ///     There are significant modifications because this was a very old method!
        /// </remarks>
        public static IObservable <T> Semaphore <T>(IObservable <T> source, int maxCount, IScheduler sched = null)
        {
            // By default use the thread pool (so this will be deferred, and can do multiple guys, which is what we want).
            sched = sched ?? Scheduler.Default;

            return(Observable.Create <T>(o =>
            {
                var cancel = new CancellationDisposable();
                var queue = new ConcurrentQueue <Notification <T> >();
                var limitter = new SemaphoreSlim(maxCount);
                Notification <T> final = null;
                int pendingAccepts = 0;
                var subscription = source.Materialize().Subscribe(
                    n =>
                {
                    if (cancel.Token.IsCancellationRequested)
                    {
                        return;
                    }

                    try { limitter.Wait(cancel.Token); }
                    catch (OperationCanceledException)
                    {
                        return;
                    }

                    Interlocked.Increment(ref pendingAccepts);
                    queue.Enqueue(n);
                    sched.Schedule(() =>
                    {
                        try
                        {
                            Notification <T> notification;
                            queue.TryDequeue(out notification);
                            if (notification.Kind != NotificationKind.OnNext)
                            {
                                final = notification;
                            }
                            else
                            {
                                notification.Accept(o);
                            }
                        }
                        finally
                        {
                            limitter.Release();
                            if (Interlocked.Decrement(ref pendingAccepts) == 0) // try to go lock-free a long a possible
                            {
                                lock (queue)                                    // take the queue as gate (only one thread should accept final notification)
                                {
                                    if (final != null &&                        // make sure the final call has been received
                                        pendingAccepts == 0                     // and we are behind the decrement of that thread
                                        )
                                    {
                                        final.Accept(o);
                                        final = null;
                                    }
                                }
                            }
                        }
                    });
                });
                return new CompositeDisposable(cancel, subscription);
            }));
        }
示例#20
0
        /// <summary>
        /// Limit the number of simultaniously executing "limitedSequences" to counter. Counter can be shared
        /// accross multiple calls.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="U"></typeparam>
        /// <param name="source"></param>
        /// <param name="limitedSequence">The transformation</param>
        /// <param name="limitter">An instance of LimitGlobalCounter. Can be shared between various calls of this.</param>
        /// <param name="sched">IScheduler to execute this on. If left null, defaults to Scheduler.Default</param>
        /// <returns>The resulting sequence transformed by limitedSequence.</returns>
        /// <remarks>
        /// When the source sequence completes, the terminating sequence will complete after each sequence from limitedSequence compleats.
        /// If source OnErrors, or limitedSequence on errors, then no further items will be processed. Once all ongoing sequences complete, the
        /// first OnError will be passed on to the resulting sequence.
        /// </remarks>
        public static IObservable <U> LimitGlobally <T, U>(this IObservable <T> source, Func <IObservable <T>, IObservable <U> > limitedSequence, LimitGlobalCounter limitter, IScheduler sched = null)
        {
            // Use the default scheduler.
            sched = sched ?? Scheduler.Default;

            return(from item in source.ObserveOn(sched)
                   from resultItem in
                   (from limited in Observable.FromAsync(() => { Debug.WriteLine("Getting"); return limitter.WaitAsync(); }).WriteLine("Got")
                    from convertedItem in limitedSequence(Observable.Return(item))
                    select convertedItem).Finally(() => { Debug.WriteLine("Releasing"); limitter.Release(); })
                   select resultItem);

#if false
            // Create an observable that will track the various things that go wrong
            return(Observable.Create <U>(o =>
            {
                var cancel = new CancellationDisposable();             // Monitor a cancel that comes along.
                var queue = new ConcurrentQueue <Notification <T> >(); // Everything that comes in get queued up as a materialized item

                Notification <U> limitSequenceError = null;            // See failure symantics above
                Notification <T> sourceSequenceEndCondition = null;
                int pendingAccepts = 0;
                var subscription = source.Materialize()
                                   .Where(_ => !cancel.Token.IsCancellationRequested)
                                   .SelectMany(v => Observable.FromAsync(() => limitter.WaitAsync(cancel.Token)).WriteLine("Just past limiter with {0}", v.ToString()).Select(_ => v))
                                   .Subscribe(n =>
                {
                    Interlocked.Increment(ref pendingAccepts);

                    // If we are in error condition, don't pump anything more through.
                    if (limitSequenceError != null || sourceSequenceEndCondition != null)
                    {
                        Interlocked.Decrement(ref pendingAccepts);
                        limitter.Release();
                        return;
                    }

                    queue.Enqueue(n);
                    sched.Schedule(() =>
                    {
                        try
                        {
                            Notification <T> notification;
                            queue.TryDequeue(out notification);
                            Debug.WriteLine("About to process notification {0}", notification.ToString());
                            if (notification.Kind == NotificationKind.OnNext || notification.Kind == NotificationKind.OnError)
                            {
                                var sub = new Subject <T>();
                                var seq = limitedSequence(sub).Materialize().Subscribe(
                                    result =>
                                {
                                    Debug.WriteLine("Getting item from function sequence {0}", result.ToString());
                                    // Did an error happen, or a completion happen before the source completed?
                                    // Ignore the completion - that is "normal".
                                    if (result.Kind == NotificationKind.OnError && limitSequenceError == null)
                                    {
                                        limitSequenceError = result;
                                    }
                                    else if (result.Kind == NotificationKind.OnNext)
                                    {
                                        result.Accept(o);
                                    }
                                },
                                    () =>
                                {
                                    // Our finally for this one. If this is the last one to get cleaned up, then we
                                    // move on.
                                    Debug.WriteLine("Function sequence has terminated! Releasing semaphore");
                                    limitter.Release();
                                    if (Interlocked.Decrement(ref pendingAccepts) == 0) // try to go lock-free a long a possible
                                    {
                                        lock (queue)                                    // take the queue as gate (only one thread should accept final notification)
                                        {
                                            if (pendingAccepts == 0)
                                            {
                                                if (limitSequenceError != null)
                                                {
                                                    // Something went wrong, terminate early!
                                                    Debug.WriteLine("Going to pass error onto external sequence");
                                                    limitSequenceError.Accept(o);
                                                    limitSequenceError = null;
                                                }
                                                else if (sourceSequenceEndCondition != null)
                                                {
                                                    // We are done, so terminate.
                                                    Debug.WriteLine("Going to pass on completed to external sequence");
                                                    o.OnCompleted();
                                                }
                                            }
                                        }
                                    }
                                }
                                    );
                                Debug.WriteLine("Going to pass notification to sequence {0}", notification.ToString());
                                notification.Accept(sub);
                                sub.OnCompleted();
                            }
                            else
                            {
                                // The sequence has terminated "normally".
                                Debug.WriteLine("Input sequence has terminated normally.");
                                Debug.Assert(sourceSequenceEndCondition == null);
                                sourceSequenceEndCondition = notification;
                                limitter.Release();
                                if (Interlocked.Decrement(ref pendingAccepts) == 0)
                                {
                                    lock (queue)
                                    {
                                        if (pendingAccepts == 0)
                                        {
                                            Debug.WriteLine("Going to pass completed onto external sequence");
                                            o.OnCompleted();
                                        }
                                    }
                                }
                            }
                        }
                        catch (Exception e)
                        {
                            Debug.WriteLine("Erorr on LimitGlobally: no error should ever make it here: {0}", e.Message);
                        }
                    });
                },
                                              () => {
                    Debug.WriteLine("Completed Source Sequence pending is {0}", pendingAccepts);
                });
                return new CompositeDisposable(cancel, subscription);
            }));
#endif
        }