Exemplo n.º 1
0
        def signal_on_next(a1, a2):
            prev_last_ack = last_ack[0]

            if isinstance(prev_last_ack, Continue):
                new_last_ack = raw_on_next(a1, a2)
            elif isinstance(prev_last_ack, Stop):
                return stop_ack
            else:

                def _(v, _):
                    if isinstance(v, Continue):
                        with self.lock:
                            ack = raw_on_next(a1, a2)
                        return ack
                    else:
                        return stop_ack

                ack = Ack()
                prev_last_ack.flat_map(_).subscribe(ack)
                new_last_ack = ack

            last_ack[0] = new_last_ack

            if isinstance(new_last_ack, Continue) or isinstance(
                    new_last_ack, Stop):
                continue_p[0].on_next(new_last_ack)
                continue_p[0].on_completed()
            else:
                new_last_ack.subscribe(continue_p[0])

            # acknowledgment used by input that receives first
            continue_p[0] = Ack()

            return new_last_ack
Exemplo n.º 2
0
        def go_async(next, next_size: int, ack: Ack, processed: int):
            def on_next(v):
                if isinstance(v, Continue):
                    next_ack = signal_next(next)
                    is_sync = isinstance(ack, Continue) or isinstance(
                        ack, Stop)
                    next_frame = self.em.next_frame_index(0) if is_sync else 0
                    fast_loop(next_ack, processed + next_size, next_frame)
                elif isinstance(v, Stop):
                    self.downstream_is_complete = True

            ack.observe_on(self.scheduler).subscribe(on_next=on_next)
Exemplo n.º 3
0
    def __init__(self, underlying: Observer, scheduler: SchedulerBase):
        self.underlying = underlying
        self.scheduler = scheduler

        self.root_ack = Ack()
        self.connected_ack = self.root_ack
        self.connected_ref = None
        self.is_connected = False
        self.is_connected_started = False
        self.scheduled_done = False
        self.schedule_error = None
        self.was_canceled = False
        self.queue = Queue()
        self.lock = config['concurrency'].RLock()
Exemplo n.º 4
0
    def on_next(self, elem):
        if not self.is_connected:

            def __(v, _):
                if isinstance(v, Continue):
                    ack = self.underlying.on_next(elem)
                    if isinstance(ack, Continue):
                        return rx.Observable.just(ack)
                    elif isinstance(ack, Stop):
                        raise NotImplementedError
                    else:
                        return ack
                else:
                    return Stop()

            new_ack = Ack()
            self.connected_ack \
                .observe_on(self.scheduler) \
                .flat_map(__) \
                .subscribe(new_ack)
            self.connected_ack = new_ack
            return self.connected_ack
        elif not self.was_canceled:
            ack = self.underlying.on_next(elem)
            return ack
        else:
            return Stop()
Exemplo n.º 5
0
    def push_on_next(self, elem, last_to_push: int = None):
        if self.upstream_is_complete or self.downstream_is_complete:
            return Stop()
        else:
            if last_to_push is None:
                with self.lock:
                    to_push = self.items_to_push
                    self.items_to_push += 1
            else:
                to_push = last_to_push

            if self.back_pressured is None:
                if to_push < self.buffer_size:
                    self.queue.put(item=elem)
                    self.push_to_consumer(to_push)
                    return continue_ack
                else:
                    ack = Ack()
                    with self.lock:
                        self.back_pressured = ack
                    self.queue.put(item=elem)
                    self.push_to_consumer(to_push)
                    return ack
            else:
                self.queue.put(item=elem)
                self.push_to_consumer(to_push)
                return self.back_pressured
Exemplo n.º 6
0
 def on_next(self, v):
     self.received.append(v)
     if 0 < self.immediate_continue:
         self.immediate_continue -= 1
         return Continue()
     else:
         self.ack = Ack()
         return self.ack
Exemplo n.º 7
0
    def on_next(self, value):

        with self.lock:
            # concurrent situation with acknowledgment in inner subscription or new subscriptions

            # empty inactive subscriptions; they are added to the list once they reach the top of the buffer again
            inactive_subsriptions = self.inactive_subsriptions
            self.inactive_subsriptions = []

            # add item to buffer
            self.buffer.append(OnNext(value))

            # current ack is used by subscriptions that weren't inactive, but reached the top of the buffer
            current_ack = Ack()
            self.current_ack = current_ack

            is_done = self.is_done

        if is_done:
            return stop_ack

        def gen_inner_ack():
            # send notification to inactive subscriptions
            for inner_subscription in inactive_subsriptions:
                inner_ack = inner_subscription.notify_on_next(value)
                yield inner_ack

        inner_ack_list = list(gen_inner_ack())

        continue_ack = [
            ack for ack in inner_ack_list if isinstance(ack, Continue)
        ]

        if 0 < len(continue_ack):
            # return any Continue ack
            return continue_ack[0]
        else:
            # return merged acknowledgments from inner subscriptions

            ack_list = [current_ack] + inner_ack_list

            upper_ack = Ack()
            rx.Observable.merge(*ack_list).first().subscribe(upper_ack)
            return upper_ack
