Skip to content

Commit d7feafa

Browse files
committedApr 26, 2024··
chore: initial working version of echo server with asyncio loop
Using `COMPAT=1 ASYNCIO=1 python echo.py`.
1 parent 327b31f commit d7feafa

File tree

2 files changed

+105
-8
lines changed

2 files changed

+105
-8
lines changed
 

‎doc/compat.md

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Compatibility with asyncio
2+
3+
As part of the effort to make Netius more compatible with asyncio, the following
4+
changes have been made:
5+
6+
- The `netius` module provides a `COMPAT` mode that allows it to be used to allows Netius protocols
7+
to be used with asyncio. This mode is enabled by setting the `COMPAT` environment variable to `True`.
8+
9+
## Testing
10+
11+
To run the echo server Protocol implementation using netius run:
12+
13+
```bash
14+
PYTHONPATH=. python3 netius/servers/echo.py
15+
```
16+
17+
To use the compat version meaning that an asyncio-like interface will be used underneath the hoods use:
18+
19+
```bash
20+
COMPAT=1 PYTHONPATH=. python3 netius/servers/echo.py
21+
```
22+
23+
To use the compat version and make use of the native asyncio event loop use the following:
24+
25+
```bash
26+
COMPAT=1 ASYNCIO=1 PYTHONPATH=. python3 netius/servers/echo.py
27+
```

‎src/netius/base/compat.py

+78-8
Original file line numberDiff line numberDiff line change
@@ -587,7 +587,12 @@ def on_connect(future):
587587
)
588588

589589
connect = loop.create_datagram_endpoint(
590-
build_protocol, family=family, remote_addr=remote_addr, *args, **kwargs
590+
build_protocol,
591+
family=family,
592+
proto=type,
593+
remote_addr=remote_addr,
594+
*args,
595+
**kwargs
591596
)
592597

593598
future = loop.create_task(connect)
@@ -715,9 +720,18 @@ def on_connect(future):
715720
ssl_context = _ssl.SSLContext()
716721
ssl_context.load_cert_chain(cer_file, keyfile=key_file)
717722
ssl = ssl_context
723+
else:
724+
ssl = None
718725

719726
connect = loop.create_connection(
720-
build_protocol, host=host, port=port, ssl=ssl, family=family, *args, **kwargs
727+
build_protocol,
728+
host=host,
729+
port=port,
730+
ssl=ssl,
731+
family=family,
732+
proto=type,
733+
*args,
734+
**kwargs
721735
)
722736

723737
future = loop.create_task(connect)
@@ -758,15 +772,15 @@ def _serve_stream_native(
758772
def on_ready():
759773
loop.serve(host=host, port=port, callback=on_complete)
760774

761-
def on_complete(service, success):
775+
def on_complete(service, serve, success):
762776
if success:
763-
on_success(service)
777+
on_success(service, serve=serve)
764778
else:
765779
on_error(service)
766780

767-
def on_success(service):
781+
def on_success(service, serve=None):
768782
server = transport.ServerTransport(loop, service)
769-
server._set_compat(protocol)
783+
server._set_compat(protocol, serve=serve)
770784
if not callback:
771785
return
772786
callback(server)
@@ -799,5 +813,61 @@ def _serve_stream_compat(
799813
*args,
800814
**kwargs
801815
):
802-
# @TODO: implement this stuff
803-
pass
816+
"""
817+
Compatible version of the stream server creation method to
818+
make use of the same netius bootstrap infrastructure and
819+
the asyncio event loop.
820+
821+
:see: https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.create_server
822+
"""
823+
824+
# @TODO: implement this stuff meaning that the compat
825+
# mode is the mode in which Netius runs compatible
826+
# with the asyncio module
827+
from . import common
828+
829+
loop = loop or common.get_loop()
830+
831+
protocol = protocol_factory()
832+
has_loop_set = hasattr(protocol, "loop_set")
833+
if has_loop_set:
834+
protocol.loop_set(loop)
835+
836+
def build_protocol():
837+
return protocol
838+
839+
def on_build(future):
840+
if future.cancelled() or future.exception():
841+
protocol.close()
842+
else:
843+
result = future.result()
844+
if callback:
845+
callback(result)
846+
847+
if ssl and cer_file and key_file:
848+
import ssl as _ssl
849+
850+
ssl_context = _ssl.SSLContext()
851+
ssl_context.load_cert_chain(cer_file, keyfile=key_file)
852+
ssl = ssl_context
853+
else:
854+
ssl = None
855+
856+
# removes some of the extra arguments that may be
857+
# present in kwargs and would create issues
858+
kwargs.pop("env", None)
859+
860+
build = loop.create_server(
861+
build_protocol,
862+
host=host,
863+
port=port,
864+
ssl=ssl or None,
865+
family=family,
866+
*args,
867+
**kwargs
868+
)
869+
870+
future = loop.create_task(build)
871+
future.add_done_callback(on_build)
872+
873+
return loop

0 commit comments

Comments
 (0)
Please sign in to comment.