From: Drew Fisher Date: Tue, 13 May 2014 07:15:54 +0000 (-0700) Subject: Allow multiple ribbon worker processes in different folders X-Git-Url: http://git.zarvox.org/%7B%7B%20url_for%28%27static%27%2C%20filename=%27style.css%27%29%20%7D%7D?a=commitdiff_plain;h=0fa35e8585e34f8fc5415a4164cc06ebe9b2ea88;p=imoo.git Allow multiple ribbon worker processes in different folders For now, spawn one ribbon per websocket. This will likely need to be revised later. --- diff --git a/reactornado/dispatcher.js b/reactornado/dispatcher.js index 9dfcda8..cca1a46 100644 --- a/reactornado/dispatcher.js +++ b/reactornado/dispatcher.js @@ -14,6 +14,8 @@ var Dispatcher = { this.handle_blist_message(obj.method, obj.params); } else if (obj.sender == "conversations") { this.handle_conversations_message(obj.method, obj.params); + } else if (obj.sender == "session") { + this.handle_session_message(obj.method, obj.params); } }, handle_blist_message: function(method, params) { @@ -30,7 +32,9 @@ var Dispatcher = { if (method == "buddy_status_changed") { window.blist[bid].status = params.status; } else if (method == "buddy_icon_changed") { - window.blist[bid].bicon_url = params.url; + var url = "/icons/" + window.session_id + "/" + params.url; + console.log(url); + window.blist[bid].bicon_url = url; } window.buddy_list.onChange(window.blist); }, @@ -59,6 +63,12 @@ var Dispatcher = { window.conversations[bid].type_state = params.state; } // TODO: repaint conversations window + }, + handle_session_message: function(method, params) { + console.log("session:", method, params); + if (method == "set_session") { + window.session_id = params["session_id"]; + } } }; diff --git a/reactornado/ribbon_passthrough.py b/reactornado/ribbon_passthrough.py index 3719aa5..a384b58 100644 --- a/reactornado/ribbon_passthrough.py +++ b/reactornado/ribbon_passthrough.py @@ -1,6 +1,7 @@ import json import logging import os +import shutil import socket import struct import subprocess @@ -12,6 +13,11 @@ import tornado.websocket pwd = os.path.dirname(os.path.abspath(__file__)) +_SESSION_BYTES = 8 + +# path to the ribbon executable +ribbon_binary = os.path.join(os.path.dirname(pwd), "ribbon", "ribbon") + logging.basicConfig( level=logging.DEBUG, format='%(asctime)s : %(levelname)s : %(name)s : %(message)s', @@ -54,36 +60,52 @@ class WSHandler(tornado.websocket.WebSocketHandler): self.dispatch_backlog() def open(self): - # Create a new connection to ribbon. + # Create a new ribbon subprocess, then connect to it. + self.sess_id = os.urandom(_SESSION_BYTES).encode('hex') + self.state_dir = os.path.join(pwd, "state", self.sess_id) + self.ribbon_subprocess = subprocess.Popen( [ribbon_binary, "--state-dir", self.state_dir], close_fds=True ) + + # TODO: find a better way to make this work, like exponential backoff + # polling for the socket that's supposed to appear + # For now, a one-second delay gives ribbon enough time to start up + import time + time.sleep(1.0) + self.ribbon_ready = False self.backlog = [] # A list of bytestrings queued to be sent on the socket. self.ribbon_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM, 0) self.ribbon_stream = tornado.iostream.IOStream(self.ribbon_socket) - self.ribbon_stream.connect( os.path.join(pwd, "state", "socket"), self.on_ribbon_ready) + self.ribbon_stream.connect(os.path.join(self.state_dir, "socket"), self.on_ribbon_ready) log.info('new connection') - self.write_message('{"key":"value"}') + m = { "sender": "session", + "method": "set_session", + "params": {"session_id": self.sess_id }, + } + self.write_message(json.dumps(m)) def on_message(self, message): log.info('message received: %r', message) data = json.loads(message) self.queue_message(message.encode("latin1")) def on_close(self): - log.info('connection closed') - + log.info('connection closed: {}'.format(self.session_id)) + # kill child ribbon + self.ribbon_subprocess.kill() + self.ribbon_subprocess.wait() + # clean up that ribbon instance's work directory + shutil.rmtree(self.state_dir) application = tornado.web.Application([ (r'/(index.html)', tornado.web.StaticFileHandler, {'path': pwd}), (r'/([a-z]*\.js)', tornado.web.StaticFileHandler, {'path': pwd}), (r'/([a-z]*\.css)', tornado.web.StaticFileHandler, {'path': pwd}), - (r'/icons/(.*)', tornado.web.StaticFileHandler, {'path': os.path.join(pwd, 'state', 'icons')}), + # mildly janky url mapping + (r'/icons/([0-9a-f]{16}/icons/.*)', tornado.web.StaticFileHandler, {'path': os.path.join(pwd, 'state')}), (r'/ws', WSHandler), ]) if __name__ == "__main__": - # Spawn the ribbon subprocess - ribbon_binary = os.path.join(os.path.dirname(pwd), "ribbon", "ribbon") - ribbon = subprocess.Popen( [ribbon_binary, "--state-dir", os.path.join(pwd, "state")], close_fds=True ) # Spawn the http server http_server = tornado.httpserver.HTTPServer(application)