Exemplo n.º 1
0
    def subscribe(observer, scheduler=None):
        window = [Subject()]
        d = CompositeDisposable()
        r = RefCountDisposable(d)

        observer.on_next(add_ref(window[0], r))

        def on_next_window(x):
            window[0].on_next(x)

        def on_error(err):
            window[0].on_error(err)
            observer.on_error(err)

        def on_completed():
            window[0].on_completed()
            observer.on_completed()

        d.add(source.subscribe_(on_next_window, on_error, on_completed, scheduler))

        def on_next_observer(w):
            window[0].on_completed()
            window[0] = Subject()
            observer.on_next(add_ref(window[0], r))

        d.add(window_boundaries.subscribe_(on_next_observer, on_error, on_completed, scheduler))
        return r
Exemplo n.º 2
0
    def _subscribe_core(self, observer=None, scheduler=None) -> typing.Disposable:
        clock = self.scheduler.to_seconds(self.scheduler.now)
        self.subscriptions.append(Subscription(clock))
        index = len(self.subscriptions) - 1
        disp = CompositeDisposable()

        def get_action(notification):
            def action(scheduler, state):
                notification.accept(observer)
                return Disposable()
            return action

        for message in self.messages:
            notification = message.value

            # Don't make closures within a loop
            action = get_action(notification)
            disp.add(self.scheduler.schedule_relative(message.time, action))

        def dispose() -> None:
            start = self.subscriptions[index].subscribe
            end = self.scheduler.to_seconds(self.scheduler.now)
            self.subscriptions[index] = Subscription(start, end)
            disp.dispose()

        return Disposable(dispose)
Exemplo n.º 3
0
        def subscribe(observer, scheduler=None):
            group = CompositeDisposable()
            is_stopped = [False]
            m = SingleAssignmentDisposable()
            group.add(m)

            def on_next(inner_source):
                inner_subscription = SingleAssignmentDisposable()
                group.add(inner_subscription)

                inner_source = from_future(inner_source) if is_future(inner_source) else inner_source

                @synchronized(source.lock)
                def on_completed():
                    group.remove(inner_subscription)
                    if is_stopped[0] and len(group) == 1:
                        observer.on_completed()

                on_next = synchronized(source.lock)(observer.on_next)
                on_error = synchronized(source.lock)(observer.on_error)
                subscription = inner_source.subscribe_(on_next, on_error, on_completed, scheduler)
                inner_subscription.disposable = subscription

            def on_completed():
                is_stopped[0] = True
                if len(group) == 1:
                    observer.on_completed()

            m.disposable = source.subscribe_(on_next, observer.on_error, on_completed, scheduler)
            return group
Exemplo n.º 4
0
        def subscribe(observer, scheduler=None):

            was_invoked = [False]

            def on_completed():
                observer.on_completed()
                try:
                    if not was_invoked[0]:
                        finally_action()
                        was_invoked[0] = True
                except Exception as err:  # pylint: disable=broad-except
                    observer.on_error(err)

            def on_error(exception):
                observer.on_error(exception)
                try:
                    if not was_invoked[0]:
                        finally_action()
                        was_invoked[0] = True
                except Exception as err:  # pylint: disable=broad-except
                    observer.on_error(err)

            composite_disposable = CompositeDisposable()
            composite_disposable.add(OnDispose(was_invoked))
            subscription = source.subscribe_(observer.on_next, on_error, on_completed, scheduler)
            composite_disposable.add(subscription)

            return composite_disposable
Exemplo n.º 5
0
        def subscribe(observer, scheduler_=None):
            _scheduler = scheduler or scheduler_ or timeout_scheduler

            n = [0]
            s = [None]
            timer_d = SerialDisposable()
            window_id = [0]
            group_disposable = CompositeDisposable(timer_d)
            ref_count_disposable = RefCountDisposable(group_disposable)

            def create_timer(_id):
                m = SingleAssignmentDisposable()
                timer_d.disposable = m

                def action(scheduler, state):
                    if _id != window_id[0]:
                        return

                    n[0] = 0
                    window_id[0] += 1
                    new_id = window_id[0]
                    s[0].on_completed()
                    s[0] = Subject()
                    observer.on_next(add_ref(s[0], ref_count_disposable))
                    create_timer(new_id)

                m.disposable = _scheduler.schedule_relative(timespan, action)

            s[0] = Subject()
            observer.on_next(add_ref(s[0], ref_count_disposable))
            create_timer(0)

            def on_next(x):
                new_window = False
                new_id = 0

                s[0].on_next(x)
                n[0] += 1
                if n[0] == count:
                    new_window = True
                    n[0] = 0
                    window_id[0] += 1
                    new_id = window_id[0]
                    s[0].on_completed()
                    s[0] = Subject()
                    observer.on_next(add_ref(s[0], ref_count_disposable))

                if new_window:
                    create_timer(new_id)

            def on_error(e):
                s[0].on_error(e)
                observer.on_error(e)

            def on_completed():
                s[0].on_completed()
                observer.on_completed()

            group_disposable.add(source.subscribe_(on_next, on_error, on_completed, scheduler_))
            return ref_count_disposable
Exemplo n.º 6
0
        def subscribe(observer, scheduler=None):
            is_open = [False]

            def on_next(left):
                if is_open[0]:
                    observer.on_next(left)

            def on_completed():
                if is_open[0]:
                    observer.on_completed()

            subs = source.subscribe_(on_next, observer.on_error, on_completed, scheduler)
            subscriptions = CompositeDisposable(subs)

            right_subscription = SingleAssignmentDisposable()
            subscriptions.add(right_subscription)

            def on_next2(x):
                is_open[0] = True
                right_subscription.dispose()

            def on_completed2():
                right_subscription.dispose()

            right_subscription.disposable = other.subscribe_(on_next2, observer.on_error, on_completed2, scheduler)

            return subscriptions
Exemplo n.º 7
0
    def run(self):
      srcs = list(self.parent.sources)

      N = len(srcs)

      self.queues = [None] * N
      self.isDone = [False] * N
      self.subscriptions = [None] * N
      self.gate = RLock()

      for i in range(0, N):
        self.queues[i] = deque()

      # Loop twice because subscribing could already yield
      # a value before all queues are initialized
      for i in range(0, N):
        d = SingleAssignmentDisposable()
        self.subscriptions[i] = d

        o = self.O(self, i)
        d.disposable = srcs[i].subscribeSafe(o)

      c = CompositeDisposable(self.subscriptions)

      def dispose():
        for q in self.queues:
          q.clear()

      c.add(Disposable.create(dispose))

      return c
Exemplo n.º 8
0
def test_groupdisposable_clear():
    disp1 = [False]
    disp2 = [False]
    def action1():
        disp1[0] = True
    d1 = Disposable(action1)

    def action2():
        disp2[0] = True
    d2 = Disposable(action2)

    g = CompositeDisposable(d1, d2)
    assert g.length == 2

    g.clear()
    assert disp1[0]
    assert disp2[0]
    assert not g.length

    disp3 = [False]
    def action3():
        disp3[0] = True
    d3 = Disposable(action3)
    g.add(d3);
    assert not disp3[0]
    assert g.length == 1
Exemplo n.º 9
0
def test_groupdisposable_contains():
    d1 = Disposable()
    d2 = Disposable()

    g = CompositeDisposable(d1, d2)

    assert g.length == 2
    assert g.contains(d1)
    assert g.contains(d2)
