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)
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)
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