Just playing with gevent, socket, h2 and wsproto. May be later I will finalize it in a package..
The project contains:
- a HTTP/2 server serving static files
- a websocket client
- a websocket abstract server
It you want to test it, follow the instructions below.
To install the dependencies, you just need to run the following command:
pipenv install
If you don't know pipenv and how to install, look at the documentation here. It is a great tool for developing!
To use the http/2 server, enter the h2_server
the following command:
python init.py
the server will listen on port 8080 and will serve files from the path you provided as input or the current working directory if you haven't provided one
Code sample
from typing import Any
from wsproto.events import AcceptConnection, CloseConnection
from websockets.client import Client
@Client.on_connect
def connect(client: Client, event: AcceptConnection) -> None:
print('connection accepted')
print(event)
@Client.on_disconnect
def disconnect(event: CloseConnection) -> None:
print('connection closed')
print(event)
@Client.on_ping
def ping(payload: bytes) -> None:
print(payload)
@Client.on_pong
def pong(payload: bytes) -> None:
print('pong message:', payload)
@Client.on_json_message
def handle_json_message(client: Client, payload: Any) -> None:
print('json message:', payload)
@Client.on_text_message
def handle_text_message(client: Client, payload: str) -> None:
print('text message:', payload)
@Client.on_binary_message
def handle_binary_message(client: Client, payload: bytearray) -> None:
print('binary message:', payload)
with Client('ws://localhost:8080/foo') as client:
client.ping()
client.send_json({'hello': 'world'})
client.send('my name is Kevin')
client.send(b'just some bytes for testing purpose')
Notes:
- If the server sends json data you will receive it on json handler and not text handler
- I don't know why but ws_proto demands a path when giving the string connection so if you use a string connection like
this one
ws://localhost:8080
the client adds a default path calledpath
. - If you run the sample above, you will notice that ping and pong handlers receive
bytearray
instead ofbytes
. Without any further research, I think that the response generated bywsproto
returnsbytearray
. Normally it should not change how you handle the data becausebytearray
behaves exactly likebytes
with some some additional improvements. - SSL is not supported.
The actual server implemented is not a full server. You need to implement its abstract methods. An implementation example is at follows:
import sys
from typing import Any
from wsproto.events import Request
from websockets.server import BaseServer
class Server(BaseServer):
def handle_request(self, request: Request) -> None:
if request.subprotocols: # this is only to demonstrate the usage of reject_request
self.reject_request(reason='the server does not handle subprotocols')
return
self.accept_request()
def handle_pong(self, data: bytes) -> None:
print(data)
def receive_bytes(self, data: bytes) -> None:
print('receive bytes:', data)
if b'ping me' in data: # this is only to demonstrate the usage of ping
self.ping(b'I ping you!')
return
self.send(data)
def receive_text(self, data: str) -> None:
print('receive text:', data)
self.send(data)
if 'bye' in data: # this is only to demonstrate the usage of close_request
self.close_request(1001, 'bye!')
def receive_json(self, data: Any) -> None:
print('receive json:', data)
self.send_json(data)
server = None
try:
hostname = sys.argv[1] if len(sys.argv) > 1 else '127.0.0.1'
custom_port = int(sys.argv[2]) if len(sys.argv) > 2 else 8080
print('running host', hostname, 'on port', custom_port)
server = Server(hostname, custom_port)
server.run()
except KeyboardInterrupt:
server.close()
Notes:
- Certificates can be supported by passing additional arguments to the run method. It must be the same arguments you pass
to
gevent.server.StreamServer
- Data passed to
handle_pong
isbytearray
. The same explanation as for the client applies here.