Exemplo n.º 8
0
                def on_next(self, inner_left):
                    ack = Ack()
                    has_right_elem = False
                    right_elem = None

                    with source.lock:
                        if isinstance(state[0], source.WaitForRightOrInner):
                            # not much to do
                            state_typed: source.WaitForRightOrInner = state[0]
                            state[0] = source.WaitForRight(
                                inner_left_elem=inner_left,
                                left_ack=state_typed.left_ack,
                                inner_left_ack=ack,
                                left_elem=source.selector_left(left_elem))
                        elif isinstance(state[0], source.Active):
                            # send zipped item to observer
                            state_typed: source.Active = state[0]
                            has_right_elem = True
                            right_elem = state_typed.right_elem
                            state[0] = source.Active(
                                left_ack=state_typed.left_ack,
                                right_elem=state_typed.right_elem,
                                right_ack=state_typed.right_ack,
                                upper_ack=ack)
                        elif isinstance(state[0], source.Completed):
                            return stop_ack
                        else:
                            raise NotImplementedError

                    if has_right_elem:
                        # send triple to observer
                        zipped_elem = source.selector(
                            source.selector_left(left_elem), right_elem,
                            inner_left)
                        upper_ack = observer.on_next(zipped_elem)

                        # race condition with on_completed
                        if isinstance(state[0], source.Active):
                            typed_state: source.Active = state[0]
                            typed_state.upper_ack = upper_ack

                        if isinstance(upper_ack, Stop):
                            with source.lock:
                                state[0] = source.Completed()
                        else:

                            def _(v):
                                if isinstance(v, Stop):
                                    with source.lock:
                                        state[0] = source.Completed()

                            upper_ack.observe_on(scheduler).subscribe(_)
                        return upper_ack
                    else:
                        return ack
Exemplo n.º 9
0
        def notify_on_next(self, value) -> Ack:
            # inner subscription gets only notified if all items from buffer are sent and ack received

            with self.source.lock:
                # increase current index
                self.source.current_index[self] += 1

            current_index = self.source.current_index[self]

            ack = self.observer.on_next(value)

            if isinstance(ack, Continue):
                self.source.inactive_subsriptions.append(self)
                return ack
            elif isinstance(ack, Stop):
                # with self.source.lock:
                #     del self.source.current_index[self]
                #     if len(self.source.current_ack) == 0:
                #         self.source.is_done = True
                self.signal_stop()
                return ack
            else:
                inner_ack = Ack()

                def _(v):
                    if isinstance(v, Continue):
                        with self.source.lock:
                            if current_index + 1 < self.source.buffer.last_idx:
                                has_elem = True
                            else:
                                # no new item has been added since call to 'notify_on_next'
                                has_elem = False
                                self.source.inactive_subsriptions.append(self)

                        if has_elem:
                            disposable = BooleanDisposable()
                            self.fast_loop(current_index, 0, disposable)
                    elif isinstance(v, Stop):
                        self.signal_stop()
                    else:
                        raise Exception(
                            'no recognized acknowledgment {}'.format(v))

                    inner_ack.on_next(v)
                    inner_ack.on_completed()

                ack.observe_on(scheduler=self.scheduler).subscribe(_)
                return inner_ack
Exemplo n.º 10
0
        def on_next(v):
            def action(_, __):
                inner_ack = observer.on_next(v)

                if isinstance(inner_ack, Continue):
                    ack.on_next(inner_ack)
                    ack.on_completed()
                elif isinstance(inner_ack, Stop):
                    ack.on_next(inner_ack)
                    ack.on_completed()
                else:
                    inner_ack.unsafe_subscribe(ack)

            self.scheduler.schedule(action)

            ack = Ack()
            return ack
Exemplo n.º 11
0
            def on_next(self, elem):
                stream_error = True

                if not is_active[0]:
                    return stop_ack
                else:
                    async_upstream_ack = Ack()
                    child = source.selector(elem)
                    stream_error = False

                    with source.lock:
                        state[0] = WaitOnActiveChild()

                    child_observer = ChildObserver(observer, scheduler, async_upstream_ack, self)
                    disposable = child.subscribe(child_observer, scheduler, subscribe_scheduler)

                    with source.lock:
                        current_state = state[0]
                        state[0] = Active(disposable)

                    if isinstance(current_state, WaitOnNextChild):
                        with source.lock:
                            state[0] = current_state

                        state_: WaitOnNextChild = current_state
                        return state_.ack
                    elif isinstance(current_state, WaitOnActiveChild):
                        if is_active[0]:
                            return async_upstream_ack
                        else:
                            self.cancel_state()
                            return stop_ack
                    elif isinstance(current_state, Cancelled):
                        self.cancel_state()
                        return stop_ack
                    else:
                        self.report_invalid_state(current_state, 'on_next')
                        return stop_ack
Exemplo n.º 12
0
            def signal_child_on_complete(self, ack: Ack, is_stop: bool):
                with source.lock:
                    current_state = state[0]
                    state[0] = WaitOnNextChild(ack)

                if isinstance(current_state, WaitOnNextChild) or isinstance(current_state, Active):
                    ack.subscribe(self.async_upstream_ack)
                elif isinstance(current_state, Cancelled):
                    ack.on_next(Stop())
                    ack.on_completed()
                elif isinstance(current_state, WaitComplete):
                    state_: WaitComplete = current_state
                    if not is_stop:
                        if state_.ex is None:
                            self.send_on_complete()
                        else:
                            observer.on_error(state_.ex)
                    else:
                        scheduler.report_failure(state_.ex)
Exemplo n.º 13
0
        def on_next_right(right):
            right_elem[0] = right
            right_ack[0] = Ack()

            with lock:
                has_right_elem[0] = True

                if has_left_elem[0]:
                    has_left = True
                else:
                    has_left = False

            if has_left:
                left = left_elem[0]

                if right_is_higher(left, right):
                    # right is higher than left
                    # complete inner observable, discard left and request new left; save right

                    with lock:
                        # avoids completing observer twice

                        # discard left element
                        has_left_elem[0] = False
                        left_elem[0] = None

                        if has_completed[0]:
                            complete_observer = True
                        else:
                            complete_observer = False

                    if complete_observer:
                        observer.on_completed()
                        return Stop()

                    left_ack[0].on_next(continue_ack)
                    left_ack[0].on_completed()

                    return right_ack[0]

                if right_is_lower(left, right):
                    # right is lower than left, discard right and request new right
                    # this is possible in initial phase or if is_lower and is_higher are not tight

                    # discard right element
                    has_right_elem[0] = False
                    right_elem[0] = None

                    return continue_ack
                else:
                    # left is equal to right, send right element, request new right

                    # discard right element
                    has_right_elem[0] = False
                    right_elem[0] = None

                    # send right element
                    ack = observer.on_next(self.selector(left, right))

                    return ack

            else:
                # no left element has been yet received; only possible in initial phase
                return right_ack[0]