Exemplo n.º 10
0
    def run(self):
      self.gate = RLock()

      groupDisposable = CompositeDisposable()
      self.refCountDisposable = RefCountDisposable(groupDisposable)

      self.createWindow()

      groupDisposable.add(self.parent.scheduler.schedulePeriodic(self.parent.timeSpan, self.tick))
      groupDisposable.add(self.parent.source.subscribeSafe(self))

      return self.refCountDisposable
Exemplo n.º 11
0
def test_groupdisposable_remove():
    disp1 = [False]
    disp2 = [False]

    def action1():
        disp1[0] = True
    d1 = Disposable(action1)

    def action2():
        disp2[0] = True
    d2 = Disposable(action2)

    g = CompositeDisposable(d1, d2)

    assert g.length == 2
    assert g.contains(d1)
    assert g.contains(d2)
    assert g.remove(d1)
    assert g.length == 1
    assert not g.contains(d1)
    assert g.contains(d2)
    assert disp1[0]
    assert g.remove(d2)
    assert not g.contains(d1)
    assert not g.contains(d2)
    assert disp2[0]

    disp3 = [False]

    def action3():
        disp3[0] = True
    d3 = Disposable(action3)
    assert not g.remove(d3)
    assert not disp3[0]
Exemplo n.º 12
0
    def _qtimer_schedule(self, time, action, state, periodic=False):
        scheduler = self
        msecs = int(self.to_seconds(time)*1000.0)

        sad = SingleAssignmentDisposable()

        periodic_state = [state]

        def interval():
            if periodic:
                periodic_state[0] = action(periodic_state[0])
            else:
                sad.disposable = action(scheduler, state)

        log.debug("timeout: %s", msecs)

        timer = self.qtcore.QTimer()
        timer.setSingleShot(not periodic)
        timer.timeout.connect(interval)
        timer.setInterval(msecs)
        timer.start()
        self._timers.add(timer)

        def dispose():
            timer.stop()
            self._timers.remove(timer)

        return CompositeDisposable(sad, Disposable(dispose))
Exemplo n.º 13
0
    def _wxtimer_schedule(self, time, action, state, periodic=False):
        scheduler = self

        sad = SingleAssignmentDisposable()

        periodic_state = [state]

        def interval():
            if periodic:
                periodic_state[0] = action(periodic_state[0])
            else:
                sad.disposable = action(scheduler, state)

        msecs = int(self.to_seconds(time) * 1000.0)
        if msecs == 0:
            msecs = 1  # wx.Timer doesn't support zero.

        log.debug("timeout: %s", msecs)

        timer = self._timer_class(interval)
        timer.Start(
            msecs,
            self.wx.TIMER_CONTINUOUS if periodic else self.wx.TIMER_ONE_SHOT)
        self._timers.add(timer)

        def dispose():
            timer.Stop()
            self._timers.remove(timer)

        return CompositeDisposable(sad, Disposable(dispose))
Exemplo n.º 14
0
    def _gtk_schedule(self,
                      time: typing.AbsoluteOrRelativeTime,
                      action: typing.ScheduledSingleOrPeriodicAction,
                      state: Optional[typing.TState] = None,
                      periodic: bool = False) -> typing.Disposable:

        msecs = max(0, int(self.to_seconds(time) * 1000.0))

        sad = SingleAssignmentDisposable()

        stopped = False

        def timer_handler(_) -> bool:
            if stopped:
                return False

            nonlocal state
            if periodic:
                state = action(state)
            else:
                sad.disposable = self.invoke_action(action, state=state)

            return periodic

        self._glib.timeout_add(msecs, timer_handler, None)

        def dispose() -> None:
            nonlocal stopped
            stopped = True

        return CompositeDisposable(sad, Disposable(dispose))
Exemplo n.º 15
0
        def unsafe_subscribe(
                self,
                subscriber: MultiCastSubscriber) -> MultiCastSubscription:
            def on_completed():
                for subject in imperative_call.subjects:
                    subject.on_completed()

            def on_error(exc: Exception):
                for subject in imperative_call.subjects:
                    subject.on_error(exc)

            composite_disposable_ = composite_disposable or CompositeDisposable(
            )

            builder = ImperativeMultiCastBuilder(
                composite_disposable=composite_disposable_,
                subscriber=subscriber,
                # source_scheduler=subscriber.source_scheduler,
                # multicast_scheduler=subscriber.multicast_scheduler,
            )

            imperative_call = func(builder)

            flowable = imperative_call.blocking_flowable.pipe(
                rxbp.op.do_action(
                    on_disposed=lambda: composite_disposable_.dispose(),
                    on_completed=on_completed,
                    on_error=on_error,
                ), ).materialize().share()

            return imperative_call.output_selector(
                flowable, ).unsafe_subscribe(subscriber=subscriber)
class FromFlowableMultiCastObserver(Observer):
    next_observer: MultiCastObserver
    subscriber: MultiCastSubscriber
    composite_disposable: CompositeDisposable()

    def on_next(self, elem: MultiCastItem) -> Ack:
        def scheduler_action():
            def action(_, __):
                try:
                    self.next_observer.on_next(elem)
                    self.next_observer.on_completed()
                except Exception as exc:
                    self.next_observer.on_error(exc)
            return self.subscriber.subscribe_schedulers[1].schedule(action)

        disposable = self.subscriber.schedule_action(
            index=0,
            action=scheduler_action,
        )
        self.composite_disposable.add(disposable)

        return continue_ack

    def on_error(self, exc: Exception) -> None:
        self.next_observer.on_error(exc)

    def on_completed(self) -> None:
        self.next_observer.on_completed()
Exemplo n.º 17
0
        def on_subscribe(observer, scheduler=None):
            def subscribe_all(parent, *children):
                parent_subscription = SingleAssignmentDisposable()
                values = [NO_VALUE for _ in children]

                def on_parent_next(value):
                    if NO_VALUE not in values:
                        result = (value, ) + tuple(values)
                        observer.on_next(result)

                def subscribe_child(i, child):
                    subscription = SingleAssignmentDisposable()

                    def on_next(value):
                        values[i] = value

                        if NO_VALUE not in values and parent_subscription.disposable is None:
                            disp = parent.subscribe(on_parent_next,
                                                    observer.on_error,
                                                    observer.on_completed,
                                                    scheduler=scheduler)
                            parent_subscription.disposable = disp

                    subscription.disposable = child.subscribe(
                        on_next, observer.on_error, scheduler=scheduler)
                    return subscription

                children_subscription = [
                    subscribe_child(i, child)
                    for i, child in enumerate(children)
                ]

                return [parent_subscription] + children_subscription

            return CompositeDisposable(subscribe_all(parent, *sources))
Exemplo n.º 18
0
    def schedule_relative(
            self,
            duetime: typing.RelativeTime,
            action: typing.ScheduledAction,
            state: Optional[typing.TState] = None) -> typing.Disposable:
        """Schedules an action to be executed after duetime.

        Args:
            duetime: Relative time after which to execute the action.
            action: Action to be executed.
            state: [Optional] state to be given to the action function.

        Returns:
            The disposable object used to cancel the scheduled action
            (best effort).
        """

        seconds = max(0.0, self.to_seconds(duetime))

        sad = SingleAssignmentDisposable()

        def interval() -> None:
            sad.disposable = action(self, state)

        log.debug("timeout: %s", seconds)
        timer = self._reactor.callLater(seconds, interval)

        def dispose() -> None:
            if not timer.called:
                timer.cancel()

        return CompositeDisposable(sad, Disposable(dispose))
