102 lines
3.2 KiB
Python
102 lines
3.2 KiB
Python
from asyncio import Future
|
|
from datetime import datetime
|
|
from typing import Any, Callable, Optional, TypeVar, Union
|
|
|
|
from reactivex import Observable, abc, from_future, throw, typing
|
|
from reactivex.disposable import (
|
|
CompositeDisposable,
|
|
SerialDisposable,
|
|
SingleAssignmentDisposable,
|
|
)
|
|
from reactivex.scheduler import TimeoutScheduler
|
|
|
|
_T = TypeVar("_T")
|
|
|
|
|
|
def timeout_(
|
|
duetime: typing.AbsoluteOrRelativeTime,
|
|
other: Optional[Union[Observable[_T], "Future[_T]"]] = None,
|
|
scheduler: Optional[abc.SchedulerBase] = None,
|
|
) -> Callable[[Observable[_T]], Observable[_T]]:
|
|
|
|
other = other or throw(Exception("Timeout"))
|
|
if isinstance(other, Future):
|
|
obs = from_future(other)
|
|
else:
|
|
obs = other
|
|
|
|
def timeout(source: Observable[_T]) -> Observable[_T]:
|
|
"""Returns the source observable sequence or the other observable
|
|
sequence if duetime elapses.
|
|
|
|
Examples:
|
|
>>> res = timeout(source)
|
|
|
|
Args:
|
|
source: Source observable to timeout
|
|
|
|
Returns:
|
|
An obserable sequence switching to the other sequence in
|
|
case of a timeout.
|
|
"""
|
|
|
|
def subscribe(
|
|
observer: abc.ObserverBase[_T],
|
|
scheduler_: Optional[abc.SchedulerBase] = None,
|
|
) -> abc.DisposableBase:
|
|
_scheduler = scheduler or scheduler_ or TimeoutScheduler.singleton()
|
|
|
|
switched = [False]
|
|
_id = [0]
|
|
|
|
original = SingleAssignmentDisposable()
|
|
subscription = SerialDisposable()
|
|
timer = SerialDisposable()
|
|
subscription.disposable = original
|
|
|
|
def create_timer() -> None:
|
|
my_id = _id[0]
|
|
|
|
def action(scheduler: abc.SchedulerBase, state: Any = None):
|
|
switched[0] = _id[0] == my_id
|
|
timer_wins = switched[0]
|
|
if timer_wins:
|
|
subscription.disposable = obs.subscribe(
|
|
observer, scheduler=scheduler
|
|
)
|
|
|
|
if isinstance(duetime, datetime):
|
|
timer.disposable = _scheduler.schedule_absolute(duetime, action)
|
|
else:
|
|
timer.disposable = _scheduler.schedule_relative(duetime, action)
|
|
|
|
create_timer()
|
|
|
|
def on_next(value: _T) -> None:
|
|
send_wins = not switched[0]
|
|
if send_wins:
|
|
_id[0] += 1
|
|
observer.on_next(value)
|
|
create_timer()
|
|
|
|
def on_error(error: Exception) -> None:
|
|
on_error_wins = not switched[0]
|
|
if on_error_wins:
|
|
_id[0] += 1
|
|
observer.on_error(error)
|
|
|
|
def on_completed() -> None:
|
|
on_completed_wins = not switched[0]
|
|
if on_completed_wins:
|
|
_id[0] += 1
|
|
observer.on_completed()
|
|
|
|
original.disposable = source.subscribe(
|
|
on_next, on_error, on_completed, scheduler=scheduler_
|
|
)
|
|
return CompositeDisposable(subscription, timer)
|
|
|
|
return Observable(subscribe)
|
|
|
|
return timeout
|