changeset 23:884268687229

Simplify call chain by mapping incoming requests directly to method calls in pubsub.py, and providing a exception handler for all backend calls.
author Ralph Meijer <ralphm@ik.nu>
date Thu, 07 Oct 2004 15:57:05 +0000
parents 9b610962d045
children 4f3bbefc6fad
files idavoll/backend.py idavoll/pubsub.py
diffstat 2 files changed, 151 insertions(+), 155 deletions(-) [+]
line wrap: on
line diff
--- a/idavoll/backend.py	Wed Oct 06 21:07:37 2004 +0000
+++ b/idavoll/backend.py	Thu Oct 07 15:57:05 2004 +0000
@@ -72,82 +72,75 @@
 
 	def do_publish(self, node_id, publisher, items):
 		try:
-			try:
-				node = self.nodes[node_id]
-				persist_items = node.configuration.persist_items
-				deliver_payloads = node.configuration.deliver_payloads
-			except KeyError:
-				raise NodeNotFound
+			node = self.nodes[node_id]
+			persist_items = node.configuration.persist_items
+			deliver_payloads = node.configuration.deliver_payloads
+		except KeyError:
+			raise NodeNotFound
 
-			try:
-				if node.affiliations[publisher] not in ['owner', 'publisher']:
-					raise NotAuthorized
-			except KeyError:
-				raise NotAuthorized()
+		try:
+			if node.affiliations[publisher] not in ['owner', 'publisher']:
+				raise NotAuthorized
+		except KeyError:
+			raise NotAuthorized()
 
-			if items and not persist_items and not deliver_payloads:
-				raise NoPayloadAllowed
-			elif not items and (persist_items or deliver_payloads):
-				raise PayloadExpected
-
-			print "publish by %s to %s" % (publisher, node_id)
+		if items and not persist_items and not deliver_payloads:
+			raise NoPayloadAllowed
+		elif not items and (persist_items or deliver_payloads):
+			raise PayloadExpected
 
-			if persist_items or deliver_payloads:
-				for item in items:
-					if item["id"] is None:
-						item["id"] = 'random'	# FIXME
+		print "publish by %s to %s" % (publisher, node_id)
 
-			if persist_items:
-				self.storeItems(node_id, publisher, items)
+		if persist_items or deliver_payloads:
+			for item in items:
+				if item["id"] is None:
+					item["id"] = 'random'	# FIXME
+
+		if persist_items:
+			self.storeItems(node_id, publisher, items)
 
-			if items and not deliver_payloads:
-				for item in items:
-					item.children = []
+		if items and not deliver_payloads:
+			for item in items:
+				item.children = []
 
-			recipients = self.get_subscribers(node_id)
-			recipients.addCallback(self.magic_filter, node_id, items)
-			recipients.addCallback(self.pubsub_service.do_notification, node_id)
+		recipients = self.get_subscribers(node_id)
+		recipients.addCallback(self.magic_filter, node_id, items)
+		recipients.addCallback(self.pubsub_service.do_notification, node_id)
 
-			return defer.succeed(None)
-		except:
-			return defer.fail(failure.Failure())
+		return defer.succeed(None)
 
 	def do_subscribe(self, node_id, subscriber, requestor):
 		# expect subscriber and requestor to be a jid.JID 
 		try:
-			try:
-				node = self.nodes[node_id]
-			except KeyError:
-				raise NodeNotFound
+			node = self.nodes[node_id]
+		except KeyError:
+			raise NodeNotFound
 
-			affiliation = node.affiliations.get(requestor.full(), 'none')
+		affiliation = node.affiliations.get(requestor.full(), 'none')
 
-			if affiliation == 'banned':
-				raise NotAuthorized
+		if affiliation == 'banned':
+			raise NotAuthorized
 
-			print subscriber.full()
-			print subscriber.userhostJID().full()
-			print requestor.full()
-
-			if subscriber.userhostJID() != requestor:
-				raise NotAuthorized
+		print subscriber.full()
+		print subscriber.userhostJID().full()
+		print requestor.full()
 
