Skip to content

Instantly share code, notes, and snippets.

@commandodev
Created September 30, 2010 04:55
Show Gist options
  • Save commandodev/604047 to your computer and use it in GitHub Desktop.
Save commandodev/604047 to your computer and use it in GitHub Desktop.
import sys
from zmq import FORWARDER, PUB, SUB, SUBSCRIBE
from zmq.devices import Device
if __name__ == "__main__":
usage = 'usage: chat_bridge pub_address sub_address'
if len (sys.argv) != 3:
print usage
sys.exit(1)
pub_addr = sys.argv[1]
sub_addr = sys.argv[2]
print "Recieving on %s" % sub_addr
print "Sending on %s" % pub_addr
device = Device(FORWARDER, SUB, PUB)
device.bind_in(sub_addr)
device.setsockopt_in(SUBSCRIBE, "")
device.bind_out(pub_addr)
device.start()
"""This is a websocket chat example with many servers. A client can connect to
any of the servers and their messages will be received by all clients connected
to any of the servers.
Run the examples like this:
$ python examples/chat_bridge.py tcp://127.0.0.1:12345 tcp://127.0.0.1:12346
and the servers like this (changing the port for each one obviously):
$ python examples/distributed_websocket_chat.py -p tcp://127.0.0.1:12345 -s tcp://127.0.0.1:12346 7000
So all messages are published to port 12345 and the device forwards all the
messages to 12346 where they are subscribed to
It requires this https://bitbucket.org/boothead/eventlet version of eventlet (for now), and a working zeromq/pyzmq install
"""
import os, sys
import eventlet
from collections import defaultdict
from eventlet import spawn_n, sleep
from eventlet import wsgi
from eventlet import websocket
from eventlet.green import zmq
from eventlet.hubs import get_hub, use_hub
from uuid import uuid1
use_hub('zeromq')
hub = get_hub()
ctx = hub.get_context()
class IDName(object):
def __init__(self):
self.id = uuid1()
self.name = None
def __str__(self):
if self.name:
return self.name
else:
return str(self.id)
def pack_message(self, msg):
return self, msg
def unpack_message(self, msg):
sender, message = msg
sender_name = 'you said' if sender.id == self.id \
else '%s says' % sender
return "%s: %s" % (sender_name, message)
participants = defaultdict(IDName)
def subscribe_and_distribute(sub_socket):
global participants
while True:
msg = sub_socket.recv_pyobj()
for ws, name_id in participants.items():
to_send = name_id.unpack_message(msg)
if to_send:
try:
ws.send(to_send)
except:
del participants[ws]
@websocket.WebSocketWSGI
def handle(ws):
global pub_socket
name_id = participants[ws]
ws.send("Connected as %s, change name with 'name: new_name'" % name_id)
try:
while True:
m = ws.wait()
if m is None:
break
if m.startswith('name:'):
old_name = str(name_id)
new_name = m.split(':', 1)[1].strip()
name_id.name = new_name
m = 'Changed name from %s' % old_name
pub_socket.send_pyobj(name_id.pack_message(m))
sleep()
finally:
del participants[ws]
def dispatch(environ, start_response):
"""Resolves to the web page or the websocket depending on the path."""
global port
if environ['PATH_INFO'] == '/chat':
return handle(environ, start_response)
else:
start_response('200 OK', [('content-type', 'text/html')])
return [open(os.path.join(
os.path.dirname(__file__),
'websocket_chat.html')).read() % dict(port=port)]
port = None
if __name__ == "__main__":
usage = 'usage: websocket_chat -p pub address -s sub address port number'
if len (sys.argv) != 6:
print usage
sys.exit(1)
pub_addr = sys.argv[2]
sub_addr = sys.argv[4]
try:
port = int(sys.argv[5])
except ValueError:
print "Error port supplied couldn't be converted to int\n", usage
sys.exit(1)
try:
pub_socket = ctx.socket(zmq.PUB)
pub_socket.connect(pub_addr)
print "Publishing to %s" % pub_addr
sub_socket = ctx.socket(zmq.SUB)
sub_socket.connect(sub_addr)
sub_socket.setsockopt(zmq.SUBSCRIBE, "")
print "Subscribing to %s" % sub_addr
except:
print "Couldn't create sockets\n", usage
sys.exit(1)
spawn_n(subscribe_and_distribute, sub_socket)
listener = eventlet.listen(('127.0.0.1', port))
print "\nVisit http://localhost:%s/ in your websocket-capable browser.\n" % port
wsgi.server(listener, dispatch)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment