Mercurial > libervia-pubsub
comparison idavoll/backend.py @ 222:698af5d720ad
Reshape Idavoll as a PubSubResource.
PubSubResource is Wokkel's newer interface for building (parts of) XMPP
publish-subscribe services and replaces the old interface of PubSubService. It
is more flexible for adding new protocol, allows for node-as-code (providing a
specific backend per node), and permits accepting requests for different
entities (virtual hosts or PEP-like settings).
This moves over the current backend to use the new interface, so new code for
previously unsupported protocol can be added down the line.
author | Ralph Meijer <ralphm@ik.nu> |
---|---|
date | Sat, 16 Oct 2010 21:03:38 +0200 |
parents | 53d2c0019458 |
children | 0eafdced5f24 |
comparison
equal
deleted
inserted
replaced
221:a430976f2977 | 222:698af5d720ad |
---|---|
19 | 19 |
20 from twisted.application import service | 20 from twisted.application import service |
21 from twisted.python import components, log | 21 from twisted.python import components, log |
22 from twisted.internet import defer, reactor | 22 from twisted.internet import defer, reactor |
23 from twisted.words.protocols.jabber.error import StanzaError | 23 from twisted.words.protocols.jabber.error import StanzaError |
24 from twisted.words.xish import domish, utility | 24 from twisted.words.xish import utility |
25 | 25 |
26 from wokkel.iwokkel import IDisco, IPubSubService | 26 from wokkel import disco |
27 from wokkel.pubsub import PubSubService, PubSubError | 27 from wokkel.iwokkel import IPubSubResource |
28 from wokkel.pubsub import PubSubResource, PubSubError | |
28 | 29 |
29 from idavoll import error, iidavoll | 30 from idavoll import error, iidavoll |
30 from idavoll.iidavoll import IBackendService, ILeafNode | 31 from idavoll.iidavoll import IBackendService, ILeafNode |
31 | 32 |
32 def _getAffiliation(node, entity): | 33 def _getAffiliation(node, entity): |
472 for d in dl: | 473 for d in dl: |
473 d.callback(None) | 474 d.callback(None) |
474 | 475 |
475 | 476 |
476 | 477 |
477 class PubSubServiceFromBackend(PubSubService): | 478 class PubSubResourceFromBackend(PubSubResource): |
478 """ | 479 """ |
479 Adapts a backend to an xmpp publish-subscribe service. | 480 Adapts a backend to an xmpp publish-subscribe service. |
480 """ | 481 """ |
481 | 482 |
482 implements(IDisco) | 483 features = [ |
484 "config-node", | |
485 "create-nodes", | |
486 "delete-any", | |
487 "delete-nodes", | |
488 "item-ids", | |
489 "meta-data", | |
490 "publish", | |
491 "purge-nodes", | |
492 "retract-items", | |
493 "retrieve-affiliations", | |
494 "retrieve-default", | |
495 "retrieve-items", | |
496 "retrieve-subscriptions", | |
497 "subscribe", | |
498 ] | |
499 | |
500 discoIdentity = disco.DiscoIdentity('pubsub', | |
501 'service', | |
502 'Idavoll publish-subscribe service') | |
503 | |
504 pubsubService = None | |
483 | 505 |
484 _errorMap = { | 506 _errorMap = { |
485 error.NodeNotFound: ('item-not-found', None, None), | 507 error.NodeNotFound: ('item-not-found', None, None), |
486 error.NodeExists: ('conflict', None, None), | 508 error.NodeExists: ('conflict', None, None), |
487 error.Forbidden: ('forbidden', None, None), | 509 error.Forbidden: ('forbidden', None, None), |
504 'unsupported', | 526 'unsupported', |
505 'publish'), | 527 'publish'), |
506 } | 528 } |
507 | 529 |
508 def __init__(self, backend): | 530 def __init__(self, backend): |
509 PubSubService.__init__(self) | 531 PubSubResource.__init__(self) |
510 | 532 |
511 self.backend = backend | 533 self.backend = backend |
512 self.hideNodes = False | 534 self.hideNodes = False |
513 | 535 |
514 self.pubSubFeatures = self._getPubSubFeatures() | |
515 | |
516 self.backend.registerNotifier(self._notify) | 536 self.backend.registerNotifier(self._notify) |
517 self.backend.registerPreDelete(self._preDelete) | 537 self.backend.registerPreDelete(self._preDelete) |
518 | 538 |
519 | |
520 def _getPubSubFeatures(self): | |
521 features = [ | |
522 "config-node", | |
523 "create-nodes", | |
524 "delete-any", | |
525 "delete-nodes", | |
526 "item-ids", | |
527 "meta-data", | |
528 "publish", | |
529 "purge-nodes", | |
530 "retract-items", | |
531 "retrieve-affiliations", | |
532 "retrieve-default", | |
533 "retrieve-items", | |
534 "retrieve-subscriptions", | |
535 "subscribe", | |
536 ] | |
537 | |
538 if self.backend.supportsInstantNodes(): | 539 if self.backend.supportsInstantNodes(): |
539 features.append("instant-nodes") | 540 self.features.append("instant-nodes") |
540 | 541 |
541 if self.backend.supportsOutcastAffiliation(): | 542 if self.backend.supportsOutcastAffiliation(): |
542 features.append("outcast-affiliation") | 543 self.features.append("outcast-affiliation") |
543 | 544 |
544 if self.backend.supportsPersistentItems(): | 545 if self.backend.supportsPersistentItems(): |
545 features.append("persistent-items") | 546 self.features.append("persistent-items") |
546 | 547 |
547 if self.backend.supportsPublisherAffiliation(): | 548 if self.backend.supportsPublisherAffiliation(): |
548 features.append("publisher-affiliation") | 549 self.features.append("publisher-affiliation") |
549 | |
550 return features | |
551 | 550 |
552 | 551 |
553 def _notify(self, data): | 552 def _notify(self, data): |
554 items = data['items'] | 553 items = data['items'] |
555 nodeIdentifier = data['nodeIdentifier'] | 554 nodeIdentifier = data['nodeIdentifier'] |
557 d = self.backend.getNotifications(nodeIdentifier, items) | 556 d = self.backend.getNotifications(nodeIdentifier, items) |
558 else: | 557 else: |
559 subscription = data['subscription'] | 558 subscription = data['subscription'] |
560 d = defer.succeed([(subscription.subscriber, [subscription], | 559 d = defer.succeed([(subscription.subscriber, [subscription], |
561 items)]) | 560 items)]) |
562 d.addCallback(lambda notifications: self.notifyPublish(self.serviceJID, | 561 d.addCallback(lambda notifications: self.pubsubService.notifyPublish( |
563 nodeIdentifier, | 562 self.serviceJID, |
564 notifications)) | 563 nodeIdentifier, |
564 notifications)) | |
565 | 565 |
566 | 566 |
567 def _preDelete(self, data): | 567 def _preDelete(self, data): |
568 nodeIdentifier = data['nodeIdentifier'] | 568 nodeIdentifier = data['nodeIdentifier'] |
569 redirectURI = data.get('redirectURI', None) | 569 redirectURI = data.get('redirectURI', None) |
570 d = self.backend.getSubscribers(nodeIdentifier) | 570 d = self.backend.getSubscribers(nodeIdentifier) |
571 d.addCallback(lambda subscribers: self.notifyDelete(self.serviceJID, | 571 d.addCallback(lambda subscribers: self.pubsubService.notifyDelete( |
572 nodeIdentifier, | 572 self.serviceJID, |
573 subscribers, | 573 nodeIdentifier, |
574 redirectURI)) | 574 subscribers, |
575 redirectURI)) | |
575 return d | 576 return d |
576 | 577 |
577 | 578 |
578 def _mapErrors(self, failure): | 579 def _mapErrors(self, failure): |
579 e = failure.trap(*self._errorMap.keys()) | 580 e = failure.trap(*self._errorMap.keys()) |
587 exc = StanzaError(condition, text=msg) | 588 exc = StanzaError(condition, text=msg) |
588 | 589 |
589 raise exc | 590 raise exc |
590 | 591 |
591 | 592 |
592 def getNodeInfo(self, requestor, service, nodeIdentifier): | 593 def getInfo(self, requestor, service, nodeIdentifier): |
593 info = {} | 594 info = {} |
594 | 595 |
595 def saveType(result): | 596 def saveType(result): |
596 info['type'] = result | 597 info['type'] = result |
597 return nodeIdentifier | 598 return nodeIdentifier |
612 d.addErrback(trapNotFound) | 613 d.addErrback(trapNotFound) |
613 d.addErrback(self._mapErrors) | 614 d.addErrback(self._mapErrors) |
614 return d | 615 return d |
615 | 616 |
616 | 617 |
617 def getNodes(self, requestor, service): | 618 def getNodes(self, requestor, service, nodeIdentifier): |
618 if service.resource: | 619 if service.resource: |
619 return defer.succeed([]) | 620 return defer.succeed([]) |
620 d = self.backend.getNodes() | 621 d = self.backend.getNodes() |
621 return d.addErrback(self._mapErrors) | 622 return d.addErrback(self._mapErrors) |
622 | 623 |
623 | 624 |
624 def publish(self, requestor, service, nodeIdentifier, items): | |
625 d = self.backend.publish(nodeIdentifier, items, requestor) | |
626 return d.addErrback(self._mapErrors) | |
627 | |
628 | |
629 def subscribe(self, requestor, service, nodeIdentifier, subscriber): | |
630 d = self.backend.subscribe(nodeIdentifier, subscriber, requestor) | |
631 return d.addErrback(self._mapErrors) | |
632 | |
633 | |
634 def unsubscribe(self, requestor, service, nodeIdentifier, subscriber): | |
635 d = self.backend.unsubscribe(nodeIdentifier, subscriber, requestor) | |
636 return d.addErrback(self._mapErrors) | |
637 | |
638 | |
639 def subscriptions(self, requestor, service): | |
640 d = self.backend.getSubscriptions(requestor) | |
641 return d.addErrback(self._mapErrors) | |
642 | |
643 | |
644 def affiliations(self, requestor, service): | |
645 d = self.backend.getAffiliations(requestor) | |
646 return d.addErrback(self._mapErrors) | |
647 | |
648 | |
649 def create(self, requestor, service, nodeIdentifier): | |
650 d = self.backend.createNode(nodeIdentifier, requestor) | |
651 return d.addErrback(self._mapErrors) | |
652 | |
653 | |
654 def getConfigurationOptions(self): | 625 def getConfigurationOptions(self): |
655 return self.backend.nodeOptions | 626 return self.backend.nodeOptions |
656 | 627 |
657 | 628 |
658 def getDefaultConfiguration(self, requestor, service, nodeType): | 629 def publish(self, request): |
659 d = self.backend.getDefaultConfiguration(nodeType) | 630 d = self.backend.publish(request.nodeIdentifier, |
660 return d.addErrback(self._mapErrors) | 631 request.items, |
661 | 632 request.sender) |
662 | 633 return d.addErrback(self._mapErrors) |
663 def getConfiguration(self, requestor, service, nodeIdentifier): | 634 |
664 d = self.backend.getNodeConfiguration(nodeIdentifier) | 635 |
665 return d.addErrback(self._mapErrors) | 636 def subscribe(self, request): |
666 | 637 d = self.backend.subscribe(request.nodeIdentifier, |
667 | 638 request.subscriber, |
668 def setConfiguration(self, requestor, service, nodeIdentifier, options): | 639 request.sender) |
669 d = self.backend.setNodeConfiguration(nodeIdentifier, options, | 640 return d.addErrback(self._mapErrors) |
670 requestor) | 641 |
671 return d.addErrback(self._mapErrors) | 642 |
672 | 643 def unsubscribe(self, request): |
673 | 644 d = self.backend.unsubscribe(request.nodeIdentifier, |
674 def items(self, requestor, service, nodeIdentifier, maxItems, | 645 request.subscriber, |
675 itemIdentifiers): | 646 request.sender) |
676 d = self.backend.getItems(nodeIdentifier, requestor, maxItems, | 647 return d.addErrback(self._mapErrors) |
677 itemIdentifiers) | 648 |
678 return d.addErrback(self._mapErrors) | 649 |
679 | 650 def subscriptions(self, request): |
680 | 651 d = self.backend.getSubscriptions(request.sender) |
681 def retract(self, requestor, service, nodeIdentifier, itemIdentifiers): | 652 return d.addErrback(self._mapErrors) |
682 d = self.backend.retractItem(nodeIdentifier, itemIdentifiers, | 653 |
683 requestor) | 654 |
684 return d.addErrback(self._mapErrors) | 655 def affiliations(self, request): |
685 | 656 d = self.backend.getAffiliations(request.sender) |
686 | 657 return d.addErrback(self._mapErrors) |
687 def purge(self, requestor, service, nodeIdentifier): | 658 |
688 d = self.backend.purgeNode(nodeIdentifier, requestor) | 659 |
689 return d.addErrback(self._mapErrors) | 660 def create(self, request): |
690 | 661 d = self.backend.createNode(request.nodeIdentifier, |
691 | 662 request.sender) |
692 def delete(self, requestor, service, nodeIdentifier): | 663 return d.addErrback(self._mapErrors) |
693 d = self.backend.deleteNode(nodeIdentifier, requestor) | 664 |
694 return d.addErrback(self._mapErrors) | 665 |
695 | 666 def default(self, request): |
696 components.registerAdapter(PubSubServiceFromBackend, | 667 d = self.backend.getDefaultConfiguration(request.nodeType) |
668 return d.addErrback(self._mapErrors) | |
669 | |
670 | |
671 def configureGet(self, request): | |
672 d = self.backend.getNodeConfiguration(request.nodeIdentifier) | |
673 return d.addErrback(self._mapErrors) | |
674 | |
675 | |
676 def configureSet(self, request): | |
677 d = self.backend.setNodeConfiguration(request.nodeIdentifier, | |
678 request.options, | |
679 request.sender) | |
680 return d.addErrback(self._mapErrors) | |
681 | |
682 | |
683 def items(self, request): | |
684 d = self.backend.getItems(request.nodeIdentifier, | |
685 request.sender, | |
686 request.maxItems, | |
687 request.itemIdentifiers) | |
688 return d.addErrback(self._mapErrors) | |
689 | |
690 | |
691 def retract(self, request): | |
692 d = self.backend.retractItem(request.nodeIdentifier, | |
693 request.itemIdentifiers, | |
694 request.sender) | |
695 return d.addErrback(self._mapErrors) | |
696 | |
697 | |
698 def purge(self, request): | |
699 d = self.backend.purgeNode(request.nodeIdentifier, | |
700 request.sender) | |
701 return d.addErrback(self._mapErrors) | |
702 | |
703 | |
704 def delete(self, request): | |
705 d = self.backend.deleteNode(request.nodeIdentifier, | |
706 request.sender) | |
707 return d.addErrback(self._mapErrors) | |
708 | |
709 components.registerAdapter(PubSubResourceFromBackend, | |
697 IBackendService, | 710 IBackendService, |
698 IPubSubService) | 711 IPubSubResource) |