Exemplo n.º 19
0
    def schedule_relative(self,
                          duetime: typing.RelativeTime,
                          action: typing.ScheduledAction,
                          state: typing.TState = None) -> typing.Disposable:
        """Schedules an action to be executed after duetime.

        Args:
            duetime: Relative time after which to execute the action.
            action: Action to be executed.

        Returns:
            The disposable object used to cancel the scheduled action
            (best effort).
        """

        seconds = self.to_seconds(duetime)
        if not seconds:
            return self.schedule(action, state)

        sad = SingleAssignmentDisposable()

        def interval():
            sad.disposable = self.invoke_action(action, state)

        timer = [eventlet.spawn_after(seconds, interval)]

        def dispose():
            # nonlocal timer
            timer[0].kill()

        return CompositeDisposable(sad, Disposable(dispose))
Exemplo n.º 20
0
    def schedule_relative(self,
                          duetime: typing.RelativeTime,
                          action: typing.ScheduledAction,
                          state: Optional[typing.TState] = None
                          ) -> typing.Disposable:
        """Schedules an action to be executed after duetime.

        Args:
            duetime: Relative time after which to execute the action.
            action: Action to be executed.
            state: [Optional] state to be given to the action function.

        Returns:
            The disposable object used to cancel the scheduled action
            (best effort).
        """

        sad = SingleAssignmentDisposable()

        def invoke_action() -> None:
            sad.disposable = self.invoke_action(action, state=state)

        msecs = int(self.to_seconds(duetime) * 1000.0)
        alarm = self.master.after(msecs, invoke_action)

        def dispose() -> None:
            self.master.after_cancel(alarm)

        return CompositeDisposable(sad, Disposable(dispose))
Exemplo n.º 21
0
    def subscribe(observer, scheduler=None):
        at_end = [None]
        has_value = [None]
        value = [None]

        def sample_subscribe(x=None):
            if has_value[0]:
                has_value[0] = False
                observer.on_next(value[0])

            if at_end[0]:
                observer.on_completed()

        def on_next(new_value):
            has_value[0] = True
            value[0] = new_value

        def on_completed():
            at_end[0] = True

        return CompositeDisposable(
            source.subscribe_(on_next, observer.on_error, on_completed,
                              scheduler),
            sampler.subscribe_(sample_subscribe, observer.on_error,
                               sample_subscribe, scheduler))
Exemplo n.º 22
0
    def observe(self, observer_info: ObserverInfo):
        """
        sources[0] ------------------------> Subject --
                                                       \
        sources[1] -> ConnectableObserver -> Subject -----> ConcatObserver
        ...                                            /
        sources[n] -> ConnectableObserver -> Subject --
        """

        conn_observers = [
            ConnectableObserver(underlying=None, ) for _ in self.sources
        ]

        iter_conn_obs = iter(conn_observers)

        concat_observer = ConcatObserver(
            next_observer=observer_info.observer,
            connectables=iter_conn_obs,
        )

        for conn_observer in conn_observers:
            conn_observer.underlying = concat_observer

        def gen_disposable_from_observer():
            for source, conn_observer in zip(self.sources[1:], conn_observers):
                yield source.observe(
                    observer_info.copy(observer=conn_observer, ))

        others_disposables = gen_disposable_from_observer()

        first_disposable = self.sources[0].observe(
            observer_info.copy(observer=concat_observer, ))

        return CompositeDisposable(first_disposable, *others_disposables)
Exemplo n.º 23
0
def from_marbles(string: str,
                 timespan: RelativeTime = 0.1,
                 lookup: Dict = None,
                 error: Exception = None,
                 scheduler: Scheduler = None) -> Observable:

    disp = CompositeDisposable()
    messages = parse(string,
                     timespan=timespan,
                     lookup=lookup,
                     error=error,
                     raise_stopped=True)

    def schedule_msg(message, observer, scheduler):
        timespan, notification = message

        def action(scheduler, state=None):
            notification.accept(observer)

        disp.add(scheduler.schedule_relative(timespan, action))

    def subscribe(observer, scheduler_):
        _scheduler = scheduler or scheduler_ or new_thread_scheduler

        for message in messages:
            # Don't make closures within a loop
            schedule_msg(message, observer, _scheduler)

        return disp

    return Observable(subscribe)
Exemplo n.º 24
0
        def subscribe(observer, scheduler=None) -> Disposable:
            cancelable = SerialDisposable()
            has_value = [False]
            value = [None]
            _id = [0]

            def on_next(x):
                throttle = None
                try:
                    throttle = throttle_duration_mapper(x)
                except Exception as e:  # pylint: disable=broad-except
                    observer.on_error(e)
                    return

                has_value[0] = True
                value[0] = x
                _id[0] += 1
                current_id = _id[0]
                d = SingleAssignmentDisposable()
                cancelable.disposable = d

                def on_next(x: Any) -> None:
                    if has_value[0] and _id[0] == current_id:
                        observer.on_next(value[0])

                    has_value[0] = False
                    d.dispose()

                def on_completed() -> None:
                    if has_value[0] and _id[0] == current_id:
                        observer.on_next(value[0])

                    has_value[0] = False
                    d.dispose()

                d.disposable = throttle.subscribe_(on_next,
                                                   observer.on_error,
                                                   on_completed,
                                                   scheduler=scheduler)

            def on_error(e) -> None:
                cancelable.dispose()
                observer.on_error(e)
                has_value[0] = False
                _id[0] += 1

            def on_completed() -> None:
                cancelable.dispose()
                if has_value[0]:
                    observer.on_next(value[0])

                observer.on_completed()
                has_value[0] = False
                _id[0] += 1

            subscription = source.subscribe_(on_next,
                                             on_error,
                                             on_completed,
                                             scheduler=scheduler)
            return CompositeDisposable(subscription, cancelable)
Exemplo n.º 25
0
    def schedule_relative(self,
                          duetime: RelativeTime,
                          action: ScheduledAction,
                          state: TState = None):
        """Schedules an action to be executed after duetime.
        """

        duetime = int(self.to_seconds(duetime) * 1000.0)

        if duetime <= 0:
            return self.schedule(action, state)

        scheduler = self
        is_disposed = False
        sad = SingleAssignmentDisposable()

        def invoke_action():
            if not is_disposed:
                sad.disposable = action(scheduler, state)

        def dispose():
            nonlocal is_disposed
            is_disposed = True

        self._post(SCHEDULE_RELATIVE, invoke_action, duetime)

        return CompositeDisposable(sad, Disposable(dispose))
Exemplo n.º 26
0
    def schedule_relative(self,
                          duetime: typing.RelativeTime,
                          action: typing.ScheduledAction,
                          state: typing.TState = None) -> typing.Disposable:
        """Schedules an action to be executed after duetime.

        Args:
            duetime: Relative time after which to execute the action.
            action: Action to be executed.

        Returns:
            The disposable object used to cancel the scheduled action
            (best effort).
        """
        scheduler = self
        msecs = int(self.to_seconds(duetime) * 1000.0)
        sad = SingleAssignmentDisposable()
        is_disposed = False

        def invoke_action():
            if not is_disposed:
                sad.disposable = action(scheduler, state)

        log.debug("relative timeout: %sms", msecs)

        # Use static method, let Qt C++ handle QTimer lifetime
        self.qtcore.QTimer.singleShot(msecs, invoke_action)

        def dispose():
            nonlocal is_disposed
            is_disposed = True

        return CompositeDisposable(sad, Disposable(dispose))
