async def _run(proc, args, kw, *, task_status): """ Helper for starting a task within a cancel scope. """ with anyio.CancelScope() as sc: task_status.started(sc) await proc(*args, **kw)
async def _run_reconnected(self, val: ValueEvent): try: with anyio.CancelScope() as scope: self._current_run = scope while True: try: await self._run_one(val) except anyio.get_cancelled_exc_class(): raise except ( BrokenPipeError, TimeoutError, EnvironmentError, anyio.IncompleteRead, ConnectionResetError, anyio.ClosedResourceError, StopAsyncIteration, ) as exc: if val is not None and not val.is_set(): val.set_error(exc) return logger.error("Disconnected") val = None await anyio.sleep(self._backoff) if self._backoff < 10: self._backoff *= 1.5 else: pass finally: self._current_run = None
async def serve(self) -> None: await self._master.register_service(self.service_name) try: await anyio.sleep_forever() except anyio.get_cancelled_exc_class(): with anyio.CancelScope(shield=True), anyio.move_on_after(1): await self._master.unregister_service(self.service_name) raise
async def aclose(self) -> None: # TODO mutex if self._instances == 1: self._instances -= 1 with anyio.CancelScope(shield=True), anyio.move_on_after(1): await self._master.unregister_publisher(self.topic_name) for subscriber in self._subscribers: await subscriber.stream.aclose() self._subscribers.clear()
async def _add_task(self, val, proc, *args): with anyio.CancelScope() as scope: val.set(scope) try: await proc(*args) finally: try: self._tasks.remove(scope) except KeyError: pass
async def register( self, send_stream: MemoryObjectSendStream[abc.MessageT], ) -> None: async with self.lock: if not self.registered: with anyio.CancelScope(shield=True), anyio.move_on_after(1): publisher_uris = await self.master.register_subscriber( self.topic_name, getattr(self.topic_type, "_type")) self.registered = True self.update_publishers(publisher_uris) self.subscriptions.add(send_stream)
async def is_disconnected(self) -> bool: if not self._is_disconnected: message: Message = {} # If message isn't immediately available, move on with anyio.CancelScope() as cs: cs.cancel() message = await self._receive() if message.get("type") == "http.disconnect": self._is_disconnected = True return self._is_disconnected
async def _writer(self, evt): with anyio.CancelScope() as scope: self._write_task = scope evt.set() while True: try: with anyio.fail_after(10): msg = await self._wqueue_r.receive() except TimeoutError: msg = NOPMsg() self.requests.append(msg) await msg.write(self._msg_proto)
async def _run_one(self, val: ValueEvent): try: async with anyio.create_task_group() as tg: self._current_tg = tg self.stream = await anyio.connect_tcp(self.host, self.port) ml, self.requests = deque(self.requests), deque() try: self._msg_proto = MessageProtocol(self, is_server=False) e_w = anyio.Event() e_r = anyio.Event() tg.spawn(self._writer, e_w) tg.spawn(self._reader, e_r) await e_r.wait() await e_w.wait() # re-send messages, but skip those that have been cancelled while ml: msg = ml.popleft() if not msg.cancelled: try: await self._wqueue_w.send(msg) except BaseException: ml.appendleft(msg) except BaseException: self.requests = ml raise await self.chat(NOPMsg()) if self._scan_args is not None: tg.spawn(partial(self.start_scan, **self._scan_args)) if val is not None: val.set(None) self._backoff = 0.1 pass # wait for tasks pass # exited tasks finally: self._current_tg = None if self.stream is not None: with anyio.CancelScope(shield=True): await self.stream.aclose() self.stream = None
async def _reader(self, evt): try: with anyio.CancelScope() as scope: self._read_task = scope evt.set() it = self._msg_proto.__aiter__() while True: try: with anyio.fail_after(15): res, data = await it.__anext__() except StopAsyncIteration: raise anyio.ClosedResourceError from None except ServerBusy: logger.debug("Server %s busy", self.host) else: msg = self.requests.popleft() await msg.process_reply(res, data, self) if not msg.done(): self.requests.appendleft(msg) except anyio.ClosedResourceError: if self._current_tg is not None: self._current_tg.cancel_scope.cancel()
async def server( # pylint: disable=dangerous-default-value # intentional tree={}, options={}, events=None, polling=False, scan=None, initial_scan=True, **kw): """ This is a mock 1wire server+client. The context manager returns the client. ``tree`` and ``opotions`` are used as in `some_server`, ``polling``, ``scan`` and ``initial_scan`` are used to set up the client, other keyword arguments are forwarded to the client constructor. """ PORT = (os.getpid() % 9999) + 40000 async with OWFS(**kw) as ow: async with anyio.create_task_group() as tg: s = None try: listener = await anyio.create_tcp_listener( local_host="127.0.0.1", local_port=PORT, reuse_port=True) async def may_close(): try: await listener.serve( partial(some_server, tree, options)) except (anyio.ClosedResourceError, anyio.BrokenResourceError): pass except trio.MultiError as exc: exc = exc.filter( lambda x: None if isinstance(x, trio.Cancelled) else x, exc) if not isinstance(exc, (anyio.ClosedResourceError, anyio.BrokenResourceError)): raise except BaseException as exc: import pdb pdb.set_trace() raise if events is not None: evt = anyio.Event() tg.spawn(events, ow, evt) await evt.wait() addr = listener.extra( anyio.abc.SocketAttribute.raw_socket).getsockname() tg.spawn(may_close) s = await ow.add_server(*addr, polling=polling, scan=scan, initial_scan=initial_scan) ow.test_server = s yield ow finally: ow.test_server = None await listener.aclose() with anyio.CancelScope(shield=True): if s is not None: await s.drop() await ow.push_event(None) await anyio.sleep(0.1) tg.cancel_scope.cancel()
async def __aexit__(self, *tb): if self.path is not None: with anyio.CancelScope(shield=True): await self.stream.aclose()
async def wait_native_future() -> None: with anyio.CancelScope(): loop = asyncio.get_event_loop() await loop.create_future()
async def aclose(self) -> None: await self._receive_stream.aclose() with anyio.CancelScope(shield=True), anyio.move_on_after(1): await self._subscription_manager.unregister(self._send_stream)