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