aboutsummaryrefslogtreecommitdiff
path: root/python/qemu/aqmp/util.py
diff options
context:
space:
mode:
authorJohn Snow <jsnow@redhat.com>2021-09-15 12:29:33 -0400
committerJohn Snow <jsnow@redhat.com>2021-09-27 12:10:29 -0400
commit4ccaab0377dec88b5cf1a55064b4953f6ab59d9f (patch)
treed5f7fabb64a8f0065f8a4acfd361a4464f2c134a /python/qemu/aqmp/util.py
parenta07616d612bebc6324b29d7ab0c9b84d4e9d7c42 (diff)
downloadqemu-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.py53
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
# -------------------------------