Package: tranzit
# What's that?_**TRANZIT**_ is an asynchronous micro web framework supporting websockets(full duplex socket communication). With **tranzit** you can easily maintainboth push & pull websocket messaging.In fact, **tranzit** is a just a tiny wrapper for wonderful**aiohttp** lib providing async websocket server (which can be runseparately) and a little *CLI* tool.<!-- TODO: all the rest of README-->## InstallationYou can install **tranzit** via pip:$ pip install tranzit## QuickstartYou can use *CLI* tool for that:$ tranzit project <PROJECT_NAME>$ cd <PROJECT_NAME>$ tranzit runNow your project runs on http://0.0.0.0:3000/ .The first command creates a skeleton project:```<PROJECT_NAME>/__init__.pyapps/__init__.pyhello/__init__.pystatic/camel.htmlcommon/static/tz.jsmain.pyserver.yml```The main.py file starts the whole thing. It gets configs from*server.yml* such as:* HTTP server host* HTTP server port* To start websocket server or not* Websocket server host* Websocket server port* Which apps to run* Is this a production start or not (not meaningful yet)> **Info:** You should always pass PROJECT_DIR to *MainServer()*constructor## Routing and ViewsAll routing (for both http requests and websocket requests) ishandled by *apps/\<app_name>/routes.py* file.`PATH_PREFIX` variable contains prefix for urls handled by thisapplication (like [http://0.0.0.0:3000/\<PATH_PREFIX>/some_url]).`APP_STATIC_DIR` variable contains absolute path to the staticfolder for this application.All views for http requests are dispatched by *routes* dict.Http views are ordinary **aiohttp** views.All websocket views are dispatched by *ws_rules* dict.See explanation below.## MiddlewaresYou can pass a list of your middlewares in *main.py*:```pythonMainServer('server.yml', PROJECT_DIR, middlewares=[my_middleware])```More on **aiohttp** middlewares [here](https://docs.aiohttp.org/en/stable/web_advanced.html#middlewares).## StaticfilesThere are two types of static files directories in the project skeleton.The first is _**\<PROJECT_NAME>/common/static/**_ . It containscommon project static files and is available viahttp://0.0.0.0:3000/static/common/YOUR_GLORIOUS.jsThe second type is app-specific:_**\<PROJECT_NAME>/apps/\<APP_NAME>/static**_ .As you may suggest, it can be found here:http://0.0.0.0:3000/static/APP_NAME/ANOTHER_GLORIOUS.js## Few words about websocketsTo establish websocket messaging you must add websocket rule inapps/\<app_name>/routes.py file just like that:```pythonws_rules = {'get_hello': WSPushHandle.get_hello}```Now this view is available via websockets.To call this view function, do something like this on theclient side:```javascriptvar ws = new WebSocket('ws://0.0.0.0:19719');ws.onmessage = function(response) {console.log(response.data);};ws.send('get_hello|');```We send message to call the view.Here is an ugly syntax for that message:`<function_name>|arg1, arg2, arg3, ... `Now take a look at the websocket view:```pythonclass WSPushHandle(object):@staticmethodasync def get_hello(*args, **kwargs):send_func = kwargs['send_func']writer = kwargs['writer']while True:await asyncio.sleep(1)await send_func(writer, 'HELLO!')```Last line is a way to send message back to the client:```pythonawait send_func(writer, 'HELLO!')```As you can see, `send_func` and `writer` instances are accessible via `**kwargs`.> **Warning:** ~~beware of yellow snow!~~ all websocket routes arein the same namespace! Avoid collisions.> **Another warning:** No security provided! Be sure to verifywebsocket request (e.g. pass user session key in WS view parameters)## Using aiohttp moduleAll of `aiohttp.web` module is accessible via `tranzit.web`.## Starting stand alone websocket serverYou can use websocket server without http server.All you need is an instance of:*tranzit.web.WebSocketServer(host, port, api)**api* is a handler class instance which implements 3 functionsas shown below:```pythonclass TranzitWSHandler(object):async def handle_text(self, loop, writer, msg):passasync def handle_binary(self, loop, writer, msg):passasync def handle_buffered(self, loop, reader, writer, first_msg):pass```Example starting stand alone websocket server:```pythonfrom tranzit.web import WebSocketServerclass MyHandler():def __init__(self, rules={}):self.rules = rulesasync def handle_text(self, loop, writer, msg):response = msg.upper()await WebSocketServer.send_text(writer, response)async def handle_binary(self, loop, writer, msg):passasync def handle_buffered(self, loop, reader, writer, first_msg):passws_server = WebSocketServer(host='0.0.0.0', port=19719, api=MyHandler())ws_server.run_forever()```