Exemplo n.º 14
0
        def on_next_left(left_elem):
            ack = Ack()

            with self.lock:
                if isinstance(state[0], self.WaitForLeftOrRight):
                    new_state = self.WaitForRightOrInner(left_ack=ack)
                elif isinstance(state[0], self.WaitForLeft):
                    state_: source.WaitForLeft = state[0]
                    new_state = self.Active(left_ack=ack,
                                            right_elem=state_.right_elem,
                                            right_ack=state_.right_ack,
                                            upper_ack=Continue())
                elif isinstance(state[0], source.Completed):
                    return stop_ack
                else:
                    raise NotImplementedError
                state[0] = new_state

            class ChildObserver(Observer):
                def __init__(self, out: Observer, scheduler):
                    self.out = out
                    self.scheduler = scheduler

                def on_next(self, inner_left):
                    ack = Ack()
                    has_right_elem = False
                    right_elem = None

                    with source.lock:
                        if isinstance(state[0], source.WaitForRightOrInner):
                            # not much to do
                            state_typed: source.WaitForRightOrInner = state[0]
                            state[0] = source.WaitForRight(
                                inner_left_elem=inner_left,
                                left_ack=state_typed.left_ack,
                                inner_left_ack=ack,
                                left_elem=source.selector_left(left_elem))
                        elif isinstance(state[0], source.Active):
                            # send zipped item to observer
                            state_typed: source.Active = state[0]
                            has_right_elem = True
                            right_elem = state_typed.right_elem
                            state[0] = source.Active(
                                left_ack=state_typed.left_ack,
                                right_elem=state_typed.right_elem,
                                right_ack=state_typed.right_ack,
                                upper_ack=ack)
                        elif isinstance(state[0], source.Completed):
                            return stop_ack
                        else:
                            raise NotImplementedError

                    if has_right_elem:
                        # send triple to observer
                        zipped_elem = source.selector(
                            source.selector_left(left_elem), right_elem,
                            inner_left)
                        upper_ack = observer.on_next(zipped_elem)

                        # race condition with on_completed
                        if isinstance(state[0], source.Active):
                            typed_state: source.Active = state[0]
                            typed_state.upper_ack = upper_ack

                        if isinstance(upper_ack, Stop):
                            with source.lock:
                                state[0] = source.Completed()
                        else:

                            def _(v):
                                if isinstance(v, Stop):
                                    with source.lock:
                                        state[0] = source.Completed()

                            upper_ack.observe_on(scheduler).subscribe(_)
                        return upper_ack
                    else:
                        return ack

                def on_error(self, err):
                    with source.lock:
                        state[0] = source.Completed()
                        observer.on_error(err)

                def on_completed(self):
                    back_pressure_right = False
                    back_pressure_left = False
                    left_ack = None
                    right_ack = None
                    upper_ack = None
                    complete_observer = False

                    with source.lock:
                        if isinstance(state[0], source.Active):
                            # normal complete

                            if right_completed[0]:
                                state[0] = source.Completed()
                                complete_observer = True
                            else:
                                # request new left and new right
                                state_typed: source.Active = state[0]
                                back_pressure_right = True
                                back_pressure_left = True
                                left_ack = state_typed.left_ack
                                right_ack = state_typed.right_ack
                                upper_ack = state_typed.upper_ack
                                state[0] = source.WaitForLeftOrRight()
                        elif isinstance(state[0], source.WaitForRightOrInner):
                            # empty inner observable

                            state_typed: source.WaitForRight = state[0]
                            # count up number of inner completed (without right completed)
                            inner_left_completed[0] += 1
                            state[0] = source.WaitForLeftOrRight()
                            back_pressure_left = True
                            left_ack = state_typed.left_ack
                            upper_ack = Continue()

                    if complete_observer:
                        observer.on_completed()

                    if back_pressure_left or back_pressure_right:

                        def _(v):
                            if isinstance(v, Stop):
                                with source.lock:
                                    state[0] = source.Completed()

                        upper_ack.subscribe(_)

                    if back_pressure_left:
                        # upper_ack should not be Stop
                        if isinstance(upper_ack, Continue):
                            left_ack.on_next(upper_ack)
                            left_ack.on_completed()
                        else:
                            upper_ack.observe_on(scheduler).subscribe(left_ack)

                    if back_pressure_right:
                        if isinstance(upper_ack, Continue):
                            right_ack.on_next(upper_ack)
                            right_ack.on_completed()
                        else:
                            upper_ack.observe_on(scheduler).subscribe(
                                right_ack)

            child = self.selector_inner(left_elem)
            child_observer = ChildObserver(observer, scheduler)

            disposable = child.subscribe(child_observer, scheduler,
                                         CurrentThreadScheduler())
            inner_disposable.disposable = disposable

            return ack
