I'm learning asyncio and trying to figure out how to pass data from one async function to a websocket loop in another async function.
In my scenario, data is POSTed to web API by some third party. I'd like to echo the POST data to connected websocket clients.
Sanic & Rx aren't requirements, but that's the path I've started down. Here's what I've come up with so far:
#!/usr/bin/env python
from sanic import Sanic
from sanic import response
from sanic.response import file
from rx import Observable
app = Sanic(__name__)
@app.route('/')
async def index(request):
return await file('ws.html')
async def observable_message(message):
return Observable.from_(message)
@app.route('/post', methods=["POST"])
async def message_inbound(request):
payload = request.json
await observable_message(payload)
return response.json({"status": "OK"})
@app.websocket('/feed')
async def feed(request, ws):
while True:
message = await app.stream
print('Sending: ' + message)
await ws.send(message)
@app.listener('before_server_start')
async def setup_observable_stream(app, loop):
app.stream = Observable.start_async(observable_message)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=9000, workers=4, debug=True)
This clearly won't work because observable_message() requires the message as an arg, and I'm trying to use it to start_async(), so I'm stumped. How can I wire these things up?
The client side can be trivial:
<!DOCTYPE html>
<html>
<head><title>POST data</title></head>
<body>
<script>
var ws = new WebSocket('ws://' + document.domain + ':' + location.port + '/feed'),
messages = document.createElement('ul');
ws.onmessage = function (event) {
var messages = document.getElementsByTagName('ul')[0],
message = document.createElement('li'),
content = document.createTextNode('Received: ' + event.data);
message.appendChild(content);
messages.appendChild(message);
};
document.body.appendChild(messages);
</script>
</body>
</html>