在websockets传输之上使用aiohttp实现json-rpc 2.0服务器和客户端
aiohttp-json-rpc的Python项目详细描述
aiohttp json rpc
使用aiohttp实现JSON-RPC 2.0 Specification
Protocol | Support |
---|---|
Websocket | since v0.1 |
POST | TODO |
GET | TODO |
安装
pip install aiohttp-json-rpc
使用量
可以使用rpc.add_method()添加rpc方法。
所有rpc方法都被传递一个aiohttp_json_rpc.communicaton.JsonRpcRequest。
服务器
下面的代码实现了一个简单的rpc服务器,它为localhost:8080上的方法ping提供服务。
fromaiohttp.webimportApplication,run_appfromaiohttp_json_rpcimportJsonRpcimportasyncioasyncdefping(request):return'pong'if__name__=='__main__':loop=asyncio.get_event_loop()rpc=JsonRpc()rpc.add_methods(('',ping),)app=Application(loop=loop)app.router.add_route('*','/',rpc.handle_request)run_app(app,host='0.0.0.0',port=8080)
客户端(js)
下面的代码实现了一个连接到上面服务器的简单rpc客户机 并将所有传入的消息打印到控制台。
<scriptsrc="//code.jquery.com/jquery-2.2.1.js"></script><script>varws=newWebSocket("ws://localhost:8080");varmessage_id=0;ws.onmessage=function(event){console.log(JSON.parse(event.data));}functionws_call_method(method,params){varrequest={jsonrpc:"2.0",id:message_id,method:method,params:params}ws.send(JSON.stringify(request));message_id++;}</script>
这些是服务器在调用ws_call_method时将给出的响应示例。
--> ws_call_method("get_methods") <--{"jsonrpc":"2.0","result":["get_methods","ping"],"id":1}--> ws_call_method("ping") <--{"jsonrpc":"2.0","method":"ping","params":"pong","id":2}
客户端(python)
还有python客户机,可以使用如下:
fromaiohttp_json_rpcimportJsonRpcClientasyncdefping_json_rpc():"""Connect to ws://localhost:8080/, call ping() and disconnect."""rpc_client=JsonRpcClient()try:awaitrpc_client.connect('localhost',8080)call_result=awaitrpc_client.call('ping')print(call_result)# prints 'pong' (if that's return val of ping)finally:awaitrpc_client.disconnect()asyncio.get_event_loop().run_until_complete(ping_json_rpc())
或者使用异步上下文管理器接口:
fromaiohttp_json_rpcimportJsonRpcClientContextasyncdefjrpc_coro():asyncwithJsonRpcClientContext('ws://localhost:8000/rpc')asjrpc:# `some_other_method` will get request.params filled with `args` and# `kwargs` keys:method_res=awaitjrpc.some_other_method('arg1',key='arg2')returnmethod_resasyncio.get_event_loop().run_until_complete(jrpc_coro())
功能
错误处理
在error specification中指定但invalidparamserror无效的所有错误都在内部处理。
如果用错误的参数调用了coroutine,则可以引发一个aiohttp_json_rpc.RpcInvalidParamsError,而不是自己发送一个错误。
jsonrpc协议定义了服务器定义错误的范围。 aiohttp_json_rpc.RpcGenericServerDefinedError实现此功能。
fromaiohttp_json_rpcimportRpcInvalidParamsErrorasyncdefadd(request):try:a=params.get('a')b=params.get('b')returna+bexceptKeyError:raiseRpcInvalidParamsErrorasyncdefadd(request):raiseRpcGenericServerDefinedError(error_code=-32050,message='Computer says no.',)
错误日志记录
由rpc方法引起的每个回溯都将被捕获并记录下来。
rpc将发送一个rpc服务器错误,并像没有发生任何事情一样继续。
asyncdefdivide(request):return1/0# will raise a ZeroDivisionError
ERROR:JsonRpc: Traceback (most recent call last): ERROR:JsonRpc: File "aiohttp_json_rpc/base.py", line 289, in handle_websocket_request ERROR:JsonRpc: rsp = yield from methods[msg['method']](ws, msg) ERROR:JsonRpc: File "./example.py", line 12, in divide ERROR:JsonRpc: return 1 / 0 ERROR:JsonRpc: ZeroDivisionError: division by zero
发布订阅
rpc对象的任何客户端都可以使用内置的rpc方法subscribe()订阅主题。
可以使用rpc.add_topics添加主题。
身份验证
auth系统的工作方式与django中的decorators类似。 有关详细信息,请参阅相应的django文档。
Decorator | Django Equivalent |
---|---|
aiohttp_json_rpc.django.auth.login_required | django.contrib.auth.decorators.login_required |
aiohttp_json_rpc.django.auth.permission_required | django.contrib.auth.decorators.permission_required |
aiohttp_json_rpc.django.auth.user_passes_test | django.contrib.auth.decorators.user_passes_test |
fromaiohttp_json_rpc.authimport(permission_required,user_passes_test,login_required,)fromaiohttp_json_rpc.auth.djangoimportDjangoAuthBackendfromaiohttp_json_rpcimportJsonRpc@login_required@permission_required('ping')@user_passes_test(lambdauser:user.is_superuser)asyncdefping(request):return'pong'if__name__=='__main__':rpc=JsonRpc(auth_backend=DjangoAuthBackend())rpc.add_methods(('',ping),)rpc.add_topics(('foo',[login_required,permission_required('foo')]))
课程参考
类aiohttp_json_rpc.jsonrpc(对象)
方法
- def add_methods(self, *args, prefix='')
参数必须是包含前缀为字符串(可能为空)和模块的元组, 对象、协同程序或导入字符串。
如果第二个参数是module或object,则将添加其中的所有协程。
- async def get_methods()
- 返回所有可用rpc方法的列表。
- def filter(self, topics)
返回已订阅给定主题的所有客户端上的生成器。
主题可以是字符串或字符串列表。
- async def notify(self, topic, data)
向订阅给定主题的所有已连接客户端发送rpc通知。
数据必须是可序列化的json。
使用filter()。
- async def subscribe(topics)
订阅主题。
主题可以是字符串或字符串列表。
- async def unsubscribe(topics)
取消订阅主题。
主题可以是字符串或字符串列表。
- async def get_topics()
- 将可订阅主题作为字符串列表。