Mercurial > libervia-pubsub
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) |