Created
November 28, 2013 21:00
-
-
Save Lawouach/7698023 to your computer and use it in GitHub Desktop.
A more elaborated chat example using ws4py. It broadcasts to all clients when a message is sent. It also sends to a single client if the message is prefixed by "@Username: ..."
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
import argparse | |
import random | |
import os | |
import cherrypy | |
from ws4py.server.cherrypyserver import WebSocketPlugin, WebSocketTool | |
from ws4py.websocket import WebSocket | |
from ws4py.messaging import TextMessage | |
USERS = ['mike', 'stella', 'john'] | |
class ChatPlugin(WebSocketPlugin): | |
def __init__(self, bus): | |
WebSocketPlugin.__init__(self, bus) | |
self.clients = {} | |
def start(self): | |
WebSocketPlugin.start(self) | |
self.bus.subscribe('add-client', self.add_client) | |
self.bus.subscribe('get-client', self.get_client) | |
self.bus.subscribe('del-client', self.del_client) | |
def stop(self): | |
WebSocketPlugin.stop(self) | |
self.bus.unsubscribe('add-client', self.add_client) | |
self.bus.unsubscribe('get-client', self.get_client) | |
self.bus.unsubscribe('del-client', self.del_client) | |
def add_client(self, name, websocket): | |
self.clients[name] = websocket | |
def get_client(self, name): | |
return self.clients[name] | |
def del_client(self, name): | |
del self.clients[name] | |
class ChatWebSocketHandler(WebSocket): | |
def opened(self): | |
cherrypy.engine.publish('add-client', self.username, self) | |
def received_message(self, m): | |
text = m.data | |
if text.find("@") == -1: | |
# echo to all | |
cherrypy.engine.publish('websocket-broadcast', m) | |
else: | |
# or echo to a single user | |
left, message = text.rsplit(':', 1) | |
print left | |
from_username, to_username = left.split('@') | |
print repr(from_username), repr(to_username), repr(self.username) | |
client = cherrypy.engine.publish('get-client', to_username.strip()).pop() | |
print client | |
client.send("@@%s: %s" % (from_username.strip()[:-1], message.strip())) | |
def closed(self, code, reason="A client left the room without a proper explanation."): | |
cherrypy.engine.publish('del-client', self.username) | |
cherrypy.engine.publish('websocket-broadcast', TextMessage(reason)) | |
class Root(object): | |
def __init__(self, host, port, ssl=False): | |
self.host = host | |
self.port = port | |
self.scheme = 'wss' if ssl else 'ws' | |
@cherrypy.expose | |
def index(self): | |
return """<html> | |
<head> | |
<script type='application/javascript' src='https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js'></script> | |
<script type='application/javascript'> | |
$(document).ready(function() { | |
websocket = '%(scheme)s://%(host)s:%(port)s/ws?username=%(username)s'; | |
if (window.WebSocket) { | |
ws = new WebSocket(websocket, ['mytest']); | |
} | |
else if (window.MozWebSocket) { | |
ws = MozWebSocket(websocket); | |
} | |
else { | |
console.log('WebSocket Not Supported'); | |
return; | |
} | |
window.onbeforeunload = function(e) { | |
$('#chat').val($('#chat').val() + 'Bye bye...\\n'); | |
ws.close(1000, '%(username)s left the room'); | |
if(!e) e = window.event; | |
e.stopPropagation(); | |
e.preventDefault(); | |
}; | |
ws.onmessage = function (evt) { | |
$('#chat').val($('#chat').val() + evt.data + '\\n'); | |
}; | |
ws.onopen = function() { | |
ws.send("%(username)s entered the room"); | |
}; | |
ws.onclose = function(evt) { | |
$('#chat').val($('#chat').val() + 'Connection closed by server: ' + evt.code + ' \"' + evt.reason + '\"\\n'); | |
}; | |
$('#send').click(function() { | |
console.log($('#message').val()); | |
ws.send('%(username)s: ' + $('#message').val()); | |
$('#message').val(""); | |
return false; | |
}); | |
}); | |
</script> | |
</head> | |
<body> | |
<form action='#' id='chatform' method='get'> | |
<textarea id='chat' cols='35' rows='10'></textarea> | |
<br /> | |
<label for='message'>%(username)s: </label><input type='text' id='message' /> | |
<input id='send' type='submit' value='Send' /> | |
</form> | |
</body> | |
</html> | |
""" % {'username': "User%d" % random.randint(0, 100), 'host': self.host, | |
'port': self.port, 'scheme': self.scheme} | |
@cherrypy.expose | |
def ws(self, username): | |
# let's track the username we chose | |
cherrypy.request.ws_handler.username = username | |
cherrypy.log("Handler created: %s" % repr(cherrypy.request.ws_handler)) | |
if __name__ == '__main__': | |
import logging | |
from ws4py import configure_logger | |
configure_logger(level=logging.DEBUG) | |
parser = argparse.ArgumentParser(description='Echo CherryPy Server') | |
parser.add_argument('--host', default='127.0.0.1') | |
parser.add_argument('-p', '--port', default=9000, type=int) | |
parser.add_argument('--ssl', action='store_true') | |
args = parser.parse_args() | |
cherrypy.config.update({'server.socket_host': args.host, | |
'server.socket_port': args.port, | |
'tools.staticdir.root': os.path.abspath(os.path.join(os.path.dirname(__file__), 'static'))}) | |
if args.ssl: | |
cherrypy.config.update({'server.ssl_certificate': './server.crt', | |
'server.ssl_private_key': './server.key'}) | |
ChatPlugin(cherrypy.engine).subscribe() | |
cherrypy.tools.websocket = WebSocketTool() | |
cherrypy.quickstart(Root(args.host, args.port, args.ssl), '', config={ | |
'/ws': { | |
'tools.websocket.on': True, | |
'tools.websocket.handler_cls': ChatWebSocketHandler, | |
'tools.websocket.protocols': ['toto', 'mytest', 'hithere'] | |
}, | |
'/js': { | |
'tools.staticdir.on': True, | |
'tools.staticdir.dir': 'js' | |
} | |
} | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment