Quick start

Let’s try to write simple http server with WSRPC handler.

import logging
import uuid

import aiohttp.web
import asyncio

from wsrpc_aiohttp import WebSocketAsync, STATIC_DIR

loop = asyncio.get_event_loop()
app = aiohttp.web.Application(loop=loop)
log = logging.getLogger(__name__)


app.router.add_route("*", "/ws/", WebSocketAsync)
app.router.add_static('/js', STATIC_DIR)
app.router.add_static('/', ".")


def get_random_uuid(socket: WebSocketAsync):
    return str(uuid.uuid4())


WebSocketAsync.add_route('uuid4', get_random_uuid)


if __name__ == '__main__':
    logging.basicConfig(level=logging.DEBUG)
    aiohttp.web.run_app(app, port=8000)

Next you have two options:

  1. Browser WSRPC client.
  2. Python WSRPC client.

Browser client

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <script type="text/javascript" src="/js/wsrpc.min.js"></script>

  <script type="text/javascript">
    var url = (window.location.protocol === "https:" ? "wss://" : "ws://") + window.location.host + '/ws/';
    RPC = WSRPC(url, 5000);
    RPC.connect();
  </script>
  <style>
  body {font-family: "Arial", serif; margin: 10px; background-color: #eee;}
  input {width: 300px;}
  input, button { display: inline-block; border: 1px solid black;}
</style>
</head>
<body>
  <input disabled id="text-field"/>
  <button id="btn">Get UUID</button>
  <script>
    var textField = document.getElementById('text-field');
    var btn = document.getElementById('btn');

    btn.onclick = function () {
      RPC.call('uuid4').then(function (result) {
        textField.value = result;
      }, function (error) {
        alert("Error when call 'uuid4' from remote side: " + error);
      });
    }
  </script>
</body>
</html>

You can try it on http://localhost:8000/web-client.html (required running server.py).

_images/web-client-demo.gif

Python client

import asyncio
from wsrpc_aiohttp import WSRPCClient


loop = asyncio.get_event_loop()


async def main():
    client = WSRPCClient("ws://127.0.0.1:8000/ws/", loop=loop)

    await client.connect()
    print(await client.proxy.uuid4())
    await client.close()


if __name__ == '__main__':
    loop.run_until_complete(main())

This is so useful for testing and shell scripts for your services.

How it works

The following sequence diagram probably to explain some high level of the data-flow.

@startuml

title How it's works


participant Browser as browser
participant "Javascript\nlibrary" as jslib
participant WebSocket as ws
participant "Python\nBackend" as backend

browser -> jslib: Browser makes\nfuncion call\n(creating promise)
jslib -> ws: Sending json

note right of ws
    {
        "serial": 1,
        "call": "uuid4",
        "arguments": {},
        "type": "call"
    }
end note

ws -> backend: Parsing json
backend -->> backend: Call python function

backend -> ws: Sending json

note left of backend
    {
        "serial": 1,
        "data": "8927d899-497a-4851-98d4-0a3a0e07fdd5",
        "type": "callback"
    }
end note

ws -> jslib: Sending through Websocket
jslib -> browser: Call JS function on client-side\n(resolving promise)


@enduml