Skip to content

Commit d07016e

Browse files
authored
Merge pull request #66 from rsocket/cli
Command line tool
2 parents 32faf97 + b78c8d3 commit d07016e

19 files changed

+528
-104
lines changed

CHANGELOG.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ v0.4.1
99
- Performance test examples available in *performance* folder
1010
- WSS (Secure websocket) example and support (aiohttp)
1111
- Refactored Websocket transport to allow providing either url or an existing websocket
12+
- Added command line tool (rsocket-py)
1213

1314
v0.4.0
1415
======

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ or install any of the extras:
1717
* aiohttp
1818
* quart
1919
* quic
20+
* cli
2021

2122
Example:
2223

@@ -62,7 +63,6 @@ all the examples
6263
| | ServerWithFragmentation | client_with_routing.py | |
6364
| server_quart_websocket.py | | client_websocket.py | |
6465
| server_aiohttp_websocket.py | | client_websocket.py | |
65-
| server_aiohttp_websocket_secure.py | | client_wss.py | |
6666

6767
# Build Status
6868

examples/client_websocket.py

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,34 @@
11
import asyncio
22
import logging
3-
import sys
43

4+
import aiohttp
5+
import asyncclick as click
6+
7+
from rsocket.helpers import single_transport_provider
58
from rsocket.payload import Payload
9+
from rsocket.rsocket_client import RSocketClient
10+
from rsocket.transports.aiohttp_websocket import TransportAioHttpClient
611
from rsocket.transports.aiohttp_websocket import websocket_client
712

813

9-
async def application(serve_port):
10-
async with websocket_client('http://localhost:%s' % serve_port) as client:
11-
result = await client.request_response(Payload(b'ping'))
12-
print(result)
14+
async def application(with_ssl: bool, serve_port: int):
15+
if with_ssl:
16+
async with aiohttp.ClientSession() as session:
17+
async with session.ws_connect('wss://localhost:%s' % serve_port, verify_ssl=False) as websocket:
18+
async with RSocketClient(
19+
single_transport_provider(TransportAioHttpClient(websocket=websocket))) as client:
20+
result = await client.request_response(Payload(b'ping'))
21+
print(result)
22+
23+
else:
24+
async with websocket_client('http://localhost:%s' % serve_port) as client:
25+
result = await client.request_response(Payload(b'ping'))
26+
print(result)
1327

1428

15-
if __name__ == '__main__':
16-
port = sys.argv[1] if len(sys.argv) > 1 else 6565
29+
@click.command()
30+
@click.option('--with-ssl', is_flag=False, default=False)
31+
@click.option('--port', is_flag=False, default=6565)
32+
async def command(with_ssl, port: int):
1733
logging.basicConfig(level=logging.DEBUG)
18-
asyncio.run(application(port))
34+
asyncio.run(application(with_ssl, port))

examples/client_wss.py

Lines changed: 0 additions & 24 deletions
This file was deleted.
Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
import logging
2-
import sys
2+
import ssl
33

4+
import asyncclick as click
45
from aiohttp import web
56

7+
from examples.fixtures import cert_gen
68
from rsocket.helpers import create_future
79
from rsocket.local_typing import Awaitable
810
from rsocket.payload import Payload
911
from rsocket.request_handler import BaseRequestHandler
10-
from rsocket.transports.aiohttp_websocket import websocket_handler_factory
12+
from rsocket.rsocket_server import RSocketServer
13+
from rsocket.transports.aiohttp_websocket import TransportAioHttpWebsocket
1114

1215

1316
class Handler(BaseRequestHandler):
@@ -16,9 +19,36 @@ async def request_response(self, payload: Payload) -> Awaitable[Payload]:
1619
return create_future(Payload(b'pong'))
1720

1821

19-
if __name__ == '__main__':
20-
port = sys.argv[1] if len(sys.argv) > 1 else 6565
22+
def websocket_handler_factory( **kwargs):
23+
async def websocket_handler(request):
24+
ws = web.WebSocketResponse()
25+
await ws.prepare(request)
26+
transport = TransportAioHttpWebsocket(ws)
27+
RSocketServer(transport, **kwargs)
28+
await transport.handle_incoming_ws_messages()
29+
return ws
30+
31+
return websocket_handler
32+
33+
34+
@click.command()
35+
@click.option('--port', help='Port to listen on', default=6565, type=int)
36+
@click.option('--with-ssl', is_flag=True, help='Enable SSL mode')
37+
async def start_server(with_ssl: bool, port: int):
2138
logging.basicConfig(level=logging.DEBUG)
2239
app = web.Application()
2340
app.add_routes([web.get('/', websocket_handler_factory(handler_factory=Handler))])
24-
web.run_app(app, port=port)
41+
42+
if with_ssl:
43+
ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
44+
45+
with cert_gen() as (certificate, key):
46+
ssl_context.load_cert_chain(certificate, key)
47+
else:
48+
ssl_context = None
49+
50+
await web._run_app(app, port=port, ssl_context=ssl_context)
51+
52+
53+
if __name__ == '__main__':
54+
start_server()

examples/server_aiohttp_websocket_secure.py

Lines changed: 0 additions & 32 deletions
This file was deleted.

