Dupa ce am vazut demonstratiile Phoenix.LiveView si am inteles ca actualizeaza pagina de web in timp real prin websocket, in cateva ore am imaginat o solutie cu Python.
Este vorba de o implementare naiva care actualizeaza cinci variabile JavaScript: cnt, operation, a, b si messages.
Codul este pentru serverul meu de aplicatii web, scris in Python si gasit pe github – AppServer, si consta in doua fisiere:
__init__.py – salvat in radacina modulului (extensiei) pentru AppServer:
import bottle
import threading
from bottle.ext.websocket import websocket
from appmodule import AppModule
app = AppModule()
def update_app(module_name, server_config):
app.update(module_name, server_config)
clients = set()
lock = threading.Lock()
@app.route('/')
@app.auth('access module')
@app.view('index.tpl')
def _():
"""
Default view
"""
title = 'Websocket Live Demo'
return dict(title=title)
@app.get('/live', apply=[websocket])
def _(ws):
"""
The Live Socket
"""
with lock:
clients.add(ws)
while True:
msg = ws.receive()
if msg is None:
break
print('clienti:{}, msg:{}'.format(len(clients), msg))
for c in clients:
c.send(msg)
with lock:
clients.remove(ws)
index.tpl – salvat in folderul view (folderul cu sabloane):
% include('header.tpl')
<h1>{{title}}</h1>
<button id="inc">+</button>
<button id="dec">-</button>
<span id="cnt">0</span>
<br>
<span id="operation"></span> -- <span id="a"></span> -- <span id="b"></span>
<br>
<form id="chatform">
Name:
<input id="name" type="text" value="name">
Message:
<input id="message" type="text" value="message" />
<input type="submit" value="Send" />
</form>
<div id="messages"></div>
<script>
var cnt = 0;
function getWebsocketUrl(url){
pathArray = location.href.split( "/" );
host = pathArray[2];
return `ws://${host}/{{module_name}}/${url}`;
}
$(document).ready(function() {
if (!window.WebSocket) {
if (window.MozWebSocket) {
window.WebSocket = window.MozWebSocket;
} else {
$('#messages').append("<li>Your browser doesn't support WebSockets.</li>");
}
}
ws = new WebSocket(getWebsocketUrl('live'));
ws.onopen = function(evt) {
$('#messages').append('<li>Connected to chat.</li>');
}
ws.onmessage = function(evt) {
ret = JSON.parse(evt.data);
for (var prop in ret) {
if(prop == 'msg')
$('#messages').append('<li>' + ret[prop] + '</li>');
else{
$('#'+prop).text(ret[prop]);
eval(`${prop} = ${ret[prop]}`);
}
};
}
$('#chatform').submit(function() {
var name = $('#name').val();
var message = $('#message').val();
var msg = `${name}: ${message}`;
ws.send(JSON.stringify({msg:msg}));
$('#message').val('').focus();
return false;
});
$("#inc").off().click(function(){
cnt = cnt + 1;
ws.send(JSON.stringify({cnt:cnt, operation:'inc', a:100, b:200}));
});
$("#dec").off().click(function(){
cnt = cnt - 1;
ws.send(JSON.stringify({cnt:cnt, operation:'dec', a:500, b:600}));
});
});
</script>
% include('footer.tpl')
Comunicatia websocket in Mozilla Firefox:
Implementarea este atat de simpla incat imi este rusine sa o public pe github, dar cat de curand voi imagina o aplicatie de chat mai complexa, care sa foloseasca un protocol compact de comunicare cu serverul prin websocket: variabilele sa aiba un id numeric si comunicatia sa fie de tip command:variabile_id:variable_value, …
Serverul de web necesita GeventWebSocketServer (pip install gevent-websocket) si extensia bottle-websocket (pip install bottle-websocket).