In my flask app I'm prompting a user to enter numbers manually in the terminal. Those numbers are then sent to the browser to update the DOM. But the problem is that the DOM is updated after function getInputs is completed even though I emit an event after each user's input. So my expectation was the DOM gets updated immediately after the event was emitted (inside the getInput function). What I want is: user enters the first number -> append it to the DOM, user enters the second number -> append it to the DOM. How to do this? Should I refactor my code somehow?
This is my flask app:
from flask import Flask, render_template
from flask_socketio import SocketIO
app = Flask(__name__)
app.config['SECRET_KEY'] = '#secret!'
socketio = SocketIO(app)
#app.route("/")
def home():
return render_template("index.html")
def messageReceived(methods=['GET', 'POST']):
print('message was received!!!')
#socketio.on('my event')
def handle_my_custom_event(json, methods=['GET', 'POST']):
print('received my event: ' + str(json))
socketio.emit('my response', json, callback=messageReceived)
#socketio.on('get inputs')
def get_inputs():
getInput(prompt="First number: ")
getInput(prompt="Second number: ")
def getInput(prompt = "Enter number: "):
x = input(prompt)
socketio.emit('my response', {"number": x})
return x
if __name__ == '__main__':
socketio.run(app, debug=True)
index.html:
<html>
<body>
<button id="btnGetInputs">Get inputs</button>
<ul id="log">
<!-- append elements here -->
</ul>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.7.3/socket.io.min.js"></script>
<script type="text/javascript">
var socket = io.connect('http://' + document.domain + ':' + location.port);
var numbers = []
socket.on('connect', function () {
socket.emit('my event', {
data: 'User Connected'
})
$("#btnGetInputs").click(function () {
socket.emit("get inputs")
})
})
socket.on('my response', function (msg) {
console.log(msg)
if (msg.number) {
numbers.push(msg.number)
items = ''
for (var i = 0; i < numbers.length; i++) {
items = items + '<li>' + numbers[i].toString() + '</li>'
}
$('#log').html(items);
}
})
</script>
</body>
</html>
Related
I am new in Flask. My goal is to generate dynamic div containers every time I upload a dxf file and next submit happens. For example: one file uploaded- one div shown; two files uploaded- two divs shown and so on.
I can convert uploaded dxf files to .png images and I would like to show these images in div elements displayed after every upload.
I use input tag to upload files (type='file') and Java Script to generate dynamic elements (divs and their child tags).
The problem is that every time I upload file, the template is loading again and no new content is shown except the image of the last uploaded dxf. Please, give me a piece of advice to solve it.
HTML
...
<form enctype="multipart/form-data" id="uploadForm" action="/upload_files" name="uploadForm" method="post">
DXF file: <input type="file" id="dxfUpload" onchange="form.submit(); createConfigure();" name="dxfUpload" />
<div id="calcHolder" name="calcHolder">
<script type="text/javascript">
function createConfigure() {
var div = document.createElement("div");
div.id = "dxf-"+Math.random() * 100000000000000000 + "-"
+ window.performance.now() * 100000000000000000;
id_div=div.id;
div.className = 'border pad';
div.style.width = "640px";
div.style.height = "200px";
document.getElementById("calcHolder").appendChild(div);
var img = document.createElement("img");
img.setAttribute("src", "{{url_for('static', filename=dxfName+'.png')}}");
img.setAttribute("alt", "no image");
img.setAttribute("height", "120px");
img.setAttribute("width", "120px");
document.getElementById(id_div).appendChild(img);
var array = ["Carbon Steel","Stainless Steel","Aluminium"];
var selectMaterial = document.createElement("select");
document.getElementById(id_div).appendChild(selectMaterial);
for (var i = 0; i < array.length; i++) {
var option = document.createElement("option");
option.value = array[i];
option.text = array[i];
selectMaterial.appendChild(option);
}
var selectThickness = document.createElement("select");
document.getElementById(id_div).appendChild(selectThickness);
for (i = 1; i <= 16; i++) {
var opt = document.createElement('option');
//opt.value = i;
opt.innerHTML = i + ' mm';
selectThickness.appendChild(opt);
}
var quantity = document.createElement("input")
quantity.type="number";
quantity.value="1";
quantity.name="quantity";
quantity.min="1";
quantity.max="50";
quantity.onkeyup= function maxReach(){if(quantity.value > 50) quantity.value=50;};
document.getElementById(id_div).appendChild(quantity);
var btn = document.createElement("button");
btn.innerHTML = "Delete";
btn.type = "button";
document.getElementById(id_div).appendChild(btn);
btn.onclick = function() {div.remove();};
}
</script>
{{ html | safe }}
</div>
</form>
...
Python
#app.route('/upload_files', methods=['POST'])
def upload_files():
try:
if request.method == 'POST':
dxf_file = request.files['dxfUpload']
full_filename = os.path.join(app.config['UPLOAD_FOLDER'],dxf_file.filename)
dxf_file.save(full_filename)
first = DXF2IMG()
first.convert_dxf2img([full_filename],img_format='.png')
html="<img src="+url_for('static', filename=dxf_file.filename+'.png' )+" width='120' height='120' />"
return render_template('upload_files.html',dxfName=dxf_file.filename, html=html)
except:
...
#something happens
The result now
Desired result
Once the form.submit() function is executed, the form will be sent as a regular post request. For this reason, the following function is no longer executed and the entire page is reloaded.
In order to submit the form and change the content of the existing page, it is necessary to use AJAX.
This example shows you how to submit the form to the server and receive a JSON response containing the URLs of the received file and the generated image.
As soon as the submit button is pressed, the form data is packed into a FormData object and sent via AJAX using the fetch function. The browser's default behavior for a submit event is suppressed and the form is reset. The received file is processed by the server and the associated URLs are sent back to the client in JSON format. Now the document can be changed with the received data.
Remember this is just a minimal example to help you achieve your goals and implement your concept.
Flask (app.py)
import os
import ezdxf
from ezdxf.addons.drawing import matplotlib
from flask import Flask
from flask import (
jsonify,
make_response,
render_template,
url_for
)
from werkzeug.utils import secure_filename
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
def dxf2png(source, target):
doc = ezdxf.readfile(source)
msp = doc.modelspace()
auditor = doc.audit()
if auditor.has_errors:
raise Exception('Conversion failed.')
matplotlib.qsave(doc.modelspace(), target)
#app.route('/upload', methods=['POST'])
def upload():
if 'dxf-file' in request.files:
file = request.files['dxf-file']
if file.filename != '':
filename = secure_filename(file.filename)
filepath = os.path.join(app.static_folder, filename)
destname, _ = os.path.splitext(filename)
destname = f'{destname}.png'
destpath = os.path.join(app.static_folder, destname)
file.save(filepath)
try:
dxf2png(filepath, destpath)
except:
os.remove(filepath)
return make_response('', 400)
return make_response(
jsonify(
target=url_for('static', filename=filename),
preview=url_for('static', filename=destname)
),
200
)
return make_response('', 400)
HTML (templates/index.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Index</title>
<style media="screen">
.preview {
width: 120px;
height: auto;
}
</style>
</head>
<body>
<form name="dxf-upload" method="post" enctype="multipart/form-data">
<input type="file" name="dxf-file" />
<input type="submit" />
</form>
<div id="dxf-files"></div>
<script type="text/javascript">
((uri) => {
function createPreview(target, preview) {
const divElem = document.createElement('div');
divElem.innerHTML = `<img src="${preview}" class="preview" />`;
const outElem = document.getElementById('dxf-files');
outElem.append(divElem);
}
const form = document.querySelector('form[name="dxf-upload"]');
form.addEventListener('submit', evt => {
evt.preventDefault();
const formData = new FormData(evt.target);
fetch(uri, {
method: 'POST',
body: formData
}).then(resp => resp.json())
.then(data => {
const { target, preview } = data;
createPreview(target, preview);
});
evt.target.reset();
});
})({{ url_for('.upload') | tojson }});
</script>
</body>
</html>
I am trying to stream market live data from a stock broker (Zerodha) via their websockets sdk, to my frontend.
I am able to log the live data in my python console, but I am not able to stream it to the frontend.
I am new to the socket programming, so please kindly excuse.
Below is the python snippet.
import json
from flask import Flask, render_template, request, redirect, session
import threading
import time
from kiteconnect import KiteTicker #WebSocket client for connecting to Kite Connect's streaming quotes service.
import logging
###
from flask_socketio import SocketIO, emit
###
app = Flask(__name__)
##
socketio = SocketIO(app, async_mode= 'threading')
##
app.config['DEBUG'] = False
ticker = None
#app.route('/streamData')
def streamData():
'''
to start stream we first have to
1.) initiliase a WS connection - done
2.) Subscribe/register the symbols - done
3.) Check on new ticks - done
4.) To do: kill the ws after x time
'''
global ticker
accessToken = getAccessToken()
ticker = KiteTicker("api key here", accessToken)#1
# Assign the callbacks.
ticker.on_connect = onConnectLocal
ticker.on_close = onDisconnectLocal
ticker.on_error = onErrorLocal
ticker.on_ticks = onNewTicksLocal#3
logging.info('Ticker: Going to connect..')
ticker.connect(threaded=True)
time.sleep(5)
symbols = ['stock', 'names', 'given', 'here']
tokens = []
kite = getKite()
fetchInstruments(kite)
for symbol in symbols:
isd = getInstrumentDataBySymbol(symbol)
token = isd['instrument_token']
logging.info('registerSymbol: %s token = %s', symbol, token)
tokens.append(token)
logging.info('Subscribing tokens %s', tokens)
ticker.subscribe(tokens)#2
print(tokens)
return render_template('stream.html', async_mode='threading') # here is where I want to stream the data
def onConnectLocal(ws, response):
logging.info('Ticker connection successful.')
def onDisconnectLocal(ws, code, reason):
logging.error('Ticker got disconnected. code = %d, reason = %s', code, reason)
def onErrorLocal(ws, code, reason):
logging.error('Ticker errored out. code = %d, reason = %s', code, reason)
##socketio.on('my_broadcast_event', namespace='/test')
def onNewTicksLocal(ws, ticks):#3 # this the method which streams data from the broker's websocket
for tick in ticks:
isd = getInstrumentDataByToken(tick['instrument_token'])
symbol = isd['tradingsymbol']
logging.info('Tick: %s CMP = %f', symbol, tick['last_price']) #this prints to the python console with no problem
socketio.emit('my_response',{'data': tick}, broadcast=True)# this makes the problem
app.run('localhost', 8080)
stream.html (frontend)
<script src="//code.jquery.com/jquery-1.12.4.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js"></script>
<script type="text/javascript" charset="utf-8">
$(document).ready(function() {
namespace = 'http://localhost:8080/streamData';
var socket = io(namespace);
socket.on('connect', function() {
socket.emit('my_event', {data: 'connected to the SocketServer...'});
});
socket.on('my_response', function(msg, cb) {
$('#log').append('<br>' + $('<div/>').text('logs #' + msg.count + ': ' + msg.data).html());
if (cb)
cb();
});
$('form#emit').submit(function(event) {
socket.emit('my_event', {data: $('#emit_data').val()});
return false;
});
$('form#broadcast').submit(function(event) {
socket.emit('my_broadcast_event', {data: $('#broadcast_data').val()});
return false;
});
$('form#disconnect').submit(function(event) {
socket.emit('disconnect_request');
return false;
});
socket.on('my_response', function(data){
console.log(data.msg)
socket.emit('my_response', {data: data.msg});
});
});
</script>
The error i get always is :-
TypeError: onNewTicksLocal() missing 1 required positional argument: 'ticks'
But as you can see above I have supplied this(I get this error when I click on the broadcast button).
Please let me know where I am going wrong (I feel, but not certain, I could be going wrong with the callbacks).
edit :- updated the html code & port number in python
I know how to broadcast but i can not target clients.
Here is my script:
import json
import trio
from quart import render_template, websocket, render_template_string
from quart_trio import QuartTrio
from quart_auth import current_user,login_required
from quart_auth import AuthUser, login_user, logout_user, AuthManager
import random
connections = set()
app = QuartTrio(__name__)
AuthManager(app)
app.secret_key = "secret key"
#app.route("/")
async def index():
clean_guy = await current_user.is_authenticated
if not clean_guy:
fake_ID = random.randrange(0, 9999) #quick dirty to test
login_user(AuthUser(fake_ID))
return await render_template_string("{{ current_user.__dict__ }}")
return await render_template_string("{{ current_user.__dict__ }}")
#app.websocket("/ws")
async def chat():
try:
connections.add(websocket._get_current_object())
async with trio.open_nursery() as nursery:
nursery.start_soon(heartbeat)
while True:
message = await websocket.receive()
await broadcast(message)
finally:
connections.remove(websocket._get_current_object())
async def broadcast(message):
for connection in connections:
await connection.send(json.dumps({"type": "message", "value": message}))
async def heartbeat():
while True:
await trio.sleep(1)
await websocket.send(json.dumps({"type": "heartbeat"}))
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
Here is my template:
<div>
<div>
<ul>
</ul>
</div>
<form>
<input type="text">
<button type="submit">Send</button>
</form>
</div>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function() {
const ws = new WebSocket(`ws://${window.location.host}/ws`);
ws.onmessage = function(event) {
const data = JSON.parse(event.data);
if (data.type === "message") {
const ulDOM = document.querySelectorAll("ul")[0];
const liDOM = document.createElement("li");
liDOM.innerText = data.value;
ulDOM.appendChild(liDOM);
}
}
document.querySelectorAll("form")[0].onsubmit = function(event) {
event.preventDefault();
const inputDOM = document.querySelectorAll("input")[0];
ws.send(inputDOM.value);
inputDOM.value = "";
return false;
};
});
</script>
Also one problem:
if i use this in my script:
return await render_template("{{ current_user.__dict__ }}")
i am not able to display it with my jinja template even if i add {{ current_user.dict }} in my template.
I also noticed that:
with mozilla: i get something stable like
{'_auth_id': 9635, 'action': <Action.PASS: 2>}
with chrome: it changes on each refresh, it looks like
{'_auth_id': 529, 'action': <Action.WRITE: 3>}
I need to display the author, and the destination , and an input with a send button, how to fix the template ?
Is it also possible to send messages to targeted users with post via curl or websocat ? how to do that ?
Quart-Auth uses cookies to identify the user on each request/websocket-request so you can always get the identity of the user from the current_user if request is authenticated. Then for your need you will need to map websocket connections to each user (so you can target messages), hence the connections mapping should be a dictionary of connections, e.g.
import random
from collections import defaultdict
from quart import request, websocket
from quart_trio import QuartTrio
from quart_auth import (
AuthUser, current_user, login_required, login_user, logout_user, AuthManager
)
connections = defaultdict(set)
app = QuartTrio(__name__)
AuthManager(app)
app.secret_key = "secret key"
#app.route("/login", methods=["POST"])
async def login():
# Figure out who the user is,
user_id = random.randrange(0, 9999)
login_user(AuthUser(fake_ID))
return {}
#app.websocket("/ws")
#login_required
async def chat():
user_id = await current_user.auth_id
try:
connections[user_id].add(websocket._get_current_object())
while True:
data = await websocket.receive_json()
await broadcast(data["message"])
finally:
connections[user_id].remove(websocket._get_current_object())
#app.route('/broadcast', methods=['POST'])
#login_required
async def send_broadcast():
data = await request.get_json()
await broadcast(data["message"], data.get("target_id"))
return {}
async def broadcast(message, target = None):
if target is None:
for user_connections in connections.values():
for connection in user_connections:
await connection.send_json({"type": "message", "value": message})
else:
for connection in connections[target]:
await connection.send_json({"type": "message", "value": message})
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
You can then send to the /broadcast either JSON that is just a message {"message": "something"} or a message with an id to target someone specifically {"message": "something for user 2", "target_id": 2}. Note as well the #login_required decorator ensures the route handler is only called for logged in users.
I created an API that can get data from MySQL. It working if the stockList is defined. However, in actual world, I need to get it from the Ionic app, and the stockList is defined by individual user.
Simply put stockList =[] does not work.
Currently the flask_app.py is as below:
from flask import Flask,jsonify,abort,make_response,request
import MySQLdb
import MySQLdb.cursors
app = Flask(__name__)
#app.route('/KLSEwatch', methods=['GET'])
def KLSEwatch():
db = MySQLdb.connect(host='vinvin.mysql.pythonanywhere-services.com',user='vinvin',passwd='xxx',db='vinukdb$default',cursorclass=MySQLdb.cursors.DictCursor)
curs = db.cursor()
stockList = ['SHELL','GENM']
placeholders = ','.join(['%s'] * len(stockList))
query = 'SELECT * FROM KLSE WHERE Stock IN ({})'.format(placeholders)
curs.execute(query,tuple(stockList))
f = curs.fetchall()
return jsonify({'Stock': f})
what I shall replace stockList as it shall get the data from user, which is from an Ionic app. The data is can be string or a 4 digits numbers
Below is the code in watchlistCtrl.js in Ionic app
//setting get counter-number of get requests-
var getCounter = 0;
for (var market in watchListQuery) {
if(watchListQuery[market].length>0){
getCounter += 1;
}
}
if(getCounter == 0)
$ionicLoading.hide();
$scope.watchedStocks = [];
for (var market in watchListQuery) {
if(watchListQuery[market].length>0){
var queryString = watchListQuery[market].toString().replace(/,/g, "','");
$webServicesFactory.get($marketProvider[market].queryURL+"/watchlist_query", {AnonymousToken: $marketProvider[market].token}, {parameters:{stockList:queryString}}).then(
function success(data) {
getCounter -=1 ;
$scope.watchedStocks = $scope.watchedStocks.concat(data);
if(getCounter <= 0)
$ionicLoading.hide();
},
function error() {
$ionicLoading.hide();
}
);
}
}//end of for each loop
You didn't show us any of your Ionic code, but here's a simple example of taking input from your Ionic app and submitting it to Flask. First, some HTML for the frontend (I'm only using Angular, since that is the common theme here - the rest of Ionic isn't relevant to this problem):
<!-- templates/home.html -->
<!doctype html>
<html lang="en">
<head>
<title>Ionic / Flask</title>
</head>
<body>
<div ng-app="app">
<div ng-controller="MyCtrl">
<p>Enter a comma-separated string value, like "BAC,XYZ"</p>
<input type="text" ng-model="stockList">
<button ng-click="submit()">Submit</button>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.14/angular.js"></script>
<script>
angular.module('app', [])
.controller('MyCtrl', function ($http, $log, $scope) {
$scope.stockList = '';
$scope.submit = function () {
$http.get('/KLSEwatch', {params: {stockList: $scope.stockList}}).then(function (result) {
$log.log('This is the query to execute: ',result.data)
})
};
})
</script>
</body>
</html>
And then here's a modified version of your Flask app, to demonstrate that this will generate the correct query:
# app.py
from flask import Flask,jsonify,abort,make_response,request, render_template
import MySQLdb
import MySQLdb.cursors
app = Flask(__name__)
app.config['DEBUG'] = True
#app.route('/')
def home():
return render_template('home.html')
#app.route('/KLSEwatch', methods=['GET'])
def KLSEwatch():
stockList = request.args['stockList'].split(',')
placeholders = ','.join(['%s'] * len(stockList))
query = 'SELECT * FROM KLSE WHERE Stock IN ({})'.format(placeholders)
print('This is the query: %s' % (query % tuple(stockList)))
return query % tuple(stockList)
app.run()
All you need to do is run the app, enter a string value into the input field & submit it, and then check the results in your browser console log, or in the output for the Flask app.
I need make a websocket server in pyqt5, read the documentation from the 5.3 version there is all necessary classes, follow these example in C ++
http://doc.qt.io/qt-5/qtwebsockets-examples.html
and this was the result:
from PyQt5 import QtCore, QtWebSockets, QtNetwork
class MyServer(QtCore.QObject):
def __init__(self, parent=None):
super(QtCore.QObject, self).__init__(parent)
self.server = QtWebSockets.QWebSocketServer('My Socket', QtWebSockets.QWebSocketServer.NonSecureMode)
if self.server.listen(QtNetwork.QHostAddress.LocalHost, 1302):
print('Connected: '+self.server.serverName()+' : '+self.server.serverAddress().toString()+':'+str(self.server.serverPort()))
else:
print('error')
self.server.newConnection.connect(self.onNewConnection)
print(self.server.isListening())
def onNewConnection(self):
print(self.sender())
print("inside")
self.server.textMessageReceived.connect(self.processTextMessage)
self.server.binaryMessageReceived.connect(self.processBinaryMessage)
self.server.disconnected.connect(self.socketDisconnected)
def processTextMessage(self, message):
print(message)
def processBinaryMessage(self, message):
print(message)
def socketDisconnected(self):
print('out')
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MyServer()
sys.exit(app.exec_())
when running isListening method, returns true, which leads me to believe that this code is correct, however I try connect by a javascript client (html5 websocket) and it returns me a server connection error, the same happens when I try shoot the server by telnet (telnet localhost 1302).
thanks for the reply, had other errors in the code, the final code if someone needs:
from PyQt5 import QtCore, QtWebSockets, QtNetwork, QtWidgets
class MyServer(QtCore.QObject):
def __init__(self, parent):
super(QtCore.QObject, self).__init__(parent)
self.clients = []
self.server = QtWebSockets.QWebSocketServer(parent.serverName(), parent.secureMode(), parent)
if self.server.listen(QtNetwork.QHostAddress.LocalHost, 1302):
print('Connected: '+self.server.serverName()+' : '+self.server.serverAddress().toString()+':'+str(self.server.serverPort()))
else:
print('error')
self.server.newConnection.connect(self.onNewConnection)
print(self.server.isListening())
def onNewConnection(self):
self.clientConnection = self.server.nextPendingConnection()
self.clientConnection.textMessageReceived.connect(self.processTextMessage)
self.clientConnection.binaryMessageReceived.connect(self.processBinaryMessage)
self.clientConnection.disconnected.connect(self.socketDisconnected)
self.clients.append(self.clientConnection)
def processTextMessage(self, message):
if (self.clientConnection):
self.clientConnection.sendTextMessage(message)
def processBinaryMessage(self, message):
if (self.clientConnection):
self.clientConnection.sendBinaryMessage(message)
def socketDisconnected(self):
if (self.clientConnection):
self.clients.remove(self.clientConnection)
self.clientConnection.deleteLater()
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
serverObject = QtWebSockets.QWebSocketServer('My Socket', QtWebSockets.QWebSocketServer.NonSecureMode)
server = MyServer(serverObject)
serverObject.closed.connect(app.quit)
app.exec_()
In fact there is a problem with signals : you don't have to connect server but clientConnections:
def onNewConnection(self):
clientConnection = self.server.nextPendingConnection()
clientConnection.disconnected.connect(clientConnection.deleteLater)
print(self.sender())
print("inside")
clientConnection.textMessageReceived.connect(self.processTextMessage)
clientConnection.binaryMessageReceived.connect(self.processBinaryMessage)
self.server.disconnected.connect(self.socketDisconnected)
Then I try with html5 client :
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>WebSocket Test</title>
<script>
//var wsUri = "ws://echo.websocket.org/";
var wsUri = "ws://127.0.0.1:1302";
var output;
function init() { output = document.getElementById("output"); testWebSocket(); }
function testWebSocket() {
websocket = new WebSocket(wsUri);
websocket.onopen = function(evt) { onOpen(evt) };
websocket.onclose = function(evt) { onClose(evt) };
websocket.onmessage = function(evt) { onMessage(evt) };
websocket.onerror = function(evt) { onError(evt) }; }
function onOpen(evt) { writeToScreen("CONNECTED"); doSend("WebSocket rocks"); }
function onClose(evt) { writeToScreen("DISCONNECTED"); }
function onMessage(evt) {
writeToScreen('<span style="color: blue;">RESPONSE: ' + evt.data+'</span>'); websocket.close();
}
function onError(evt) { writeToScreen('<span style="color: red;">ERROR:</span> ' + evt.data); }
function doSend(message) {
writeToScreen("SENT: " + message); websocket.send(message);
}
function writeToScreen(message) {
var pre = document.createElement("p");
pre.style.wordWrap = "break-word";
pre.innerHTML = message;
output.appendChild(pre); }
window.addEventListener("load", init, false);
</script>
</head>
<body>
<h2>WebSocket Test</h2>
<div id="output"></div>
</body>
</html>
Then we have at least the connection and the printing of client Message "WebSocket rocks" in the server side. But code is still to be completed