Files
pycapnp/examples/async_ssl_server.py
Jacob Alexander 1a127bec6f Adding pure python SSL test using asyncio
- Uses thread.capnp
- Follows same format as thread_client.py/thread_server.py and
async_client.py/async_server.py
- Including a basic self signed certificate for testing convenience
- Python 3.7 has a bug cleaning up SSL when using asyncio.run
  https://bugs.python.org/issue36709
  Have a slightly more verbose workaround to do proper cleanup
2019-09-26 21:42:54 -07:00

95 lines
2.3 KiB
Python
Executable File

#!/usr/bin/env python
from __future__ import print_function
import argparse
import capnp
import thread_capnp
import asyncio
import socket
import ssl
class ExampleImpl(thread_capnp.Example.Server):
"Implementation of the Example threading Cap'n Proto interface."
def subscribeStatus(self, subscriber, **kwargs):
return capnp.getTimer().after_delay(10**9) \
.then(lambda: subscriber.status(True)) \
.then(lambda _: self.subscribeStatus(subscriber))
def longRunning(self, **kwargs):
return capnp.getTimer().after_delay(3 * 10**9)
async def myreader(server, reader):
while True:
data = await reader.read(4096)
# Close connection if 0 bytes read
if len(data) == 0:
server.close()
await server.write(data)
async def mywriter(server, writer):
while True:
data = await server.read(4096)
writer.write(data.tobytes())
await writer.drain()
async def myserver(reader, writer):
# Start TwoPartyServer using TwoWayPipe (only requires bootstrap)
server = capnp.TwoPartyServer(bootstrap=ExampleImpl())
# Assemble reader and writer tasks, run in the background
coroutines = [myreader(server, reader), mywriter(server, writer)]
asyncio.gather(*coroutines, return_exceptions=True)
await server.poll_forever()
def parse_args():
parser = argparse.ArgumentParser(usage='''Runs the server bound to the\
given address/port ADDRESS. ''')
parser.add_argument("address", help="ADDRESS:PORT")
return parser.parse_args()
async def main():
address = parse_args().address
host = address.split(':')
addr = host[0]
port = host[1]
# Setup SSL context
ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
ctx.load_cert_chain('selfsigned.cert', 'selfsigned.key')
# Handle both IPv4 and IPv6 cases
try:
print("Try IPv4")
server = await asyncio.start_server(
myserver,
addr, port,
ssl=ctx,
)
except:
print("Try IPv6")
server = await asyncio.start_server(
myserver,
addr, port,
ssl=ctx,
family=socket.AF_INET6,
)
async with server:
await server.serve_forever()
if __name__ == '__main__':
asyncio.run(main())