diff idavoll/gateway.py @ 206:274a45d2a5ab

Implement root collection that includes all leaf nodes.
author Ralph Meijer <ralphm@ik.nu>
date Mon, 04 Aug 2008 13:47:10 +0000
parents b4bf0a5ce50d
children 7f3ffb7a1a9e
line wrap: on
line diff
--- a/idavoll/gateway.py	Mon Aug 04 07:10:45 2008 +0000
+++ b/idavoll/gateway.py	Mon Aug 04 13:47:10 2008 +0000
@@ -66,7 +66,7 @@
         raise XMPPURIParseError("Empty URI path component")
 
     try:
-        jid = JID(entity)
+        service = JID(entity)
     except Exception, e:
         raise XMPPURIParseError("Invalid JID: %s" % e.message)
 
@@ -75,9 +75,17 @@
     try:
         nodeIdentifier = params['node'][0]
     except (KeyError, ValueError):
-        raise XMPPURIParseError("No node in query component of URI")
+        nodeIdentifier = ''
+
+    return service, nodeIdentifier
+
+
 
-    return jid, nodeIdentifier
+def getXMPPURI(service, nodeIdentifier):
+    """
+    Construct an XMPP URI from a service JID and node identifier.
+    """
+    return "xmpp:%s?;node=%s" % (service.full(), nodeIdentifier or '')
 
 
 
@@ -134,10 +142,11 @@
         """
 
         def toResponse(nodeIdentifier):
-            uri = 'xmpp:%s?;node=%s' % (self.serviceJID.full(), nodeIdentifier)
+            uri = getXMPPURI(self.serviceJID, nodeIdentifier)
             stream = simplejson.dumps({'uri': uri})
-            return http.Response(responsecode.OK, stream=stream)
-
+            contentType = http_headers.MimeType.fromString(MIME_JSON)
+            return http.Response(responsecode.OK, stream=stream,
+                                 headers={'Content-Type': contentType})
         d = self.backend.createNode(None, self.owner)
         d.addCallback(toResponse)
         return d
@@ -237,9 +246,11 @@
         """
 
         def toResponse(nodeIdentifier):
-            uri = 'xmpp:%s?;node=%s' % (self.serviceJID.full(), nodeIdentifier)
+            uri = getXMPPURI(self.serviceJID, nodeIdentifier)
             stream = simplejson.dumps({'uri': uri})
-            return http.Response(responsecode.OK, stream=stream)
+            contentType = http_headers.MimeType.fromString(MIME_JSON)
+            return http.Response(responsecode.OK, stream=stream,
+                                 headers={'Content-Type': contentType})
 
         def gotNode(nodeIdentifier, payload):
             item = Item(id='current', payload=payload)
@@ -286,8 +297,10 @@
 
     def render(self, request):
         def responseFromNodes(nodeIdentifiers):
-            return http.Response(responsecode.OK,
-                                 stream=simplejson.dumps(nodeIdentifiers))
+            stream = simplejson.dumps(nodeIdentifiers)
+            contentType = http_headers.MimeType.fromString(MIME_JSON)
+            return http.Response(responsecode.OK, stream=stream,
+                                 headers={'Content-Type': contentType})
 
         d = self.service.getNodes()
         d.addCallback(responseFromNodes)
@@ -328,7 +341,7 @@
 
 
 def constructFeed(service, nodeIdentifier, entries, title):
-    nodeURI = 'xmpp:%s?;node=%s' % (service.full(), nodeIdentifier)
+    nodeURI = getXMPPURI(service, nodeIdentifier)
     now = strftime("%Y-%m-%dT%H:%M:%SZ", gmtime())
 
     # Collect the received entries in a feed
@@ -428,6 +441,9 @@
         """
 
         atomEntries = extractAtomEntries(event.items)
+        service = event.sender
+        nodeIdentifier = event.nodeIdentifier
+        headers = event.headers
 
         # Don't notify if there are no atom entries
         if not atomEntries:
@@ -438,12 +454,16 @@
             payload = atomEntries[0]
         else:
             contentType = 'application/atom+xml;type=feed'
-            payload = constructFeed(event.sender, event.nodeIdentifier,
-                                    atomEntries,
+            payload = constructFeed(service, nodeIdentifier, atomEntries,
                                     title='Received item collection')
 
-        self.callCallbacks(event.sender, event.nodeIdentifier, payload,
-                           contentType)
+        self.callCallbacks(service, nodeIdentifier, payload, contentType)
+
+        if 'Collection' in headers:
+            for collection in headers['Collection']:
+                nodeIdentifier = collection or ''
+                self.callCallbacks(service, nodeIdentifier, payload,
+                                   contentType)
 
 
     def deleteReceived(self, event):
@@ -451,8 +471,9 @@
         Fire up HTTP client to do callback
         """
 
-        self.callCallbacks(event.sender, event.nodeIdentifier,
-                           eventType='DELETED')
+        service = event.sender
+        nodeIdentifier = event.nodeIdentifier
+        self.callCallbacks(service, nodeIdentifier, eventType='DELETED')
 
 
     def _postTo(self, callbacks, service, nodeIdentifier,
@@ -462,7 +483,7 @@
             return
 
         postdata = None
-        nodeURI = 'xmpp:%s?;node=%s' % (service.full(), nodeIdentifier)
+        nodeURI = getXMPPURI(service, nodeIdentifier)
         headers = {'Referer': nodeURI.encode('utf-8'),
                    'PubSub-Service': service.full().encode('utf-8')}
 
@@ -491,9 +512,7 @@
         def eb(failure):
             failure.trap(error.NoCallbacks)
 
-            # No callbacks were registered for this node. Unsubscribe.
-            d = self.unsubscribe(service, nodeIdentifier, self.jid)
-            return d
+            # No callbacks were registered for this node. Unsubscribe?
 
         d = self.storage.getCallbacks(service, nodeIdentifier)
         d.addCallback(self._postTo, service, nodeIdentifier, payload,
@@ -524,6 +543,8 @@
                 (responsecode.FORBIDDEN, "Node not found"),
             error.NotSubscribed:
                 (responsecode.FORBIDDEN, "No such subscription found"),
+            error.SubscriptionExists:
+                (responsecode.FORBIDDEN, "Subscription already exists"),
     }
 
     def __init__(self, service):
@@ -734,6 +755,13 @@
         pass
 
 
+    def ping(self):
+        f = getPageWithFactory(self._makeURI(''),
+                               method='HEAD',
+                               agent=self.agent)
+        return f.deferred
+
+
     def create(self):
         f = getPageWithFactory(self._makeURI('create'),
                     method='POST',