-			try:
-				subscription = node.subscriptions[subscriber.full()]
-			except KeyError:
-				subscription = Subscription('subscribed')
-				node.subscriptions[subscriber.full()] = subscription
-
-			print node.subscriptions
+		if subscriber.userhostJID() != requestor:
+			raise NotAuthorized
 
-			return defer.succeed({
-					'affiliation': affiliation,
-					'node': node_id,
-					'jid': subscriber,
-					'subscription': subscription.state})
-		except:
-			return defer.fail(failure.Failure)
+		try:
+			subscription = node.subscriptions[subscriber.full()]
+		except KeyError:
+			subscription = Subscription('subscribed')
+			node.subscriptions[subscriber.full()] = subscription
 
+		print node.subscriptions
+
+		return defer.succeed({
+				'affiliation': affiliation,
+				'node': node_id,
+				'jid': subscriber,
+				'subscription': subscription.state})
 		
 	def magic_filter(self, subscribers, node_id, items):
 		list = {}
@@ -159,14 +152,9 @@
 	def get_subscribers(self, node_id):
 		d = defer.Deferred()
 		try:
-			result = self.nodes[node_id].subscriptions.keys()
+			return defer.succeed(self.nodes[node_id].subscriptions.keys())
 		except:
-			f = failure.Failure()
-			reactor.callLater(0, d.errback, f)
-		else:
-			reactor.callLater(0, d.callback, result)
-
-		return d
+			return defer.fail()
 
 	def storeItems(self, node_id, publisher, items):
 		for item in items:
@@ -174,19 +162,17 @@
 
 		print self.nodes[node_id].items
 
-	def create_node(node_id, owner):
+	def create_node(self, node_id, owner):
 		result = {}
 
-		try:
-			if not node_id:
-				raise NoInstantNodes
+		if not node_id:
+			raise NoInstantNodes
 
-			if node_id in self.nodes:
-				raise NodeExists
-			
-			self.nodes[node_id] = Node(node_id)
-			node.affiliations[owner.full()] = 'owner'
-			return defer.succeed({'node_id': node.id})
-		except:
-			return defer.fail(failure.Failure)
+		if node_id in self.nodes:
+			raise NodeExists
+	
+		node = Node(node_id)
+		node.affiliations[owner.full()] = 'owner'
+		self.nodes[node_id] = node
 
+		return defer.succeed({'node_id': node.id})
--- a/idavoll/pubsub.py	Wed Oct 06 21:07:37 2004 +0000
+++ b/idavoll/pubsub.py	Thu Oct 07 15:57:05 2004 +0000
@@ -1,6 +1,8 @@
 from twisted.protocols.jabber import component,jid
 from twisted.xish import utility, domish
 from twisted.python import components
+from twisted.internet import defer
+
 import backend
 import xmpp_error
 
@@ -22,6 +24,25 @@
 PUBSUB_CONFIGURE_GET = PUBSUB_GET + '/configure'
 PUBSUB_CONFIGURE_SET = PUBSUB_SET + '/configure'
 
+class PubSubError(Exception):
+	pubsub_error = None
+	msg = ''
+
+class NotImplemented(PubSubError):
+	pass
+
+class OptionsUnavailable(PubSubError):
+	pubsub_error = 'subscription-options-unavailable'
+
+class SubscriptionOptionsUnavailable(PubSubError):
+	pubsub_error = 'subscription-options-unavailable'
+
+class NodeNotConfigurable(PubSubError):
+	pubsub_error = 'node-not-configurable'
+
+class CreateNodeNotConfigurable(PubSubError):
+	pubsub_error = 'node-not-configurable'
+
 error_map = {
 	backend.NotAuthorized:			'not-authorized',
 	backend.NodeNotFound:			'item-not-found',
@@ -29,28 +50,19 @@
 	backend.PayloadExpected:		'bad-request',
 	backend.NoInstantNodes:			'not-acceptable',
 	backend.NodeExists:				'conflict',
+	NotImplemented:					'feature-not-implemented',
+	OptionsUnavailable:				'feature-not-implemented',
+	SubscriptionOptionsUnavailable:	'not-acceptable',
+	NodeNotConfigurable:			'feature-not-implemented',
+	CreateNodeNotConfigurable:		'not-acceptable',
 }
 
