comparison idavoll/pubsub.py @ 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 e01bbbfa8a46
children 256dcda26752
comparison
equal deleted inserted replaced
22:9b610962d045 23:884268687229
1 from twisted.protocols.jabber import component,jid 1 from twisted.protocols.jabber import component,jid
2 from twisted.xish import utility, domish 2 from twisted.xish import utility, domish
3 from twisted.python import components 3 from twisted.python import components
4 from twisted.internet import defer
5
4 import backend 6 import backend
5 import xmpp_error 7 import xmpp_error
6 8
7 NS_COMPONENT = 'jabber:component:accept' 9 NS_COMPONENT = 'jabber:component:accept'
8 NS_PUBSUB = 'http://jabber.org/protocol/pubsub' 10 NS_PUBSUB = 'http://jabber.org/protocol/pubsub'
20 PUBSUB_OPTIONS_GET = PUBSUB_GET + '/options' 22 PUBSUB_OPTIONS_GET = PUBSUB_GET + '/options'
21 PUBSUB_OPTIONS_SET = PUBSUB_SET + '/options' 23 PUBSUB_OPTIONS_SET = PUBSUB_SET + '/options'
22 PUBSUB_CONFIGURE_GET = PUBSUB_GET + '/configure' 24 PUBSUB_CONFIGURE_GET = PUBSUB_GET + '/configure'
23 PUBSUB_CONFIGURE_SET = PUBSUB_SET + '/configure' 25 PUBSUB_CONFIGURE_SET = PUBSUB_SET + '/configure'
24 26
27 class PubSubError(Exception):
28 pubsub_error = None
29 msg = ''
30
31 class NotImplemented(PubSubError):
32 pass
33
34 class OptionsUnavailable(PubSubError):
35 pubsub_error = 'subscription-options-unavailable'
36
37 class SubscriptionOptionsUnavailable(PubSubError):
38 pubsub_error = 'subscription-options-unavailable'
39
40 class NodeNotConfigurable(PubSubError):
41 pubsub_error = 'node-not-configurable'
42
43 class CreateNodeNotConfigurable(PubSubError):
44 pubsub_error = 'node-not-configurable'
45
25 error_map = { 46 error_map = {
26 backend.NotAuthorized: 'not-authorized', 47 backend.NotAuthorized: 'not-authorized',
27 backend.NodeNotFound: 'item-not-found', 48 backend.NodeNotFound: 'item-not-found',
28 backend.NoPayloadAllowed: 'bad-request', 49 backend.NoPayloadAllowed: 'bad-request',
29 backend.PayloadExpected: 'bad-request', 50 backend.PayloadExpected: 'bad-request',
30 backend.NoInstantNodes: 'not-acceptable', 51 backend.NoInstantNodes: 'not-acceptable',
31 backend.NodeExists: 'conflict', 52 backend.NodeExists: 'conflict',
53 NotImplemented: 'feature-not-implemented',
54 OptionsUnavailable: 'feature-not-implemented',
55 SubscriptionOptionsUnavailable: 'not-acceptable',
56 NodeNotConfigurable: 'feature-not-implemented',
57 CreateNodeNotConfigurable: 'not-acceptable',
32 } 58 }
33 59
34 class ComponentServiceFromBackend(component.Service, utility.EventDispatcher): 60 class ComponentServiceFromBackend(component.Service):
35 61
36 def __init__(self, backend): 62 def __init__(self, backend):
37 utility.EventDispatcher.__init__(self)
38 self.backend = backend 63 self.backend = backend
39 self.backend.pubsub_service = self 64 self.backend.pubsub_service = self
40 self.addObserver(PUBSUB_PUBLISH, self.onPublish) 65
41
42 # make sure subscribe and create are handled before resp. options and
43 # configure
44 self.addObserver(PUBSUB_SUBSCRIBE, self.onSubscribe, 0)
45 self.addObserver(PUBSUB_OPTIONS_SET, self.onOptionsSet, 1)
46 self.addObserver(PUBSUB_CREATE, self.onSubscribe, 0)
47 self.addObserver(PUBSUB_CONFIGURE_SET, self.onConfigureSet, 1)
48
49 self.addObserver(PUBSUB_OPTIONS_GET, self.onOptionsGet)
50 self.addObserver(PUBSUB_CONFIGURE_GET, self.onConfigureGet)
51 self.addObserver(PUBSUB_GET, self.notImplemented, -1)
52 self.addObserver(PUBSUB_SET, self.notImplemented, -1)
53
54 def componentConnected(self, xmlstream): 66 def componentConnected(self, xmlstream):
55 xmlstream.addObserver(PUBSUB_SET, self.onPubSub) 67 xmlstream.addObserver(PUBSUB_SET, self.onPubSub)
56 xmlstream.addObserver(PUBSUB_GET, self.onPubSub) 68 xmlstream.addObserver(PUBSUB_GET, self.onPubSub)
57 69
58 def getIdentities(self, node): 70 def getIdentities(self, node):
74 86
75 def error(self, failure, iq): 87 def error(self, failure, iq):
76 try: 88 try:
77 r = failure.trap(*error_map.keys()) 89 r = failure.trap(*error_map.keys())
78 xmpp_error.error_from_iq(iq, error_map[r], failure.value.msg) 90 xmpp_error.error_from_iq(iq, error_map[r], failure.value.msg)
91 if isinstance(failure.value, PubSubError) and \
92 failure.value.pubsub_error is not None:
93 iq.error.addElement((NS_PUBSUB_ERRORS,
94 failure.value.pubsub_error),
95 NS_PUBSUB_ERRORS)
79 return iq 96 return iq
80 except: 97 except:
81 xmpp_error.error_from_iq(iq, 'internal-server-error') 98 xmpp_error.error_from_iq(iq, 'internal-server-error')
82 self.send(iq) 99 self.send(iq)
83 raise 100 raise
86 iq.swapAttributeValues("to", "from") 103 iq.swapAttributeValues("to", "from")
87 iq["type"] = 'result' 104 iq["type"] = 'result'
88 iq.children = result or [] 105 iq.children = result or []
89 return iq 106 return iq
90 107
91 def notImplemented(self, iq):
92 self.send(xmpp_error.error_from_iq(iq, 'feature-not-implemented'))
93
94 def onPubSub(self, iq): 108 def onPubSub(self, iq):
95 self.dispatch(iq) 109 for elem in iq.pubsub.elements():
110 if not elem.hasAttribute('xmlns'):
111 action = elem.name
112 break
113
114 if not action:
115 return
116
117 try:
118 try:
119 handler = getattr(self, 'on%s%s' % (action.capitalize(),
120 iq["type"].capitalize()))
121 except KeyError:
122 raise NotImplemented
123 else:
124 d = handler(iq)
125 except:
126 d = defer.fail()
127
128 d.addCallback(self.success, iq)
129 d.addErrback(self.error, iq)
130 d.addCallback(self.send)
96 iq.handled = True 131 iq.handled = True
97 132
98 def onPublish(self, iq): 133 # action handlers
134
135 def onPublishSet(self, iq):
99 node = iq.pubsub.publish["node"] 136 node = iq.pubsub.publish["node"]
100 137
101 items = [] 138 items = []
102 for child in iq.pubsub.publish.children: 139 for child in iq.pubsub.publish.children:
103 if child.__class__ == domish.Element and child.name == 'item': 140 if child.__class__ == domish.Element and child.name == 'item':
104 items.append(child) 141 items.append(child)
105 142
106 print items 143 print items
107 144
108 d = self.backend.do_publish(node, jid.JID(iq["from"]).userhost(), items) 145 return self.backend.do_publish(node,
109 d.addCallback(self.success, iq) 146 jid.JID(iq["from"]).userhost(),
110 d.addErrback(self.error, iq) 147 items)
111 d.addCallback(self.send)
112 148
113 def onOptionsGet(self, iq): 149 def onOptionsGet(self, iq):
114 xmpp_error.error_from_iq(iq, 'feature-not-implemented') 150 raise OptionsUnavailable
115 iq.error.addElement((NS_PUBSUB_ERRORS, 'subscription-options-unavailable'), NS_PUBSUB_ERRORS)
116 self.send(iq)
117 151
118 def onOptionsSet(self, iq): 152 def onOptionsSet(self, iq):
119 if iq.pubsub.subscribe: 153 raise OptionsUnavailable
120 # this should be handled by the subscribe handler
121 return
122
123 xmpp_error.error_from_iq(iq, 'feature-not-implemented')
124 iq.error.addElement((NS_PUBSUB_ERRORS, 'subscription-options-unavailable'), NS_PUBSUB_ERRORS)
125 self.send(iq)
126 154
127 def onConfigureGet(self, iq): 155 def onConfigureGet(self, iq):
128 xmpp_error.error_from_iq(iq, 'feature-not-implemented') 156 raise NodeNotConfigurable
129 iq.error.addElement((NS_PUBSUB_ERRORS, 'node-not-configurable'), NS_PUBSUB_ERRORS)
130 self.send(iq)
131 157
132 def onConfigureSet(self, iq): 158 def onConfigureSet(self, iq):
133 if iq.pubsub.create: 159 raise NodeNotConfigurable
134 # this should be handled by the create handler 160
135 return 161 def onSubscribeSet(self, iq):
136
137 xmpp_error.error_from_iq(iq, 'feature-not-implemented')
138 iq.error.addElement((NS_PUBSUB_ERRORS, 'node-not-configurable'), NS_PUBSUB_ERRORS)
139 self.send(iq)
140
141 def onSubscribe(self, iq):
142 if iq.pubsub.options: 162 if iq.pubsub.options:
143 xmpp_error.error_from_iq(iq, 'not-acceptable') 163 raise SubscribeOptionsUnavailable
144 iq.error.addElement((NS_PUBSUB_ERRORS, 'subscription-options-unavailable'), NS_PUBSUB_ERRORS)
145 self.send(iq)
146 return
147 164
148 node_id = iq.pubsub.subscribe["node"] 165 node_id = iq.pubsub.subscribe["node"]
149 subscriber = jid.JID(iq.pubsub.subscribe["jid"]) 166 subscriber = jid.JID(iq.pubsub.subscribe["jid"])
150 requestor = jid.JID(iq["from"]).userhostJID() 167 requestor = jid.JID(iq["from"]).userhostJID()
151 d = self.backend.do_subscribe(node_id, subscriber, requestor) 168 d = self.backend.do_subscribe(node_id, subscriber, requestor)
161 entity["jid"] = result["jid"].full() 178 entity["jid"] = result["jid"].full()
162 entity["affiliation"] = result["affiliation"] 179 entity["affiliation"] = result["affiliation"]
163 entity["subscription"] = result["subscription"] 180 entity["subscription"] = result["subscription"]
164 return reply 181 return reply
165 182
183 def onCreateSet(self, iq):
184 if iq.pubsub.options:
185 raise CreateNodeNotConfigurable
186
187 node = iq.pubsub.create["node"]
188 owner = jid.JID(iq["from"]).userhostJID()
189
190 d = self.backend.create_node(node, owner)
191 d.addCallback(self.return_create_response, iq)
192 return d
193
194 def return_create_response(self, result, iq):
195 if iq.pubsub.create["node"] is None:
196 reply = domish.Element('pubsub', NS_PUBSUB)
197 entity = reply.addElement('create')
198 entity['node'] = result['node_id']
199 return reply
200
201 # other methods
202
166 def do_notification(self, list, node): 203 def do_notification(self, list, node):
167
168 for recipient, items in list.items(): 204 for recipient, items in list.items():
169 self.notify(node, items, recipient) 205 self.notify(node, items, recipient)
170 206
171 def notify(self, node, itemlist, recipient): 207 def notify(self, node, itemlist, recipient):
172 message = domish.Element((NS_COMPONENT, "message")) 208 message = domish.Element((NS_COMPONENT, "message"))
176 items = x.addElement("items") 212 items = x.addElement("items")
177 items["node"] = node 213 items["node"] = node
178 items.children.extend(itemlist) 214 items.children.extend(itemlist)
179 self.send(message) 215 self.send(message)
180 216
181 def onCreate(self, iq):
182 if iq.pubsub.options:
183 xmpp_error.error_from_iq(iq, 'not-acceptable')
184 iq.error.addElement((NS_PUBSUB_ERRORS, 'node-not-configurable'), NS_PUBSUB_ERRORS)
185 self.send(iq)
186 return
187
188 node = iq.pubsub.create["node"]
189 owner = jid.JID(iq["from"]).userhostJID()
190
191 try:
192 d = self.backend.create_node(node, owner)
193 d.addCallback(self.return_create_response, iq)
194 d.addCallback(self.succeed, iq)
195 d.addErrback(self.error, iq)
196 d.addCallback(self.send)
197 except:
198 pass
199
200 def return_create_response(self, result, iq):
201 if iq.pubsub.create["node"] is None:
202 reply = domish.Element('pubsub', NS_PUBSUB)
203 entity = reply.addElement('create')
204 entity['node'] = result['node_id']
205 return reply
206
207 components.registerAdapter(ComponentServiceFromBackend, backend.IBackendService, component.IService) 217 components.registerAdapter(ComponentServiceFromBackend, backend.IBackendService, component.IService)
208 218