Exemplo n.º 27
0
    def subscribe(observer, scheduler=None):
        scheduler = scheduler or current_thread_scheduler

        subscription = SerialDisposable()
        cancelable = SerialDisposable()
        last_exception = [None]
        is_disposed = []

        def action(action1, state=None):
            def on_error(exn):
                last_exception[0] = exn
                cancelable.disposable = scheduler.schedule(action)

            if is_disposed:
                return

            try:
                current = next(sources)
            except StopIteration:
                if last_exception[0]:
                    observer.on_error(last_exception[0])
                else:
                    observer.on_completed()
            except Exception as ex:  # pylint: disable=broad-except
                observer.on_error(ex)
            else:
                d = SingleAssignmentDisposable()
                subscription.disposable = d
                d.disposable = current.subscribe_(observer.on_next, on_error, observer.on_completed, scheduler)

        cancelable.disposable = scheduler.schedule(action)

        def dispose():
            is_disposed.append(True)
        return CompositeDisposable(subscription, cancelable, Disposable(dispose))
Exemplo n.º 28
0
    def schedule(self,
                 action: typing.ScheduledAction,
                 state: Optional[typing.TState] = None
                 ) -> typing.Disposable:
        """Schedules an action to be executed.

        Args:
            action: Action to be executed.
            state: [Optional] state to be given to the action function.

        Returns:
            The disposable object used to cancel the scheduled action
            (best effort).
        """
        sad = SingleAssignmentDisposable()

        def interval() -> None:
            sad.disposable = self.invoke_action(action, state=state)

        handle = self._loop.call_soon_threadsafe(interval)

        def dispose() -> None:
            future = Future()

            def cancel_handle() -> None:
                handle.cancel()
                future.set_result(0)

            self._loop.call_soon_threadsafe(cancel_handle)
            future.result()

        return CompositeDisposable(sad, Disposable(dispose))
Exemplo n.º 29
0
    def subscribe(
            observer: typing.Observer,
            scheduler_: Optional[typing.Scheduler] = None
    ) -> typing.Disposable:
        _scheduler = scheduler or scheduler_ or CurrentThreadScheduler.singleton(
        )
        iterator = iter(iterable)
        disposed = False

        def action(_: typing.Scheduler, __: Any = None) -> None:
            nonlocal disposed

            try:
                while not disposed:
                    value = next(iterator)
                    observer.on_next(value)
            except StopIteration:
                observer.on_completed()
            except Exception as error:  # pylint: disable=broad-except
                observer.on_error(error)

        def dispose() -> None:
            nonlocal disposed
            disposed = True

        disp = Disposable(dispose)
        return CompositeDisposable(_scheduler.schedule(action), disp)
Exemplo n.º 30
0
    def observe(self, observer_info: ObserverInfo):
        self.observer = observer_info.observer

        class ZipLeftObserver(Observer):
            def on_next(_, elem: ElementType) -> Ack:
                return self._on_next_left(elem)

            def on_error(_, exc: Exception):
                self._on_error(exc)

            def on_completed(_):
                self._on_completed_left()

        class ZipRightObserver(Observer):
            def on_next(_, elem: ElementType) -> Ack:
                return self._on_next_right(elem)

            def on_error(_, exc: Exception):
                self._on_error(exc)

            def on_completed(_):
                self._on_completed_right()

        left_observer = ZipLeftObserver()
        left_subscription = observer_info.copy(observer=left_observer, )
        d1 = self.left.observe(left_subscription)

        right_observer = ZipRightObserver()
        right_subscription = observer_info.copy(observer=right_observer, )
        d2 = self.right.observe(right_subscription)

        return CompositeDisposable(d1, d2)
Exemplo n.º 31
0
    def schedule_relative(self, duetime, action, state=None):
        """Schedules an action to be executed after duetime.

        Keyword arguments:
        duetime -- {timedelta} Relative time after which to execute the action.
        action -- {Function} Action to be executed.

        Returns {Disposable} The disposable object used to cancel the scheduled
        action (best effort)."""

        scheduler = self
        seconds = self.to_seconds(duetime)
        if not seconds:
            return scheduler.schedule(action, state)

        sad = SingleAssignmentDisposable()

        def interval():
            sad.disposable = action(scheduler, state)

        log.debug("timeout: %s", seconds)
        timer = [gevent.spawn_later(seconds, interval)]

        def dispose():
            # nonlocal timer
            timer[0].kill()

        return CompositeDisposable(sad, Disposable(dispose))
Exemplo n.º 32
0
    def schedule_relative(
            self,
            duetime: RelativeTime,
            action,
            state=None,
    ):
        if isinstance(duetime, datetime.datetime):
            timedelta = duetime - datetime.datetime.fromtimestamp(0)
            timespan = float(timedelta.total_seconds())
        elif isinstance(duetime, datetime.timedelta):
            timespan = float(duetime.total_seconds())
        else:
            timespan = duetime

        def func():
            action(self, None)

        disposable = [MultipleAssignmentDisposable()]

        def _():
            def __():
                future = self.executor.submit(func)
                disposable[0] = Disposable(lambda: future.cancel())
            self.loop.call_later(timespan, __)

        future = self.loop.call_soon_threadsafe(_)
        return CompositeDisposable(disposable, Disposable(lambda: future.cancel()))
Exemplo n.º 33
0
    def schedule_relative(self,
                          duetime: typing.RelativeTime,
                          action: typing.ScheduledAction,
                          state: Optional[typing.TState] = None
                          ) -> typing.Disposable:
        """Schedules an action to be executed after duetime.

        Args:
            duetime: Relative time after which to execute the action.
            action: Action to be executed.
            state: [Optional] state to be given to the action function.

        Returns:
            The disposable object used to cancel the scheduled action
            (best effort).
        """

        from twisted.internet.task import deferLater

        seconds = self.to_seconds(duetime)

        sad = SingleAssignmentDisposable()

        def interval() -> None:
            sad.disposable = action(self, state)

        log.debug("timeout: %s", seconds)
        handle = deferLater(self.reactor, seconds, interval).addErrback(lambda _: None)

        def dispose() -> None:
            if not handle.called:
                handle.cancel()

        return CompositeDisposable(sad, Disposable(dispose))
Exemplo n.º 34
0
    def observe(self, observer_info: ObserverInfo):
        observer_info = observer_info.observer

        d1 = BooleanDisposable()

        def action(_, __):
            try:
                item = next(self.iterator)
                has_next = True
            except StopIteration:
                has_next = False
            except Exception as e:
                # stream errors
                observer_info.on_error(e)
                return Disposable()

            if not has_next:
                observer_info.on_completed()
            else:
                # start sending items
                self.fast_loop(item,
                               observer_info,
                               self.scheduler,
                               d1,
                               self.scheduler.get_execution_model(),
                               sync_index=0)

        d2 = self.subscribe_scheduler.schedule(action)
        return CompositeDisposable(d1, d2)
Exemplo n.º 35
0
    def schedule_relative(
            self,
            duetime: typing.RelativeTime,
            action: typing.ScheduledAction,
            state: Optional[typing.TState] = None) -> typing.Disposable:
        """Schedules an action to be executed after duetime.

        Args:
            duetime: Relative time after which to execute the action.
            action: Action to be executed.
            state: [Optional] state to be given to the action function.

        Returns:
            The disposable object used to cancel the scheduled action
            (best effort).
        """

        seconds = self.to_seconds(duetime)
        if seconds <= 0.0:
            return self.schedule(action, state)

        sad = SingleAssignmentDisposable()

        def interval() -> None:
            sad.disposable = self.invoke_action(action, state)

        timer = Timer(seconds, interval)
        timer.daemon = True
        timer.start()

        def dispose() -> None:
            timer.cancel()

        return CompositeDisposable(sad, Disposable(dispose))