-class ComponentServiceFromBackend(component.Service, utility.EventDispatcher):
+class ComponentServiceFromBackend(component.Service):
 
 	def __init__(self, backend):
-		utility.EventDispatcher.__init__(self)
 		self.backend = backend
 		self.backend.pubsub_service = self
-		self.addObserver(PUBSUB_PUBLISH, self.onPublish)
-
-		# make sure subscribe and create are handled before resp. options and
-		# configure
-		self.addObserver(PUBSUB_SUBSCRIBE, self.onSubscribe, 0)
-		self.addObserver(PUBSUB_OPTIONS_SET, self.onOptionsSet, 1)
-		self.addObserver(PUBSUB_CREATE, self.onSubscribe, 0)
-		self.addObserver(PUBSUB_CONFIGURE_SET, self.onConfigureSet, 1)
-
-		self.addObserver(PUBSUB_OPTIONS_GET, self.onOptionsGet)
-		self.addObserver(PUBSUB_CONFIGURE_GET, self.onConfigureGet)
-		self.addObserver(PUBSUB_GET, self.notImplemented, -1)
-		self.addObserver(PUBSUB_SET, self.notImplemented, -1)
-
+		
 	def componentConnected(self, xmlstream):
 		xmlstream.addObserver(PUBSUB_SET, self.onPubSub)
 		xmlstream.addObserver(PUBSUB_GET, self.onPubSub)
@@ -76,6 +88,11 @@
 		try: 
 			r = failure.trap(*error_map.keys())
 			xmpp_error.error_from_iq(iq, error_map[r], failure.value.msg)
+			if isinstance(failure.value, PubSubError) and \
+			   failure.value.pubsub_error is not None:
+				iq.error.addElement((NS_PUBSUB_ERRORS,
+					                 failure.value.pubsub_error),
+									NS_PUBSUB_ERRORS)
 			return iq
 		except:
 			xmpp_error.error_from_iq(iq, 'internal-server-error')
@@ -88,14 +105,34 @@
 		iq.children = result or []
 		return iq
 
-	def notImplemented(self, iq):
-		self.send(xmpp_error.error_from_iq(iq, 'feature-not-implemented'))
+	def onPubSub(self, iq):
+		for elem in iq.pubsub.elements():
+			if not elem.hasAttribute('xmlns'):
+				action = elem.name
+				break
+
+		if not action:
+			return
 
-	def onPubSub(self, iq):
-		self.dispatch(iq)
+		try:
+			try:
+				handler = getattr(self, 'on%s%s' % (action.capitalize(),
+													iq["type"].capitalize()))
+			except KeyError:
+				raise NotImplemented
+			else:
+				d = handler(iq)
+		except:
+			d = defer.fail()
+				
+		d.addCallback(self.success, iq)
+		d.addErrback(self.error, iq)
+		d.addCallback(self.send)
 		iq.handled = True
 
-	def onPublish(self, iq):
+	# action handlers
+
+	def onPublishSet(self, iq):
 		node = iq.pubsub.publish["node"]
 
 		items = []
@@ -105,45 +142,25 @@
 
 		print items
 
-		d = self.backend.do_publish(node, jid.JID(iq["from"]).userhost(), items)
-		d.addCallback(self.success, iq)
-		d.addErrback(self.error, iq)
-		d.addCallback(self.send)
+		return self.backend.do_publish(node,
+				                       jid.JID(iq["from"]).userhost(),
+									   items)
 
 	def onOptionsGet(self, iq):
