comparison idavoll/pubsub.py @ 31:fa866793075d

Split up implementation in several Services that match the division in the backend interfaces. Add appropriate adapter calls.
author Ralph Meijer <ralphm@ik.nu>
date Tue, 26 Oct 2004 16:29:44 +0000
parents 256dcda26752
children c9ddca3cce20
comparison
equal deleted inserted replaced
30:ff7c73b253bf 31:fa866793075d
23 PUBSUB_OPTIONS_SET = PUBSUB_SET + '/options' 23 PUBSUB_OPTIONS_SET = PUBSUB_SET + '/options'
24 PUBSUB_CONFIGURE_GET = PUBSUB_GET + '/configure' 24 PUBSUB_CONFIGURE_GET = PUBSUB_GET + '/configure'
25 PUBSUB_CONFIGURE_SET = PUBSUB_SET + '/configure' 25 PUBSUB_CONFIGURE_SET = PUBSUB_SET + '/configure'
26 26
27 class PubSubError(Exception): 27 class PubSubError(Exception):
28 pubsub_error = None 28 pubsub_error = None
29 msg = '' 29 msg = ''
30 30
31 class NotImplemented(PubSubError): 31 class NotImplemented(PubSubError):
32 pass 32 pass
33 33
34 class OptionsUnavailable(PubSubError): 34 class OptionsUnavailable(PubSubError):
35 pubsub_error = 'subscription-options-unavailable' 35 pubsub_error = 'subscription-options-unavailable'
36 36
37 class SubscriptionOptionsUnavailable(PubSubError): 37 class SubscriptionOptionsUnavailable(PubSubError):
38 pubsub_error = 'subscription-options-unavailable' 38 pubsub_error = 'subscription-options-unavailable'
39 39
40 class NodeNotConfigurable(PubSubError): 40 class NodeNotConfigurable(PubSubError):
41 pubsub_error = 'node-not-configurable' 41 pubsub_error = 'node-not-configurable'
42 42
43 class CreateNodeNotConfigurable(PubSubError): 43 class CreateNodeNotConfigurable(PubSubError):
44 pubsub_error = 'node-not-configurable' 44 pubsub_error = 'node-not-configurable'
45 45
46 error_map = { 46 error_map = {
47 backend.NotAuthorized: 'not-authorized', 47 backend.NotAuthorized: 'not-authorized',
48 backend.NodeNotFound: 'item-not-found', 48 backend.NodeNotFound: 'item-not-found',
49 backend.NoPayloadAllowed: 'bad-request', 49 backend.NoPayloadAllowed: 'bad-request',
50 backend.PayloadExpected: 'bad-request', 50 backend.PayloadExpected: 'bad-request',
51 backend.NoInstantNodes: 'not-acceptable', 51 backend.NoInstantNodes: 'not-acceptable',
52 backend.NodeExists: 'conflict', 52 backend.NodeExists: 'conflict',
53 NotImplemented: 'feature-not-implemented', 53 backend.NotImplemented: 'feature-not-implemented',
54 OptionsUnavailable: 'feature-not-implemented', 54 NotImplemented: 'feature-not-implemented',
55 SubscriptionOptionsUnavailable: 'not-acceptable', 55 OptionsUnavailable: 'feature-not-implemented',
56 NodeNotConfigurable: 'feature-not-implemented', 56 SubscriptionOptionsUnavailable: 'not-acceptable',
57 CreateNodeNotConfigurable: 'not-acceptable', 57 NodeNotConfigurable: 'feature-not-implemented',
58 CreateNodeNotConfigurable: 'not-acceptable',
58 } 59 }
59 60
60 class ComponentServiceFromBackend(component.Service): 61 class Service(component.Service):
61 62
62 def __init__(self, backend): 63 __implements__ = component.IService
63 self.backend = backend 64
64 self.backend.pubsub_service = self 65 def __init__(self, backend):
65 66 self.backend = backend
66 def componentConnected(self, xmlstream): 67
67 xmlstream.addObserver(PUBSUB_SET, self.onPubSub) 68 def componentConnected(self, xmlstream):
68 xmlstream.addObserver(PUBSUB_GET, self.onPubSub) 69 pass
69 70
70 def getIdentities(self, node): 71 def error(self, failure, iq):
71 results = [] 72 try:
72 if not node: 73 r = failure.trap(*error_map.keys())
73 results.append({ 74 xmpp_error.error_from_iq(iq, error_map[r], failure.value.msg)
74 'category': 'pubsub', 75 if isinstance(failure.value, PubSubError) and \
75 'type': 'generic', 76 failure.value.pubsub_error is not None:
76 'name': 'Generic Pubsub Service' 77 iq.error.addElement((NS_PUBSUB_ERRORS,
77 }) 78 failure.value.pubsub_error),
78 return results 79 NS_PUBSUB_ERRORS)
79 80 return iq
80 def getFeatures(self, node): 81 except:
81 return [ 82 xmpp_error.error_from_iq(iq, 'internal-server-error')
82 "http://jabber.org/protocol/pubsub#outcast-affil", 83 self.send(iq)
83 "http://jabber.org/protocol/pubsub#publisher-affil", 84 raise
84 "http://jabber.org/protocol/pubsub#persistent-items", 85
85 ] 86 def success(self, result, iq):
86 87 iq.swapAttributeValues("to", "from")
87 def error(self, failure, iq): 88 iq["type"] = 'result'
88 try: 89 iq.children = result or []
89 r = failure.trap(*error_map.keys()) 90 return iq
90 xmpp_error.error_from_iq(iq, error_map[r], failure.value.msg) 91
91 if isinstance(failure.value, PubSubError) and \ 92 def handler_wrapper(self, handler, iq):
92 failure.value.pubsub_error is not None: 93 try:
93 iq.error.addElement((NS_PUBSUB_ERRORS, 94 d = handler(iq)
94 failure.value.pubsub_error), 95 except:
95 NS_PUBSUB_ERRORS) 96 d = defer.fail()
96 return iq 97
97 except: 98 d.addCallback(self.success, iq)
98 xmpp_error.error_from_iq(iq, 'internal-server-error') 99 d.addErrback(self.error, iq)
99 self.send(iq) 100 d.addCallback(self.send)
100 raise 101 iq.handled = True
101 102
102 def success(self, result, iq): 103 class ComponentServiceFromService(Service):
103 iq.swapAttributeValues("to", "from") 104
104 iq["type"] = 'result' 105 def getIdentities(self, node):
105 iq.children = result or [] 106 results = []
106 return iq 107 if not node:
107 108 results.append({
108 def onPubSub(self, iq): 109 'category': 'pubsub',
109 for elem in iq.pubsub.elements(): 110 'type': 'generic',
110 if not elem.hasAttribute('xmlns'): 111 'name': 'Generic Pubsub Service'
111 action = elem.name 112 })
112 break 113 return results
113 114
114 if not action: 115 def getFeatures(self, node):
115 return 116 features = []
116 117
117 try: 118 affiliations = self.backend.get_supported_affiliations()
118 try: 119 if 'outcast' in affiliations:
119 handler = getattr(self, 'on%s%s' % (action.capitalize(), 120 features.append("http://jabber.org/protocol/pubsub#outcast-affil")
120 iq["type"].capitalize())) 121
121 except KeyError: 122 if 'publisher' in affiliations:
122 raise NotImplemented 123 features.append("http://jabber.org/protocol/pubsub#publisher-affil")
123 else: 124
124 d = handler(iq) 125 # "http://jabber.org/protocol/pubsub#persistent-items"
125 except: 126
126 d = defer.fail() 127 return features
127 128
128 d.addCallback(self.success, iq) 129 components.registerAdapter(ComponentServiceFromService, backend.IBackendService, component.IService)
129 d.addErrback(self.error, iq) 130
130 d.addCallback(self.send) 131 class ComponentServiceFromNotificationService(Service):
131 iq.handled = True 132
132 133 def __init__(self, backend):
133 # action handlers 134 Service.__init__(self, backend)
134 135 self.backend.register_notifier(self.notify)
135 def onPublishSet(self, iq): 136
136 node = iq.pubsub.publish["node"] 137 def notify(self, object):
137 138 node_id = object["node_id"]
138 items = [] 139 items = object["items"]
139 for child in iq.pubsub.publish.children: 140 d = self.backend.get_notification_list(node_id, items)
140 if child.__class__ == domish.Element and child.name == 'item': 141 d.addCallback(self._notify, node_id)
141 items.append(child) 142
142 143 def _notify(self, list, node_id):
143 print items 144 for recipient, items in list.items():
144 145 self._notify_recipient(recipient, node_id, items)
145 return self.backend.do_publish(node, 146
146 jid.JID(iq["from"]).userhost(), 147 def _notify_recipient(self, recipient, node_id, itemlist):
147 items) 148 message = domish.Element((NS_COMPONENT, "message"))
148 149 message["from"] = self.parent.jabberId
149 def onOptionsGet(self, iq): 150 message["to"] = recipient
150 raise OptionsUnavailable 151 event = message.addElement((NS_PUBSUB_EVENT, "event"), NS_PUBSUB_EVENT)
151 152 items = event.addElement("items")
152 def onOptionsSet(self, iq): 153 items["node"] = node_id
153 raise OptionsUnavailable 154 items.children.extend(itemlist)
154 155 self.send(message)
155 def onConfigureGet(self, iq): 156
156 raise NodeNotConfigurable 157 components.registerAdapter(ComponentServiceFromNotificationService, backend.INotificationService, component.IService)
157 158
158 def onConfigureSet(self, iq): 159 class ComponentServiceFromPublishService(Service):
159 raise NodeNotConfigurable 160
160 161 def componentConnected(self, xmlstream):
161 def onSubscribeSet(self, iq): 162 xmlstream.addObserver(PUBSUB_PUBLISH, self.onPublish)
162 if iq.pubsub.options: 163
163 raise SubscribeOptionsUnavailable 164 def onPublish(self, iq):
164 165 self.handler_wrapper(self._onPublish, iq)
165 node_id = iq.pubsub.subscribe["node"] 166
166 subscriber = jid.JID(iq.pubsub.subscribe["jid"]) 167 def _onPublish(self, iq):
167 requestor = jid.JID(iq["from"]).userhostJID() 168 node = iq.pubsub.publish["node"]
168 d = self.backend.do_subscribe(node_id, subscriber, requestor) 169
169 d.addCallback(self.return_subscription) 170 items = []
170 d.addCallback(self.succeed, iq) 171 for child in iq.pubsub.publish.children:
171 d.addErrback(self.error, iq) 172 if child.__class__ == domish.Element and child.name == 'item':
172 d.addCallback(self.send) 173 items.append(child)
173 174
174 def return_subscription(self, result): 175 print items
175 reply = domish.Element("pubsub", NS_PUBSUB) 176
176 entity = reply.addElement("entity") 177 return self.backend.publish(node, items,
177 entity["node"] = result["node"] 178 jid.JID(iq["from"]).userhostJID())
178 entity["jid"] = result["jid"].full() 179
179 entity["affiliation"] = result["affiliation"] 180 components.registerAdapter(ComponentServiceFromPublishService, backend.IPublishService, component.IService)
180 entity["subscription"] = result["subscription"] 181
181 return reply 182 class ComponentServiceFromSubscriptionService(Service):
182 183
183 def onCreateSet(self, iq): 184 def componentConnected(self, xmlstream):
184 if iq.pubsub.options: 185 xmlstream.addObserver(PUBSUB_SUBSCRIBE, self.onSubscribe)
185 raise CreateNodeNotConfigurable 186
186 187 def onSubscribe(self, iq):
187 node = iq.pubsub.create["node"] 188 self.handler_wrapper(self._onSubscribe, iq)
188 owner = jid.JID(iq["from"]).userhostJID() 189
189 190 def _onSubscribe(self, iq):
190 d = self.backend.create_node(node, owner) 191 if iq.pubsub.options:
191 d.addCallback(self.return_create_response, iq) 192 raise SubscribeOptionsUnavailable
192 return d 193
193 194 node_id = iq.pubsub.subscribe["node"]
194 def return_create_response(self, result, iq): 195 subscriber = jid.JID(iq.pubsub.subscribe["jid"])
195 if iq.pubsub.create["node"] is None: 196 requestor = jid.JID(iq["from"]).userhostJID()
196 reply = domish.Element('pubsub', NS_PUBSUB) 197 d = self.backend.do_subscribe(node_id, subscriber, requestor)
197 entity = reply.addElement('create') 198 d.addCallback(self.return_subscription)
198 entity['node'] = result['node_id'] 199 d.addCallback(self.succeed, iq)
199 return reply 200 d.addErrback(self.error, iq)
200 201 d.addCallback(self.send)
201 # other methods 202
202 203 def _onConfigureGet(self, iq):
203 def do_notification(self, list, node): 204 raise NodeNotConfigurable
204 for recipient, items in list.items(): 205
205 self.notify(node, items, recipient) 206 def _onConfigureSet(self, iq):
206 207 raise NodeNotConfigurable
207 def notify(self, node, itemlist, recipient): 208
208 message = domish.Element((NS_COMPONENT, "message")) 209 def return_subscription(self, result):
209 message["from"] = self.parent.jabberId 210 reply = domish.Element("pubsub", NS_PUBSUB)
210 message["to"] = recipient 211 entity = reply.addElement("entity")
211 event = message.addElement((NS_PUBSUB_EVENT, "event"), NS_PUBSUB_EVENT) 212 entity["node"] = result["node"]
212 items = event.addElement("items") 213 entity["jid"] = result["jid"].full()
213 items["node"] = node 214 entity["affiliation"] = result["affiliation"]
214 items.children.extend(itemlist) 215 entity["subscription"] = result["subscription"]
215 self.send(message) 216 return reply
216 217
217 components.registerAdapter(ComponentServiceFromBackend, backend.IService, component.IService) 218 components.registerAdapter(ComponentServiceFromSubscriptionService, backend.ISubscriptionService, component.IService)
218 219
220 class ComponentServiceFromNodeCreationService(Service):
221
222 def componentConnected(self, xmlstream):
223 xmlstream.addObserver(PUBSUB_CREATE, self.onCreate)
224
225 def onCreate(self, iq):
226 self.handler_wrapper(self._onCreate, iq)
227
228 def _onCreate(self, iq):
229 if iq.pubsub.options:
230 raise CreateNodeNotConfigurable
231
232 node = iq.pubsub.create["node"]
233 owner = jid.JID(iq["from"]).userhostJID()
234
235 d = self.backend.create_node(node, owner)
236 d.addCallback(self.return_create_response, iq)
237 return d
238
239 def _onOptionsGet(self, iq):
240 raise OptionsUnavailable
241
242 def _onOptionsSet(self, iq):
243 raise OptionsUnavailable
244
245 def return_create_response(self, result, iq):
246 if iq.pubsub.create["node"] is None:
247 reply = domish.Element('pubsub', NS_PUBSUB)
248 entity = reply.addElement('create')
249 entity['node'] = result['node_id']
250 return reply
251
252 components.registerAdapter(ComponentServiceFromNodeCreationService, backend.INodeCreationService, component.IService)