javascript - ws4py - send/received_message not working -
i'm encountering issues on making websocket server/client.
this websocket clas:
wslist = [] class loginlivewebsockethandler(websocket): # /live/ws/zones loggedon = false def opened(self): log("opened!") wslist.append(self) def received_message(self, m): log("received message!") log(m) log(m.data) m = str(m.data) if not m.startswith("login: ") & (not self.loggedon): return if m.startswith("login: ") & self.loggedon: return if m.startswith("login: ") & (not self.loggedon): split = m.replace("login: ", "").split(":") try: id = split[0] key = split[1] except keyerror: self.send("login: 0", false) return try: usr = users.getuser(id, key) nick = usr["nick"] loggedin = true token = usr["groupme_token"] active = usr["active"] except keyerror or typeerror: self.send("login: 0", false) return if (not loggedin) | (not active) | (not local.token) | (local.user["faction"] != "f"): self.send("login: 0", false) return self.send("login: 1", false) self.loggedon = true return def closed(self, code, reason=""): log("closed!") wslist.remove(self)
and javascript page (note, not whole):
function init() { showblocking("connecting...", "progress-bar-success"); var wsprotocol = (location.protocol == "https:") ? "wss://" : "ws://"; var loc = location.pathname; loc = loc.replace(/live\u002flive$/i, ""); var wsurl = wsprotocol + location.host + loc + "/live/ws_zones"; console.log(wsurl); var ws = new websocket(wsurl); var key = getcookie("key"); var id = getcookie("id"); var closed = true; ws.onopen = function(evt) { console.log("onopen"); $('#pbheader').text("logging in..."); ws.send("login: " + id + ":" + key); closed = false; } ws.onmessage = function(evt) { console.log("onmessage"); var channel = evt.data.substring(0, 7); var data = evt.data.substr(6); if (channel == "login: ") { if (data == "0") { ws.close(); closed = true; alert("invalid login, please re-login."); $('#pbheader').text("invalid login!"); history.back(); } else if (data == "1") { hideblocking(); } } else if (channel == "zonea: ") { // add new thing... // %gridref% %zoneid% %zonename% %faction% %legion% %faceless% %swarm% var datadict = json.parse(data); var replitem = itemtemplate.replace("%count%", count).replace("%gridref%", datadict.gridref).replace("%zoneid%", datadict.zoneid).replace("%zonename%", datadict.zonename).replace("%faction%", datadict.faction).replace("%legion%", datadict.legion).replace("%faceless%", datadict.faceless).replace("%swarm%", datadict.swarm); $('#live').prepend(replitem); var curritem = $('#item' + count); settimeout(function () { fadeoutremove(curritem); }, 60*1000); count = count + 1; } } ws.onclose = function(evt) { console.log("closed"); closed = true; } ws.onerror = function(evt) { console.log("error"); closed = true; } } window.addeventlistener("load", init, false);
mounting service:
log("starting webserver (cherrypy)") cherrypy.server.unsubscribe() if config.do_ssl true: server1 = cherrypy._cpserver.server() server1.socket_port = config.listen_port_ssl server1._socket_host = config.listen server1.thread_pool = 30 server1.ssl_certificate = config.ssl_certificate server1.ssl_private_key = config.ssl_private_key server1.ssl_certificate_chain = config.ssl_chain server1.ssl_module = config.ssl_handler server1.subscribe() server2 = cherrypy._cpserver.server() server2.socket_port = config.listen_port server2._socket_host = config.listen server2.thread_pool = 30 server2.subscribe() websocketplugin(cherrypy.engine).subscribe() cherrypy.tools.websocket = websockettool() cherrypy.tree.mount(apiservice.apiservice(), "/api", config={"/": {'error_page.404': apiservice.ep}}) cherrypy.tree.mount(jsonservice.jsonservice(), "/json", config={"/": {'error_page.404': jsonservice.ep}}) cherrypy.tree.mount(usrapiservice.usrapiservice(), "/usrapi", config={"/": {'error_page.404': usrapiservice.ep}}) cherrypy.tree.mount(usrapiadminservice.usrapiadminservice(), "/usrapi/admin", config={ "/": {'error_page.404': usrapiservice.ep}}) cherrypy.tree.mount(rootservice.rootservice(), "/", config={"/": {'error_page.404': rootservice.ep}}) cherrypy.tree.mount(adminservice.adminservice(), "/admin", config={"/": {'error_page.404': adminservice.ep}}) cherrypy.tree.mount(helperpanel.helperpanel(), "/helper", config={"/": {'error_page.404': helperpanel.ep}}) cherrypy.tree.mount(liveservice.liveservice(), "/live", config={"/": {'error_page.404': liveservice.ep}, "/ws_zones": {'tools.websocket.on': true, 'tools.websocket.handler_cls': liveservice.loginlivewebsockethandler }}) cherrypy.tree.mount(none, "/static", config={"/": {'error_page.404': adminservice.ep, 'tools.staticdir.on': true, 'tools.staticdir.dir': os.path.join(__current_dir, "web/static")}}) cherrypy.engine.start() log("started webserver (cherrypy)")
liveservice:
class liveservice(object): @cherrypy.expose @require(level=0) def index(self, user, usrname, usrhelper, usradmin): return render("index", usrname, usrhelper, usradmin) @cherrypy.expose @require(level=4) # require login, groupme, active , faceless def live(self, user, usrname, usrhelper, usradmin): return render("websocket/zonesdata", usrname, usrhelper, usradmin) @cherrypy.expose def ws_zones(self): log("handler created: %s" % repr(cherrypy.request.ws_handler)) cherrypy.request.ws_handler.send(b"login 0", false)
so, mounting , starting works, whole run in production months now, new liveservice ws not working. in log, im getting [21/jul/2015:16:55:28] engine starting websocket processing
, opened
messages, never receive or able send messages. when change liveservice.loginliveservicewebsockethandler echowebsocket gets messages , sends them, on ws_zones handler
cherrypy.request.ws_handler.send(b"login 0", false)
is not working. wether b or not.
analysis
first thing should pay attention debugging tools @ disposal. instance, when try app in firefox, firebug (or web console) tells you:
firefox can't establish connection server @ ws://127.0.0.1:8080/live/ws_zones.
chromium console has more useful error message:
websocket connection 'ws://127.0.0.1:8080/live/ws_zones' failed: error during websocket handshake: invalid status line
ok, have handshake problem.
if open wireshark (or sniffer) can see indeed our login 0
appears before ws4py
replies handshake response (or maybe there race condition).
i can understand confusion, because in several places ws4py
documentation either alludes or directly guides wrong way. let's see:
alludes — can not send normal handler.
@cherrypy.expose def ws(self): # can access class instance through handler = cherrypy.request.ws_handler
guides incorrectly — can not send opened
hook.
def opened(self): """ called server when upgrade handshake has succeeeded. """ pass
so think it's either outdated documentation or bug.
solution
for suggest initiate communication on client side. if have pre-login "chat", can make little protocol on top of web sockets (you end doing anyway). this:
#!/usr/bin/env python3 import json import cherrypy ws4py.server.cherrypyserver import websocketplugin, websockettool ws4py.websocket import websocket class loginlivewebsockethandler(websocket): wsset = set() '''class level attr, not rebind''' def opened(self): '''you can not send yet, because handshake has not been completed. yes, documentation not correct ;-) ''' cherrypy.log('opened!') self.wsset.add(self) def closed(self, code, reason = ''): cherrypy.log('closed!') self.wsset.remove(self) def received_message(self, message): cherrypy.log('received message!') message = json.loads(message.data.decode()) if message['cmd'] == 'init': self.send('login 0') else: self.send(message['payload'] + ' pong') class liveservice(object): @cherrypy.expose def index(self): return '''<!doctype html> <html> <body> <div id='log'></div> <script type='application/javascript'> var ws = new websocket('ws://127.0.0.1:8080/live/ws_zones'); ws.onopen = function(event) { ws.send(json.stringify({'cmd': 'init'})); }; ws.onmessage = function(event) { document.getelementbyid('log').innerhtml += event.data + '<br/>'; }; var handle = setinterval(function() { if(ws.readystate == websocket.closing || ws.readystate == websocket.closed) { clearinterval(handle); } else { ws.send(json.stringify({'cmd': 'chat', 'payload': 'ping'})); } }, 1000); </script> </body> </html> ''' @cherrypy.expose def ws_zones(self): '''you can not send yet, because handshake has not been completed''' cherrypy.log('handler created: %r' % cherrypy.request.ws_handler) if __name__ == '__main__': cherrypy.config.update({ 'server.socket_host' : '127.0.0.1', 'server.socket_port' : 8080, 'server.thread_pool' : 8 }) cherrypy.tools.websocket = websockettool() websocketplugin(cherrypy.engine).subscribe() cherrypy.tree.mount(liveservice(), '/live', { '/ws_zones' : { 'tools.websocket.on' : true, 'tools.websocket.handler_cls' : loginlivewebsockethandler } }) cherrypy.engine.signals.subscribe() cherrypy.engine.start() cherrypy.engine.block()
Comments
Post a Comment