Exemplo n.º 36
0
        def run(self):
            self.scheduler = self.parent.scheduler

            self.cancelTimer = SerialDisposable()

            self.gate = RLock()
            self.active = False  # as soon as a value arrived
            self.running = False  # on relative: True, on absolute: True after absolute time
            self.queue = deque()
            self.hasCompleted = False
            self.completeAt = 0
            self.hasFailed = False
            self.exception = None

            self.delay = 0
            self.startTime = self.scheduler.now()

            if self.parent.isAbsolute:
                self.ready = False
                self.cancelTimer.disposable = self.scheduler.scheduleWithAbsolute(
                    self.parent.dueTime, self.start)
            else:
                self.ready = True
                self.delay = Scheduler.normalize(self.parent.dueTime)

            self.sourceSubscription = SingleAssignmentDisposable()
            self.sourceSubscription.disposable = self.parent.source.subscribeSafe(
                self)

            return CompositeDisposable(self.sourceSubscription,
                                       self.cancelTimer)
Exemplo n.º 37
0
    def _gtk_schedule(self,
                      time: typing.AbsoluteOrRelativeTime,
                      action: typing.ScheduledSingleOrPeriodicAction,
                      state: Optional[typing.TState] = None,
                      periodic: bool = False) -> typing.Disposable:
        # Do not import GLib into global scope because Qt and GLib
        # don't like each other there
        from gi.repository import GLib

        msecs = int(self.to_seconds(time) * 1000.0)

        sad = SingleAssignmentDisposable()

        periodic_state = state
        stopped = False

        def timer_handler(_) -> bool:
            if stopped:
                return False

            if periodic:
                nonlocal periodic_state
                periodic_state = action(periodic_state)
            else:
                sad.disposable = self.invoke_action(action, state=state)

            return periodic

        GLib.timeout_add(msecs, timer_handler, None)

        def dispose() -> None:
            nonlocal stopped
            stopped = True

        return CompositeDisposable(sad, Disposable(dispose))
Exemplo n.º 38
0
    def schedule(self,
                 action: typing.ScheduledAction,
                 state: Optional[typing.TState] = None) -> typing.Disposable:
        """Schedules an action to be executed.

        Args:
            action: Action to be executed.
            state: [Optional] state to be given to the action function.

        Returns:
            The disposable object used to cancel the scheduled action
            (best effort).
        """

        sad = SingleAssignmentDisposable()

        def interval() -> None:
            sad.disposable = self.invoke_action(action, state)

        timer = Timer(0, interval)
        timer.daemon = True
        timer.start()

        def dispose() -> None:
            timer.cancel()

        return CompositeDisposable(sad, Disposable(dispose))
Exemplo n.º 39
0
    def subscribe(observer, scheduler=None):

        scheduler = scheduler or current_thread_scheduler

        subscription = SerialDisposable()
        cancelable = SerialDisposable()

        def action(scheduler, state=None):
            try:
                source = next(sources_)
            except StopIteration:
                observer.on_completed()
                return

            # Allow source to be a factory method taking an error
            source = source(state) if callable(source) else source
            current = rx.from_future(source) if is_future(source) else source

            d = SingleAssignmentDisposable()
            subscription.disposable = d

            def on_resume(state=None):
                scheduler.schedule(action, state)

            d.disposable = current.subscribe_(observer.on_next, on_resume,
                                              on_resume, scheduler)

        cancelable.disposable = scheduler.schedule(action)
        return CompositeDisposable(subscription, cancelable)
Exemplo n.º 40
0
    def _wxtimer_schedule(self,
                          time: typing.AbsoluteOrRelativeTime,
                          action: typing.ScheduledSingleOrPeriodicAction,
                          state: Optional[typing.TState] = None,
                          periodic: bool = False) -> typing.Disposable:
        scheduler = self

        sad = SingleAssignmentDisposable()

        def interval() -> None:
            nonlocal state
            if periodic:
                state = action(state)
            else:
                sad.disposable = action(scheduler, state)

        msecs = int(self.to_seconds(time) * 1000.0)

        log.debug("timeout wx: %s", msecs)

        timer = self._timer_class(interval)
        timer.Start(
            msecs,
            self.wx.TIMER_CONTINUOUS if periodic else self.wx.TIMER_ONE_SHOT)
        self._timers.add(timer)

        def dispose() -> None:
            timer.Stop()
            self._timers.remove(timer)

        return CompositeDisposable(sad, Disposable(dispose))
Exemplo n.º 41
0
    def _gtk_schedule(self, time, action, state, periodic=False):
        # Do not import GLib into global scope because Qt and GLib
        # don't like each other there
        from gi.repository import GLib

        scheduler = self
        msecs = int(self.to_seconds(time)*1000)

        sad = SingleAssignmentDisposable()

        periodic_state = [state]
        stopped = [False]

        def timer_handler(_):
            if stopped[0]:
                return False

            if periodic:
                periodic_state[0] = action(periodic_state[0])
            else:
                sad.disposable = action(scheduler, state)

            return periodic

        GLib.timeout_add(msecs, timer_handler, None)

        def dispose():
            stopped[0] = True

        return CompositeDisposable(sad, Disposable(dispose))
Exemplo n.º 42
0
    def run(self):
      self.gate = RLock()
      self.s = Subject()
      self.n = 0
      self.windowId = 0

      self.timerDisposable = SerialDisposable()
      groupDisposable = CompositeDisposable(self.timerDisposable)
      self.refCountDisposable = RefCountDisposable(groupDisposable)

      # AddRef was originally WindowObservable but this is just an alias for AddRef
      self.observer.onNext(AddRef(self.s, self.refCountDisposable))
      self.createTimer(0)

      groupDisposable.add(self.parent.source.subscribeSafe(self))

      return self.refCountDisposable
Exemplo n.º 43
0
class RecursiveScheduledFunction(object):
  def __init__(self, action, scheduler, method = None):
    self.action = action
    self.group = CompositeDisposable()
    self.lock = RLock()

    if method == None:
      self.schedule = scheduler.scheduleWithState
    else:
      self.schedule = getattr(scheduler, method)

  def run(self, state):
    self.action(state, self.actionCallback)

  def actionCallback(self, newState, dueTime = None):
    self.isDone = False
    self.isAdded = False

    if dueTime == None:
      self.cancel = self.schedule(
        newState,
        self.schedulerCallback
      )
    else:
      self.cancel = self.schedule(
        newState,
        dueTime,
        self.schedulerCallback
      )

    with self.lock:
      if not self.isDone:
        self.group.add(self.cancel)
        self.isAdded = True

  def schedulerCallback(self, scheduler, state):
    with self.lock:
      if self.isAdded:
        self.group.remove(self.cancel)
      else:
        self.isDone = True

    self.run(state)

    return Disposable.empty()
Exemplo n.º 44
0
  def run(self, observer, cancel, setSink):
    self.groupDisposable = CompositeDisposable()
    self.refCountDisposable = RefCountDisposable(self.groupDisposable)

    sink = self.Sink(self, observer, cancel)
    setSink(sink)
    self.groupDisposable.add(self.source.subscribeSafe(sink))

    return self.refCountDisposable
Exemplo n.º 45
0
  def __init__(self, action, scheduler, method = None):
    self.action = action
    self.group = CompositeDisposable()
    self.lock = RLock()

    if method == None:
      self.schedule = scheduler.scheduleWithState
    else:
      self.schedule = getattr(scheduler, method)
Exemplo n.º 46
0
    def run(self):
      self.totalTime = 0
      self.nextShift = self.parent.timeShift
      self.nextSpan = self.parent.timeSpan

      self.gate = RLock()
      self.queue = deque()

      self.timerDisposable = SerialDisposable()

      groupDisposable = CompositeDisposable(self.timerDisposable)
      self.refCountDisposable = RefCountDisposable(groupDisposable)

      self.createWindow()
      self.createTimer()

      groupDisposable.add(self.parent.source.subscribeSafe(self))

      return self.refCountDisposable
