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