For channels 1, see here
The Django-channels2-jsonrpc is aimed to enable JSON-RPC functionnality on top of the excellent django channels project and especially their Websockets functionality. It is aimed to be:
- Fully integrated with Channels
- Fully implement JSON-RPC 1 and 2 protocol
- Support both WebSocket and HTTP transports
- Easy integration
The only Django-channels-jsonrpc dependency is the Django channels project
Download and extract the latest pre-built release.
Install the dependencies and devDependencies and start the server.
$ pip install django-channels2-jsonrpc
See complete example here, and in particular consumer.py
It is intended to be used as a Websocket consumer. See documentation except... simplier...
Import JsonRpcWebsocketConsumer, AsyncJsonRpcWebsocketConsumer or AsyncRpcHttpConsumer class and create the consumer
from channels_jsonrpc import JsonRpcWebsocketConsumer
class MyJsonRpcConsumer(JsonRpcConsumer):
def connect(self, message, **kwargs):
"""
Perform things on WebSocket connection start
"""
self.accept()
print("connect")
# Do stuff if needed
def disconnect(self, message, **kwargs):
"""
Perform things on WebSocket connection close
""" print("disconnect")
# Do stuff if needed
JsonRpcWebsocketConsumer derives from Channels JsonWebsocketConsumer, you can read about all it's features here: https://channels.readthedocs.io/en/latest/topics/consumers.html#websocketconsumer Then the last step is to create the RPC methos hooks. IT is done with the decorator:
@MyJsonRpcConsumer.rpc_method()
Like this:
@MyJsonRpcConsumer.rpc_method()
def ping():
return "pong"
MyJsonRpcConsumer.rpc_method() accept a string as a parameter to 'rename' the function
@MyJsonRpcConsumer.rpc_method("mymodule.rpc.ping")
def ping():
return "pong"
Will now be callable with "method":"mymodule.rpc.ping" in the rpc call:
{"id":1, "jsonrpc":"2.0","method":"mymodule.rpc.ping","params":{}}
RPC methods can obviously accept parameters. They also return "results" or "errors":
@MyJsonRpcConsumer.rpc_method("mymodule.rpc.ping")
def ping(fake_an_error):
if fake_an_error:
# Will return an error to the client
# --> {"id":1, "jsonrpc":"2.0","method":"mymodule.rpc.ping","params":{}} # <-- {"id": 1, "jsonrpc": "2.0", "error": {"message": "fake_error", "code": -32000, "data": ["fake_error"]}} raise Exception("fake_error")
else:
# Will return a result to the client
# --> {"id":1, "jsonrpc":"2.0","method":"mymodule.rpc.ping","params":{}} # <-- {"id": 1, "jsonrpc": "2.0", "result": "pong"} return "pong"
Simply derive your customer from an asynchronous customer like AsyncJsonRpcWebsocketConsumer
from channels_jsonrpc import AsyncJsonRpcWebsocketConsumer
class MyAsyncJsonRpcConsumer(AsyncJsonRpcWebsocketConsumer):
pass
@MyAsyncJsonRpcConsumer.rpc_method("mymodule.rpc.ping")
async def ping(fake_an_error):
return "ping"
The original channel message - that can contain sessions (if activated with http_user) and other important info can be easily accessed by retrieving the **kwargs
and get a parameter named consumer
MyJsonRpcConsumerTest.rpc_method()
def json_rpc_method(param1, **kwargs):
consumer = kwargs["consumer"]
##do something with consumer
Example:
class MyJsonRpcConsumerTest(JsonRpcConsumer):
# Set to True to automatically port users from HTTP cookies
# (you don't need channel_session_user, this implies it) # https://channels.readthedocs.io/en/stable/generics.html#websockets http_user = True
....
@MyJsonRpcConsumerTest.rpc_method()
def ping(**kwargs):
consumer = kwargs["consumer"]
consumer.scope["session"]["test"] = True
return "pong"
Same as Channels. See
here
The JsonRpcConsumer class can be tested the same way Channels Consumers are tested. See here
MIT
Have fun with Websockets!
Free Software, Hell Yeah!