1
"""Shows how you can implement a simple WebSocket echo server using the
4
from werkzeug.exceptions import InternalServerError
5
from werkzeug.serving import run_simple
6
from werkzeug.wrappers import Request
7
from werkzeug.wrappers import Response
8
from wsproto import ConnectionType
9
from wsproto import WSConnection
10
from wsproto.events import AcceptConnection
11
from wsproto.events import CloseConnection
12
from wsproto.events import Message
13
from wsproto.events import Ping
14
from wsproto.events import Request as WSRequest
15
from wsproto.events import TextMessage
16
from wsproto.frame_protocol import CloseReason
20
def websocket(request):
21
# The underlying socket must be provided by the server. Gunicorn and
22
# Werkzeug's dev server are known to support this.
23
stream = request.environ.get("werkzeug.socket")
26
stream = request.environ.get("gunicorn.socket")
29
raise InternalServerError()
31
# Initialize the wsproto connection. Need to recreate the request
32
# data that was read by the WSGI server already.
33
ws = WSConnection(ConnectionType.SERVER)
34
in_data = b"GET %s HTTP/1.1\r\n" % request.path.encode("utf8")
36
for header, value in request.headers.items():
37
in_data += f"{header}: {value}\r\n".encode()
40
ws.receive_data(in_data)
46
for event in ws.events():
47
if isinstance(event, WSRequest):
48
out_data += ws.send(AcceptConnection())
49
elif isinstance(event, CloseConnection):
50
out_data += ws.send(event.response())
52
elif isinstance(event, Ping):
53
out_data += ws.send(event.response())
54
elif isinstance(event, TextMessage):
55
# echo the incoming message back to the client
56
if event.data == "quit":
58
CloseConnection(CloseReason.NORMAL_CLOSURE, "bye")
62
out_data += ws.send(Message(data=event.data))
70
in_data = stream.recv(4096)
71
ws.receive_data(in_data)
73
# The connection will be closed at this point, but WSGI still
74
# requires a response.
75
return Response("", status=204)
78
if __name__ == "__main__":
79
run_simple("localhost", 5000, websocket)