comparison 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
comparison
equal deleted inserted replaced
205:e6b710bf2b24 206:274a45d2a5ab
64 64
65 if not entity: 65 if not entity:
66 raise XMPPURIParseError("Empty URI path component") 66 raise XMPPURIParseError("Empty URI path component")
67 67
68 try: 68 try:
69 jid = JID(entity) 69 service = JID(entity)
70 except Exception, e: 70 except Exception, e:
71 raise XMPPURIParseError("Invalid JID: %s" % e.message) 71 raise XMPPURIParseError("Invalid JID: %s" % e.message)
72 72
73 params = cgi.parse_qs(query) 73 params = cgi.parse_qs(query)
74 74
75 try: 75 try:
76 nodeIdentifier = params['node'][0] 76 nodeIdentifier = params['node'][0]
77 except (KeyError, ValueError): 77 except (KeyError, ValueError):
78 raise XMPPURIParseError("No node in query component of URI") 78 nodeIdentifier = ''
79 79
80 return jid, nodeIdentifier 80 return service, nodeIdentifier
81
82
83
84 def getXMPPURI(service, nodeIdentifier):
85 """
86 Construct an XMPP URI from a service JID and node identifier.
87 """
88 return "xmpp:%s?;node=%s" % (service.full(), nodeIdentifier or '')
81 89
82 90
83 91
84 class WebStreamParser(object): 92 class WebStreamParser(object):
85 def __init__(self): 93 def __init__(self):
132 """ 140 """
133 Respond to a POST request to create a new node. 141 Respond to a POST request to create a new node.
134 """ 142 """
135 143
136 def toResponse(nodeIdentifier): 144 def toResponse(nodeIdentifier):
137 uri = 'xmpp:%s?;node=%s' % (self.serviceJID.full(), nodeIdentifier) 145 uri = getXMPPURI(self.serviceJID, nodeIdentifier)
138 stream = simplejson.dumps({'uri': uri}) 146 stream = simplejson.dumps({'uri': uri})
139 return http.Response(responsecode.OK, stream=stream) 147 contentType = http_headers.MimeType.fromString(MIME_JSON)
140 148 return http.Response(responsecode.OK, stream=stream,
149 headers={'Content-Type': contentType})
141 d = self.backend.createNode(None, self.owner) 150 d = self.backend.createNode(None, self.owner)
142 d.addCallback(toResponse) 151 d.addCallback(toResponse)
143 return d 152 return d
144 153
145 154
235 """ 244 """
236 Respond to a POST request to create a new item. 245 Respond to a POST request to create a new item.
237 """ 246 """
238 247
239 def toResponse(nodeIdentifier): 248 def toResponse(nodeIdentifier):
240 uri = 'xmpp:%s?;node=%s' % (self.serviceJID.full(), nodeIdentifier) 249 uri = getXMPPURI(self.serviceJID, nodeIdentifier)
241 stream = simplejson.dumps({'uri': uri}) 250 stream = simplejson.dumps({'uri': uri})
242 return http.Response(responsecode.OK, stream=stream) 251 contentType = http_headers.MimeType.fromString(MIME_JSON)
252 return http.Response(responsecode.OK, stream=stream,
253 headers={'Content-Type': contentType})
243 254
244 def gotNode(nodeIdentifier, payload): 255 def gotNode(nodeIdentifier, payload):
245 item = Item(id='current', payload=payload) 256 item = Item(id='current', payload=payload)
246 d = self.backend.publish(nodeIdentifier, [item], self.owner) 257 d = self.backend.publish(nodeIdentifier, [item], self.owner)
247 d.addCallback(lambda _: nodeIdentifier) 258 d.addCallback(lambda _: nodeIdentifier)
284 self.service = service 295 self.service = service
285 296
286 297
287 def render(self, request): 298 def render(self, request):
288 def responseFromNodes(nodeIdentifiers): 299 def responseFromNodes(nodeIdentifiers):
289 return http.Response(responsecode.OK, 300 stream = simplejson.dumps(nodeIdentifiers)
290 stream=simplejson.dumps(nodeIdentifiers)) 301 contentType = http_headers.MimeType.fromString(MIME_JSON)
302 return http.Response(responsecode.OK, stream=stream,
303 headers={'Content-Type': contentType})
291 304
292 d = self.service.getNodes() 305 d = self.service.getNodes()
293 d.addCallback(responseFromNodes) 306 d.addCallback(responseFromNodes)
294 return d 307 return d
295 308
326 return atomEntries 339 return atomEntries
327 340
328 341
329 342
330 def constructFeed(service, nodeIdentifier, entries, title): 343 def constructFeed(service, nodeIdentifier, entries, title):
331 nodeURI = 'xmpp:%s?;node=%s' % (service.full(), nodeIdentifier) 344 nodeURI = getXMPPURI(service, nodeIdentifier)
332 now = strftime("%Y-%m-%dT%H:%M:%SZ", gmtime()) 345 now = strftime("%Y-%m-%dT%H:%M:%SZ", gmtime())
333 346
334 # Collect the received entries in a feed 347 # Collect the received entries in a feed
335 feed = domish.Element((NS_ATOM, 'feed')) 348 feed = domish.Element((NS_ATOM, 'feed'))
336 feed.addElement('title', content=title) 349 feed.addElement('title', content=title)
426 """ 439 """
427 Fire up HTTP client to do callback 440 Fire up HTTP client to do callback
428 """ 441 """
429 442
430 atomEntries = extractAtomEntries(event.items) 443 atomEntries = extractAtomEntries(event.items)
444 service = event.sender
445 nodeIdentifier = event.nodeIdentifier
446 headers = event.headers
431 447
432 # Don't notify if there are no atom entries 448 # Don't notify if there are no atom entries
433 if not atomEntries: 449 if not atomEntries:
434 return 450 return
435 451
436 if len(atomEntries) == 1: 452 if len(atomEntries) == 1:
437 contentType = 'application/atom+xml;type=entry' 453 contentType = 'application/atom+xml;type=entry'
438 payload = atomEntries[0] 454 payload = atomEntries[0]
439 else: 455 else:
440 contentType = 'application/atom+xml;type=feed' 456 contentType = 'application/atom+xml;type=feed'
441 payload = constructFeed(event.sender, event.nodeIdentifier, 457 payload = constructFeed(service, nodeIdentifier, atomEntries,
442 atomEntries,
443 title='Received item collection') 458 title='Received item collection')
444 459
445 self.callCallbacks(event.sender, event.nodeIdentifier, payload, 460 self.callCallbacks(service, nodeIdentifier, payload, contentType)
446 contentType) 461
462 if 'Collection' in headers:
463 for collection in headers['Collection']:
464 nodeIdentifier = collection or ''
465 self.callCallbacks(service, nodeIdentifier, payload,
466 contentType)
447 467
448 468
449 def deleteReceived(self, event): 469 def deleteReceived(self, event):
450 """ 470 """
451 Fire up HTTP client to do callback 471 Fire up HTTP client to do callback
452 """ 472 """
453 473
454 self.callCallbacks(event.sender, event.nodeIdentifier, 474 service = event.sender
455 eventType='DELETED') 475 nodeIdentifier = event.nodeIdentifier
476 self.callCallbacks(service, nodeIdentifier, eventType='DELETED')
456 477
457 478
458 def _postTo(self, callbacks, service, nodeIdentifier, 479 def _postTo(self, callbacks, service, nodeIdentifier,
459 payload=None, contentType=None, eventType=None): 480 payload=None, contentType=None, eventType=None):
460 481
461 if not callbacks: 482 if not callbacks:
462 return 483 return
463 484
464 postdata = None 485 postdata = None
465 nodeURI = 'xmpp:%s?;node=%s' % (service.full(), nodeIdentifier) 486 nodeURI = getXMPPURI(service, nodeIdentifier)
466 headers = {'Referer': nodeURI.encode('utf-8'), 487 headers = {'Referer': nodeURI.encode('utf-8'),
467 'PubSub-Service': service.full().encode('utf-8')} 488 'PubSub-Service': service.full().encode('utf-8')}
468 489
469 if payload: 490 if payload:
470 postdata = payload.toXml().encode('utf-8') 491 postdata = payload.toXml().encode('utf-8')
489 payload=None, contentType=None, eventType=None): 510 payload=None, contentType=None, eventType=None):
490 511
491 def eb(failure): 512 def eb(failure):
492 failure.trap(error.NoCallbacks) 513 failure.trap(error.NoCallbacks)
493 514
494 # No callbacks were registered for this node. Unsubscribe. 515 # No callbacks were registered for this node. Unsubscribe?
495 d = self.unsubscribe(service, nodeIdentifier, self.jid)
496 return d
497 516
498 d = self.storage.getCallbacks(service, nodeIdentifier) 517 d = self.storage.getCallbacks(service, nodeIdentifier)
499 d.addCallback(self._postTo, service, nodeIdentifier, payload, 518 d.addCallback(self._postTo, service, nodeIdentifier, payload,
500 contentType, eventType) 519 contentType, eventType)
501 d.addErrback(eb) 520 d.addErrback(eb)
522 errorMap = { 541 errorMap = {
523 error.NodeNotFound: 542 error.NodeNotFound:
524 (responsecode.FORBIDDEN, "Node not found"), 543 (responsecode.FORBIDDEN, "Node not found"),
525 error.NotSubscribed: 544 error.NotSubscribed:
526 (responsecode.FORBIDDEN, "No such subscription found"), 545 (responsecode.FORBIDDEN, "No such subscription found"),
546 error.SubscriptionExists:
547 (responsecode.FORBIDDEN, "Subscription already exists"),
527 } 548 }
528 549
529 def __init__(self, service): 550 def __init__(self, service):
530 self.service = service 551 self.service = service
531 self.params = None 552 self.params = None
732 753
733 def callback(self, data, headers): 754 def callback(self, data, headers):
734 pass 755 pass
735 756
736 757
758 def ping(self):
759 f = getPageWithFactory(self._makeURI(''),
760 method='HEAD',
761 agent=self.agent)
762 return f.deferred
763
764
737 def create(self): 765 def create(self):
738 f = getPageWithFactory(self._makeURI('create'), 766 f = getPageWithFactory(self._makeURI('create'),
739 method='POST', 767 method='POST',
740 agent=self.agent) 768 agent=self.agent)
741 return f.deferred.addCallback(simplejson.loads) 769 return f.deferred.addCallback(simplejson.loads)