Exemplo n.º 15
0
    def unsafe_subscribe(self, observer, scheduler, subscribe_scheduler):
        is_done = [None]
        last_ack = [continue_ack]
        elem_a1 = [None]
        has_elem_a1 = [None]
        elem_a2 = [None]
        has_elem_a2 = [None]
        continue_p = [Ack()]
        complete_with_next = [False]

        def raw_on_next(a1, a2):
            if is_done[0]:
                return stop_ack
            else:
                stream_error = True

                try:
                    c = self.selector(a1, a2)
                    stream_error = False
                    ack = observer.on_next(c)
                    if complete_with_next[0]:
                        if isinstance(ack, Continue) or isinstance(ack, Stop):
                            signal_on_complete(False)
                        else:
                            ack.observe_on(scheduler).subscribe(
                                on_completed=lambda: signal_on_complete(False))
                except Exception as ex:
                    if stream_error:
                        is_done[0] = True
                        observer.on_error(ex)
                        return stop_ack
                    else:
                        raise
                finally:
                    has_elem_a1[0] = False
                    has_elem_a2[0] = False

                return ack

        def signal_on_next(a1, a2):
            prev_last_ack = last_ack[0]

            if isinstance(prev_last_ack, Continue):
                new_last_ack = raw_on_next(a1, a2)
            elif isinstance(prev_last_ack, Stop):
                return stop_ack
            else:

                def _(v, _):
                    if isinstance(v, Continue):
                        with self.lock:
                            ack = raw_on_next(a1, a2)
                        return ack
                    else:
                        return stop_ack

                ack = Ack()
                prev_last_ack.flat_map(_).subscribe(ack)
                new_last_ack = ack

            last_ack[0] = new_last_ack

            if isinstance(new_last_ack, Continue) or isinstance(
                    new_last_ack, Stop):
                continue_p[0].on_next(new_last_ack)
                continue_p[0].on_completed()
            else:
                new_last_ack.subscribe(continue_p[0])

            # acknowledgment used by input that receives first
            continue_p[0] = Ack()

            return new_last_ack

        def signal_on_error(ex):
            with self.lock:
                if not is_done[0]:
                    is_done[0] = True
                    observer.on_error(ex)
                    last_ack[0] = stop_ack

        def signal_on_complete(has_elem):
            def raw_on_completed():
                if not is_done[0]:
                    is_done[0] = True
                    observer.on_completed()

            with self.lock:
                if not has_elem:
                    if isinstance(last_ack[0], Continue):
                        raw_on_completed()
                    elif isinstance(last_ack[0], Stop):
                        pass
                    else:

                        def _(v):
                            if isinstance(v, Continue):
                                with self.lock:
                                    raw_on_completed()
                            else:
                                pass

                        last_ack[0].observe_on(scheduler).subscribe(on_next=_)

                    continue_p[0].on_next(stop_ack)
                    last_ack[0] = stop_ack
                else:
                    complete_with_next[0] = True

        def on_next_left(elem):
            with self.lock:
                if is_done[0]:
                    return_ack = stop_ack
                else:
                    elem_a1[0] = elem
                    if not has_elem_a1[0]:
                        has_elem_a1[0] = True

                    if has_elem_a2[0]:
                        return_ack = signal_on_next(elem_a1[0], elem_a2[0])
                    else:
                        return_ack = continue_p[0]
                return return_ack

        def on_next_right(elem):
            with self.lock:
                if is_done[0]:
                    return_ack = stop_ack
                else:
                    elem_a2[0] = elem
                    if not has_elem_a2[0]:
                        has_elem_a2[0] = True

                    if has_elem_a1[0]:
                        return_ack = signal_on_next(elem_a1[0], elem_a2[0])
                    else:
                        return_ack = continue_p[0]
                return return_ack

        def on_error(ex):
            signal_on_error(ex)

        def on_completed_left():
            return signal_on_complete(has_elem_a1[0])

        def on_completed_right():
            return signal_on_complete(has_elem_a2[0])

        left_observer = AnonymousObserver(on_next=on_next_left,
                                          on_error=on_error,
                                          on_completed=on_completed_left)
        d1 = self.left.unsafe_subscribe(left_observer, scheduler,
                                        subscribe_scheduler)

        right_observer = AnonymousObserver(on_next=on_next_right,
                                           on_error=on_error,
                                           on_completed=on_completed_right)
        d2 = self.right.unsafe_subscribe(right_observer, scheduler,
                                         subscribe_scheduler)

        return CompositeDisposable(d1, d2)
Exemplo n.º 16
0
    def __init__(self, value, initial):
        self.lock = config["concurrency"].RLock()

        self.value = value
        self.counter = initial
        self.promise = Ack()
Exemplo n.º 17
0
 def on_next(self, v):
     self.received.append(v)
     self.ack = Ack()
     self.inner_obs = TestObserver()
     self.inner_selector(v).subscribe(self.inner_obs, self.scheduler, CurrentThreadScheduler())
     return self.ack
Exemplo n.º 18
0
        def on_next_left(left_val):
            # left has been requested because of initial state,
            # or because right is higher than left

            left_elem[0] = left_val
            left_ack[0] = Ack()
            publish_subject[0] = PublishSubject()

            # send next inner observable; subscribe needs to happen immediately
            outer_ack[0] = left_observer[0].on_next(
                (left_val, publish_subject[0]))  # todo: make this private

            with lock:
                has_left_elem[0] = True

                if has_right_elem[0]:
                    has_right = True
                else:
                    # race condition: left element is receieved first
                    has_right = False

            if has_right:
                right_val = right_elem[0]

                if left_is_lower(left_val, right_val):
                    # right is higher than left
                    # send (empty) inner observable and request new left; don't discard right element
                    # inner observable is empty, because left has just been received

                    # discard left element
                    has_left_elem[0] = False
                    left_elem[0] = None

                    # complete (empty) inner observable
                    publish_subject[0].on_completed()

                    # continue next left element after outer acknowledgment
                    return outer_ack[0]
                if left_is_higher(left_val, right_val):
                    # right is lower than left, discard right and request new right
                    # this is possible in initial phase or if is_lower and is_higher are not tight

                    assert right_ack[0] is not None, 'missing acknowledgment'

                    with lock:
                        # avoids completing observer twice

                        # discard right element
                        has_right_elem[0] = False
                        right_elem[0] = None

                        if has_completed[0]:
                            complete_observer = True
                        else:
                            complete_observer = False

                    if complete_observer:
                        left_observer[0].on_completed()
                        right_observer[0].on_completed()
                        return Stop()

                    ack = right_observer[0].on_next((False, right_val))

                    # request new right
                    ack.connect_ack(next_ack=right_ack[0])

                else:
                    # left is equal to right, send right element, request new right

                    with lock:
                        # avoids completing observer twice

                        # discard right element
                        has_right_elem[0] = False
                        right_elem[0] = None

                        if has_completed[0]:
                            complete_observer = True
                        else:
                            complete_observer = False

                    if complete_observer:
                        left_observer[0].on_completed()
                        right_observer[0].on_completed()
                        return Stop()

                    # send right element
                    ack = publish_subject[0].on_next(right_val)
                    ack2 = right_observer[0].on_next((True, right_val))

                    # request new right element
                    ack.connect_ack_2(ack2=ack2, next_ack=right_ack[0])

            return_ack = left_ack[0].merge_ack(outer_ack[0])

            # return left_ack[0]
            return return_ack
