sontek avatar sontek committed 51c8876

support for xhr-polling

Comments (0)

Files changed (2)

socketio/packet.py

 socketio_packet_attributes = ['type', 'name', 'data', 'endpoint', 'args',
                               'ackId', 'reason', 'advice', 'qs', 'id']
 
+FRAME_SEPARATOR = u'\ufffd'
+
+def decode_frames(data):
+    """Decode socket.io encoded messages. Returns list of packets.
+
+    `data`
+        encoded messages
+
+    """
+    # Single message - nothing to decode here
+    assert isinstance(data, unicode), 'frame is not unicode'
+
+    if not data.startswith(FRAME_SEPARATOR):
+        return [data]
+
+    # Multiple messages
+    idx = 0
+    packets = []
+
+    while data[idx:idx + 1] == FRAME_SEPARATOR:
+        idx += 1
+
+        # Grab message length
+        len_start = idx
+        idx = data.find(FRAME_SEPARATOR, idx)
+        msg_len = int(data[len_start:idx])
+        idx += 1
+
+        # Grab message
+        msg_data = data[idx:idx + msg_len]
+        idx += msg_len
+
+        packets.append(msg_data)
+
+    return packets
+
+def encode_frames(packets):
+    """Encode list of packets. Expects packets in unicode
+
+    `packets`
+        List of packets to encode
+    """
+    # No packets - return empty string
+    if not packets:
+        return ''
+
+    # Exactly one packet - don't do any frame encoding
+    if len(packets) == 1:
+        return packets[0].encode('utf-8')
+
+    # Multiple packets
+    frames = u''.join(u'%s%d%s%s' % (FRAME_SEPARATOR, len(p),
+                                     FRAME_SEPARATOR, p)
+                      for p in packets)
+
+    return frames.encode('utf-8')
+
 
 def encode(data):
     """
                 decoded_msg['reason'] = REASONS_VALUES[int(data)]
             else:
                 decoded_msg['reason'] = ''
-            
     elif msg_type == "8": # noop
         return None
     else:

socketio/virtsocket.py

 from gevent.event import Event
 
 from socketio import packet
+from packet import decode_frames
 
 def default_error_handler(socket, error_name, error_message, endpoint, msg_id,
                           quiet):
         map.
         """
         for ns_name, ns in self.active_ns.iteritems():
-            ns.disconnect()
+            if hasattr(ns, 'disconnect'):
+                ns.disconnect()
         # TODO: Find a better way to remove the Namespaces from the ``active_ns``
         #       zone.  Have the Ns.disconnect() call remove itself from the
         #       underlying socket ?
     def send_packet(self, pkt):
         """Low-level interface to queue a packet on the wire (encoded as wire
         protocol"""
+        #TODO: Might need to encode_frames here to stack multiple messages 
+        # for xhr polling?
         self.put_client_msg(packet.encode(pkt))
 
     def spawn(self, fn, *args, **kwargs):
 
         while True:
             rawdata = self.get_server_msg()
+            frames = decode_frames(rawdata.decode('utf-8'))
 
-            if rawdata:
-                try:
-                    pkt = packet.decode(rawdata)
-                except (ValueError, KeyError, Exception), e:
-                    self.error('invalid_packet', "There was a decoding error when dealing with packet with event: %s (%s)" % (rawdata[:15], e))
-                    continue
+            for frame in frames:
+                if frame:
+                    try:
+                        pkt = packet.decode(frame)
+                    except (ValueError, KeyError, Exception), e:
+                        self.error('invalid_packet', "There was a decoding error when dealing with packet with event: %s (%s)" % (frame[:15], e))
+                        continue
 
-                if pkt['type'] == 'heartbeat':
-                    # This is already dealth with in put_server_msg() when
-                    # any incoming raw data arrives.
-                    continue
+                    if pkt['type'] == 'heartbeat':
+                        # This is already dealth with in put_server_msg() when
+                        # any incoming raw data arrives.
+                        continue
 
-                endpoint = pkt['endpoint']
+                    endpoint = pkt['endpoint']
 
-                if endpoint not in self.namespaces:
-                    self.error("no_such_namespace", "The endpoint you tried to connect to doesn't exist: %s" % endpoint, endpoint=endpoint)
-                    continue
-                elif endpoint in self.active_ns:
-                    pkt_ns = self.active_ns[endpoint]
-                else:
-                    new_ns_class = self.namespaces[endpoint]
-                    pkt_ns = new_ns_class(self.environ, endpoint,
-                                               request=self.request)
-                    self.active_ns[endpoint] = pkt_ns
+                    if endpoint not in self.namespaces:
+                        self.error("no_such_namespace", "The endpoint you tried to connect to doesn't exist: %s" % endpoint, endpoint=endpoint)
+                        continue
+                    elif endpoint in self.active_ns:
+                        pkt_ns = self.active_ns[endpoint]
+                    else:
+                        new_ns_class = self.namespaces[endpoint]
+                        pkt_ns = new_ns_class(self.environ, endpoint,
+                                                request=self.request)
+                        self.active_ns[endpoint] = pkt_ns
 
-                pkt_ns.process_packet(pkt)
+                    pkt_ns.process_packet(pkt)
 
             if not self.connected:
                 self.kill() # ?? what,s the best clean-up when its not a
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.