Exemplo n.º 47
0
    def run(self):
      self.gate = RLock()
      self.isStopped = False
      self.group = CompositeDisposable()

      self.sourceSubscription = SingleAssignmentDisposable()
      self.group.add(self.sourceSubscription)
      self.sourceSubscription.disposable = self.parent.sources.subscribeSafe(self)

      return self.group
Exemplo n.º 48
0
    def run(self):
      self.delays = CompositeDisposable()
      self.gate = RLock()
      self.atEnd = False
      self.subscription = SerialDisposable()

      if self.parent.subscriptionDelay == None:
        self.start()
      else:
        self.subscription.disposable = self.parent.subscriptionDelay.subscribeSafe(self.Sigma(self))

      return CompositeDisposable(self.subscription, self.delays)
Exemplo n.º 49
0
    def subscribe(observer, scheduler=None):
        m = SerialDisposable()
        d = CompositeDisposable(m)
        r = RefCountDisposable(d)
        window = [Subject()]

        observer.on_next(add_ref(window[0], r))

        def on_next(value):
            window[0].on_next(value)

        def on_error(error):
            window[0].on_error(error)
            observer.on_error(error)

        def on_completed():
            window[0].on_completed()
            observer.on_completed()

        d.add(source.subscribe_(on_next, on_error, on_completed, scheduler))

        def create_window_on_completed():
            try:
                window_close = window_closing_mapper()
            except Exception as exception:
                observer.on_error(exception)
                return

            def on_completed():
                window[0].on_completed()
                window[0] = Subject()
                observer.on_next(add_ref(window[0], r))
                create_window_on_completed()

            m1 = SingleAssignmentDisposable()
            m.disposable = m1
            m1.disposable = window_close.pipe(ops.take(1)).subscribe_(noop, on_error, on_completed, scheduler)

        create_window_on_completed()
        return r
Exemplo n.º 50
0
def test_groupdisposable_addafterdispose():
    disp1 = [False]
    disp2 = [False]

    def action1():
        disp1[0] = True

    d1 = Disposable(action1)

    def action2():
        disp2[0] = True

    d2 = Disposable(action2)

    g = CompositeDisposable(d1)
    assert g.length == 1
    g.dispose()
    assert disp1[0]
    assert g.length == 0
    g.add(d2)
    assert disp2[0]
    assert g.length == 0
Exemplo n.º 51
0
        def subscribe(observer, scheduler=None):
            active_count = [0]
            group = CompositeDisposable()
            is_stopped = [False]
            queue = []

            def subscribe(xs):
                subscription = SingleAssignmentDisposable()
                group.add(subscription)

                @synchronized(source.lock)
                def on_completed():
                    group.remove(subscription)
                    if queue:
                        s = queue.pop(0)
                        subscribe(s)
                    else:
                        active_count[0] -= 1
                        if is_stopped[0] and active_count[0] == 0:
                            observer.on_completed()

                on_next = synchronized(source.lock)(observer.on_next)
                on_error = synchronized(source.lock)(observer.on_error)
                subscription.disposable = xs.subscribe_(on_next, on_error, on_completed, scheduler)

            def on_next(inner_source):
                if active_count[0] < max_concurrent:
                    active_count[0] += 1
                    subscribe(inner_source)
                else:
                    queue.append(inner_source)

            def on_completed():
                is_stopped[0] = True
                if active_count[0] == 0:
                    observer.on_completed()

            group.add(source.subscribe_(on_next, observer.on_error, on_completed, scheduler))
            return group
Exemplo n.º 52
0
        def subscribe(observer, scheduler=None):
            has_current = [False]
            is_stopped = [False]
            m = SingleAssignmentDisposable()
            g = CompositeDisposable()

            g.add(m)

            def on_next(inner_source):
                if not has_current[0]:
                    has_current[0] = True

                    inner_source = rx.from_future(inner_source) if is_future(inner_source) else inner_source

                    inner_subscription = SingleAssignmentDisposable()
                    g.add(inner_subscription)

                    def on_completed_inner():
                        g.remove(inner_subscription)
                        has_current[0] = False
                        if is_stopped[0] and len(g) == 1:
                            observer.on_completed()

                    inner_subscription.disposable = inner_source.subscribe_(
                        observer.on_next,
                        observer.on_error,
                        on_completed_inner,
                        scheduler
                    )

            def on_completed():
                is_stopped[0] = True
                if not has_current[0] and len(g) == 1:
                    observer.on_completed()

            m.disposable = source.subscribe_(on_next, observer.on_error, on_completed, scheduler)
            return g
Exemplo n.º 53
0
    def run(self):
      self.gate = RLock()
      self.group = CompositeDisposable()
      self.refCount = RefCountDisposable(self.group)

      leftSubscription = SingleAssignmentDisposable()
      self.group.add(leftSubscription)
      self.leftID = 0
      self.leftMap = {}

      rightSubscription = SingleAssignmentDisposable()
      self.group.add(rightSubscription)
      self.rightID = 0
      self.rightMap = {}

      leftSubscription.disposable = self.parent.left.subscribeSafe(self.Left(self, leftSubscription))
      rightSubscription.disposable = self.parent.right.subscribeSafe(self.Right(self, rightSubscription))

      return self.refCount
Exemplo n.º 54
0
        def subscribe(observer, scheduler=None):
            group = CompositeDisposable()
            rcd = RefCountDisposable(group)
            left_map = OrderedDict()
            right_map = OrderedDict()
            left_id = [0]
            right_id = [0]

            def on_next_left(value):
                subject = Subject()

                with left.lock:
                    _id = left_id[0]
                    left_id[0] += 1
                    left_map[_id] = subject

                try:
                    result = (value, add_ref(subject, rcd))
                except Exception as e:
                    log.error("*** Exception: %s" % e)
                    for left_value in left_map.values():
                        left_value.on_error(e)

                    observer.on_error(e)
                    return

                observer.on_next(result)

                for right_value in right_map.values():
                    subject.on_next(right_value)

                md = SingleAssignmentDisposable()
                group.add(md)

                def expire():
                    if _id in left_map:
                        del left_map[_id]
                        subject.on_completed()

                    group.remove(md)

                try:
                    duration = left_duration_mapper(value)
                except Exception as e:
                    for left_value in left_map.values():
                        left_value.on_error(e)

                    observer.on_error(e)
                    return

                def on_error(error):
                    for left_value in left_map.values():
                        left_value.on_error(error)

                    observer.on_error(error)

                md.disposable = duration.pipe(ops.take(1)).subscribe_(nothing, on_error, expire, scheduler)

            def on_error_left(error):
                for left_value in left_map.values():
                    left_value.on_error(error)

                observer.on_error(error)

            group.add(left.subscribe_(on_next_left, on_error_left, observer.on_completed, scheduler))

            def send_right(value):
                with left.lock:
                    _id = right_id[0]
                    right_id[0] += 1
                    right_map[_id] = value

                md = SingleAssignmentDisposable()
                group.add(md)

                def expire():
                    del right_map[_id]
                    group.remove(md)

                try:
                    duration = right_duration_mapper(value)
                except Exception as e:
                    for left_value in left_map.values():
                        left_value.on_error(e)

                    observer.on_error(e)
                    return

                def on_error(error):
                    with left.lock:
                        for left_value in left_map.values():
                            left_value.on_error(error)

                        observer.on_error(error)

                md.disposable = duration.pipe(ops.take(1)).subscribe_(nothing, on_error, expire, scheduler)

                with left.lock:
                    for left_value in left_map.values():
                        left_value.on_next(value)

            def on_error_right(error):
                for left_value in left_map.values():
                    left_value.on_error(error)

                observer.on_error(error)

            group.add(right.subscribe_(send_right, on_error_right, scheduler=scheduler))
            return rcd