Exemplo n.º 19
0
        def on_next_right(right_val):
            right_elem[0] = right_val
            right_ack[0] = Ack()

            with lock:
                has_right_elem[0] = True

                if has_left_elem[0]:
                    has_left = True
                else:
                    has_left = False

            if has_left:
                left_val = left_elem[0]

                # print('left={}, right={}'.format(left_val, right_val))

                if is_higher(left_val, right_val):
                    # right is higher than left
                    # complete inner observable, discard left and request new left; save right

                    with lock:
                        # avoids completing observer twice

                        # discard left element
                        has_left_elem[0] = False
                        left_elem[0] = None

                        if has_completed[0]:
                            complete_observer = True
                        else:
                            complete_observer = False

                    if complete_observer:
                        left_observer[0].on_completed()
                        right_observer[0].on_completed()
                        return Stop()

                    # complete inner observable
                    publish_subject[0].on_completed()

                    left_ack[0].on_next(continue_ack)
                    left_ack[0].on_completed()

                    return right_ack[0]

                if is_lower(left_val, right_val):
                    # right is lower than left, discard right and request new right
                    # this is possible in initial phase or if is_lower and is_higher are not tight

                    ack = right_observer[0].on_next((False, right_val))

                    # discard right element
                    has_right_elem[0] = False
                    right_elem[0] = None

                    return ack
                else:
                    # left is equal to right, send right element, request new right

                    # discard right element
                    has_right_elem[0] = False
                    right_elem[0] = None

                    # send right element
                    ack = publish_subject[0].on_next(right_val)
                    ack2 = right_observer[0].on_next((True, right_val))

                    return ack.merge_ack(ack2)

            else:
                # no left element has been yet received; only possible in initial phase
                return right_ack[0]
Exemplo n.º 20
0
        def on_next_left(left):
            # left has been requested because of initial state,
            # or because right is higher than left

            left_elem[0] = left
            left_ack[0] = Ack()

            with lock:
                has_left_elem[0] = True

                if has_right_elem[0]:
                    has_right = True
                else:
                    # race condition: left element is receieved first
                    has_right = False

            if has_right:
                right = right_elem[0]

                if left_is_lower(left, right):
                    # right is higher than left
                    # request new left; don't discard right element

                    # discard left element
                    has_left_elem[0] = False
                    left_elem[0] = None

                    return continue_ack

                if left_is_higher(left, right):
                    # right is lower than left, discard right and request new right
                    # this is possible in initial phase or if is_lower and is_higher are not tight

                    assert right_ack[0] is not None, 'missing acknowledgment'

                    with lock:
                        # avoids completing observer twice

                        # discard right element
                        has_right_elem[0] = False
                        right_elem[0] = None

                        if has_completed[0]:
                            complete_observer = True
                        else:
                            complete_observer = False

                    if complete_observer:
                        # left_observer.on_completed()
                        observer.on_completed()
                        return Stop()

                    right_ack[0].on_next(continue_ack)
                    right_ack[0].on_completed()

                else:
                    # left is equal to right, send right element, request new right

                    with lock:
                        # avoids completing observer twice

                        # discard right element
                        has_right_elem[0] = False
                        right_elem[0] = None

                        if has_completed[0]:
                            complete_observer = True
                        else:
                            complete_observer = False

                    if complete_observer:
                        # left_observer.on_completed()
                        observer.on_completed()
                        return Stop()

                    # send right element
                    ack = observer.on_next(self.selector(left, right))

                    # request new right element
                    ack.connect_ack(right_ack[0])

                    # # request new left element
                    # return ack

            return left_ack[0]
