diff options
author | John Snow <jsnow@redhat.com> | 2021-09-15 12:29:33 -0400 |
---|---|---|
committer | John Snow <jsnow@redhat.com> | 2021-09-27 12:10:29 -0400 |
commit | 4ccaab0377dec88b5cf1a55064b4953f6ab59d9f (patch) | |
tree | d5f7fabb64a8f0065f8a4acfd361a4464f2c134a /python/qemu/aqmp/util.py | |
parent | a07616d612bebc6324b29d7ab0c9b84d4e9d7c42 (diff) | |
download | qemu-4ccaab0377dec88b5cf1a55064b4953f6ab59d9f.zip qemu-4ccaab0377dec88b5cf1a55064b4953f6ab59d9f.tar.gz qemu-4ccaab0377dec88b5cf1a55064b4953f6ab59d9f.tar.bz2 |
python/aqmp: add generic async message-based protocol support
This is the bare minimum that you need to establish a full-duplex async
message-based protocol with Python's asyncio.
The features to be added in forthcoming commits are:
- Runstate tracking
- Logging
- Support for incoming connections via accept()
- _cb_outbound, _cb_inbound message hooks
- _readline() method
Signed-off-by: John Snow <jsnow@redhat.com>
Message-id: 20210915162955.333025-6-jsnow@redhat.com
Signed-off-by: John Snow <jsnow@redhat.com>
Diffstat (limited to 'python/qemu/aqmp/util.py')
-rw-r--r-- | python/qemu/aqmp/util.py | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/python/qemu/aqmp/util.py b/python/qemu/aqmp/util.py index 28acd99..5b8f968 100644 --- a/python/qemu/aqmp/util.py +++ b/python/qemu/aqmp/util.py @@ -13,12 +13,65 @@ from typing import ( Coroutine, Optional, TypeVar, + cast, ) T = TypeVar('T') +# -------------------------- +# Section: Utility Functions +# -------------------------- + + +async def flush(writer: asyncio.StreamWriter) -> None: + """ + Utility function to ensure a StreamWriter is *fully* drained. + + `asyncio.StreamWriter.drain` only promises we will return to below + the "high-water mark". This function ensures we flush the entire + buffer -- by setting the high water mark to 0 and then calling + drain. The flow control limits are restored after the call is + completed. + """ + transport = cast(asyncio.WriteTransport, writer.transport) + + # https://github.com/python/typeshed/issues/5779 + low, high = transport.get_write_buffer_limits() # type: ignore + transport.set_write_buffer_limits(0, 0) + try: + await writer.drain() + finally: + transport.set_write_buffer_limits(high, low) + + +def upper_half(func: T) -> T: + """ + Do-nothing decorator that annotates a method as an "upper-half" method. + + These methods must not call bottom-half functions directly, but can + schedule them to run. + """ + return func + + +def bottom_half(func: T) -> T: + """ + Do-nothing decorator that annotates a method as a "bottom-half" method. + + These methods must take great care to handle their own exceptions whenever + possible. If they go unhandled, they will cause termination of the loop. + + These methods do not, in general, have the ability to directly + report information to a caller’s context and will usually be + collected as a Task result instead. + + They must not call upper-half functions directly. + """ + return func + + # ------------------------------- # Section: Compatibility Wrappers # ------------------------------- |