class StompDispatcherResource(resource.Resource): logger = logging.get_logger('orbited.system.test.stompdispatcher') def render(self, request): self.logger.info("request received") if config['[test]']['stompdispatcher.enabled'] == '1': destination = request.args['dest'][0] message = request.args['msg'][0] self.logger.info("sending %s to %s" % (message, destination)) config['morbid_instance'].send(destination, message) else: self.logger.info( "stompdispatcher not enabled - message not dispatched") return "alert('stompdispatcher not enabled');"
def setupSite(backend): from orbited import logging, config config.map['[access]'][('localhost',61613)] = ['*'] logging.setup(config.map) import orbited.start orbited.start.logger = logging.get_logger('orbited.start') root = static.File(os.path.dirname(backhardding.__file__) + "/html") root.putChild('control', BackharddiNGControl(backend)) static_files = static.File(os.path.dirname(orbited.__file__) + "/static") root.putChild('static', static_files) orbited.start._setup_protocols(root) site = server.Site(root,'/dev/null') return site
class TCPResource(resource.Resource): logger = logging.get_logger('orbited.cometsession.TCPResource') def __init__(self, listeningPort): resource.Resource.__init__(self) self.listeningPort = listeningPort self.static_files = static.File( os.path.join(os.path.dirname(__file__), 'static')) self.connections = {} def render(self, request): key = None while key is None or key in self.connections: key = str(uuid.uuid4()).replace('-', '') # request.client and request.host should be address.IPv4Address classes hostHeader = request.received_headers.get('host', '') self.connections[key] = TCPConnectionResource(self, key, request.client, request.host, hostHeader) self.listeningPort.connectionMade(self.connections[key]) self.logger.debug('created conn: ', repr(self.connections[key])) request.setHeader('cache-control', 'no-cache, must-revalidate') return key def getChild(self, path, request): if path == 'static': return self.static_files if path not in self.connections: if 'htmlfile' in request.path: return transports.htmlfile.CloseResource() return error.NoResource("<script>alert('whoops');</script>") # print 'returning self.connections[%s]' % (path,) return self.connections[path] def removeConn(self, conn): if conn.key in self.connections: del self.connections[conn.key] def connectionMade(self, conn): self.listeningPort.connectionMade(conn)
class XHRStreamingTransport(CometTransport): logger = logging.get_logger('orbited.transports.xhrstream.XHRStreamingTransport') def opened(self): self.totalBytes = 0 # Force reconnect ever 45 seconds # self.close_timer = reactor.callLater(45, self.triggerCloseTimeout) self.request.setHeader('content-type', 'application/x-orbited-event-stream') # Safari/Tiger may need 256 bytes self.request.write(' ' * 256) def triggerCloseTimeout(self): self.logger.debug('triggerCloseTimeout called') self.close() def write(self, packets): self.logger.debug('write %r' % packets) # TODO why join the packets here? why not do N request.write? payload = self.encode(packets) self.logger.debug('WRITE ' + payload) self.request.write(payload) self.totalBytes += len(payload) if (self.totalBytes > MAXBYTES): self.logger.debug('over maxbytes limit') self.close() def encode(self, packets): output = [] for packet in packets: for i, arg in enumerate(packet): if i == len(packet) -1: output.append('0') else: output.append('1') output.append(str(len(arg))) output.append(',') output.append(arg) return "".join(output) def writeHeartbeat(self): self.logger.debug('writeHeartbeat, ' + repr(self)) self.request.write('x')
class LongPollingTransport(CometTransport): logger = logging.get_logger( 'orbited.transports.longpoll.LongPollingTransport') def opened(self): self.totalBytes = 0 # Force reconnect ever 45 seconds self.close_timer = reactor.callLater(30, self.triggerCloseTimeout) # self.request.setHeader('content-type', 'application/x-orbited-event-stream') self.request.setHeader('cache-control', 'no-cache, must-revalidate') def triggerCloseTimeout(self): self.close() def write(self, packets): # TODO: we can optimize this. In the case where packets contains a # single packet, and its a ping, just don't send it. (instead, # close the connection. the re-open will prompt the ack) self.logger.debug('write %r' % packets) payload = self.encode(packets) self.logger.debug('WRITE ' + payload) self.request.write(payload) self.close() def encode(self, packets): output = [] for packet in packets: for i, arg in enumerate(packet): if i == len(packet) - 1: output.append('0') else: output.append('1') output.append(str(len(arg))) output.append(',') output.append(arg) return "".join(output) def writeHeartbeat(self): # NOTE: no heartbeats... pass
class ProxyOutgoingProtocol(Protocol): """ Handles the protocol between orbited and backend server. """ logger = logging.get_logger('orbited.proxy.ProxyOutgoingProtocol') def __init__(self, incomingConn): # TODO rename this to incomingProtocol self.incomingConn = incomingConn def connectionMade(self): self.incomingConn.outgoingConnectionEstablished(self) config.map['globalVars']['connections'] += 1 def dataReceived(self, data): self.logger.debug("dataReceived %r" % data) self.incomingConn.write(data) def connectionLost(self, reason): self.incomingConn.outgoingConnectionLost(self, reason) config.map['globalVars']['connections'] -= 1
class PollingTransport(CometTransport): logger = logging.get_logger('orbited.transports.poll.PollingTransport') def opened(self): self.request.setHeader('cache-control', 'no-cache, must-revalidate') # NOTE: we override this so we can close as soon as we send out any waiting # packets. We can't put the self.close call inside of self.write # because sometimes there will be no packets to write. def flush(self): self.logger.debug('flush') CometTransport.flush(self) self.close() def write(self, packets): self.logger.debug('write %r' % packets) payload = self.encode(packets) self.logger.debug('WRITE ' + payload) self.request.write(payload) def encode(self, packets): output = [] for packet in packets: for i, arg in enumerate(packet): if i == len(packet) - 1: output.append('0') else: output.append('1') output.append(str(len(arg))) output.append(',') output.append(arg) return "".join(output) def writeHeartbeat(self): # NOTE: no heartbeats... pass
from orbited import logging from twisted.web import server, resource from twisted.internet import defer, reactor logger = logging.get_logger('orbited.transports.base.CometTransport') class CometTransport(resource.Resource): HEARTBEAT_INTERVAL = 5 def __init__(self, conn): self.conn = conn self.open = False self.closed = False def render(self, request): self.open = True self.packets = [] self.request = request self.opened() # self.request.notifiyFinish().addCallback(self.finished) self.resetHeartbeat() self.closeDeferred = defer.Deferred() self.conn.transportOpened(self) return server.NOT_DONE_YET def resetHeartbeat(self): self.heartbeatTimer = reactor.callLater(self.HEARTBEAT_INTERVAL, self.doHeartbeat) def doHeartbeat(self): if self.closed: logger.debug("don't send hearbeat -- we should be closed", ) raise Exception("show tb...") else:
from orbited import logging from twisted.web import server, resource from twisted.internet import defer, reactor logger = logging.get_logger('orbited.transports.base.CometTransport') class CometTransport(resource.Resource): HEARTBEAT_INTERVAL = 5 def __init__(self, conn): self.conn = conn self.open = False self.closed = False def render(self, request): self.open = True self.packets = [] self.request = request self.opened() # self.request.notifiyFinish().addCallback(self.finished) self.resetHeartbeat() self.closeDeferred = defer.Deferred() self.conn.transportOpened(self) return server.NOT_DONE_YET def resetHeartbeat(self): self.heartbeatTimer = reactor.callLater(self.HEARTBEAT_INTERVAL, self.doHeartbeat) def doHeartbeat(self): if self.closed:
def main(): try: import twisted except ImportError: print "Orbited requires Twisted, which is not installed. See http://twistedmatrix.com/trac/ for installation instructions." sys.exit(1) import platform if platform.system() == "Windows": try: import win32api except ImportError: print "Orbited for Windows requires the Python for Windows Extensions, which are not installed. See http://python.net/crew/mhammond/win32/ for installation instructions." sys.exit(1) from optparse import OptionParser parser = OptionParser() parser.add_option("-c", "--config", dest="config", default=None, help="path to configuration file") parser.add_option("-v", "--version", dest="version", action="store_true", default=False, help="print Orbited version") parser.add_option("-p", "--profile", dest="profile", action="store_true", default=False, help="run Orbited with a profiler") parser.add_option( "-q", "--quickstart", dest="quickstart", action="store_true", default=False, help="run Orbited on port 8000 and MorbidQ on port 61613") (options, args) = parser.parse_args() if args: print 'the "orbited" command does not accept positional arguments. type "orbited -h" for options.' sys.exit(1) if options.version: print "Orbited version: %s" % (version, ) sys.exit(0) if options.quickstart: config.map['[listen]'].append('http://:8000') config.map['[listen]'].append('stomp://:61613') config.map['[access]'][('localhost', 61613)] = ['*'] print "Quickstarting Orbited" else: # load configuration from configuration # file and from command line arguments. config.setup(options=options) logging.setup(config.map) # we can now safely get loggers. global logger logger = logging.get_logger('orbited.start') # NB: we need to install the reactor before using twisted. reactor_name = config.map['[global]'].get('reactor') if reactor_name: install = _import('twisted.internet.%sreactor.install' % reactor_name) install() logger.info('using %s reactor' % reactor_name) ############ # This crude garbage corrects a bug in twisted # Orbited ticket: http://orbited.org/ticket/111 # Twisted ticket: http://twistedmatrix.com/trac/ticket/2447 import twisted.web.http twisted.web.http.HTTPChannel.setTimeout = lambda self, arg: None twisted.web.http.HTTPChannel.resetTimeout = lambda self: None ############ from twisted.internet import reactor from twisted.web import resource from twisted.web import server from twisted.web import static import orbited.system root = resource.Resource() static_files = static.File( os.path.join(os.path.dirname(__file__), 'static')) root.putChild('static', static_files) root.putChild('system', orbited.system.SystemResource()) if config.map['[test]']['stompdispatcher.enabled'] == '1': logger.info('stompdispatcher enabled') #static_files.putChild('orbited.swf', static.File(os.path.join(os.path.dirname(__file__), 'flash', 'orbited.swf'))) site = server.Site(root) _setup_protocols(root) _setup_static(root, config.map) start_listening(site, config.map, logger) # switch uid and gid to configured user and group. if os.name == 'posix' and os.getuid() == 0: user = config.map['[global]'].get('user') group = config.map['[global]'].get('group') if user: import pwd import grp try: pw = pwd.getpwnam(user) uid = pw.pw_uid if group: gr = grp.getgrnam(group) gid = gr.gr_gid else: gid = pw.pw_gid gr = grp.getgrgid(gid) group = gr.gr_name except Exception, e: logger.error('Aborting; Unknown user or group: %s' % e) sys.exit(1) logger.info('switching to user %s (uid=%d) and group %s (gid=%d)' % (user, uid, group, gid)) os.setgid(gid) os.setuid(uid) else: logger.error( 'Aborting; You must define a user (and optionally a group) in the configuration file.' ) sys.exit(1)
from orbited.util import format_block from orbited import json from twisted.internet import reactor from orbited import logging from orbited.transports.base import CometTransport from twisted.web import resource MAXBYTES = 1048576 # MAXBYTES = 64 # for testing from orbited import logging logger = logging.get_logger("orbited.transports.htmlfile.HTMLFileTransport") class HTMLFileTransport(CometTransport): initialData = format_block( """ <html> <head> <script src="../static/HTMLFileFrame.js"></script> </head> <body> """ ) initialData += " " * max(0, 256 - len(initialData)) + "\n" def opened(self): logger.debug("opened!") # Force reconnect ever 30 seconds self.totalBytes = 0
from orbited.util import format_block from orbited import json from twisted.internet import reactor from base import CometTransport from orbited import logging logger = logging.get_logger('orbited.transports.sse.SSETransport') class SSETransport(CometTransport): HEARTBEAT_INTERVAL = 30 def opened(self): self.request.setHeader('content-type', 'application/x-dom-event-stream') self.request.setHeader('cache-control', 'no-cache, must-revalidate') def write(self, packets): payload = json.encode(packets) data = ('Event: payload\n' + '\n'.join(['data: %s' % line for line in payload.splitlines()]) + '\n\n') self.request.write(data) def writeHeartbeat(self): logger.debug('writeHeartbeat') self.request.write('Event: heartbeat\n\n')
def main(): try: import twisted except ImportError: print "Orbited requires Twisted, which is not installed. See http://twistedmatrix.com/trac/ for installation instructions." sys.exit(1) ################# # This corrects a bug in Twisted 8.2.0 for certain Python 2.6 builds on Windows # Twisted ticket: http://twistedmatrix.com/trac/ticket/3868 # -mario try: from twisted.python import lockfile except ImportError: from orbited import __path__ as orbited_path sys.path.append(os.path.join(orbited_path[0],"hotfixes","win32api")) from twisted.python import lockfile lockfile.kill = None ################# from optparse import OptionParser parser = OptionParser() parser.add_option( "-c", "--config", dest="config", default=None, help="path to configuration file" ) parser.add_option( "-v", "--version", dest="version", action="store_true", default=False, help="print Orbited version" ) parser.add_option( "-p", "--profile", dest="profile", action="store_true", default=False, help="run Orbited with a profiler" ) parser.add_option( "-q", "--quickstart", dest="quickstart", action="store_true", default=False, help="run Orbited on port 8000 and MorbidQ on port 61613" ) (options, args) = parser.parse_args() if args: print 'the "orbited" command does not accept positional arguments. type "orbited -h" for options.' sys.exit(1) if options.version: print "Orbited version: %s" % (version,) sys.exit(0) if options.quickstart: config.map['[listen]'].append('http://:8000') config.map['[listen]'].append('stomp://:61613') config.map['[access]'][('localhost',61613)] = ['*'] print "Quickstarting Orbited" else: # load configuration from configuration # file and from command line arguments. config.setup(options=options) logging.setup(config.map) # we can now safely get loggers. global logger; logger = logging.get_logger('orbited.start') # NB: we need to install the reactor before using twisted. reactor_name = config.map['[global]'].get('reactor') if reactor_name: install = _import('twisted.internet.%sreactor.install' % reactor_name) install() logger.info('using %s reactor' % reactor_name) ############ # This crude garbage corrects a bug in twisted # Orbited ticket: http://orbited.org/ticket/111 # Twisted ticket: http://twistedmatrix.com/trac/ticket/2447 import twisted.web.http twisted.web.http.HTTPChannel.setTimeout = lambda self, arg: None twisted.web.http.HTTPChannel.resetTimeout = lambda self: None ############ from twisted.internet import reactor from twisted.web import resource from twisted.web import server from twisted.web import static import orbited.system root = resource.Resource() static_files = static.File(os.path.join(os.path.dirname(__file__), 'static')) root.putChild('static', static_files) root.putChild('system', orbited.system.SystemResource()) if config.map['[test]']['stompdispatcher.enabled'] == '1': logger.info('stompdispatcher enabled') #static_files.putChild('orbited.swf', static.File(os.path.join(os.path.dirname(__file__), 'flash', 'orbited.swf'))) site = server.Site(root) _setup_protocols(root) _setup_static(root, config.map) start_listening(site, config.map, logger) # switch uid and gid to configured user and group. if os.name == 'posix' and os.getuid() == 0: user = config.map['[global]'].get('user') group = config.map['[global]'].get('group') if user: import pwd import grp try: pw = pwd.getpwnam(user) uid = pw.pw_uid if group: gr = grp.getgrnam(group) gid = gr.gr_gid else: gid = pw.pw_gid gr = grp.getgrgid(gid) group = gr.gr_name except Exception, e: logger.error('Aborting; Unknown user or group: %s' % e) sys.exit(1) logger.info('switching to user %s (uid=%d) and group %s (gid=%d)' % (user, uid, group, gid)) os.setgid(gid) os.setuid(uid) else: logger.error('Aborting; You must define a user (and optionally a group) in the configuration file.') sys.exit(1)
class ProxyIncomingProtocol(Protocol): """ Handles the protocol between the browser and orbited, and proxies the data to a backend server. """ logger = logging.get_logger('orbited.proxy.ProxyIncomingProtocol') def connectionMade(self): # TODO: add handshake timer self.transport.pingTimeout = pingTimeout self.transport.pingInterval = pingInterval self.logger.debug("connectionMade") self.state = 'handshake' # TODO rename this to outgoingProtocol self.outgoingConn = None self.completedHandshake = False def dataReceived(self, data): # NB: this only receives whole frames; so we will just decode # data as-is. # NB: its cometsession.py:TCPConnectionResource that makes sure # we receive whole frames here. self.logger.debug('dataReceived: data=%r' % data) self.logger.debug('self.outgoingConn is', self.outgoingConn) if self.outgoingConn: # NB: outgoingConn is-a ProxyOutgoingProtocol self.logger.debug("write (out): %r" % data) return self.outgoingConn.transport.write(data) if self.state == "handshake": try: data = data.strip() host, port = data.split(':') port = int(port) self.completedHandshake = True except: self.logger.error("failed to connect on handshake", tb=True) self.transport.write("0" + str(ERRORS['InvalidHandshake'])) self.transport.loseConnection() return peer = self.transport.getPeer() self.fromHost = peer.host self.fromPort = peer.port self.toHost = host self.toPort = port allowed = False for source in config.map['[access]'].get((host, port), []): if source == self.transport.hostHeader or source == '*': allowed = True break if not allowed: self.logger.warn( 'Unauthorized connect from %r:%d to %r:%d' % (self.fromHost, self.fromPort, self.toHost, self.toPort)) self.transport.write("0" + str(ERRORS['Unauthorized'])) self.transport.loseConnection() return self.logger.access( 'new connection from %s:%s to %s:%d' % (self.fromHost, self.fromPort, self.toHost, self.toPort)) self.state = 'connecting' client = ClientCreator(reactor, ProxyOutgoingProtocol, self) client.connectTCP(host, port).addErrback(self.errorConnection) # TODO: connect timeout or onConnectFailed handling... else: self.transport.write("0" + str(ERRORS['InvalidHandshake'])) self.state = 'closed' self.transport.loseConnection() def errorConnection(self, err): self.logger.warn("Connection Error %s" % (err, )) self.transport.write("0" + str(ERRORS['RemoteConnectionFailed'])) self.transport.loseConnection() def connectionLost(self, reason): self.logger.debug("connectionLost %s" % reason) if self.outgoingConn: self.outgoingConn.transport.loseConnection() if self.completedHandshake: self.logger.access( 'connection closed from %s:%s to %s:%s' % (self.fromHost, self.fromPort, self.toHost, self.toPort)) def outgoingConnectionEstablished(self, outgoingConn): if self.state == 'closed': return outgoingConn.transport.loseConnection() self.outgoingConn = outgoingConn self.transport.write('1') self.state = 'proxy' # Not really necessary... def outgoingConnectionLost(self, outgoingConn, reason): self.logger.debug("remoteConnectionLost %s" % reason) self.transport.loseConnection() def write(self, data): # data = base64.b64encode(data) self.logger.debug("write %r" % data) self.transport.write(data)
class TCPConnectionResource(resource.Resource): pingTimeout = 30 pingInterval = 30 logger = logging.get_logger('orbited.cometsession.TCPConnectionResource') def __init__(self, root, key, peer, host, hostHeader, **options): resource.Resource.__init__(self) self.root = root self.key = key self.peer = peer self.host = host self.hostHeader = hostHeader self.transport = None self.cometTransport = None self.parentTransport = None self.options = {} self.msgQueue = [] self.unackQueue = [] self.lastAckId = 0 self.packetId = 0 self.pingTimer = None self.timeoutTimer = None self.closeTimer = None self.lostTriggered = False self.resetPingTimer() self.open = False self.closed = False self.closing = False def getPeer(self): return self.peer def getHost(self): return self.host def write(self, data): self.send(data) # this is never used, right? def writeSequence(self, data): for datum in data: self.write(datum) def loseConnection(self): # TODO: self.close() ? self.close('loseConnection', True) return None def connectionLost(self): self.logger.debug('connectionLost... already triggered?', self.lostTriggered) if not self.lostTriggered: self.logger.debug('do trigger') self.lostTriggered = True self.parentTransport.connectionLost() def getChild(self, path, request): if path in transports.map: return transports.create(path, self) return error.NoResource("No such child resource.") def render(self, request): self.logger.debug('render: request=%r' % request) stream = request.content.read() self.logger.debug('render: request.content=%r' % stream) ack = request.args.get('ack', [None])[0] if ack: try: ack = int(ack) self.ack(ack) except ValueError: pass encoding = request.received_headers.get('tcp-encoding', None) # TODO instead of .write/.finish just return OK? request.write('OK') request.finish() self.resetPingTimer() # TODO why not call parseData here? reactor.callLater(0, self.parseData, stream) return server.NOT_DONE_YET def parseData(self, data): # TODO: this method is filled with areas that really should be put # inside try/except blocks. We don't want errors caused by # malicious IO. self.logger.debug('RECV: ' + data) frames = [] curFrame = [] while data: self.logger.debug([data, frames, curFrame]) isLast = data[0] == '0' l, data = data[1:].split(',', 1) l = int(l) arg = data[:l] data = data[l:] curFrame.append(arg) if isLast: frames.append(curFrame) curFrame = [] # TODO: do we really need the id? maybe we should take it out # of the protocol... # -mcarter 7-29-08 # I think its a safenet for unintentinal bugs; we should # compare it with the last one we received, and error or # ignore if its not what we expect. # -- rgl for args in frames: self.logger.debug('parseData: frame=%r' % args) id = args[0] name = args[1] if name == 'close': if len(args) != 2: # TODO kill the connection with error. pass self.loseConnection() elif name == 'data': # TODO: should there be a try/except around this block? # we don't want app-level code to break and cause # only some packets to be delivered. if len(args) != 3: # TODO kill the connection with error. pass data = base64.b64decode(args[2]) # NB: parentTransport is-a FakeTCPTransport. self.parentTransport.dataReceived(data) elif name == 'ping': if len(args) != 2: # TODO kill the connection with error. pass # TODO: do we have to do anything? I don't think so... # -mcarter 7-30-08 self.logger.debug('parseData: PING? PONG!') # Called by the callback attached to the CometTransport def transportClosed(self, transport): if transport is self.cometTransport: self.cometTransport = None # Called by transports.CometTransport.render def transportOpened(self, transport): self.resetPingTimer() if self.cometTransport: self.cometTransport.close() self.cometTransport = None self.logger.debug("new transport: " + repr(transport)) self.cometTransport = transport transport.CONNECTION = self transport.onClose().addCallback(self.transportClosed) ack = transport.request.args.get('ack', [None])[0] if ack: try: ack = int(ack) self.ack(ack) except ValueError: pass self.resendUnackQueue() self.sendMsgQueue() if not self.open: self.open = True self.cometTransport.sendPacket("open", self.packetId) self.cometTransport.flush() def resetPingTimer(self): self.cancelTimers() self.pingTimer = reactor.callLater(self.pingInterval, self.sendPing) def sendPing(self): self.pingTimer = None self.send(TCPPing()) self.timeoutTimer = reactor.callLater(self.pingTimeout, self.timeout) def timeout(self): self.timeoutTimer = None self.close("timeout", True) def cancelTimers(self): if self.timeoutTimer: self.timeoutTimer.cancel() self.timeoutTimer = None if self.pingTimer: self.pingTimer.cancel() self.pingTimer = None def hardClose(self): self.closed = True self.cancelTimers() if self.closeTimer: self.closeTimer.cancel() self.closeTimer = None if self.cometTransport: self.cometTransport.close() self.cometTransport = None self.connectionLost() self.root.removeConn(self) def close(self, reason="", now=False): if self.closed: self.logger.debug('close called - already closed') return self.closing = True self.logger.debug('close reason=%s %s' % (reason, repr(self))) self.send(TCPClose(reason)) if now: self.hardClose() elif not self.closing: self.cancelTimers() self.closeTimer = reactor.callLater(self.pingInterval, self.hardClose) def ack(self, ackId): self.logger.debug('ack ackId=%s' % (ackId, )) ackId = min(ackId, self.packetId) if ackId <= self.lastAckId: return for i in range(ackId - self.lastAckId): (data, packetId) = self.unackQueue.pop(0) if isinstance(data, TCPClose): # Really close self.close("close acked", True) self.lastAckId = ackId def sendMsgQueue(self): while self.msgQueue and self.cometTransport: self.send(self.msgQueue.pop(0), flush=False) def send(self, data, flush=True): if not self.cometTransport: self.msgQueue.append(data) else: self.packetId += 1 self._send(data, self.packetId) self.unackQueue.append((data, self.packetId)) if flush: self.cometTransport.flush() def _send(self, data, packetId=""): self.logger.debug('_send data=%r packetId=%s' % (data, packetId)) if isinstance(data, TCPPing): self.cometTransport.sendPacket('ping', str(packetId)) elif isinstance(data, TCPClose): self.cometTransport.sendPacket('close', str(packetId), data.reason) elif isinstance(data, TCPOption): self.cometTransport.sendPacket('opt', str(packetId), data.payload) else: self.cometTransport.sendPacket('data', str(packetId), base64.b64encode(data)) def resendUnackQueue(self): if not self.unackQueue: return for (data, packetId) in self.unackQueue: self._send(data, packetId) ackId = self.lastAckId + len(self.unackQueue)
from orbited.util import format_block from orbited import json from twisted.internet import reactor from orbited import logging from orbited.transports.base import CometTransport from twisted.web import resource MAXBYTES = 1048576 #MAXBYTES = 64 # for testing from orbited import logging logger = logging.get_logger('orbited.transports.htmlfile.HTMLFileTransport') class HTMLFileTransport(CometTransport): initialData = format_block(''' <html> <head> <script src="../static/HTMLFileFrame.js"></script> </head> <body> ''') initialData += ' ' * max(0, 256 - len(initialData)) + '\n' def opened(self): logger.debug('opened!') # Force reconnect ever 30 seconds self.totalBytes = 0 # self.closeTimer = reactor.callLater(5, self.triggerCloseTimeout) # See "How to prevent caching in Internet Explorer" # at http://support.microsoft.com/kb/234067 self.request.setHeader('cache-control', 'no-cache, must-revalidate')
class Port(object): """ A cometsession.Port object can be used in two different ways. # Method 1 reactor.listenWith(cometsession.Port, 9999, SomeFactory()) # Method 2 root = twisted.web.resource.Resource() site = twisted.web.server.Site(root) reactor.listenTcp(site, 9999) reactor.listenWith(cometsession.Port, factory=SomeFactory(), resource=root, childName='tcp') Either of these methods should acheive the same effect, but Method2 allows you To listen with multiple protocols on the same port by using different urls. """ implements(interfaces.IListeningPort) logger = logging.get_logger('orbited.cometsession.Port') def __init__(self, port=None, factory=None, backlog=50, interface='', reactor=None, resource=None, childName=None): self.port = port self.factory = factory self.backlog = backlog self.interface = interface self.resource = resource self.childName = childName self.wrapped_port = None self.listening = False def startListening(self): self.logger.debug('startingListening') if not self.listening: self.listening = True if self.port: self.logger.debug('creating new site and resource') self.wrapped_factory = setup_site(self) self.wrapped_port = reactor.listenTCP(self.port, self.wrapped_factory, self.backlog, self.interface) elif self.resource and self.childName: self.logger.debug('adding into existing resource as %s' % self.childName) self.resource.putChild(self.childName, TCPResource(self)) else: raise CannotListenError("Already listening...") def stopListening(): self.logger.debug('stopListening') if self.wrapped_port: self.listening = False self.wrapped_port.stopListening() elif self.resource: pass # TODO: self.resource.removeChild(self.childName) ? def connectionMade(self, transportProtocol): """ proto is the tcp-emulation protocol protocol is the real protocol on top of the transport that depends on proto """ self.logger.debug('connectionMade') protocol = self.factory.buildProtocol(transportProtocol.getPeer()) if protocol is None: transportProtocol.loseConnection() return transport = FakeTCPTransport(transportProtocol, protocol) transportProtocol.parentTransport = transport protocol.makeConnection(transport) def getHost(): if self.wrapped_port: return self.wrapped_port.getHost() elif self.resource: pass
def main(): try: import twisted except ImportError: print "Orbited requires Twisted, which is not installed. See http://twistedmatrix.com/trac/ for installation instructions." sys.exit(1) import platform if platform.system() == "Windows": try: import win32api except ImportError: print "Orbited for Windows requires the Python for Windows Extensions, which are not installed. See http://python.net/crew/mhammond/win32/ for installation instructions." sys.exit(1) from optparse import OptionParser parser = OptionParser() parser.add_option("-c", "--config", dest="config", default=None, help="path to configuration file") parser.add_option( "-v", "--version", dest="version", action="store_true", default=False, help="print Orbited version" ) parser.add_option( "-p", "--profile", dest="profile", action="store_true", default=False, help="run Orbited with a profiler" ) parser.add_option( "-q", "--quickstart", dest="quickstart", action="store_true", default=False, help="run Orbited on port 8000 and MorbidQ on port 61613", ) (options, args) = parser.parse_args() if args: print 'the "orbited" command does not accept positional arguments. type "orbited -h" for options.' sys.exit(1) if options.version: print "Orbited version: %s" % (version,) sys.exit(0) if options.quickstart: config.map["[listen]"].append("http://:8000") config.map["[listen]"].append("stomp://:61613") config.map["[access]"][("localhost", 61613)] = ["*"] print "Quickstarting Orbited" else: # load configuration from configuration # file and from command line arguments. config.setup(options=options) logging.setup(config.map) # we can now safely get loggers. global logger logger = logging.get_logger("orbited.start") # NB: we need to install the reactor before using twisted. reactor_name = config.map["[global]"].get("reactor") if reactor_name: install = _import("twisted.internet.%sreactor.install" % reactor_name) install() logger.info("using %s reactor" % reactor_name) ############ # This crude garbage corrects a bug in twisted # Orbited ticket: http://orbited.org/ticket/111 # Twisted ticket: http://twistedmatrix.com/trac/ticket/2447 import twisted.web.http twisted.web.http.HTTPChannel.setTimeout = lambda self, arg: None twisted.web.http.HTTPChannel.resetTimeout = lambda self: None ############ from twisted.internet import reactor from twisted.web import resource from twisted.web import server from twisted.web import static import orbited.system root = resource.Resource() static_files = static.File(os.path.join(os.path.dirname(__file__), "static")) root.putChild("static", static_files) root.putChild("system", orbited.system.SystemResource()) if config.map["[test]"]["stompdispatcher.enabled"] == "1": logger.info("stompdispatcher enabled") # static_files.putChild('orbited.swf', static.File(os.path.join(os.path.dirname(__file__), 'flash', 'orbited.swf'))) site = server.Site(root) _setup_protocols(root) _setup_static(root, config.map) start_listening(site, config.map, logger) # switch uid and gid to configured user and group. if os.name == "posix" and os.getuid() == 0: user = config.map["[global]"].get("user") group = config.map["[global]"].get("group") if user: import pwd import grp try: pw = pwd.getpwnam(user) uid = pw.pw_uid if group: gr = grp.getgrnam(group) gid = gr.gr_gid else: gid = pw.pw_gid gr = grp.getgrgid(gid) group = gr.gr_name except Exception, e: logger.error("Aborting; Unknown user or group: %s" % e) sys.exit(1) logger.info("switching to user %s (uid=%d) and group %s (gid=%d)" % (user, uid, group, gid)) os.setgid(gid) os.setuid(uid) else: logger.error("Aborting; You must define a user (and optionally a group) in the configuration file.") sys.exit(1)
from orbited.util import format_block from orbited import json from twisted.internet import reactor from base import CometTransport from orbited import logging logger = logging.get_logger('orbited.transports.sse.SSETransport') class SSETransport(CometTransport): HEARTBEAT_INTERVAL = 30 def opened(self): self.request.setHeader('content-type', 'application/x-dom-event-stream') self.request.setHeader('cache-control', 'no-cache, must-revalidate') def write(self, packets): payload = json.encode(packets) data = ( 'Event: payload\n' + '\n'.join(['data: %s' % line for line in payload.splitlines()]) + '\n\n' ) self.request.write(data) def writeHeartbeat(self): logger.debug('writeHeartbeat'); self.request.write('Event: heartbeat\n\n')