Exemplo n.º 55
0
class GroupByUntil(Producer):
  def __init__(self, source, keySelector, elementSelector, durationSelector):
    self.source = source
    self.keySelector = keySelector
    self.elementSelector = elementSelector
    self.durationSelector = durationSelector

  def run(self, observer, cancel, setSink):
    self.groupDisposable = CompositeDisposable()
    self.refCountDisposable = RefCountDisposable(self.groupDisposable)

    sink = self.Sink(self, observer, cancel)
    setSink(sink)
    self.groupDisposable.add(self.source.subscribeSafe(sink))

    return self.refCountDisposable


  class Sink(rx.linq.sink.Sink):
    def __init__(self, parent, observer, cancel):
      super(GroupByUntil.Sink, self).__init__(observer, cancel)
      self.parent = parent
      self.map = {}
      self.null = None
      self.nullGate = RLock()
      self.nullGateForDeltas = RLock()
      self.observerGate = RLock()
      self.writerGate = RLock()

    def onNext(self, value):
      key = None

      try:
        key = self.parent.keySelector(value)
      except Exception as e:
        self.onError(e)
        return

      fireNewMapEntry = False
      writer = None

      try:
        if key == None:
          with self.nullGate:
            if self.null == None:
              self.null = Subject()
              fireNewMapEntry = True

            writer = self.null
        else:
          if key in self.map:
            writer = self.map[key]
          else:
            writer = Subject()
            self.map[key] = writer
            fireNewMapEntry = True
      except Exception as e:
        self.onError(e)
        return

      if fireNewMapEntry:
        group = GroupObservable(key, writer, self.parent.refCountDisposable)

        duration = None
        durationGroup = GroupObservable(key, writer)

        try:
          duration = self.parent.durationSelector(durationGroup)
        except Exception as e:
          self.onError(e)
          return

        with self.observerGate:
          self.observer.onNext(group)

        md = SingleAssignmentDisposable()
        self.parent.groupDisposable.add(md)
        md.disposable = duration.subscribeSafe(self.Delta(self, key, writer, md))

      element = None

      try:
        element = self.parent.elementSelector(value)
      except Exception as e:
        self.onError(e)
      else:
        with self.writerGate:
          writer.onNext(element)

    def onError(self, exception):
      #
      # NOTE: A race with OnCompleted triggered by a duration selector is fine when
      #       using Subject<T>. It will transition into a terminal state, making one
      #       of the two calls a no-op by swapping in a DoneObserver<T>.
      #
      null = None

      with self.nullGate:
        null = self.null

      if null != None:
        null.onError(exception)

      for x in self.map.values():
        x.onError(exception)

      with self.observerGate:
        self.observer.onError(exception)

      self.dispose()

    def onCompleted(self):
      #
      # NOTE: A race with OnCompleted triggered by a duration selector is fine when
      #       using Subject<T>. It will transition into a terminal state, making one
      #       of the two calls a no-op by swapping in a DoneObserver<T>.
      #
      null = None

      with self.nullGate:
        null = self.null

      if null != None:
        null.onCompleted()

      for x in self.map.values():
        x.onCompleted()

      with self.observerGate:
        self.observer.onCompleted()

      self.dispose()


    class Delta(Observer):
      def __init__(self, parent, key, writer, cancelSelf):
        self.parent = parent
        self.key = key
        self.writer = writer
        self.cancelSelf = cancelSelf

      def onNext(self, value):
        self.onCompleted()

      def onError(self, exception):
        self.parent.onError(exception)
        self.cancelSelf.dispose()

      def onCompleted(self):
        if self.key == None:
          null = None

          with self.parent.nullGate:
            null = self.parent.null
            self.parent.null = None

          with self.parent.nullGateForDeltas:
            null.onCompleted()
        else:
          try:
            del self.parent.map[self.key]
          except KeyError:
            pass
          else:
            with self.parent.writerGate:
              self.writer.onCompleted()

        self.parent.parent.groupDisposable.remove(self.cancelSelf)
Exemplo n.º 56
0
  class SerialSink(rx.linq.sink.Sink):
    def __init__(self, parent, observer, cancel):
      super(Merge.SerialSink, self).__init__(observer, cancel)
      self.parent = parent

    def run(self):
      self.gate = RLock()
      self.isStopped = False
      self.group = CompositeDisposable()

      self.sourceSubscription = SingleAssignmentDisposable()
      self.group.add(self.sourceSubscription)
      self.sourceSubscription.disposable = self.parent.sources.subscribeSafe(self)

      return self.group

    def onNext(self, value):
      innerSubscription = SingleAssignmentDisposable()
      self.group.add(innerSubscription)
      innerSubscription.disposable = value.subscribeSafe(self.LockObserver(self, innerSubscription))

    def onError(self, exception):
      with self.gate:
        self.observer.onError(exception)
        self.dispose()

    def onCompleted(self):
      self.isStopped = True

      if self.group.length == 1:
        #
        # Notice there can be a race between OnCompleted of the source and any
        # of the inner sequences, where both see _group.Count == 1, and one is
        # waiting for the lock. There won't be a double OnCompleted observation
        # though, because the call to Dispose silences the observer by swapping
        # in a NopObserver<T>.
        #
        with self.gate:
          self.observer.onCompleted()
          self.dispose()
      else:
        self.sourceSubscription.dispose()

    class LockObserver(Observer):
      def __init__(self, parent, subscription):
        self.parent = parent
        self.subscription = subscription

      def onNext(self, value):
        with self.parent.gate:
          self.parent.observer.onNext(value)

      def onError(self, exception):
        with self.parent.gate:
          self.parent.observer.onError(exception)
          self.parent.dispose()

      def onCompleted(self):
        self.parent.group.remove(self.subscription)

        if self.parent.isStopped and self.parent.group.length == 1:
          #
          # Notice there can be a race between OnCompleted of the source and any
          # of the inner sequences, where both see _group.Count == 1, and one is
          # waiting for the lock. There won't be a double OnCompleted observation
          # though, because the call to Dispose silences the observer by swapping
          # in a NopObserver<T>.
          #
          with self.parent.gate:
            self.parent.observer.onCompleted()
            self.parent.dispose()
Exemplo n.º 57
0
 def subscribe(observer, scheduler=None):
     composite_disposable = CompositeDisposable()
     composite_disposable.add(OnDispose())
     subscription = source.subscribe_(observer.on_next, observer.on_error, observer.on_completed, scheduler)
     composite_disposable.add(subscription)
     return composite_disposable
