Mercurial > libervia-pubsub
annotate src/twisted/plugins/pubsub.py @ 374:40e5edd7ea11
storage: changed items order:
items were so far ordered by item_id, i.e. by order of creation.
This has been changed to order them by date of last update, so an item overwritting an old one appears on top (with former behaviour, it was staying at the same place).
The XEP is not clear on that, but this seems more in correct with § 6.5.7 which says "implementations SHOULD return the N most recent (as opposed to the N oldest) items".
author | Goffi <goffi@goffi.org> |
---|---|
date | Thu, 03 Jan 2019 20:31:03 +0100 |
parents | dabee42494ac |
children | 9a787881b824 |
rev | line source |
---|---|
233 | 1 #!/usr/bin/python |
2 #-*- coding: utf-8 -*- | |
3 | |
368 | 4 # Copyright (c) 2012-2018 Jérôme Poisson |
312
5d7c3787672e
fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents:
311
diff
changeset
|
5 # Copyright (c) 2003-2011 Ralph Meijer |
233 | 6 |
7 | |
312
5d7c3787672e
fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents:
311
diff
changeset
|
8 # This program is free software: you can redistribute it and/or modify |
5d7c3787672e
fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents:
311
diff
changeset
|
9 # it under the terms of the GNU Affero General Public License as published by |
5d7c3787672e
fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents:
311
diff
changeset
|
10 # the Free Software Foundation, either version 3 of the License, or |
5d7c3787672e
fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents:
311
diff
changeset
|
11 # (at your option) any later version. |
233 | 12 |
312
5d7c3787672e
fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents:
311
diff
changeset
|
13 # This program is distributed in the hope that it will be useful, |
5d7c3787672e
fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents:
311
diff
changeset
|
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of |
5d7c3787672e
fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents:
311
diff
changeset
|
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
5d7c3787672e
fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents:
311
diff
changeset
|
16 # GNU Affero General Public License for more details. |
233 | 17 |
312
5d7c3787672e
fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents:
311
diff
changeset
|
18 # You should have received a copy of the GNU Affero General Public License |
5d7c3787672e
fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents:
311
diff
changeset
|
19 # along with this program. If not, see <http://www.gnu.org/licenses/>. |
5d7c3787672e
fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents:
311
diff
changeset
|
20 # -- |
233 | 21 |
312
5d7c3787672e
fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents:
311
diff
changeset
|
22 # This program is based on Idavoll (http://idavoll.ik.nu/), |
5d7c3787672e
fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents:
311
diff
changeset
|
23 # originaly written by Ralph Meijer (http://ralphm.net/blog/) |
5d7c3787672e
fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents:
311
diff
changeset
|
24 # It is sublicensed under AGPL v3 (or any later version) as allowed by the original |
5d7c3787672e
fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents:
311
diff
changeset
|
25 # license. |
233 | 26 |
312
5d7c3787672e
fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents:
311
diff
changeset
|
27 # -- |
233 | 28 |
312
5d7c3787672e
fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents:
311
diff
changeset
|
29 # Here is a copy of the original license: |
5d7c3787672e
fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents:
311
diff
changeset
|
30 |
5d7c3787672e
fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents:
311
diff
changeset
|
31 # Copyright (c) 2003-2011 Ralph Meijer |
233 | 32 |
312
5d7c3787672e
fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents:
311
diff
changeset
|
33 # Permission is hereby granted, free of charge, to any person obtaining |
5d7c3787672e
fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents:
311
diff
changeset
|
34 # a copy of this software and associated documentation files (the |
5d7c3787672e
fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents:
311
diff
changeset
|
35 # "Software"), to deal in the Software without restriction, including |
5d7c3787672e
fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents:
311
diff
changeset
|
36 # without limitation the rights to use, copy, modify, merge, publish, |
5d7c3787672e
fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents:
311
diff
changeset
|
37 # distribute, sublicense, and/or sell copies of the Software, and to |
5d7c3787672e
fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents:
311
diff
changeset
|
38 # permit persons to whom the Software is furnished to do so, subject to |
5d7c3787672e
fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents:
311
diff
changeset
|
39 # the following conditions: |
233 | 40 |
312
5d7c3787672e
fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents:
311
diff
changeset
|
41 # The above copyright notice and this permission notice shall be |
5d7c3787672e
fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents:
311
diff
changeset
|
42 # included in all copies or substantial portions of the Software. |
233 | 43 |
312
5d7c3787672e
fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents:
311
diff
changeset
|
44 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
5d7c3787672e
fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents:
311
diff
changeset
|
45 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
5d7c3787672e
fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents:
311
diff
changeset
|
46 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
5d7c3787672e
fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents:
311
diff
changeset
|
47 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
5d7c3787672e
fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents:
311
diff
changeset
|
48 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
5d7c3787672e
fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents:
311
diff
changeset
|
49 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
5d7c3787672e
fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents:
311
diff
changeset
|
50 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
233 | 51 |
155 | 52 |
369 | 53 import sat_pubsub |
54 from twisted.application.service import IServiceMaker | |
55 from twisted.application import service | |
56 from twisted.python import usage | |
57 from twisted.words.protocols.jabber.jid import JID | |
58 from twisted.plugin import IPlugin | |
59 | |
60 from wokkel.component import Component | |
61 from wokkel.disco import DiscoHandler | |
62 from wokkel.generic import FallbackHandler, VersionHandler | |
63 from wokkel.iwokkel import IPubSubResource | |
64 from wokkel import data_form | |
65 from wokkel import pubsub | |
66 from wokkel import rsm | |
67 from wokkel import mam | |
68 from zope.interface import implements | |
69 | |
70 from sat_pubsub import const | |
71 from sat_pubsub import mam as pubsub_mam | |
72 from sat_pubsub.backend import BackendService | |
73 from sat_pubsub.schema import SchemaHandler | |
74 from sat_pubsub.privilege import PrivilegesHandler | |
75 from sat_pubsub.delegation import DelegationsHandler | |
76 from os.path import expanduser, realpath | |
77 import ConfigParser | |
78 | |
79 | |
80 OPT_PARAMETERS_BOTH = [ | |
81 ['jid', None, None, 'JID this component will be available at'], | |
82 ['xmpp_pwd', None, None, 'XMPP server component password'], | |
83 ['rhost', None, '127.0.0.1', 'XMPP server host'], | |
84 ['rport', None, '5347', 'XMPP server port'], | |
85 ['backend', None, 'pgsql', 'Choice of storage backend'], | |
86 ['db_user', None, None, 'Database user (pgsql backend)'], | |
87 ['db_name', None, 'pubsub', 'Database name (pgsql backend)'], | |
88 ['db_pass', None, None, 'Database password (pgsql backend)'], | |
89 ['db_host', None, None, 'Database host (pgsql backend)'], | |
90 ['db_port', None, None, 'Database port (pgsql backend)'], | |
91 ] | |
92 # here for future use | |
93 OPT_PARAMETERS_CFG = [] | |
94 | |
95 CONFIG_FILENAME = u'sat' | |
96 # List of the configuration filenames sorted by ascending priority | |
97 CONFIG_FILES = [realpath(expanduser(path) + CONFIG_FILENAME + '.conf') for path in ( | |
98 '/etc/', '/etc/{}/'.format(CONFIG_FILENAME), | |
99 '~/', '~/.', | |
100 '.config/', '.config/.', | |
101 '', '.')] | |
102 CONFIG_SECTION = 'pubsub' | |
103 | |
104 | |
105 class Options(usage.Options): | |
106 optParameters = OPT_PARAMETERS_BOTH | |
107 | |
108 optFlags = [ | |
109 ('verbose', 'v', 'Show traffic'), | |
110 ('hide-nodes', None, 'Hide all nodes for disco') | |
111 ] | |
112 | |
113 def __init__(self): | |
114 """Read SàT Pubsub configuration file in order to overwrite the hard-coded default values. | |
115 | |
116 Priority for the usage of the values is (from lowest to highest): | |
117 - hard-coded default values | |
118 - values from SàT configuration files | |
119 - values passed on the command line | |
120 """ | |
121 # If we do it the reading later: after the command line options have been parsed, there's no good way to know | |
122 # if the options values are the hard-coded ones or if they have been passed on the command line. | |
123 | |
124 # FIXME: must be refactored + code can be factorised with backend | |
125 config_parser = ConfigParser.SafeConfigParser() | |
126 config_parser.read(CONFIG_FILES) | |
127 for param in self.optParameters + OPT_PARAMETERS_CFG: | |
128 name = param[0] | |
129 try: | |
130 value = config_parser.get(CONFIG_SECTION, name) | |
131 if isinstance(value, unicode): | |
132 value = value.encode('utf-8') | |
133 try: | |
134 param[2] = param[4](value) | |
135 except IndexError: # the coerce method is optional | |
136 param[2] = value | |
137 except (ConfigParser.NoSectionError, ConfigParser.NoOptionError): | |
138 pass | |
139 usage.Options.__init__(self) | |
140 for opt_data in OPT_PARAMETERS_CFG: | |
141 self[opt_data[0]] = opt_data[2] | |
155 | 142 |
369 | 143 def postOptions(self): |
144 if self['backend'] not in ['pgsql', 'memory']: | |
145 raise usage.UsageError, "Unknown backend!" | |
146 if self['backend'] == 'memory': | |
147 raise NotImplementedError('memory backend is not available at the moment') | |
148 | |
149 self['jid'] = JID(self['jid']) if self['jid'] else None | |
150 | |
151 | |
152 class SatPubsubMaker(object): | |
153 implements(IServiceMaker, IPlugin) | |
154 tapname = "sat-pubsub" | |
155 description = u"Salut à Toi Publish-Subscribe Service Component".encode('utf-8') | |
156 options = Options | |
157 | |
158 def makeService(self, config): | |
159 if not config['jid'] or not config['xmpp_pwd']: | |
160 raise usage.UsageError("You must specify jid and xmpp_pwd") | |
161 s = service.MultiService() | |
162 | |
163 # Create backend service with storage | |
164 | |
165 if config['backend'] == 'pgsql': | |
166 from twisted.enterprise import adbapi | |
167 from sat_pubsub.pgsql_storage import Storage | |
168 from psycopg2.extras import NamedTupleConnection | |
169 keys_map = { | |
170 'db_user': 'user', | |
171 'db_pass': 'password', | |
172 'db_name': 'database', | |
173 'db_host': 'host', | |
174 'db_port': 'port', | |
175 } | |
176 kwargs = {} | |
177 for config_k, k in keys_map.iteritems(): | |
178 v = config.get(config_k) | |
179 if v is None: | |
180 continue | |
181 kwargs[k] = v | |
182 dbpool = adbapi.ConnectionPool('psycopg2', | |
183 cp_reconnect=True, | |
184 client_encoding='utf-8', | |
185 connection_factory=NamedTupleConnection, | |
186 **kwargs | |
187 ) | |
188 st = Storage(dbpool) | |
189 elif config['backend'] == 'memory': | |
190 from sat_pubsub.memory_storage import Storage | |
191 st = Storage() | |
192 | |
193 bs = BackendService(st) | |
194 bs.setName('backend') | |
195 bs.setServiceParent(s) | |
196 | |
197 # Set up XMPP server-side component with publish-subscribe capabilities | |
198 | |
199 cs = Component(config["rhost"], int(config["rport"]), | |
200 config["jid"].full(), config["xmpp_pwd"]) | |
201 cs.setName('component') | |
202 cs.setServiceParent(s) | |
203 | |
204 cs.factory.maxDelay = 900 | |
205 | |
206 if config["verbose"]: | |
207 cs.logTraffic = True | |
208 | |
209 FallbackHandler().setHandlerParent(cs) | |
210 VersionHandler(u'SàT Pubsub', sat_pubsub.__version__).setHandlerParent(cs) | |
211 DiscoHandler().setHandlerParent(cs) | |
212 | |
213 ph = PrivilegesHandler(config['jid']) | |
214 ph.setHandlerParent(cs) | |
215 bs.privilege = ph | |
216 | |
217 resource = IPubSubResource(bs) | |
218 resource.hideNodes = config["hide-nodes"] | |
219 resource.serviceJID = config["jid"] | |
220 | |
221 ps = (rsm if const.FLAG_ENABLE_RSM else pubsub).PubSubService(resource) | |
222 ps.setHandlerParent(cs) | |
223 resource.pubsubService = ps | |
224 | |
225 if const.FLAG_ENABLE_MAM: | |
226 mam_resource = pubsub_mam.MAMResource(bs) | |
227 mam_s = mam.MAMService(mam_resource) | |
228 mam_s.addFilter(data_form.Field(var=const.MAM_FILTER_CATEGORY)) | |
229 mam_s.setHandlerParent(cs) | |
230 | |
231 sh = SchemaHandler() | |
232 sh.setHandlerParent(cs) | |
233 | |
234 # XXX: delegation must be instancied at the end, | |
235 # because it does some MonkeyPatching on handlers | |
236 dh = DelegationsHandler() | |
237 dh.setHandlerParent(cs) | |
238 bs.delegation = dh | |
239 | |
240 return s | |
241 | |
242 serviceMaker = SatPubsubMaker() |