Mercurial > libervia-pubsub
annotate idavoll/memory_storage.py @ 179:42e23a62b57f
Guard against missing config for sending last published item on subscription.
author | Ralph Meijer <ralphm@ik.nu> |
---|---|
date | Thu, 10 Apr 2008 14:06:00 +0000 |
parents | 246911bcb699 |
children | fc687620599b |
rev | line source |
---|---|
171
bc269696ef42
Reply with the correct error condition on subscription when not subscribed.
Ralph Meijer <ralphm@ik.nu>
parents:
167
diff
changeset
|
1 # Copyright (c) 2003-2008 Ralph Meijer |
155
5191ba7c4df8
Work towards first release 0.5.0.
Ralph Meijer <ralphm@ik.nu>
parents:
148
diff
changeset
|
2 # See LICENSE for details. |
5191ba7c4df8
Work towards first release 0.5.0.
Ralph Meijer <ralphm@ik.nu>
parents:
148
diff
changeset
|
3 |
107 | 4 import copy |
5 from zope.interface import implements | |
6 from twisted.internet import defer | |
7 from twisted.words.protocols.jabber import jid | |
167
ef22e4150caa
Move protocol implementations (pubsub, disco, forms) to and depend on wokkel.
Ralph Meijer <ralphm@ik.nu>
parents:
155
diff
changeset
|
8 |
ef22e4150caa
Move protocol implementations (pubsub, disco, forms) to and depend on wokkel.
Ralph Meijer <ralphm@ik.nu>
parents:
155
diff
changeset
|
9 from idavoll import error, iidavoll |
107 | 10 |
115 | 11 default_config = {"pubsub#persist_items": True, |
173
246911bcb699
Make node type part of node configuration.
Ralph Meijer <ralphm@ik.nu>
parents:
171
diff
changeset
|
12 "pubsub#deliver_payloads": True, |
179
42e23a62b57f
Guard against missing config for sending last published item on subscription.
Ralph Meijer <ralphm@ik.nu>
parents:
173
diff
changeset
|
13 "pubsub#send_last_published_item": True, |
173
246911bcb699
Make node type part of node configuration.
Ralph Meijer <ralphm@ik.nu>
parents:
171
diff
changeset
|
14 "pubsub#node_type": "leaf"} |
107 | 15 |
16 class Storage: | |
17 | |
167
ef22e4150caa
Move protocol implementations (pubsub, disco, forms) to and depend on wokkel.
Ralph Meijer <ralphm@ik.nu>
parents:
155
diff
changeset
|
18 implements(iidavoll.IStorage) |
107 | 19 |
20 def __init__(self): | |
21 self._nodes = {} | |
22 | |
23 def get_node(self, node_id): | |
24 try: | |
25 node = self._nodes[node_id] | |
26 except KeyError: | |
167
ef22e4150caa
Move protocol implementations (pubsub, disco, forms) to and depend on wokkel.
Ralph Meijer <ralphm@ik.nu>
parents:
155
diff
changeset
|
27 return defer.fail(error.NodeNotFound()) |
107 | 28 |
29 return defer.succeed(node) | |
30 | |
31 def get_node_ids(self): | |
32 return defer.succeed(self._nodes.keys()) | |
33 | |
173
246911bcb699
Make node type part of node configuration.
Ralph Meijer <ralphm@ik.nu>
parents:
171
diff
changeset
|
34 def create_node(self, node_id, owner, config=None): |
107 | 35 if node_id in self._nodes: |
167
ef22e4150caa
Move protocol implementations (pubsub, disco, forms) to and depend on wokkel.
Ralph Meijer <ralphm@ik.nu>
parents:
155
diff
changeset
|
36 return defer.fail(error.NodeExists()) |
107 | 37 |
38 if not config: | |
39 config = copy.copy(default_config) | |
40 | |
173
246911bcb699
Make node type part of node configuration.
Ralph Meijer <ralphm@ik.nu>
parents:
171
diff
changeset
|
41 if config['pubsub#node_type'] != 'leaf': |
107 | 42 raise NotImplementedError |
43 | |
44 node = LeafNode(node_id, owner, config) | |
45 self._nodes[node_id] = node | |
46 | |
47 return defer.succeed(None) | |
48 | |
49 def delete_node(self, node_id): | |
50 try: | |
51 del self._nodes[node_id] | |
52 except KeyError: | |
167
ef22e4150caa
Move protocol implementations (pubsub, disco, forms) to and depend on wokkel.
Ralph Meijer <ralphm@ik.nu>
parents:
155
diff
changeset
|
53 return defer.fail(error.NodeNotFound()) |
107 | 54 |
55 return defer.succeed(None) | |
56 | |
57 def get_affiliations(self, entity): | |
112 | 58 entity = entity.userhost() |
59 return defer.succeed([(node.id, node._affiliations[entity]) | |
107 | 60 for name, node in self._nodes.iteritems() |
112 | 61 if entity in node._affiliations]) |
107 | 62 |
63 def get_subscriptions(self, entity): | |
64 subscriptions = [] | |
65 for node in self._nodes.itervalues(): | |
66 for subscriber, subscription in node._subscriptions.iteritems(): | |
148
b03e5ad81173
Change all calls to jid.JID to jid.internJID to avoid redoing stringprep.
Ralph Meijer <ralphm@ik.nu>
parents:
146
diff
changeset
|
67 subscriber = jid.internJID(subscriber) |
112 | 68 if subscriber.userhostJID() == entity.userhostJID(): |
107 | 69 subscriptions.append((node.id, subscriber, |
70 subscription.state)) | |
71 | |
72 return defer.succeed(subscriptions) | |
171
bc269696ef42
Reply with the correct error condition on subscription when not subscribed.
Ralph Meijer <ralphm@ik.nu>
parents:
167
diff
changeset
|
73 |
bc269696ef42
Reply with the correct error condition on subscription when not subscribed.
Ralph Meijer <ralphm@ik.nu>
parents:
167
diff
changeset
|
74 |
107 | 75 class Node: |
76 | |
167
ef22e4150caa
Move protocol implementations (pubsub, disco, forms) to and depend on wokkel.
Ralph Meijer <ralphm@ik.nu>
parents:
155
diff
changeset
|
77 implements(iidavoll.INode) |
107 | 78 |
79 def __init__(self, node_id, owner, config): | |
80 self.id = node_id | |
112 | 81 self._affiliations = {owner.userhost(): 'owner'} |
107 | 82 self._subscriptions = {} |
83 self._config = config | |
84 | |
85 def get_type(self): | |
86 return self.type | |
87 | |
88 def get_configuration(self): | |
89 return self._config | |
171
bc269696ef42
Reply with the correct error condition on subscription when not subscribed.
Ralph Meijer <ralphm@ik.nu>
parents:
167
diff
changeset
|
90 |
107 | 91 def get_meta_data(self): |
92 config = copy.copy(self._config) | |
93 config["pubsub#node_type"] = self.type | |
94 return config | |
95 | |
96 def set_configuration(self, options): | |
97 for option in options: | |
98 if option in self._config: | |
99 self._config[option] = options[option] | |
100 | |
101 return defer.succeed(None) | |
171
bc269696ef42
Reply with the correct error condition on subscription when not subscribed.
Ralph Meijer <ralphm@ik.nu>
parents:
167
diff
changeset
|
102 |
107 | 103 def get_affiliation(self, entity): |
104 return defer.succeed(self._affiliations.get(entity.full())) | |
105 | |
120
8892331314c8
Change Node.add_subscription() to return a Failure when a subscription already
Ralph Meijer <ralphm@ik.nu>
parents:
115
diff
changeset
|
106 def get_subscription(self, subscriber): |
107 | 107 try: |
108 subscription = self._subscriptions[subscriber.full()] | |
120
8892331314c8
Change Node.add_subscription() to return a Failure when a subscription already
Ralph Meijer <ralphm@ik.nu>
parents:
115
diff
changeset
|
109 except KeyError: |
8892331314c8
Change Node.add_subscription() to return a Failure when a subscription already
Ralph Meijer <ralphm@ik.nu>
parents:
115
diff
changeset
|
110 state = None |
8892331314c8
Change Node.add_subscription() to return a Failure when a subscription already
Ralph Meijer <ralphm@ik.nu>
parents:
115
diff
changeset
|
111 else: |
8892331314c8
Change Node.add_subscription() to return a Failure when a subscription already
Ralph Meijer <ralphm@ik.nu>
parents:
115
diff
changeset
|
112 state = subscription.state |
8892331314c8
Change Node.add_subscription() to return a Failure when a subscription already
Ralph Meijer <ralphm@ik.nu>
parents:
115
diff
changeset
|
113 return defer.succeed(state) |
107 | 114 |
120
8892331314c8
Change Node.add_subscription() to return a Failure when a subscription already
Ralph Meijer <ralphm@ik.nu>
parents:
115
diff
changeset
|
115 def add_subscription(self, subscriber, state): |
8892331314c8
Change Node.add_subscription() to return a Failure when a subscription already
Ralph Meijer <ralphm@ik.nu>
parents:
115
diff
changeset
|
116 if self._subscriptions.get(subscriber.full()): |
167
ef22e4150caa
Move protocol implementations (pubsub, disco, forms) to and depend on wokkel.
Ralph Meijer <ralphm@ik.nu>
parents:
155
diff
changeset
|
117 return defer.fail(error.SubscriptionExists()) |
ef22e4150caa
Move protocol implementations (pubsub, disco, forms) to and depend on wokkel.
Ralph Meijer <ralphm@ik.nu>
parents:
155
diff
changeset
|
118 |
120
8892331314c8
Change Node.add_subscription() to return a Failure when a subscription already
Ralph Meijer <ralphm@ik.nu>
parents:
115
diff
changeset
|
119 subscription = Subscription(state) |
8892331314c8
Change Node.add_subscription() to return a Failure when a subscription already
Ralph Meijer <ralphm@ik.nu>
parents:
115
diff
changeset
|
120 self._subscriptions[subscriber.full()] = subscription |
8892331314c8
Change Node.add_subscription() to return a Failure when a subscription already
Ralph Meijer <ralphm@ik.nu>
parents:
115
diff
changeset
|
121 return defer.succeed(None) |
107 | 122 |
123 def remove_subscription(self, subscriber): | |
120
8892331314c8
Change Node.add_subscription() to return a Failure when a subscription already
Ralph Meijer <ralphm@ik.nu>
parents:
115
diff
changeset
|
124 try: |
8892331314c8
Change Node.add_subscription() to return a Failure when a subscription already
Ralph Meijer <ralphm@ik.nu>
parents:
115
diff
changeset
|
125 del self._subscriptions[subscriber.full()] |
8892331314c8
Change Node.add_subscription() to return a Failure when a subscription already
Ralph Meijer <ralphm@ik.nu>
parents:
115
diff
changeset
|
126 except KeyError: |
171
bc269696ef42
Reply with the correct error condition on subscription when not subscribed.
Ralph Meijer <ralphm@ik.nu>
parents:
167
diff
changeset
|
127 return defer.fail(error.NotSubscribed()) |
107 | 128 |
129 return defer.succeed(None) | |
130 | |
131 def get_subscribers(self): | |
148
b03e5ad81173
Change all calls to jid.JID to jid.internJID to avoid redoing stringprep.
Ralph Meijer <ralphm@ik.nu>
parents:
146
diff
changeset
|
132 subscribers = [jid.internJID(subscriber) for subscriber, subscription |
107 | 133 in self._subscriptions.iteritems() |
134 if subscription.state == 'subscribed'] | |
135 | |
136 return defer.succeed(subscribers) | |
137 | |
146
b4490bdc77e5
Change semantics of Node.is_subscribed() to match all subscriptions for an
Ralph Meijer <ralphm@ik.nu>
parents:
145
diff
changeset
|
138 def is_subscribed(self, entity): |
b4490bdc77e5
Change semantics of Node.is_subscribed() to match all subscriptions for an
Ralph Meijer <ralphm@ik.nu>
parents:
145
diff
changeset
|
139 for subscriber, subscription in self._subscriptions.iteritems(): |
148
b03e5ad81173
Change all calls to jid.JID to jid.internJID to avoid redoing stringprep.
Ralph Meijer <ralphm@ik.nu>
parents:
146
diff
changeset
|
140 if jid.internJID(subscriber).userhost() == entity.userhost() and \ |
146
b4490bdc77e5
Change semantics of Node.is_subscribed() to match all subscriptions for an
Ralph Meijer <ralphm@ik.nu>
parents:
145
diff
changeset
|
141 subscription.state == 'subscribed': |
b4490bdc77e5
Change semantics of Node.is_subscribed() to match all subscriptions for an
Ralph Meijer <ralphm@ik.nu>
parents:
145
diff
changeset
|
142 return defer.succeed(True) |
171
bc269696ef42
Reply with the correct error condition on subscription when not subscribed.
Ralph Meijer <ralphm@ik.nu>
parents:
167
diff
changeset
|
143 |
146
b4490bdc77e5
Change semantics of Node.is_subscribed() to match all subscriptions for an
Ralph Meijer <ralphm@ik.nu>
parents:
145
diff
changeset
|
144 return defer.succeed(False) |
107 | 145 |
145
f393bccec4bc
Add get_affiliations to Node class in storage facilities in preparation of
Ralph Meijer <ralphm@ik.nu>
parents:
142
diff
changeset
|
146 def get_affiliations(self): |
148
b03e5ad81173
Change all calls to jid.JID to jid.internJID to avoid redoing stringprep.
Ralph Meijer <ralphm@ik.nu>
parents:
146
diff
changeset
|
147 affiliations = [(jid.internJID(entity), affiliation) for entity, affiliation |
145
f393bccec4bc
Add get_affiliations to Node class in storage facilities in preparation of
Ralph Meijer <ralphm@ik.nu>
parents:
142
diff
changeset
|
148 in self._affiliations.iteritems()] |
f393bccec4bc
Add get_affiliations to Node class in storage facilities in preparation of
Ralph Meijer <ralphm@ik.nu>
parents:
142
diff
changeset
|
149 |
f393bccec4bc
Add get_affiliations to Node class in storage facilities in preparation of
Ralph Meijer <ralphm@ik.nu>
parents:
142
diff
changeset
|
150 return defer.succeed(affiliations) |
f393bccec4bc
Add get_affiliations to Node class in storage facilities in preparation of
Ralph Meijer <ralphm@ik.nu>
parents:
142
diff
changeset
|
151 |
171
bc269696ef42
Reply with the correct error condition on subscription when not subscribed.
Ralph Meijer <ralphm@ik.nu>
parents:
167
diff
changeset
|
152 |
146
b4490bdc77e5
Change semantics of Node.is_subscribed() to match all subscriptions for an
Ralph Meijer <ralphm@ik.nu>
parents:
145
diff
changeset
|
153 class LeafNodeMixin: |
107 | 154 |
155 type = 'leaf' | |
156 | |
146
b4490bdc77e5
Change semantics of Node.is_subscribed() to match all subscriptions for an
Ralph Meijer <ralphm@ik.nu>
parents:
145
diff
changeset
|
157 def __init__(self): |
107 | 158 self._items = {} |
159 self._itemlist = [] | |
160 | |
161 def store_items(self, items, publisher): | |
162 for data in items: | |
163 id = data["id"] | |
139
8f6956b9a688
Follow API change in Twisted Xish, while still being compatible with
Ralph Meijer <ralphm@ik.nu>
parents:
126
diff
changeset
|
164 data = data.toXml() |
8f6956b9a688
Follow API change in Twisted Xish, while still being compatible with
Ralph Meijer <ralphm@ik.nu>
parents:
126
diff
changeset
|
165 if isinstance(data, str): |
8f6956b9a688
Follow API change in Twisted Xish, while still being compatible with
Ralph Meijer <ralphm@ik.nu>
parents:
126
diff
changeset
|
166 data = data.decode('utf-8') |
8f6956b9a688
Follow API change in Twisted Xish, while still being compatible with
Ralph Meijer <ralphm@ik.nu>
parents:
126
diff
changeset
|
167 item = (data, publisher) |
107 | 168 if id in self._items: |
169 self._itemlist.remove(self._items[id]) | |
170 self._items[id] = item | |
171 self._itemlist.append(item) | |
172 | |
173 return defer.succeed(None) | |
174 | |
175 def remove_items(self, item_ids): | |
176 deleted = [] | |
177 | |
178 for item_id in item_ids: | |
142
812300cdbc22
Changed behaviour of retraction of items so that only the actually deleted
Ralph Meijer <ralphm@ik.nu>
parents:
139
diff
changeset
|
179 try: |
812300cdbc22
Changed behaviour of retraction of items so that only the actually deleted
Ralph Meijer <ralphm@ik.nu>
parents:
139
diff
changeset
|
180 item = self._items[item_id] |
812300cdbc22
Changed behaviour of retraction of items so that only the actually deleted
Ralph Meijer <ralphm@ik.nu>
parents:
139
diff
changeset
|
181 except KeyError: |
812300cdbc22
Changed behaviour of retraction of items so that only the actually deleted
Ralph Meijer <ralphm@ik.nu>
parents:
139
diff
changeset
|
182 pass |
812300cdbc22
Changed behaviour of retraction of items so that only the actually deleted
Ralph Meijer <ralphm@ik.nu>
parents:
139
diff
changeset
|
183 else: |
812300cdbc22
Changed behaviour of retraction of items so that only the actually deleted
Ralph Meijer <ralphm@ik.nu>
parents:
139
diff
changeset
|
184 self._itemlist.remove(item) |
812300cdbc22
Changed behaviour of retraction of items so that only the actually deleted
Ralph Meijer <ralphm@ik.nu>
parents:
139
diff
changeset
|
185 del self._items[item_id] |
812300cdbc22
Changed behaviour of retraction of items so that only the actually deleted
Ralph Meijer <ralphm@ik.nu>
parents:
139
diff
changeset
|
186 deleted.append(item_id) |
171
bc269696ef42
Reply with the correct error condition on subscription when not subscribed.
Ralph Meijer <ralphm@ik.nu>
parents:
167
diff
changeset
|
187 |
142
812300cdbc22
Changed behaviour of retraction of items so that only the actually deleted
Ralph Meijer <ralphm@ik.nu>
parents:
139
diff
changeset
|
188 return defer.succeed(deleted) |
107 | 189 |
190 def get_items(self, max_items=None): | |
191 if max_items: | |
192 list = self._itemlist[-max_items:] | |
193 else: | |
194 list = self._itemlist | |
139
8f6956b9a688
Follow API change in Twisted Xish, while still being compatible with
Ralph Meijer <ralphm@ik.nu>
parents:
126
diff
changeset
|
195 return defer.succeed([item[0] for item in list]) |
171
bc269696ef42
Reply with the correct error condition on subscription when not subscribed.
Ralph Meijer <ralphm@ik.nu>
parents:
167
diff
changeset
|
196 |
107 | 197 def get_items_by_id(self, item_ids): |
198 items = [] | |
199 for item_id in item_ids: | |
200 try: | |
201 item = self._items[item_id] | |
202 except KeyError: | |
203 pass | |
204 else: | |
139
8f6956b9a688
Follow API change in Twisted Xish, while still being compatible with
Ralph Meijer <ralphm@ik.nu>
parents:
126
diff
changeset
|
205 items.append(item[0]) |
107 | 206 return defer.succeed(items) |
207 | |
208 def purge(self): | |
209 self._items = {} | |
210 self._itemlist = [] | |
211 | |
212 return defer.succeed(None) | |
213 | |
171
bc269696ef42
Reply with the correct error condition on subscription when not subscribed.
Ralph Meijer <ralphm@ik.nu>
parents:
167
diff
changeset
|
214 |
146
b4490bdc77e5
Change semantics of Node.is_subscribed() to match all subscriptions for an
Ralph Meijer <ralphm@ik.nu>
parents:
145
diff
changeset
|
215 class LeafNode(Node, LeafNodeMixin): |
b4490bdc77e5
Change semantics of Node.is_subscribed() to match all subscriptions for an
Ralph Meijer <ralphm@ik.nu>
parents:
145
diff
changeset
|
216 |
167
ef22e4150caa
Move protocol implementations (pubsub, disco, forms) to and depend on wokkel.
Ralph Meijer <ralphm@ik.nu>
parents:
155
diff
changeset
|
217 implements(iidavoll.ILeafNode) |
146
b4490bdc77e5
Change semantics of Node.is_subscribed() to match all subscriptions for an
Ralph Meijer <ralphm@ik.nu>
parents:
145
diff
changeset
|
218 |
b4490bdc77e5
Change semantics of Node.is_subscribed() to match all subscriptions for an
Ralph Meijer <ralphm@ik.nu>
parents:
145
diff
changeset
|
219 def __init__(self, node_id, owner, config): |
b4490bdc77e5
Change semantics of Node.is_subscribed() to match all subscriptions for an
Ralph Meijer <ralphm@ik.nu>
parents:
145
diff
changeset
|
220 Node.__init__(self, node_id, owner, config) |
b4490bdc77e5
Change semantics of Node.is_subscribed() to match all subscriptions for an
Ralph Meijer <ralphm@ik.nu>
parents:
145
diff
changeset
|
221 LeafNodeMixin.__init__(self) |
b4490bdc77e5
Change semantics of Node.is_subscribed() to match all subscriptions for an
Ralph Meijer <ralphm@ik.nu>
parents:
145
diff
changeset
|
222 |
171
bc269696ef42
Reply with the correct error condition on subscription when not subscribed.
Ralph Meijer <ralphm@ik.nu>
parents:
167
diff
changeset
|
223 |
107 | 224 class Subscription: |
225 | |
226 def __init__(self, state): | |
227 self.state = state |