examples/server_with_routing.py

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
import asyncio
22
import logging
3-
import sys
3+
import ssl
44
from dataclasses import dataclass
55
from datetime import timedelta
66
from typing import Optional
77

8+
import asyncclick as click
9+
from aiohttp import web
10+
811
from examples.example_fixtures import large_data1
12+
from examples.fixtures import cert_gen
913
from examples.response_channel import response_stream_1, LoggingSubscriber
1014
from response_stream import response_stream_2
1115
from rsocket.extensions.authentication import Authentication, AuthenticationSimple
@@ -15,6 +19,7 @@
1519
from rsocket.routing.request_router import RequestRouter
1620
from rsocket.routing.routing_request_handler import RoutingRequestHandler
1721
from rsocket.rsocket_server import RSocketServer
22+
from rsocket.transports.aiohttp_websocket import TransportAioHttpWebsocket
1823
from rsocket.transports.tcp import TransportTCP
1924

2025
router = RequestRouter()
@@ -106,16 +111,49 @@ def handle_client(reader, writer):
106111
RSocketServer(TransportTCP(reader, writer), handler_factory=handler_factory)
107112

108113

109-
async def run_server(server_port):
110-
logging.info('Starting server at localhost:%s', server_port)
114+
def websocket_handler_factory(**kwargs):
115+
async def websocket_handler(request):
116+
ws = web.WebSocketResponse()
117+
await ws.prepare(request)
118+
transport = TransportAioHttpWebsocket(ws)
119+
RSocketServer(transport, **kwargs)
120+
await transport.handle_incoming_ws_messages()
121+
return ws
122+
123+
return websocket_handler
124+
125+
126+
@click.command()
127+
@click.option('--port', help='Port to listen on', default=6565, type=int)
128+
@click.option('--with-ssl', is_flag=True, help='Enable SSL mode')
129+
@click.option('--transport', is_flag=False, default='tcp')
130+
async def start_server(with_ssl: bool, port: int, transport: str):
131+
logging.basicConfig(level=logging.DEBUG)
132+
133+
logging.info(f'Starting {transport} server at localhost:{port}')
134+
135+
if transport in ['ws', 'wss']:
136+
app = web.Application()
137+
app.add_routes([web.get('/', websocket_handler_factory(handler_factory=handler_factory))])
138+
139+
if with_ssl:
140+
ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
141+
142+
with cert_gen() as (certificate, key):
143+
ssl_context.load_cert_chain(certificate, key)
144+
else:
145+
ssl_context = None
111146

112-
server = await asyncio.start_server(handle_client, 'localhost', server_port)
147+
await web._run_app(app, port=port, ssl_context=ssl_context)
148+
elif transport == 'tcp':
113149

114-
async with server:
115-
await server.serve_forever()
150+
server = await asyncio.start_server(handle_client, 'localhost', port)
151+
152+
async with server:
153+
await server.serve_forever()
154+
else:
155+
raise Exception(f'Unsupported transport {transport}')
116156

117157

118158
if __name__ == '__main__':
119-
port = sys.argv[1] if len(sys.argv) > 1 else 6565
120-
logging.basicConfig(level=logging.DEBUG)
121-
asyncio.run(run_server(port))
159+
start_server()

examples/test_examples.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,12 @@ def test_client_server_over_websocket_aiohttp(unused_tcp_port):
9090

9191

9292
def test_client_server_over_websocket_secure_aiohttp(unused_tcp_port):
93-
pid = os.spawnlp(os.P_NOWAIT, 'python3', 'python3', './server_aiohttp_websocket_secure.py', str(unused_tcp_port))
93+
pid = os.spawnlp(os.P_NOWAIT, 'python3', 'python3', 'server_aiohttp_websocket.py', '--port', str(unused_tcp_port),
94+
'--with-ssl')
9495

9596
try:
9697
sleep(2)
97-
client = subprocess.Popen(['python3', './client_wss.py', str(unused_tcp_port)])
98+
client = subprocess.Popen(['python3', './client_websocket.py', '--port', str(unused_tcp_port), '--with-ssl'])
9899
client.wait(timeout=3)
99100

100101
assert client.returncode == 0
@@ -103,11 +104,11 @@ def test_client_server_over_websocket_secure_aiohttp(unused_tcp_port):
103104

104105

105106
def test_client_server_over_websocket_quart(unused_tcp_port):
106-
pid = os.spawnlp(os.P_NOWAIT, 'python3', 'python3', './server_quart_websocket.py', str(unused_tcp_port))
107+
pid = os.spawnlp(os.P_NOWAIT, 'python3', 'python3', './server_quart_websocket.py', '--port', str(unused_tcp_port))
107108

108109
try:
109110
sleep(2)
110-
client = subprocess.Popen(['python3', './client_websocket.py', str(unused_tcp_port)])
111+
client = subprocess.Popen(['python3', './client_websocket.py', '--port', str(unused_tcp_port)])
111112
client.wait(timeout=3)
112113

113114
assert client.returncode == 0

requirements.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@ quart==0.18.2
1111
coveralls==3.3.1
1212
aioquic==0.9.20
1313
reactivex==4.0.4
14-
starlette==0.16.0
14+
starlette==0.16.0
15+
asyncclick==8.1.3.4

rsocket/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__version__ = '0.4.1'

0 commit comments

Comments
 (0)