Exemplo n.º 21
0
        def on_next_right(right):
            ack = Ack()
            upper_ack = None
            has_inner_left_elem = False
            request_left_right = False
            request_right = False

            with self.lock:
                if 0 < inner_left_completed[0]:
                    inner_left_completed[0] -= 1
                    request_right = True
                    upper_ack = Continue()
                    # new_state = self.WaitForLeftOrRight()
                    new_state = state[0]
                elif isinstance(state[0], self.WaitForLeftOrRight):
                    new_state = self.WaitForLeft(right_elem=right,
                                                 right_ack=ack)
                elif isinstance(state[0], self.WaitForRightOrInner):
                    state_: FlatZipObservable.WaitForRightOrInner = state[0]
                    if inner_left_completed[0] == 0:
                        new_state = self.Active(left_ack=state_.left_ack,
                                                right_elem=right,
                                                right_ack=ack,
                                                upper_ack=Continue())
                    else:
                        inner_left_completed[0] -= 1
                        new_state = self.WaitForLeftOrRight()
                elif isinstance(state[0], self.WaitForRight):
                    state_: FlatZipObservable.WaitForRight = state[0]
                    has_inner_left_elem = True
                    left_elem = state_.left_elem
                    left_ack = state_.left_ack
                    inner_left_elem = state_.inner_left_elem
                    inner_left_ack = state_.inner_left_ack
                    new_state = state[0]
                elif isinstance(state[0], source.Completed):
                    return stop_ack
                else:
                    raise NotImplementedError
                state[0] = new_state

            if has_inner_left_elem:
                zipped_elem = self.selector(left_elem, right, inner_left_elem)
                upper_ack = observer.on_next(zipped_elem)

                if isinstance(upper_ack, Stop):
                    with self.lock:
                        state[0] = self.Completed
                        return upper_ack

                request_inner_elem = False
                with self.lock:
                    if 0 < inner_left_completed[0]:
                        # inner left completed, request new left and right
                        new_state = self.WaitForLeftOrRight()
                        request_left_right = True
                    else:
                        # state is the same, change state to active
                        new_state = self.Active(left_ack=left_ack,
                                                right_elem=right,
                                                right_ack=ack,
                                                upper_ack=upper_ack)
                        request_inner_elem = True
                    state[0] = new_state

                if request_inner_elem:
                    if isinstance(upper_ack, Continue) or isinstance(
                            upper_ack, Stop):
                        inner_left_ack.on_next(upper_ack)
                        inner_left_ack.on_completed()
                    else:
                        upper_ack.observe_on(scheduler).subscribe(
                            inner_left_ack)

                if request_left_right:
                    if isinstance(upper_ack, Continue):
                        left_ack.on_next(upper_ack)
                        left_ack.on_completed()
                    else:
                        upper_ack.observe_on(scheduler).subscribe(left_ack)

            if request_left_right or request_right:
                if isinstance(upper_ack, Continue):
                    ack.on_next(upper_ack)
                    ack.on_completed()
                else:
                    upper_ack.observe_on(scheduler).subscribe(ack)

            return ack
