def _subscribe_core(self, observer): clock = self.scheduler.to_relative(self.scheduler.now) self.subscriptions.append(Subscription(clock)) index = len(self.subscriptions) - 1 disposable = CompositeDisposable() def get_action(notification): def action(scheduler, state): notification.accept(observer) return Disposable.empty() return action for message in self.messages: notification = message.value # Don't make closures within a loop action = get_action(notification) disposable.add(self.scheduler.schedule_relative(message.time, action)) def dispose(): start = self.subscriptions[index].subscribe end = self.scheduler.to_relative(self.scheduler.now) self.subscriptions[index] = Subscription(start, end) disposable.dispose() return Disposable.create(dispose)
def test_groupdisposable_clear(): disp1 = False disp2 = False def action1(): nonlocal disp1 disp1 = True d1 = Disposable(action1) def action2(): nonlocal disp2 disp2 = True d2 = Disposable(action2) g = CompositeDisposable(d1, d2) assert g.length == 2 g.clear() assert disp1 assert disp2 assert not g.length disp3 = False def action3(): nonlocal disp3 disp3 = True d3 = Disposable(action3) g.add(d3); assert not disp3 assert g.length == 1
def subscribe(observer): m = SingleAssignmentDisposable() group = CompositeDisposable() is_stopped = [False] group.add(m) def on_next(inner_source): inner_subscription = SingleAssignmentDisposable() group.add(inner_subscription) inner_source = Observable.from_future(inner_source) def on_complete(): group.remove(inner_subscription) if is_stopped[0] and group.length == 1: observer.on_completed() disposable = inner_source.subscribe( observer.on_next, observer.on_error, on_complete) inner_subscription.disposable = disposable def on_complete(): is_stopped[0] = True if group.length == 1: observer.on_completed() m.disposable = sources.subscribe(on_next, observer.on_error, on_complete) return group
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 = Observable.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) disposable = inner_source.subscribe_(on_next, on_error, on_completed, scheduler) inner_subscription.disposable = disposable 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
def subscribe(self, on_next, on_error=None, on_completed=None): print ("ColdObservable:subscribe()") if isinstance(on_next, AbstractObserver): observer = on_next else: observer = Observer(on_next, on_error, on_completed) self.subscriptions.append(Subscription(self.scheduler.clock)) index = len(self.subscriptions) - 1 disposable = CompositeDisposable() def get_action(notification): def action(scheduler, state): notification.accept(observer) return Disposable.empty() return action for message in self.messages: notification = message.value print ("Notification: ", notification) # Don't make closures within a loop action = get_action(notification) disposable.add(self.scheduler.schedule_relative(message.time, action)) def dispose(): print ("ColdObservable:dispose()") start = self.subscriptions[index].subscribe end = self.scheduler.clock self.subscriptions[index] = Subscription(start, end) disposable.dispose() return Disposable(dispose)
def subscribe(observer): 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() disposables = CompositeDisposable( source.subscribe(on_next, observer.on_error, on_completed)) right_subscription = SingleAssignmentDisposable() disposables.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) return disposables
def subscribe(observer): window = Subject() d = CompositeDisposable() r = RefCountDisposable(d) observer.on_next(add_ref(window, r)) def on_next_window(x): window.on_next(x) def on_error(err): window.on_error(err) observer.on_error(err) def on_completed(): window.on_completed() observer.on_completed() d.add(source.subscribe(on_next_window, on_error, on_completed)) def on_next_observer(w): window.on_completed() window = Subject() observer.on_next(add_ref(window, r)) d.add(window_boundaries.subscribe(on_next_observer, on_error, on_copleted)) return r
def subscribe(observer): m = SingleAssignmentDisposable() group = CompositeDisposable() is_stopped = False group.add(m) def on_next(inner_source): inner_subscription = SingleAssignmentDisposable() group.add(inner_subscription) def on_complete(): nonlocal group group.remove(inner_subscription) if is_stopped and group.length == 1: observer.on_completed() disposable = inner_source.subscribe( observer.on_next, observer.on_error, on_complete) inner_subscription.disposable = disposable def on_complete(): nonlocal is_stopped is_stopped = True if group.length == 1: observer.on_completed() m.disposable = sources.subscribe(on_next, observer.on_error, on_complete) return group
def subscribe(observer): active_plans = [] external_subscriptions = {} def on_error(err): for v in external_subscriptions.values(): v.on_error(err) observer.on_error(err) out_observer = AnonymousObserver(observer.on_next, on_error, observer.on_completed) def deactivate(active_plan): active_plans.remove(active_plan) if not len(active_plans): observer.on_completed() try: for plan in plans: active_plans.append( plan.activate(external_subscriptions, out_observer, deactivate)) except Exception as ex: Observable.throw(ex).subscribe(observer) group = CompositeDisposable() for join_observer in external_subscriptions.values(): join_observer.subscribe() group.add(join_observer) return group
def subscribe(observer): active_plans = [] external_subscriptions = {} def on_error(err): for v in external_subscriptions.values(): v.on_error(err) observer.on_error(err) out_observer = AnonymousObserver(observer.on_next, on_error, observer.on_completed) def deactivate(active_plan): active_plans.remove(active_plan) if not len(active_plans): observer.on_completed() try: for plan in plans: active_plans.append(plan.activate(external_subscriptions, out_observer, deactivate)) except Exception as ex: Observable.throw(ex).subscribe(observer) group = CompositeDisposable() for join_observer in external_subscriptions.values(): join_observer.subscribe() group.add(join_observer) return group
def test_groupdisposable_clear(): disp1 = [False] disp2 = [False] def action1(): disp1[0] = True d1 = Disposable.create(action1) def action2(): disp2[0] = True d2 = Disposable.create(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.create(action3) g.add(d3); assert not disp3[0] assert g.length == 1
def subscribe(observer): 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 = Observable.from_future(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) def on_completed(): is_stopped[0] = True if not has_current[0] and len(g) == 1: observer.on_completed() m.disposable = sources.subscribe(on_next, observer.on_error, on_completed) return g
def subscribe(observer): 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() disposables = CompositeDisposable(source.subscribe(on_next, observer.on_error, on_completed)) right_subscription = SingleAssignmentDisposable() disposables.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) return disposables
def subscribe(observer): m = SingleAssignmentDisposable() group = CompositeDisposable() is_stopped = False group.add(m) def on_next(inner_source): inner_subscription = SingleAssignmentDisposable() group.add(inner_subscription) def on_complete(): nonlocal group group.remove(inner_subscription) if is_stopped and group.length == 1: observer.on_completed() disposable = inner_source.subscribe(observer.on_next, observer.on_error, on_complete) inner_subscription.disposable = disposable def on_complete(): nonlocal is_stopped is_stopped = True if group.length == 1: observer.on_completed() m.disposable = sources.subscribe(on_next, observer.on_error, on_complete) return group
def subscribe(observer): 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)) return ref_count_disposable
def subscribe(observer): 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)) return ref_count_disposable
def test_groupdisposable_contains(): d1 = Disposable.empty() d2 = Disposable.empty() g = CompositeDisposable(d1, d2) assert g.length == 2 assert g.contains(d1) assert g.contains(d2)
def _subscribe_core(self, observer, scheduler=None): g = CompositeDisposable() def action(scheduler, state): observer.on_next(self.head) g.add(self.tail.merge_all().subscribe(observer, scheduler)) g.add(scheduler.schedule(action)) return g
def _subscribe(self, observer): g = CompositeDisposable() def action(scheduler, state): observer.on_next(self.head) g.add(self.tail.merge_observable().subscribe(observer)) g.add(current_thread_scheduler.schedule(action)) return g
def subscribe(observer): delays = CompositeDisposable() at_end = False def done(): if (at_end and delays.length == 0): observer.on_completed() subscription = SerialDisposable() def start(): def on_next(x): try: delay = selector(x) except Exception as error: observer.on_error(error) return d = SingleAssignmentDisposable() delays.add(d) def on_next(_): observer.on_next(x) delays.remove(d) done() def on_completed(): observer.on_next(x) delays.remove(d) done() d.disposable = delay.subscribe(on_next, observer.on_error, on_completed) def on_completed(): nonlocal at_end at_end = True subscription.dispose() done() subscription.disposable = source.subscribe( on_next, observer.on_error, on_completed) if not sub_delay: start() else: subscription.disposable( sub_delay.subscribe(lambda _: start(), observer.on_error, lambda: start())) return CompositeDisposable(subscription, delays)
def subscribe(observer): disposable = Disposable.empty() try: resource = resource_factory() if resource: disposable = resource source = observable_factory(resource) except Exception as exception: d = Observable.throw_exception(exception).subscribe(observer) return CompositeDisposable(d, disposable) return CompositeDisposable(source.subscribe(observer), disposable)
def create_observer(observer): subscription = CompositeDisposable() for name in observables.keys(): if not subjects[name].is_disposed: subscription.add(observables[name].subscribe(observer=subjects[name], on_error=log_error)) observer.on_next(subscription) def dispose(): subscription.dispose() for x in subjects: if hasattr(subjects, x): subjects[x].dispose() return dispose
def subscribe(observer, scheduler=None): delays = CompositeDisposable() at_end = [False] def done(): if (at_end[0] and delays.length == 0): observer.on_completed() subscription = SerialDisposable() def start(): def on_next(x): try: delay = mapper(x) except Exception as error: observer.on_error(error) return d = SingleAssignmentDisposable() delays.add(d) def on_next(_): observer.on_next(x) delays.remove(d) done() def on_completed(): observer.on_next(x) delays.remove(d) done() d.disposable = delay.subscribe_(on_next, observer.on_error, on_completed, scheduler) def on_completed(): at_end[0] = True subscription.dispose() done() subscription.disposable = source.subscribe_( on_next, observer.on_error, on_completed, scheduler) if not sub_delay: start() else: subscription.disposable( sub_delay.subscribe_(lambda _: start(), observer.on_error, start)) return CompositeDisposable(subscription, delays)
def test_groupdisposable_remove(): disp1 = [False] disp2 = [False] def action1(): disp1[0] = True d1 = Disposable.create(action1) def action2(): disp2[0] = True d2 = Disposable.create(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.create(action3) assert not g.remove(d3) assert not disp3[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 msecs = self.to_relative(duetime) if msecs == 0: return scheduler.schedule(action, state) disposable = SingleAssignmentDisposable() def interval(): disposable.disposable = action(scheduler, state) log.debug("timeout: %s", msecs) alarm = self.master.after(msecs, interval) def dispose(): # nonlocal alarm self.master.after_cancel(alarm) return CompositeDisposable(disposable, Disposable(dispose))
def subscribe(observer): subscription = SerialDisposable() cancelable = SerialDisposable() enum = iter(sources) is_disposed = [] def action(action1, state=None): if is_disposed: return def on_completed(): cancelable.disposable = scheduler.schedule(action) try: current = next(enum) except StopIteration: observer.on_completed() except Exception as ex: observer.on_error(ex) else: d = SingleAssignmentDisposable() subscription.disposable = d d.disposable = current.subscribe(observer.on_next, observer.on_error, on_completed) cancelable.disposable = scheduler.schedule(action) def dispose(): is_disposed.append(True) return CompositeDisposable(subscription, cancelable, Disposable.create(dispose))
def subscribe(observer): at_end = None has_value = None value = None def sample_subscribe(x): nonlocal has_value if has_value: has_value = False observer.on_next(value) if at_end: observer.on_completed() def on_next(new_value): nonlocal value, has_value has_value = True value = new_value def on_completed(): nonlocal at_end at_end = True return CompositeDisposable( source.subscribe(on_next, observer.on_error, on_completed), sampler.subscribe(sample_subscribe, observer.on_error, sample_subscribe))
def subscribe(observer): def on_completed(x): observer.on_completed() return CompositeDisposable( source.subscribe(observer), other.subscribe(on_completed, observer.on_error, noop))
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 = self.to_relative(time) disposable = SingleAssignmentDisposable() periodic_state = [state] stopped = [False] def timer_handler(_): if stopped[0]: return False if periodic: periodic_state[0] = action(periodic_state[0]) else: disposable.disposable = action(scheduler, state) return periodic GLib.timeout_add(msecs, timer_handler, None) def dispose(): stopped[0] = True return CompositeDisposable(disposable, Disposable.create(dispose))
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).""" from twisted.internet.task import deferLater scheduler = self seconds = self.to_relative(duetime) / 1000.0 disposable = SingleAssignmentDisposable() def interval(): disposable.disposable = action(scheduler, state) log.debug("timeout: %s", seconds) handle = deferLater(self.reactor, seconds, interval).addErrback(lambda _: None) def dispose(): if not handle.called: handle.cancel() return CompositeDisposable(disposable, Disposable.create(dispose))
def invoke_rec_date(scheduler, pair, method): state = pair.get('first') action = pair.get('second') group = CompositeDisposable() def inner_action(state2, duetime): is_added = False is_done = [False] def schedule_work(_, state3): action(state3, inner_action) if is_added: group.remove(d) else: is_done[0] = True return Disposable.empty() d = getattr(scheduler, method)(duetime=duetime, action=schedule_work, state=state2) if not is_done[0]: group.add(d) is_added = True action(state, inner_action) return group
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_relative(duetime) / 1000.0 disposable = SingleAssignmentDisposable() def interval(): disposable.disposable = action(scheduler, state) log.debug("timeout: %s", seconds) handle = [self.reactor.callLater(seconds, interval)] def dispose(): handle[0].cancel() return CompositeDisposable(disposable, Disposable(dispose))
def schedule_relative(self, duetime, action, state=None): """Schedules an action to be executed at 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_relative(duetime) / 1000.0 if seconds == 0: return scheduler.schedule(action, state) disposable = SingleAssignmentDisposable() def interval(): disposable.disposable = self.invoke_action(action, state) handle = [self.loop.call_later(seconds, interval)] def dispose(): # nonlocal handle handle[0].cancel() return CompositeDisposable(disposable, Disposable.create(dispose))
def subscribe(observer): enum = iter(sources) is_disposed = [False] subscription = SerialDisposable() def action(action1, state=None): if is_disposed[0]: return try: current = next(enum) except StopIteration: observer.on_completed() except Exception as ex: observer.on_error(ex) else: d = SingleAssignmentDisposable() subscription.disposable = d d.disposable = current.subscribe( observer.on_next, observer.on_error, lambda: action1() ) cancelable = immediate_scheduler.schedule_recursive(action) def dispose(): is_disposed[0] = True return CompositeDisposable(subscription, cancelable, Disposable.create(dispose))
def _wxtimer_schedule(self, time, action, state, periodic=False): scheduler = self msecs = self.to_relative(time) disposable = SingleAssignmentDisposable() periodic_state = [state] def interval(): if periodic: periodic_state[0] = action(periodic_state[0]) else: disposable.disposable = action(scheduler, state) log.debug("timeout: %s", msecs) if msecs == 0: msecs = 1 # wx.Timer doesn't support zero. 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(disposable, Disposable.create(dispose))
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 = scheduler.to_relative(duetime) / 1000.0 if not seconds: return scheduler.schedule(action, state) disposable = SingleAssignmentDisposable() def interval(): disposable.disposable = self.invoke_action(action, state) log.debug("timeout: %s", seconds) handle = self.loop.call_later(seconds, interval) def dispose(): self.loop.remove_timeout(handle) return CompositeDisposable(disposable, Disposable.create(dispose))
def subscribe(observer): 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 = Observable.from_future(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) cancelable.disposable = scheduler.schedule(action) return CompositeDisposable(subscription, cancelable)
def invoke_rec_immediate(scheduler, pair): state = pair.get('state') action = pair.get('action') group = CompositeDisposable() def inner_action(state2=None): is_added = False is_done = [False] def schedule_work(_, state3): action(inner_action, state3) if is_added: group.remove(d) else: is_done[0] = True return Disposable.empty() d = scheduler.schedule(schedule_work, state2) if not is_done[0]: group.add(d) is_added = True action(inner_action, state) return group
def _qtimer_schedule(self, time, action, state, periodic=False): scheduler = self msecs = self.to_relative(time) disposable = SingleAssignmentDisposable() periodic_state = [state] def interval(): if periodic: periodic_state[0] = action(periodic_state[0]) else: disposable.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(disposable, Disposable.create(dispose))
def subscribe(observer): active_count = 0 group = CompositeDisposable() is_stopped = False q = [] def subscribe(xs): subscription = SingleAssignmentDisposable() group.add(subscription) def on_completed(): nonlocal active_count group.remove(subscription) if q.length > 0: s = q.shift() subscribe(s) else: active_count -= 1 if is_stopped and active_count == 0: observer.on_completed() subscription.disposable = xs.subscribe(observer.on_next, observer.on_error, on_completed) def on_next(inner_source): nonlocal active_count if active_count < max_concurrent_or_other: active_count += 1 subscribe(inner_source) else: q.append(inner_source) def on_completed(): nonlocal is_stopped is_stopped = True if active_count == 0: observer.on_completed() group.add(sources.subscribe(on_next, observer.on_error, on_completed)) return group
def subscribe(observer): n = len(sources) queues = [[] for _ in range(n)] is_done = [False] * n def next(i): if all([len(q) for q in queues]): res = [x.pop(0) for x in queues] observer.on_next(res) elif all([x for j, x in enumerate(is_done) if j != i]): observer.on_completed() return def done(i): is_done[i] = True if all(is_done): observer.on_completed() return subscriptions = [None]*n def func(i): subscriptions[i] = SingleAssignmentDisposable() def on_next(x): queues[i].append(x) next(i) subscriptions[i].disposable = sources[i].subscribe(on_next, observer.on_error, lambda: done(i)) for idx in range(n): func(idx) composite_disposable = CompositeDisposable(subscriptions) def action(): for _ in queues: queues[n] = [] composite_disposable.add(Disposable.create(action)) return composite_disposable
def subscribe(observer): m = SerialDisposable() d = CompositeDisposable(m) r = RefCountDisposable(d) window = Subject() observer.on_next(add_ref(window, r)) def on_next(x): window.on_next(x) def on_error(ex): window.on_error(ex) observer.on_error(ex) def on_completed(): window.on_completed() observer.on_completed() d.add(source.subscribe(on_next, on_error, on_completed)) def create_window_close(): try: window_close = window_closing_selector() except Exception as exception: log.error("*** Exception: %s" % exception) observer.on_error(exception) return def on_completed(): window.on_completed() window = Subject() observer.on_next(add_ref(window, r)) create_window_close() m1 = SingleAssignmentDisposable() m.disposable(m1) m1.disposable(window_close.take(1).subscribe(noop, on_error, on_completed)) create_window_close() return r
def init(self): logger.info('Starting %s', self) self._subscription = CompositeDisposable( self._subscribe_for_get_server_time_command(), self._subscribe_for_get_price_command(), self._subscribe_for_get_balance_command(), self._subscribe_for_get_active_orders_command(), self._subscribe_for_get_completed_orders_command(), self._subscribe_for_create_sell_order_command(), self._subscribe_for_create_buy_order_command(), self._subscribe_for_cancel_order_command(), )
def test_groupdisposable_addafterdispose(): disp1 = [False] disp2 = [False] def action1(): disp1[0] = True d1 = Disposable.create(action1) def action2(): disp2[0] = True d2 = Disposable.create(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
def subscribe(observer): active_count = [0] group = CompositeDisposable() is_stopped = [False] q = [] def subscribe(xs): subscription = SingleAssignmentDisposable() group.add(subscription) def on_completed(): group.remove(subscription) if len(q): s = q.pop(0) subscribe(s) else: active_count[0] -= 1 if is_stopped[0] and active_count[0] == 0: observer.on_completed() subscription.disposable = xs.subscribe(observer.on_next, observer.on_error, on_completed) def on_next(inner_source): if active_count[0] < max_concurrent: active_count[0] += 1 subscribe(inner_source) else: q.append(inner_source) def on_completed(): is_stopped[0] = True if active_count[0] == 0: observer.on_completed() group.add(sources.subscribe(on_next, observer.on_error, on_completed)) return group
def init(self): logger.info('Starting %s', self) self._subscription = CompositeDisposable( self._subscribe_for_poll_server_time(), self._subscribe_for_poll_price(), self._subscribe_for_poll_balance(), self._subscribe_for_poll_active_orders(), self._subscribe_for_poll_completed_orders(), self._subscribe_for_time_and_price(), self._subscribe_for_balance(), self._subscribe_for_active_orders(), self._subscribe_for_completed_orders(), self._subscribe_for_jumping_price() )
def subscribe(observer): 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 = Observable.from_future(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 ) def on_completed(): is_stopped[0] = True if not has_current[0] and len(g) == 1: observer.on_completed() m.disposable = sources.subscribe(on_next, observer.on_error, on_completed) return g
def test_groupdisposable_addafterdispose(): disp1 = False disp2 = False def action1(): nonlocal disp1 disp1 = True d1 = Disposable(action1) def action2(): nonlocal disp2 disp2 = True d2 = Disposable(action2) g = CompositeDisposable(d1) assert g.length == 1 g.dispose() assert disp1 assert g.length == 0 g.add(d2) assert disp2 assert g.length == 0
def test_groupdisposable_remove(): disp1 = False disp2 = False def action1(): nonlocal disp1 disp1 = True d1 = Disposable(action1) def action2(): nonlocal disp2 disp2 = 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 assert g.remove(d2) assert not g.contains(d1) assert not g.contains(d2) assert disp2 disp3 = False; def action3(): nonlocal disp3 disp3 = True d3 = Disposable(action3) assert not g.remove(d3) assert not disp3
def subscribe(observer): mapping = OrderedDict() group_disposable = CompositeDisposable() ref_count_disposable = RefCountDisposable(group_disposable) def on_next(x): writer = None element = None duration = None key = None try: key = key_selector(x) except Exception as e: for w in mapping.values(): w.on_error(e) observer.on_error(e) return fire_new_map_entry = False writer = mapping.get(key) if not writer: writer = Subject() mapping[key] = writer fire_new_map_entry = True if fire_new_map_entry: group = GroupedObservable(key, writer, ref_count_disposable) duration_group = GroupedObservable(key, writer) try: duration = duration_selector(duration_group) except Exception as e: for w in mapping.values(): w.on_error(e) observer.on_error(e) return observer.on_next(group) md = SingleAssignmentDisposable() group_disposable.add(md) def expire(): if mapping[serialized_key]: del mapping[serialized_key] writer.on_completed() group_disposable.remove(md) def on_next(value): pass def on_error(exn): for wr in mapping.values(): wr.on_error(exn) observer.on_error(exn) def on_completed(): expire() md.disposable = duration.take(1).subscribe(on_next, on_error, on_completed) try: element = element_selector(x) except Exception as e: for w in mapping.values(): w.on_error(e) observer.on_error(e) return writer.on_next(element) def on_error(ex): for w in mapping.values(): w.on_error(ex) observer.on_error(ex) def on_completed(): for w in mapping.values(): w.on_completed() observer.on_completed() group_disposable.add(source.subscribe(on_next, on_error, on_completed)) return ref_count_disposable
def subscribe(observer): group = CompositeDisposable() left_done = [False] left_map = OrderedDict() left_id = [0] right_done = [False] right_map = OrderedDict() right_id = [0] def on_next_left(value): duration = None current_id = left_id[0] left_id[0] += 1 md = SingleAssignmentDisposable() left_map[current_id] = value group.add(md) def expire(): if current_id in left_map: del left_map[current_id] if not len(left_map) and left_done[0]: observer.on_completed() return group.remove(md) try: duration = left_duration_selector(value) except Exception as exception: log.error("*** Exception: %s" % exception) observer.on_error(exception) return md.disposable = duration.take(1).subscribe(noop, observer.on_error, lambda: expire()) for val in right_map.values(): try: result = result_selector(value, val) except Exception as exception: log.error("*** Exception: %s" % exception) observer.on_error(exception) return observer.on_next(result) def on_completed_left(): left_done[0] = True if right_done[0] or not len(left_map): observer.on_completed() group.add(left.subscribe(on_next_left, observer.on_error, on_completed_left)) def on_next_right(value): duration = None current_id = right_id[0] right_id[0] += 1 md = SingleAssignmentDisposable() right_map[current_id] = value group.add(md) def expire(): if current_id in right_map: del right_map[current_id] if not len(right_map) and right_done[0]: observer.on_completed() return group.remove(md) try: duration = right_duration_selector(value) except Exception as exception: log.error("*** Exception: %s" % exception) observer.on_error(exception) return md.disposable = duration.take(1).subscribe(noop, observer.on_error, lambda: expire()) for val in left_map.values(): try: result = result_selector(val, value) except Exception as exception: log.error("*** Exception: %s" % exception) observer.on_error(exception) return observer.on_next(result) def on_completed_right(): right_done[0] = True if left_done[0] or not len(right_map): observer.on_completed() group.add(right.subscribe(on_next_right, observer.on_error, on_completed_right)) return group
def subscribe(observer): nothing = lambda _: None group = CompositeDisposable() r = RefCountDisposable(group) left_map = OrderedDict() right_map = OrderedDict() left_id = [0] right_id = [0] def on_next_left(value): s = Subject() _id = left_id[0] left_id[0] += 1 left_map[_id] = s try: result = result_selector(value, add_ref(s, r)) 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(): s.on_next(right_value) md = SingleAssignmentDisposable() group.add(md) def expire(): if _id in left_map: del left_map[_id] s.on_completed() group.remove(md) try: duration = left_duration_selector(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(e): for left_value in left_map.values(): left_value.on_error(e) observer.on_error(e) md.disposable = duration.take(1).subscribe( nothing, on_error, expire) def on_error_left(e): for left_value in left_map.values(): left_value.on_error(e) observer.on_error(e) group.add(left.subscribe(on_next_left, on_error_left, observer.on_completed)) def on_next_right(value): _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_selector(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(e): for left_value in left_map.values(): left_value.on_error(e) observer.on_error(e) md.disposable = duration.take(1).subscribe( nothing, on_error, expire) for left_value in left_map.values(): left_value.on_next(value) def on_error_right(e): for left_value in left_map.values(): left_value.on_error(e) observer.on_error(e) group.add(right.subscribe(on_next_right, on_error_right)) return r
class Trader: POLL_IMMEDIATELY = 1 POLL_SERVER_TIME_INTERVAL = 1000 POLL_PRICE_INTERVAL = 10000 POLL_BALANCE_INTERVAL = 600000 POLL_ACTIVE_ORDERS_INTERVAL = 3600000 POLL_COMPLETED_ORDERS_INTERVAL = 10000 SHOW_TIME_AND_PRICE_INTERVAL = 600000 REASON_PRICE_JUMP = 0 REASON_ORDER_COMPLETED = 1 def __init__(self, options: TradingOptions, events: Observable, commands: Observable): self._subscription = None self._options = options self._events = events self._commands = commands def __repr__(self): return 'Trader(pair=%s)' % self._options.pair def _get_time(self): return (self._events .filter(lambda event: isinstance(event, events.TimeEvent)) .map(lambda event: event.value)) def _get_price(self): return (self._events .filter(lambda event: isinstance(event, events.PriceEvent)) .filter(lambda event: event.pair == self._options.pair) .map(lambda event: event.value)) def _get_balance(self, event_stream, currency): return (event_stream .filter(lambda event: isinstance(event, events.BalanceEvent)) .filter(lambda event: event.currency == currency) .map(lambda event: event.value) .scan(lambda p, balance: d(balance=balance, change=(Decimal(0) if p.balance is None else balance - p.balance)), d(balance=None, change=None))) def _get_first_currency_balance(self): return self._get_balance(self._events, self._options.pair.first) def _get_second_currency_balance(self): return self._get_balance(self._events, self._options.pair.second) def _get_active_orders(self): return (self._events .filter(lambda event: isinstance(event, events.ActiveOrdersEvent)) .filter(lambda event: event.pair == self._options.pair) .map(lambda event: event.orders)) def _get_completed_orders_singly(self, event_stream, pair): return (event_stream .filter(lambda event: isinstance(event, events.CompletedOrdersEvent)) .filter(lambda event: event.pair == pair) .map(lambda event: event.orders) .scan(lambda p, orders: d(orders=orders, change=(set() if p.orders is None else set(orders) - set(p.orders))), d(orders=None, change=None)) .map(lambda p: p.change) .switch_map(Observable.from_iterable)) def _get_jumping_price(self): return (self._get_price() .scan(lambda prev, price: prev if prev and abs(price - prev) / prev < self._options.price_jump_value else price) .distinct_until_changed() .skip(1)) def init(self): logger.info('Starting %s', self) self._subscription = CompositeDisposable( self._subscribe_for_poll_server_time(), self._subscribe_for_poll_price(), self._subscribe_for_poll_balance(), self._subscribe_for_poll_active_orders(), self._subscribe_for_poll_completed_orders(), self._subscribe_for_time_and_price(), self._subscribe_for_balance(), self._subscribe_for_active_orders(), self._subscribe_for_completed_orders(), self._subscribe_for_jumping_price() ) def _subscribe_for_poll_server_time(self): return (Observable .timer(self.POLL_IMMEDIATELY, self.POLL_SERVER_TIME_INTERVAL, MAIN_THREAD) .subscribe(lambda count: self._commands.on_next(commands.GetServerTimeCommand()))) def _subscribe_for_poll_price(self): return (Observable .timer(self.POLL_IMMEDIATELY, self.POLL_PRICE_INTERVAL, MAIN_THREAD) .subscribe(lambda count: self._commands.on_next(commands.GetPriceCommand(self._options.pair)))) def _subscribe_for_poll_balance(self): return CompositeDisposable( (Observable .timer(self.POLL_IMMEDIATELY, self.POLL_BALANCE_INTERVAL, MAIN_THREAD) .subscribe(lambda count: self._commands.on_next(commands.GetBalanceCommand(self._options.pair.first)))), (Observable .timer(self.POLL_IMMEDIATELY, self.POLL_BALANCE_INTERVAL, MAIN_THREAD) .subscribe(lambda count: self._commands.on_next(commands.GetBalanceCommand(self._options.pair.second)))) ) def _subscribe_for_poll_active_orders(self): return (Observable .timer(self.POLL_IMMEDIATELY, self.POLL_ACTIVE_ORDERS_INTERVAL, MAIN_THREAD) .subscribe(lambda count: self._commands.on_next(commands.GetActiveOrdersCommand(self._options.pair)))) def _subscribe_for_poll_completed_orders(self): return (Observable .timer(self.POLL_IMMEDIATELY, self.POLL_COMPLETED_ORDERS_INTERVAL, MAIN_THREAD) .subscribe(lambda count: self._commands.on_next(commands.GetCompletedOrdersCommand(self._options.pair)))) def _subscribe_for_time_and_price(self): return (Observable .combine_latest( self._get_time(), self._get_price(), d('time', 'price') ) .throttle_first(self.SHOW_TIME_AND_PRICE_INTERVAL, MAIN_THREAD) .subscribe(lambda p: logger.info('[%s] Time now is %s, price is %s', self._options.pair, p.time, p.price))) def _subscribe_for_balance(self): return (Observable .combine_latest( self._get_first_currency_balance().map(lambda p: d(balance1=p.balance, change1=p.change)), self._get_second_currency_balance().map(lambda p: d(balance2=p.balance, change2=p.change)), d('balance1', 'change1', 'balance2', 'change2') ) .distinct_until_changed(lambda p: (p.balance1, p.balance2)) .subscribe(lambda p: logger.info('[%s] Balance is %s %s (%s) and %s %s (%s)', self._options.pair, p.balance1, self._options.pair.first, p.change1, p.balance2, self._options.pair.second, p.change2))) def _subscribe_for_active_orders(self): return CompositeDisposable( (self._get_active_orders() .subscribe(lambda orders: logger.info('[%s] Active orders: %s', self._options.pair, ', '.join(map(repr, orders))) if orders else logger.info('[%s] No active orders found', self._options.pair))), (self._get_active_orders() .switch_map(Observable.from_iterable) .filter(lambda order: datetime.utcnow() - order.created > config.ORDER_OUTDATE_PERIOD) .subscribe(self._cancel_order)) ) def _get_new_orders(self, completed_orders, min_amount): return (completed_orders .map(self._get_type_and_amount_and_price_for_new_order) .map(d('order_type', 'amount', 'price')) .filter(lambda p: p.amount >= min_amount)) def _get_new_sell_orders(self, event_stream, pair, min_amount): return (Observable .combine_latest( (self._get_new_orders(self._get_completed_orders_singly(event_stream, pair), min_amount) .filter(lambda p: p.order_type == Order.TYPE_SELL)), self._get_first_currency_balance().map(lambda p: p.balance), d('amount', 'price', 'balance') ) .distinct_until_changed(lambda p: (p.amount, p.price)) .filter(lambda p: p.amount <= p.balance)) def _get_new_buy_orders(self, event_stream, pair, min_amount): return (Observable .combine_latest( (self._get_new_orders(self._get_completed_orders_singly(event_stream, pair), min_amount) .filter(lambda p: p.order_type == Order.TYPE_BUY)), self._get_second_currency_balance().map(lambda p: p.balance), d('amount', 'price', 'balance') ) .distinct_until_changed(lambda p: (p.amount, p.price)) .filter(lambda p: p.amount * p.price <= p.balance)) def _subscribe_for_completed_orders(self): return CompositeDisposable( (self._get_completed_orders_singly(self._events, self._options.pair) .subscribe(lambda order: logger.info('[%s] %s completed', self._options.pair, order))), (self._get_new_sell_orders(self._events, self._options.pair, self._options.min_amount) .subscribe(lambda p: self._create_sell_order(p.amount, p.price, self.REASON_ORDER_COMPLETED))), (self._get_new_buy_orders(self._events, self._options.pair, self._options.min_amount) .subscribe(lambda p: self._create_buy_order(p.amount, p.price, self.REASON_ORDER_COMPLETED))) ) def _subscribe_for_jumping_price(self): return CompositeDisposable( (Observable .combine_latest( self._get_jumping_price().map(partial(self._get_new_price, Order.TYPE_SELL)), self._get_first_currency_balance().map(lambda p: p.balance), d('price', 'balance') ) .distinct_until_changed(lambda p: p.price) .filter(lambda p: self._options.deal_amount <= p.balance) .subscribe(lambda p: self._create_sell_order(self._options.deal_amount, p.price, self.REASON_PRICE_JUMP))), (Observable .combine_latest( self._get_jumping_price().map(partial(self._get_new_price, Order.TYPE_BUY)), self._get_second_currency_balance().map(lambda p: p.balance), d('price', 'balance') ) .distinct_until_changed(lambda p: p.price) .filter(lambda p: self._options.deal_amount * p.price <= p.balance) .subscribe(lambda p: self._create_buy_order(self._options.deal_amount, p.price, self.REASON_PRICE_JUMP))), ) def _get_type_and_amount_and_price_for_new_order(self, order): if order.type == Order.TYPE_SELL: return Order.TYPE_BUY, order.amount, self._get_new_price(Order.TYPE_BUY, order.price) if order.type == Order.TYPE_BUY: return Order.TYPE_SELL, order.amount, self._get_new_price(Order.TYPE_SELL, order.price) raise Exception('unknown order type %s' % order.type) def _get_new_price(self, order_type, price): margin = self._options.margin + self._get_random_margin_jitter(self._options.margin_jitter) if order_type == Order.TYPE_SELL: return normalize_value(price + price * margin, self._options.pair.second.places) if order_type == Order.TYPE_BUY: return normalize_value(price - price * margin, self._options.pair.second.places) raise Exception('unknown order type %s' % order_type) def _create_sell_order(self, amount, price, reason): logger.info('[%s] Create sell order: %s for %s, reason is %s', self._options.pair, amount, price, reason) self._commands.on_next(commands.CreateSellOrderCommand(self._options.pair, amount, price)) def _create_buy_order(self, amount, price, reason): logger.info('[%s] Create buy order: %s for %s, reason is %s', self._options.pair, amount, price, reason) self._commands.on_next(commands.CreateBuyOrderCommand(self._options.pair, amount, price)) def _get_random_margin_jitter(self, jitter): return normalize_value(Decimal(uniform(-float(jitter), float(jitter))), 4) def _cancel_order(self, order): logger.info('[%s] Cancel outdated order %s created %s (%s ago)', self._options.pair, order, order.created, datetime.utcnow() - order.created) self._commands.on_next(commands.CancelOrderCommand(order.id)) def deinit(self): logger.info('Stopping %s', self) if self._subscription is not None: self._subscription.dispose()
def subscribe(observer): nothing = lambda _: None group = CompositeDisposable() r = RefCountDisposable(group) left_map = OrderedDict() right_map = OrderedDict() left_id = 0 right_id = 0 def on_next_left(value): s = Subject() _id = left_id left_id += 1 left_map.add(_id, s) try: result = result_selector(value, add_ref(s, r)) except Exception as e: log.error("*** Exception: %s" % e) left_values = left_map.getValues() for left_value in left_values: left_value.on_error(e) observer.on_error(e) return observer.on_next(result) right_values = right_map.getValues() for right_value in right_values: s.on_next(right_value) md = SingleAssignmentDisposable() group.add(md) def expire(): if left_map.remove(_id): s.on_completed() group.remove(md) try: duration = left_duration_selector(value) except Exception as e: left_values = left_map.getValues() for left_value in left_values: left_value.on_error(e) observer.on_error(e) return def on_error(e): left_values = left_map.getValues() for left_value in left_values: left_value.on_error(e) observer.on_error(e) md.disposable = duration.take(1).subscribe( nothing, on_error, expire) def on_error_left(e): left_values = left_map.values() for left_value in left_values: left_value.on_error(e) observer.on_error(e) group.add(left.subscribe(on_next_left, on_error_left, observer.on_completed)) def on_next_right(value): left_values, i, len _id = right_id right_id += 1 right_map.add(id, value) md = SingleAssignmentDisposable() group.add(md) def expire(): right_map.remove(id) group.remove(md) try: duration = right_duration_selector(value) except Exception as e: left_values = left_map.getValues() for left_value in left_values: left_value.on_error(e) observer.on_error(e) return def on_error(e): left_values = left_map.getValues() for left_value in left_map: left_value.on_error(e) observer.on_error(e) md.disposable = duration.take(1).subscribe( nothing, on_error, expire) left_values = left_map.getValues() for left_value in left_values: left_values.on_next(value) def on_error_right(e): left_values = left_map.values() for left_value in left_values: left_value.on_error(e) observer.on_error(e) group.add(right.subscribe(on_next_right, on_error_right)) return r
def subscribe(observer): group = CompositeDisposable() left_done = False left_map = OrderedDict() left_id = 0 right_done = False right_map = OrderedDict() right_id = 0 def on_next_left(value): nonlocal left_id duration = None current_id = left_id left_id += 1 md = SingleAssignmentDisposable() #log.debug("**** left_map[%s] = %s" % (current_id, value)) #log.debug(value.get_hash_code()) left_map[current_id] = value group.add(md) def expire(): if current_id in left_map: del left_map[current_id] if not len(left_map) and left_done: observer.on_completed() return group.remove(md) try: duration = left_duration_selector(value) except Exception as exception: log.error("*** Exception: %s" % exception) observer.on_error(exception) return md.disposable = duration.take(1).subscribe(noop, observer.on_error, lambda: expire()) values = right_map.values() for val in values: try: result = result_selector(value, val) except Exception as exception: log.error("*** Exception: %s" % exception) observer.on_error(exception) return observer.on_next(result) def on_completed_left(): nonlocal left_done left_done = True if right_done or not len(left_map): observer.on_completed() group.add(left.subscribe(on_next_left, observer.on_error, on_completed_left)) def on_next_right(value): nonlocal right_id duration = None current_id = right_id right_id += 1 md = SingleAssignmentDisposable() right_map[current_id] = value group.add(md) def expire(): if current_id in right_map: del right_map[current_id] if not len(right_map) and right_done: observer.on_completed() return group.remove(md) try: duration = right_duration_selector(value) except Exception as exception: log.error("*** Exception: %s" % exception) observer.on_error(exception) return md.disposable = duration.take(1).subscribe(noop, observer.on_error, lambda: expire()) values = left_map.values() for val in values: try: result = result_selector(val, value) except Exception as exception: log.error("*** Exception: %s" % exception) observer.on_error(exception) return observer.on_next(result) def on_completed_right(): nonlocal right_done right_done = True if left_done or not len(right_map): observer.on_completed() group.add(right.subscribe(on_next_right, observer.on_error, on_completed_right)) return group