-		xmpp_error.error_from_iq(iq, 'feature-not-implemented')
-		iq.error.addElement((NS_PUBSUB_ERRORS, 'subscription-options-unavailable'), NS_PUBSUB_ERRORS)
-		self.send(iq)
+		raise OptionsUnavailable
 
 	def onOptionsSet(self, iq):
-		if iq.pubsub.subscribe:
-			# this should be handled by the subscribe handler
-			return
-
-		xmpp_error.error_from_iq(iq, 'feature-not-implemented')
-		iq.error.addElement((NS_PUBSUB_ERRORS, 'subscription-options-unavailable'), NS_PUBSUB_ERRORS)
-		self.send(iq)
+		raise OptionsUnavailable
 
 	def onConfigureGet(self, iq):
-		xmpp_error.error_from_iq(iq, 'feature-not-implemented')
-		iq.error.addElement((NS_PUBSUB_ERRORS, 'node-not-configurable'), NS_PUBSUB_ERRORS)
-		self.send(iq)
+		raise NodeNotConfigurable
 
 	def onConfigureSet(self, iq):
-		if iq.pubsub.create:
-			# this should be handled by the create handler
-			return
+		raise NodeNotConfigurable
 
-		xmpp_error.error_from_iq(iq, 'feature-not-implemented')
-		iq.error.addElement((NS_PUBSUB_ERRORS, 'node-not-configurable'), NS_PUBSUB_ERRORS)
-		self.send(iq)
-
-	def onSubscribe(self, iq):
+	def onSubscribeSet(self, iq):
 		if iq.pubsub.options:
-			xmpp_error.error_from_iq(iq, 'not-acceptable')
-			iq.error.addElement((NS_PUBSUB_ERRORS, 'subscription-options-unavailable'), NS_PUBSUB_ERRORS)
-			self.send(iq)
-			return
+			raise SubscribeOptionsUnavailable
 
 		node_id = iq.pubsub.subscribe["node"]
 		subscriber = jid.JID(iq.pubsub.subscribe["jid"])
@@ -163,8 +180,27 @@
 		entity["subscription"] = result["subscription"]
 		return reply
 
+	def onCreateSet(self, iq):
+		if iq.pubsub.options:
+			raise CreateNodeNotConfigurable
+
+		node = iq.pubsub.create["node"]
+		owner = jid.JID(iq["from"]).userhostJID()
+
+		d = self.backend.create_node(node, owner)
+		d.addCallback(self.return_create_response, iq)
+		return d
+
+	def return_create_response(self, result, iq):
+		if iq.pubsub.create["node"] is None:
+			reply = domish.Element('pubsub', NS_PUBSUB)
+			entity = reply.addElement('create')
+			entity['node'] = result['node_id']
+			return reply
+
+	# other methods
+
 	def do_notification(self, list, node):
-
 		for recipient, items in list.items():
 			self.notify(node, items, recipient)
 
@@ -178,31 +214,5 @@
 		items.children.extend(itemlist)
 		self.send(message)
 		
-	def onCreate(self, iq):
-		if iq.pubsub.options:
-			xmpp_error.error_from_iq(iq, 'not-acceptable')
-			iq.error.addElement((NS_PUBSUB_ERRORS, 'node-not-configurable'), NS_PUBSUB_ERRORS)
-			self.send(iq)
-			return
-
-		node = iq.pubsub.create["node"]
-		owner = jid.JID(iq["from"]).userhostJID()
-
-		try:
-			d = self.backend.create_node(node, owner)
-			d.addCallback(self.return_create_response, iq)
-			d.addCallback(self.succeed, iq)
-			d.addErrback(self.error, iq)
-			d.addCallback(self.send)
-		except:
-			pass
-
-	def return_create_response(self, result, iq):
-		if iq.pubsub.create["node"] is None:
-			reply = domish.Element('pubsub', NS_PUBSUB)
-			entity = reply.addElement('create')
-			entity['node'] = result['node_id']
-			return reply
-
 components.registerAdapter(ComponentServiceFromBackend, backend.IBackendService, component.IService)