Closed totaam closed 1 year ago
aioquic
is not available in Fedora and the number of dependencies required to run the http3 server example is a little bit ridiculous: python3-wsproto
, python3-httpbin
, python3-asgiref
, python3-starlette
and python3-aiofiles
.
Not counting all the dependencies that each one of these packages brings...
It gets worse since we also need to run the GTK main loop until we can drop GTK (#1995). There are various ways of doing this:
And perhaps soon in pygobject directly: Implement asyncio event loop based on glib
Next, creating asyncio
sockets requires using a specific API: asyncio.loop.create_datagram_endpoint / loop.create_connection, which means that socket sharing is going to be more difficult to implement.
This may help in bridging with the rest of the code:
I've done some testing with Aioquic. Basically I've just glued asyncio with aioquic to the existing codebase. The main issue is starting a new main loop inside a thread, inside the existing GTK loop. Also the list of dependencies is way too big (starlette and what not).
The source of aioquic seems pretty neat. I think the best way forward is to use this code as an example to implement our own low-level implementation of a http/3 quic server.
as an example to implement our own low-level implementation of a http/3 quic server
Yes! This part of the library looks really clean and, at first glance, without too many dependencies, only things like https://github.com/aiortc/pylsqpack Gio supports UDP so there is no reason why we can't use the GTK main loop for handling packet events.
We need an asyncio event loop: https://github.com/aiortc/aioquic/blob/444be09157aed3c81881d18647484165dd07139c/src/aioquic/asyncio/server.py#L202
The patches for pygobject are still languishing as a PR and asyncio-glib is unmaintained.
And gbulb has had no update since earlier this year.
Then there's also glibcoro: glibcoro makes the GLib
/ GTK
event loop compatible with Python’s asyncio
Meanwhile, this answer: https://stackoverflow.com/a/26719999/428751 suggests running the aio part in a separate thread. Downside is: _One does need to be careful, however, to use thread-safe functions to communicate between the GUI (main) thread and the asyncio thread. This means using loop.call_soon_threadsafe or asyncio.run_coroutine_threadsafe to submit things to asyncio from GTK, and GLib.idleadd to submit things to GTK from asyncio.
Decisions!
There's still a lot to do:
quic_queue_server
? (multiprocessing?)
aioquic.asyncio.server.serve
and we can use lower level APIs like QuicServer.datagram_received
from GLib
IO events?list_directory
in the "old" http handlerPOST
requests? HEAD
?quic_socket.close
- at least exit quic_queue_server
when all sockets are closedQuicConfiguration
server_name
should come from ssl options?max_data
/ max_stream_data
should be higher?quic_logger
to our own logging framework (with remote logging)http3_server.py
, remove wsproto
?FrameProtocol._serialize_frame
with our faster Cython mask
version?WebSocketHandler.send
call self.connection.send_data
repeatedly instead of concatenating header, mask and dataxpra start --no-daemon -d quic --start=xterm
--bind-tcp=0.0.0.0:10000
--bind-quic=localhost:20000 --ssl-cert=./cert.pem --ssl-key=./key.pem
Allows http3 clients to connect:
./examples/http3_client.py "https://localhost:20000/Sessions?hello=foo&bar=2" -k -v --output-dir=./output
Apparently, chrome needs to be told to use the QUIC protocol
As of d4c7fc8989d8a492b0f481fa5a092b3f875e7a35, I can connect via quic
using a self signed cert:
xpra start --bind-quic=localhost:20000 --start=xterm :100 \
--ssl-cert=./cert.pem --ssl-key=./key.pem
xpra attach quic://localhost:20000/ --ssl-server-verify-mode=none
As per QUIC Throughput and Fairness over Dual Connectivity:
So running a quic server may require tweaking the kernel parameters:
sysctl -w net.core.rmem_max=26214400
sysctl -w net.core.rmem_default=26214400
On sending audio and video using lossy frames - from RFC9221 which is supported by aioquic:
send_datagram
functions don't have callbacks, quic.recovery.on_packets_lost
?Also need to figure out how to modify the video encoders for:
Some notes on audio: do we want to use datagrams and rtpjitterbuffer? See How to make rtpjitterbuffer work on a stream without timestamps?
Looks like asyncio integration with support to await Gio async functions is going to be merged! But we'll have to keep the threaded implementation around until all the supported distros ship with the new pygobject... which could take many years.
Looks like asyncio
will be integrated with pygobject
Gio
soon: asyncio integration with support to await Gio async functions so we will be able to drop the ugly asyncio_thread workaround in the future.
WebTransport can now be used with the html5 client:
https://github.com/Xpra-org/xpra-html5/issues/143#issuecomment-2198058969
It would be nice to also support a xpra attach webtransport://host:port/
mode for the Python client.
QUIC could easily replace the old UDP transport. There are frameworks and APIs that wrap QUIC with easy to use callbacks, like https://github.com/aiortc/aioquic documentation (see also https://github.com/MagicStack/uvloop) We would get HTTP/3 and encryption almost for free and a reliable event based framework for managing connection state.
Examples include an http3 server and clients, etc..
The re-send / packet-drop callbacks could easily re-use the techniques that were used for UDP (#639) which was removed in 2022238ababa40382d2b8d6b019fb2d757ec9955.
Worth noting that aioquic requires Python 3.7 or better, and the OpenSSL development headers so this won't be available on RHEL 8.