Exemplo n.º 22
0
class ConnectableSubscriber(Observer):
    def __init__(self, underlying: Observer, scheduler: SchedulerBase):
        self.underlying = underlying
        self.scheduler = scheduler

        self.root_ack = Ack()
        self.connected_ack = self.root_ack
        self.connected_ref = None
        self.is_connected = False
        self.is_connected_started = False
        self.scheduled_done = False
        self.schedule_error = None
        self.was_canceled = False
        self.queue = Queue()
        self.lock = config['concurrency'].RLock()

    def connect(self):
        with self.lock:
            if not self.is_connected and not self.is_connected_started:
                self.is_connected_started = True

                buffer_was_drained = Ack()

                def on_next(v):
                    if isinstance(v, Continue):
                        self.root_ack.on_next(Continue())
                        self.root_ack.on_completed()
                        source.is_connected = True
                        source.queue = None
                        # source.connected_ack = None
                        # todo: fill in
                    elif isinstance(v, Stop):
                        raise NotImplementedError
                    else:
                        raise NotImplementedError

                buffer_was_drained.subscribe(on_next=on_next)

                source = self

                class CustomObserver(Observer):
                    def __init__(self):
                        self.ack = None

                    def on_next(self, v):
                        ack = source.underlying.on_next(v)
                        self.ack = ack

                        def on_next(v):
                            if isinstance(v, Stop):
                                buffer_was_drained.on_next(v)
                                buffer_was_drained.on_completed()

                        ack.subscribe(on_next=on_next)

                        return ack

                    def on_error(self, err):
                        raise NotImplementedError

                    def on_completed(self):
                        if not source.scheduled_done:
                            if self.ack is None:
                                buffer_was_drained.on_next(Continue())
                                buffer_was_drained.on_completed()
                            else:

                                def on_next(v):
                                    if isinstance(v, Continue):
                                        buffer_was_drained.on_next(Continue())
                                        buffer_was_drained.on_completed()

                                self.ack.subscribe(on_next)
                        elif source.schedule_error is not None:
                            raise NotImplementedError
                        else:
                            source.underlying.on_completed()

                class EmptyObject:
                    pass

                self.queue.put(EmptyObject)
                disposable = IteratorAsObservable(iter(self.queue.get, EmptyObject)) \
                    .subscribe(CustomObserver(), self.scheduler, CurrentThreadScheduler())

                self.connected_ref = buffer_was_drained, disposable
        return self.connected_ref

    def push_first(self, elem):
        with self.lock:
            if self.is_connected or self.is_connected_started:
                throw_exception = True
            elif not self.scheduled_done:
                throw_exception = False
                self.queue.put(elem, block=False)
            else:
                throw_exception = False

        if throw_exception:
            raise Exception(
                'Observer was already connected, so cannot pushFirst')

    def push_first_all(self, cs: Iterable):
        with self.lock:
            if self.is_connected or self.is_connected_started:
                throw_exception = True
            elif not self.scheduled_done:
                throw_exception = False
                for elem in cs:
                    self.queue.put(elem, block=False)
            else:
                throw_exception = False

        if throw_exception:
            raise Exception(
                'Observer was already connected, so cannot pushFirst')

    def push_complete(self):
        with self.lock:
            if self.is_connected or self.is_connected_started:
                throw_exception = True
            elif not self.scheduled_done:
                throw_exception = False
                self.scheduled_done = True
            else:
                throw_exception = False

        if throw_exception:
            raise Exception(
                'Observer was already connected, so cannot pushFirst')

    def push_error(self, ex: Exception):
        with self.lock:
            if self.is_connected or self.is_connected_started:
                throw_exception = True
            elif not self.scheduled_done:
                throw_exception = False
                self.scheduled_done = True
                self.schedule_error = ex
            else:
                throw_exception = False

        if throw_exception:
            raise Exception(
                'Observer was already connected, so cannot pushFirst')

    def on_next(self, elem):
        if not self.is_connected:

            def __(v, _):
                if isinstance(v, Continue):
                    ack = self.underlying.on_next(elem)
                    if isinstance(ack, Continue):
                        return rx.Observable.just(ack)
                    elif isinstance(ack, Stop):
                        raise NotImplementedError
                    else:
                        return ack
                else:
                    return Stop()

            new_ack = Ack()
            self.connected_ack \
                .observe_on(self.scheduler) \
                .flat_map(__) \
                .subscribe(new_ack)
            self.connected_ack = new_ack
            return self.connected_ack
        elif not self.was_canceled:
            ack = self.underlying.on_next(elem)
            return ack
        else:
            return Stop()

    def on_error(self, err):
        def on_next(v):
            if isinstance(v, Continue):
                self.underlying.on_error(err)
        self.connected_ack.observe_on(self.scheduler) \
            .subscribe(on_next=on_next)

    def on_completed(self):
        def on_next(v):
            if isinstance(v, Continue):
                self.underlying.on_completed()
        self.connected_ack.observe_on(self.scheduler) \
            .subscribe(on_next=on_next)
Exemplo n.º 23
0
    def connect(self):
        with self.lock:
            if not self.is_connected and not self.is_connected_started:
                self.is_connected_started = True

                buffer_was_drained = Ack()

                def on_next(v):
                    if isinstance(v, Continue):
                        self.root_ack.on_next(Continue())
                        self.root_ack.on_completed()
                        source.is_connected = True
                        source.queue = None
                        # source.connected_ack = None
                        # todo: fill in
                    elif isinstance(v, Stop):
                        raise NotImplementedError
                    else:
                        raise NotImplementedError

                buffer_was_drained.subscribe(on_next=on_next)

                source = self

                class CustomObserver(Observer):
                    def __init__(self):
                        self.ack = None

                    def on_next(self, v):
                        ack = source.underlying.on_next(v)
                        self.ack = ack

                        def on_next(v):
                            if isinstance(v, Stop):
                                buffer_was_drained.on_next(v)
                                buffer_was_drained.on_completed()

                        ack.subscribe(on_next=on_next)

                        return ack

                    def on_error(self, err):
                        raise NotImplementedError

                    def on_completed(self):
                        if not source.scheduled_done:
                            if self.ack is None:
                                buffer_was_drained.on_next(Continue())
                                buffer_was_drained.on_completed()
                            else:

                                def on_next(v):
                                    if isinstance(v, Continue):
                                        buffer_was_drained.on_next(Continue())
                                        buffer_was_drained.on_completed()

                                self.ack.subscribe(on_next)
                        elif source.schedule_error is not None:
                            raise NotImplementedError
                        else:
                            source.underlying.on_completed()

                class EmptyObject:
                    pass

                self.queue.put(EmptyObject)
                disposable = IteratorAsObservable(iter(self.queue.get, EmptyObject)) \
                    .subscribe(CustomObserver(), self.scheduler, CurrentThreadScheduler())

                self.connected_ref = buffer_was_drained, disposable
        return self.connected_ref
Exemplo n.º 24
0
 def on_next(self, v):
     self.received.append(v)
     self.ack = Ack()
     return self.ack