Exemplo n.º 58
0
        def subscribe(observer, scheduler_=None):
            _scheduler = scheduler or scheduler_ or timeout_scheduler

            timer_d = SerialDisposable()
            next_shift = [timeshift]
            next_span = [timespan]
            total_time = [DELTA_ZERO]
            q = []

            group_disposable = CompositeDisposable(timer_d)
            ref_count_disposable = RefCountDisposable(group_disposable)

            def create_timer():
                m = SingleAssignmentDisposable()
                timer_d.disposable = m
                is_span = False
                is_shift = False

                if next_span[0] == next_shift[0]:
                    is_span = True
                    is_shift = True
                elif next_span[0] < next_shift[0]:
                    is_span = True
                else:
                    is_shift = True

                new_total_time = next_span[0] if is_span else next_shift[0]

                ts = new_total_time - total_time[0]
                total_time[0] = new_total_time
                if is_span:
                    next_span[0] += timeshift

                if is_shift:
                    next_shift[0] += timeshift

                def action(scheduler, state=None):
                    s = None

                    if is_shift:
                        s = Subject()
                        q.append(s)
                        observer.on_next(add_ref(s, ref_count_disposable))

                    if is_span:
                        s = q.pop(0)
                        s.on_completed()

                    create_timer()
                m.disposable = _scheduler.schedule_relative(ts, action)

            q.append(Subject())
            observer.on_next(add_ref(q[0], ref_count_disposable))
            create_timer()

            def on_next(x):
                for s in q:
                    s.on_next(x)

            def on_error(e):
                for s in q:
                    s.on_error(e)

                observer.on_error(e)

            def on_completed():
                for s in q:
                    s.on_completed()

                observer.on_completed()

            group_disposable.add(source.subscribe_(on_next, on_error, on_completed, scheduler_))
            return ref_count_disposable
Exemplo n.º 59
0
  class Sink(rx.linq.sink.Sink):
    def __init__(self, parent, observer, cancel):
      super(GroupJoin.Sink, self).__init__(observer, cancel)
      self.parent = parent

    def run(self):
      self.gate = RLock()
      self.group = CompositeDisposable()
      self.refCount = RefCountDisposable(self.group)

      leftSubscription = SingleAssignmentDisposable()
      self.group.add(leftSubscription)
      self.leftID = 0
      self.leftMap = {}

      rightSubscription = SingleAssignmentDisposable()
      self.group.add(rightSubscription)
      self.rightID = 0
      self.rightMap = {}

      leftSubscription.disposable = self.parent.left.subscribeSafe(self.Left(self, leftSubscription))
      rightSubscription.disposable = self.parent.right.subscribeSafe(self.Right(self, rightSubscription))

      return self.refCount

    class Left(Observer):
      def __init__(self, parent, subscription):
        self.parent = parent
        self.subscription = subscription

      def expire(self, resourceId, group, resource):
        with self.parent.gate:
          if resourceId in self.parent.leftMap:
            del self.parent.leftMap[resourceId]
            group.onCompleted()

        self.parent.group.remove(resource)

      def onNext(self, value):
        s = Subject()
        resourceId = 0

        with self.parent.gate:
          self.parent.leftID += 1
          resourceId = self.parent.leftID
          self.parent.leftMap[resourceId] = s

        # AddRef was originally WindowObservable but this is just an alias for AddRef
        window = AddRef(s, self.parent.refCount)
        md = SingleAssignmentDisposable()
        self.parent.group.add(md)

        try:
          duration = self.parent.parent.leftDurationSelector(value)
        except Exception as e:
          self.onError(e)
          return
        else:
          md.disposable = duration.subscribeSafe(self.Delta(self, resourceId, s, md))

        try:
          result = self.parent.parent.resultSelector(value, window)
        except Exception as e:
          self.onError(e)
          return
        else:
          with self.parent.gate:
            self.parent.observer.onNext(result)

            for rightValue in self.parent.rightMap.values():
              s.onNext(rightValue)

      def onError(self, exception):
        with self.parent.gate:
          for o in self.parent.leftMap.values():
            o.onError(exception)

          self.parent.observer.onError(exception)
          self.parent.dispose()

      def onCompleted(self):
        with self.parent.gate:
          self.parent.observer.onCompleted()
          self.parent.dispose()

        self.dispose()


      class Delta(Observer):
        """Expires parent on Next or Completed"""

        def __init__(self, parent, resourceId, group, resource):
          self.parent = parent
          self.resourceId = resourceId
          self.group = group
          self.resource = resource

        def onNext(self, value):
          self.parent.expire(self.resourceId, self.group, self.resource)

        def onError(self, exception):
          self.parent.onError(exception)

        def onCompleted(self):
          self.parent.expire(self.resourceId, self.group, self.resource)
      #end Delta
    #end Left

    class Right(Observer):
      def __init__(self, parent, subscription):
        self.parent = parent
        self.subscription = subscription


      def expire(self, resourceId, resource):
        with self.parent.gate:
          self.parent.rightMap.pop(resourceId, None)

        self.parent.group.remove(resource)

      def onNext(self, value):
        resourceId = 0

        with self.parent.gate:
          self.parent.rightID += 1
          resourceId = self.parent.rightID
          self.parent.rightMap[resourceId] = value

        md = SingleAssignmentDisposable()
        self.parent.group.add(md)

        try:
          duration = self.parent.parent.rightDurationSelector(value)
        except Exception as e:
          self.onError(e)
          return
        else:
          md.disposable = duration.subscribeSafe(self.Delta(self, resourceId, md))

        with self.parent.gate:
          for o in self.parent.leftMap.values():
            o.onNext(value)

      def onError(self, exception):
        with self.parent.gate:
          for o in self.parent.leftMap.values():
            o.onError(exception)

          self.parent.observer.onError(exception)
          self.parent.dispose()

      def onCompleted(self):
        self.dispose()


      class Delta(Observer):
        """Expires parent on Next or Completed"""
        def __init__(self, parent, resourceId, resource):
          self.parent = parent
          self.resourceId = resourceId
          self.resource = resource

        def onNext(self, value):
          self.parent.expire(self.resourceId, self.resource)

        def onError(self, exception):
          self.parent.onError(exception)

        def onCompleted(self):
          self.parent.expire(self.resourceId, self.resource)
Exemplo n.º 60
0
  class ConcurrentSink(rx.linq.sink.Sink):
    def __init__(self, parent, observer, cancel):
      super(Merge.ConcurrentSink, self).__init__(observer, cancel)
      self.parent = parent

    def run(self):
      self.gate = RLock()
      self.q = Queue()
      self.isStopped = False
      self.activeCount = 0

      self.group = CompositeDisposable()
      self.sourceSubscription = SingleAssignmentDisposable()
      self.group.add(self.sourceSubscription)
      self.sourceSubscription.disposable = self.parent.sources.subscribeSafe(self)

      return self.group

    def onNext(self, value):
      with self.gate:
        if self.activeCount < self.parent.maxConcurrency:
          self.activeCount += 1
          self.subscribe(value)
        else:
          self.q.put_nowait(value)

    def onError(self, exception):
      with self.gate:
        self.observer.onError(exception)
        self.dispose()

    def onCompleted(self):
      with self.gate:
        self.isStopped = True

        if self.activeCount == 0:
          self.observer.onCompleted()
          self.dispose()
        else:
          self.sourceSubscription.dispose()

    def subscribe(self, innerSource):
      subscription = SingleAssignmentDisposable()
      self.group.add(subscription)
      subscription.disposable = innerSource.subscribeSafe(self.LockObserver(self, subscription))

    class LockObserver(Observer):
      def __init__(self, parent, subscription):
        self.parent = parent
        self.subscription = subscription

      def onNext(self, value):
        with self.parent.gate:
          self.parent.observer.onNext(value)

      def onError(self, exception):
        with self.parent.gate:
          self.parent.observer.onError(exception)
          self.parent.dispose()

      def onCompleted(self):
        self.parent.group.remove(self.subscription)

        with self.parent.gate:
          if self.parent.q.qsize() > 0:
            s = self.q.get()
            self.parent.subscribe(s)
          else:
            self.parent.activeCount -= 1

            if self.parent.isStopped and self.parent.activeCount == 0:
              self.parent.observer.onCompleted()
              self.parent.dispose()