Mercurial > psgxs
comparison storage.js @ 0:9ee956af41e3
Initial commit
author | Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> |
---|---|
date | Sun, 27 Jun 2010 22:05:12 +0200 |
parents | |
children | c2954a9e5665 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:9ee956af41e3 |
---|---|
1 /* | |
2 * Copyright (C) 2010 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> | |
3 * | |
4 * This file is part of PSĜS, a PubSub server written in JavaScript. | |
5 * | |
6 * PSĜS is free software: you can redistribute it and/or modify | |
7 * it under the terms of the GNU Affero General Public License as | |
8 * published by the Free Software Foundation, either version 3 of the | |
9 * License. | |
10 * | |
11 * PSĜS is distributed in the hope that it will be useful, | |
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 * GNU Affero General Public License for more details. | |
15 * | |
16 * You should have received a copy of the GNU Affero General Public License | |
17 * along with PSĜS. If not, see <http://www.gnu.org/licenses/>. | |
18 */ | |
19 | |
20 var sys = require('sys'); | |
21 var sha1hex = require('sha1').hex; | |
22 require('./iso8601'); | |
23 var errors = require('./errors'); | |
24 var config = require('./configuration'); | |
25 var service_configuration = config.service_configuration; | |
26 var Configuration = config.Configuration; | |
27 var utils = require('./util'); | |
28 var toBareJID = utils.toBareJID; | |
29 | |
30 var nodes = require('./nodes'); | |
31 var Node = nodes.Node; | |
32 var Item = nodes.Item; | |
33 | |
34 var fs = require('fs'); | |
35 | |
36 var list = {}; | |
37 | |
38 var storage = exports; | |
39 storage.createNode = function(nodeID, params) { | |
40 for (var i in list) | |
41 if (i == nodeID) | |
42 return errors.owner.create.nodeid_already_exists.n; | |
43 | |
44 list[nodeID] = new Node(params); | |
45 storage.save(); | |
46 return errors.success; | |
47 }; | |
48 | |
49 storage.getMetadata = function(nodeID) { | |
50 var node = storage.getNode(nodeID); | |
51 if (typeof node == 'number') | |
52 return node; | |
53 | |
54 if (!config.enabled('meta-data')) | |
55 return {}; | |
56 | |
57 var md = {}; | |
58 for (var i in service_configuration.node_metadata) { | |
59 if (i == 'FORM_TYPE') | |
60 continue; | |
61 | |
62 if (node.configuration[i]) | |
63 md[i] = node.configuration[i]; | |
64 else if (node.metadata[i]) | |
65 md[i] = node.metadata[i]; | |
66 } | |
67 return md; | |
68 }; | |
69 | |
70 storage.getConfiguration = function(nodeID) { | |
71 var node = storage.getNode(nodeID); | |
72 if (typeof node == 'number') | |
73 return node; | |
74 | |
75 if (config.enabled('config-node')) | |
76 return node.configuration; | |
77 | |
78 return {}; //FIXME | |
79 }; | |
80 | |
81 storage.configure = function(nodeID, params) { | |
82 var node = storage.getNode(nodeID); | |
83 if (typeof node == 'number') | |
84 return node; | |
85 | |
86 if (!config.enabled('config-node')) | |
87 return 42; //FIXME | |
88 | |
89 for (var i in params) | |
90 if (service_configuration.node_config[i]) | |
91 node.configuration[i] = params[i]; | |
92 | |
93 storage.save(); | |
94 return errors.success; | |
95 }; | |
96 | |
97 storage.configureSubscription = function(nodeID, jid, params) { | |
98 var node = storage.getNode(nodeID); | |
99 if (typeof node == 'number') | |
100 return node; | |
101 | |
102 if (!config.enabled('subscription-options')) | |
103 return 42; //FIXME | |
104 | |
105 var options = node.subscribers[jid].options; | |
106 if (!options) | |
107 return 42; //FIXME | |
108 | |
109 for (var i in params) | |
110 if (service_configuration.subscribe_options[i]) | |
111 options[i] = params[i]; | |
112 | |
113 storage.save(); | |
114 return errors.success; | |
115 }; | |
116 | |
117 storage.getChildren = function(node) { | |
118 var n; | |
119 var items = {}; | |
120 if (node) | |
121 n = storage.getNode(node).items; | |
122 else | |
123 n = list; | |
124 | |
125 for (var i in n) { | |
126 var type; | |
127 if (n[i].content) | |
128 type = 'item'; | |
129 else | |
130 type = 'node'; | |
131 items[i] = type; | |
132 } | |
133 return items; | |
134 }; | |
135 | |
136 storage.getNode = function(nodeID) { | |
137 if (list[nodeID]) | |
138 return list[nodeID]; | |
139 return errors.sub.subscribe.node_does_not_exist.n; | |
140 }; | |
141 | |
142 storage.existsNode = function(nodeID) { | |
143 if (list[nodeID]) | |
144 return true; | |
145 return false; | |
146 }; | |
147 | |
148 storage.purgeNode = function(nodeID) { | |
149 var node = storage.getNode(nodeID); | |
150 if (typeof n == 'number') | |
151 return node; | |
152 | |
153 var notifs = storage.getSubscriptionsFromNodeID(nodeID); | |
154 | |
155 var item = storage.getLastItem(nodeID); | |
156 if (typeof item == 'number') { | |
157 node.items = {}; | |
158 } else { | |
159 items = node.items[item]; | |
160 node.items = {}; | |
161 node.items[item] = items; | |
162 } | |
163 | |
164 storage.save(); | |
165 return notifs; | |
166 }; | |
167 | |
168 storage.deleteNodeWithRedirect = function(nodeID, uri) { | |
169 var del = storage.deleteNode(nodeID); | |
170 if (typeof del == 'number') | |
171 return del; | |
172 | |
173 list[nodeID] = uri; | |
174 storage.save(); | |
175 return errors.success; | |
176 }; | |
177 | |
178 storage.deleteNode = function(nodeID) { | |
179 var node = storage.getNode(nodeID); | |
180 if (typeof n == 'number') | |
181 return node; | |
182 | |
183 var notifs = {}; | |
184 for (var i in node.subscribers) | |
185 notifs[i] = {}; | |
186 for (var i in node.owner) | |
187 notifs[node.owner[i]] = {}; | |
188 if (config.enabled('publisher-affiliation')) | |
189 for (var i in node.publisher) | |
190 notifs[node.publisher[i]] = {}; | |
191 if (config.enabled('publish-only-affiliation')) | |
192 for (var i in node.publishOnly) | |
193 notifs[node.publishOnly[i]] = {}; | |
194 | |
195 delete list[nodeID]; | |
196 storage.save(); | |
197 return notifs; | |
198 }; | |
199 | |
200 storage.setItem = function(nodeID, itemID, content) { | |
201 var node = storage.getNode(nodeID); | |
202 if (typeof node == 'number') | |
203 return node; | |
204 | |
205 if (typeof itemID != 'string') | |
206 itemID = utils.makeRandomId(); | |
207 | |
208 i = node.setItem(itemID, content); | |
209 if (content) | |
210 i.content = content; | |
211 | |
212 storage.save(); | |
213 return storage.getSubscriptionsFromNodeID(nodeID) | |
214 }; | |
215 | |
216 storage.deleteItem = function(nodeID, itemID) { | |
217 var node = storage.getNode(nodeID); | |
218 if (typeof node == 'number') | |
219 return node; | |
220 | |
221 if (typeof itemID != 'string') | |
222 return errors.pub.retract.item_or_itemid_required.n; | |
223 | |
224 item = node.setItem(itemID); | |
225 if (typeof item == 'number') | |
226 return item; | |
227 | |
228 storage.save(); | |
229 return storage.getSubscriptionsFromNodeID(nodeID) | |
230 }; | |
231 | |
232 storage.getItems = function(nodeID) { | |
233 var node; | |
234 if (typeof nodeID == 'string') | |
235 node = storage.getNode(nodeID); | |
236 else | |
237 node = nodeID; | |
238 | |
239 if (typeof node == 'number') | |
240 return node; | |
241 | |
242 return node.items; | |
243 }; | |
244 | |
245 storage.getLastItem = function(nodeID, number) { | |
246 var items = storage.getItems(nodeID); | |
247 if (typeof items == 'number') | |
248 return items; | |
249 | |
250 if (items == {}) | |
251 return 42; //FIXME | |
252 | |
253 if (number) { | |
254 var last = []; | |
255 var j = 0; | |
256 for (var i in items) { | |
257 last.push({name: i, date: items[i].date, content: items[i].content}); | |
258 j++; | |
259 } | |
260 if (j < number) | |
261 return last; | |
262 | |
263 var cmp = function(a, b) { | |
264 return b.date - a.date; | |
265 } | |
266 last = last.sort(cmp).slice(0, number); | |
267 } else { | |
268 var last; | |
269 for (var i in items) | |
270 if ((typeof last == 'undefined') || (items[i].date >= items[last].date)) | |
271 last = i; | |
272 } | |
273 | |
274 if (last) | |
275 return last; | |
276 return 42; //FIXME | |
277 }; | |
278 | |
279 storage.existsItem = function(nodeID, itemID) { | |
280 var items = storage.getItems(nodeID); | |
281 if (typeof items == 'number') | |
282 return items; | |
283 | |
284 for (var i in items) | |
285 if (i == itemID) | |
286 return items[i]; | |
287 return false; | |
288 }; | |
289 | |
290 storage.getItem = function(nodeID, itemID) { | |
291 if (!storage.existsItem(nodeID, itemID)) | |
292 return 42; //FIXME | |
293 | |
294 var items = storage.existsItem(nodeID, itemID); | |
295 if (typeof items == 'number') | |
296 return items; | |
297 if (items) | |
298 return items.content; | |
299 return errors.item_not_found; | |
300 }; | |
301 | |
302 storage.getSubscription = function(jid, nodeID) { | |
303 var subs = {}; | |
304 if (nodeID) { | |
305 var node = storage.getNode(nodeID); | |
306 for (var sub in node.subscribers) | |
307 if (toBareJID(sub) == jid) | |
308 return node.subscribers[sub] | |
309 } else { | |
310 for (var node in list) { | |
311 for (var sub in list[node].subscribers) { | |
312 if (toBareJID(sub) == jid) | |
313 subs[node] = list[node].subscribers[sub]; | |
314 } | |
315 } | |
316 } | |
317 return subs; | |
318 }; | |
319 | |
320 storage.getSubscriptionsFromNodeID = function(nodeID) { | |
321 var node; | |
322 if (typeof nodeID == 'string') { | |
323 node = storage.getNode(nodeID); | |
324 if (typeof node == 'number') | |
325 return node; | |
326 } else | |
327 node = nodeID; | |
328 | |
329 var subs = {}; | |
330 for (var sub in node.subscribers) { | |
331 if (typeof sub == 'string') { | |
332 var subscription = {subid: node.subscribers[sub].subid, type: node.subscribers[sub].type}; | |
333 if (node.subscribers[sub].options) | |
334 subscription.options = node.subscribers[sub].options; | |
335 subs[sub] = subscription; | |
336 } | |
337 } | |
338 return subs; | |
339 }; | |
340 | |
341 storage.subscribe = function(nodeID, jid, type, params) { | |
342 if (!config.enabled('subscribe')) | |
343 return errors.sub.subscribe.not_supported.n; | |
344 | |
345 var node = storage.getNode(nodeID); | |
346 if (typeof node == 'number') | |
347 return node; | |
348 | |
349 if (typeof type == 'undefined') | |
350 type = 'subscribed'; | |
351 | |
352 if (type == 'none') { | |
353 if (!node.subscribers[jid]) | |
354 return errors.sub.unsubscribe.no_such_subscriber.n; | |
355 } | |
356 | |
357 var subid = node.setSubscriber(jid, type, null, params); | |
358 storage.save(); | |
359 return {subid: subid, type: type}; | |
360 }; | |
361 | |
362 storage.setAffiliation = function(nodeID, jid, affil) { | |
363 var node = storage.getNode(nodeID); | |
364 if (typeof node == 'number') | |
365 return node; | |
366 | |
367 if (affil == 'owner') | |
368 node.owner.push(jid); | |
369 else if (config.enabled('publisher-affiliation') && affil == 'publisher') | |
370 node.publisher.push(jid); | |
371 else if (config.enabled('publish-only-affiliation') && affil == 'publish-only') | |
372 node.publishOnly.push(jid); | |
373 else if (config.enabled('member-affiliation') && affil == 'member') | |
374 node.member.push(jid); | |
375 else if (config.enabled('outcast-affiliation') && affil == 'outcast') | |
376 node.outcast.push(jid); | |
377 | |
378 storage.save(); | |
379 return errors.success; | |
380 }; | |
381 | |
382 storage.getAffiliation = function(jid, nodeID) { | |
383 var node; | |
384 if (typeof nodeID == 'string') { | |
385 node = storage.getNode(nodeID); | |
386 if (typeof node == 'number') | |
387 return node; | |
388 } else | |
389 node = nodeID; | |
390 | |
391 for (var affil in node.owner) | |
392 if (typeof affil == 'string' && node.owner[affil] == jid) | |
393 return 'owner'; | |
394 if (config.enabled('publisher-affiliation')) | |
395 for (var affil in node.publisher) | |
396 if (typeof affil == 'string' && node.publisher[affil] == jid) | |
397 return 'publisher'; | |
398 if (config.enabled('publish-only-affiliation')) | |
399 for (var affil in node.publishOnly) | |
400 if (typeof affil == 'string' && node.publishOnly[affil] == jid) | |
401 return 'publish-only'; | |
402 if (config.enabled('outcast-affiliation')) | |
403 for (var affil in node.outcast) | |
404 if (typeof affil == 'string' && node.outcast[affil] == jid) | |
405 return 'outcast'; | |
406 return 'none'; | |
407 }; | |
408 | |
409 storage.getAffiliationsFromJID = function(jid) { | |
410 var affils = {}; | |
411 for (var node in list) { | |
412 var n = list[node]; | |
413 for (var affil in n.owner) | |
414 if (typeof affil == 'string' && n.owner[affil] == jid) { | |
415 affils[node] = 'owner'; | |
416 break; | |
417 } | |
418 if (config.enabled('publisher-affiliation')) | |
419 for (var affil in n.publisher) | |
420 if (typeof affil == 'string' && n.publisher[affil] == jid) { | |
421 affils[node] = 'publisher'; | |
422 break; | |
423 } | |
424 if (config.enabled('publish-only-affiliation')) | |
425 for (var affil in n.publishOnly) | |
426 if (typeof affil == 'string' && n.publishOnly[affil] == jid) { | |
427 affils[node] = 'publish-only'; | |
428 break; | |
429 } | |
430 if (config.enabled('outcast-affiliation')) | |
431 for (var affil in n.outcast) | |
432 if (typeof affil == 'string' && n.outcast[affil] == jid) { | |
433 affils[node] = 'outcast'; | |
434 break; | |
435 } | |
436 } | |
437 return affils; | |
438 }; | |
439 | |
440 storage.getAffiliationsFromNodeID = function(nodeID) { | |
441 var node; | |
442 if (typeof nodeID == 'string') { | |
443 node = storage.getNode(nodeID); | |
444 if (typeof node == 'number') | |
445 return node; | |
446 } else | |
447 node = nodeID; | |
448 | |
449 var affils = {}; | |
450 for (var jid in node.owner) | |
451 if (typeof jid == 'string') | |
452 affils[node.owner[jid]] = 'owner'; | |
453 if (config.enabled('publisher-affiliation')) | |
454 for (var jid in node.publisher) | |
455 if (typeof jid == 'string') | |
456 affils[node.publisher[jid]] = 'publisher'; | |
457 if (config.enabled('publish-only-affiliation')) | |
458 for (var jid in node.publishOnly) | |
459 if (typeof jid == 'string') | |
460 affils[node.publishOnly[jid]] = 'publish-only'; | |
461 if (config.enabled('member-affiliation')) | |
462 for (var jid in node.member) | |
463 if (typeof jid == 'string') | |
464 affils[node.member[jid]] = 'member'; | |
465 if (config.enabled('outcast-affiliation')) | |
466 for (var jid in node.outcast) | |
467 if (typeof jid == 'string') | |
468 affils[node.outcast[jid]] = 'outcast'; | |
469 return affils; | |
470 }; | |
471 | |
472 storage.save = function(file) { | |
473 function sanitize(o) { | |
474 var n = {}; | |
475 for (var i in o) { | |
476 if (i == 'content' || o[i].setISO8601) | |
477 n[i] = o[i].toString(); | |
478 else if (o[i] instanceof Array) | |
479 n[i] = o[i]; | |
480 else if (typeof o[i] == 'object') | |
481 n[i] = sanitize(o[i]); | |
482 else if (typeof o[i] == 'function') | |
483 ; | |
484 else | |
485 n[i] = o[i]; | |
486 } | |
487 return n; | |
488 } | |
489 | |
490 var data = sanitize(list); | |
491 | |
492 if (!file) | |
493 file = 'save.json'; | |
494 | |
495 fs.writeFile(file, sys.inspect(data, null, null)); | |
496 } | |
497 | |
498 storage.load = function(file) { | |
499 var xmpp = require('xmpp'); | |
500 function parseStanza(path, content) { | |
501 var stanza = null; | |
502 var stream = new xmpp.Stream({ | |
503 stanza: function (stanza) { | |
504 path[content] = stanza; | |
505 } | |
506 }); | |
507 stream.opened = true; | |
508 stream.data(path[content]); | |
509 } | |
510 | |
511 function endParsing(o) { | |
512 var regexp = /\d{4}-\d\d-\d\dT\d\d:\d\d:\d\dZ/; | |
513 for (var i in o) { | |
514 if (typeof o[i] == 'string' && i == 'content') | |
515 parseStanza(o, i); | |
516 else if (typeof o[i] == 'string' && regexp(o[i])) { | |
517 var today = new Date(); | |
518 today.setISO8601(o[i]); | |
519 o[i] = today; | |
520 } else if (typeof o[i] == 'object') | |
521 endParsing(o[i]); | |
522 } | |
523 return o; | |
524 } | |
525 | |
526 if (!file) | |
527 file = 'save.json'; | |
528 | |
529 var data = fs.readFileSync(file); | |
530 var obj = eval('('+data+')'); | |
531 list = endParsing(obj); | |
532 } | |
533 | |
534 storage.debug = function() { | |
535 sys.puts('\033[1;33m' + sys.inspect(list, null, null) + '\033[0m'); | |
536 }; |