Mercurial > prosody-hg
comparison util/pubsub.lua @ 7697:bd854e762875
Merge 0.10->trunk
| author | Kim Alvefur <zash@zash.se> |
|---|---|
| date | Sun, 16 Oct 2016 00:39:10 +0200 |
| parents | e813e8cf6046 1c410b4f3a58 |
| children | 5022e6181193 |
comparison
equal
deleted
inserted
replaced
| 7694:bffbea1187ca | 7697:bd854e762875 |
|---|---|
| 1 local events = require "util.events"; | 1 local events = require "util.events"; |
| 2 local t_remove = table.remove; | 2 local cache = require "util.cache"; |
| 3 | 3 |
| 4 local service = {}; | 4 local service = {}; |
| 5 local service_mt = { __index = service }; | 5 local service_mt = { __index = service }; |
| 6 | 6 |
| 7 local default_config = { __index = { | 7 local default_config = { __index = { |
| 8 itemstore = function (config) return cache.new(tonumber(config["pubsub#max_items"])) end; | |
| 8 broadcaster = function () end; | 9 broadcaster = function () end; |
| 9 get_affiliation = function () end; | 10 get_affiliation = function () end; |
| 10 capabilities = {}; | 11 capabilities = {}; |
| 11 } }; | 12 } }; |
| 12 local default_node_config = { __index = { | 13 local default_node_config = { __index = { |
| 214 -- | 215 -- |
| 215 if self.nodes[node] then | 216 if self.nodes[node] then |
| 216 return false, "conflict"; | 217 return false, "conflict"; |
| 217 end | 218 end |
| 218 | 219 |
| 219 self.data[node] = {}; | |
| 220 self.nodes[node] = { | 220 self.nodes[node] = { |
| 221 name = node; | 221 name = node; |
| 222 subscribers = {}; | 222 subscribers = {}; |
| 223 config = setmetatable(options or {}, {__index=self.node_defaults}); | 223 config = setmetatable(options or {}, {__index=self.node_defaults}); |
| 224 affiliations = {}; | 224 affiliations = {}; |
| 225 }; | 225 }; |
| 226 setmetatable(self.nodes[node], { __index = { data = self.data[node] } }); -- COMPAT | 226 self.data[node] = self.config.itemstore(self.nodes[node].config); |
| 227 self.events.fire_event("node-created", { node = node, actor = actor }); | 227 self.events.fire_event("node-created", { node = node, actor = actor }); |
| 228 local ok, err = self:set_affiliation(node, true, actor, "owner"); | 228 local ok, err = self:set_affiliation(node, true, actor, "owner"); |
| 229 if not ok then | 229 if not ok then |
| 230 self.nodes[node] = nil; | 230 self.nodes[node] = nil; |
| 231 self.data[node] = nil; | 231 self.data[node] = nil; |
| 248 self.events.fire_event("node-deleted", { node = node, actor = actor }); | 248 self.events.fire_event("node-deleted", { node = node, actor = actor }); |
| 249 self.config.broadcaster("delete", node, node_obj.subscribers); | 249 self.config.broadcaster("delete", node, node_obj.subscribers); |
| 250 return true; | 250 return true; |
| 251 end | 251 end |
| 252 | 252 |
| 253 local function remove_item_by_id(data, id) | |
| 254 if not data[id] then return end | |
| 255 data[id] = nil; | |
| 256 for i, _id in ipairs(data) do | |
| 257 if id == _id then | |
| 258 t_remove(data, i); | |
| 259 return i; | |
| 260 end | |
| 261 end | |
| 262 end | |
| 263 | |
| 264 local function trim_items(data, max) | |
| 265 max = tonumber(max); | |
| 266 if not max or #data <= max then return end | |
| 267 repeat | |
| 268 data[t_remove(data, 1)] = nil; | |
| 269 until #data <= max | |
| 270 end | |
| 271 | |
| 272 function service:publish(node, actor, id, item) | 253 function service:publish(node, actor, id, item) |
| 273 -- Access checking | 254 -- Access checking |
| 274 if not self:may(node, actor, "publish") then | 255 if not self:may(node, actor, "publish") then |
| 275 return false, "forbidden"; | 256 return false, "forbidden"; |
| 276 end | 257 end |
| 285 return ok, err; | 266 return ok, err; |
| 286 end | 267 end |
| 287 node_obj = self.nodes[node]; | 268 node_obj = self.nodes[node]; |
| 288 end | 269 end |
| 289 local node_data = self.data[node]; | 270 local node_data = self.data[node]; |
| 290 remove_item_by_id(node_data, id); | 271 local ok = node_data:set(id, item); |
| 291 node_data[#node_data + 1] = id; | 272 if not ok then |
| 292 node_data[id] = item; | 273 return nil, "internal-server-error"; |
| 293 trim_items(node_data, node_obj.config["pubsub#max_items"]); | 274 end |
| 294 self.events.fire_event("item-published", { node = node, actor = actor, id = id, item = item }); | 275 self.events.fire_event("item-published", { node = node, actor = actor, id = id, item = item }); |
| 295 self.config.broadcaster("items", node, node_obj.subscribers, item, actor); | 276 self.config.broadcaster("items", node, node_obj.subscribers, item, actor); |
| 296 return true; | 277 return true; |
| 297 end | 278 end |
| 298 | 279 |
| 301 if not self:may(node, actor, "retract") then | 282 if not self:may(node, actor, "retract") then |
| 302 return false, "forbidden"; | 283 return false, "forbidden"; |
| 303 end | 284 end |
| 304 -- | 285 -- |
| 305 local node_obj = self.nodes[node]; | 286 local node_obj = self.nodes[node]; |
| 306 if (not node_obj) or (not self.data[node][id]) then | 287 if (not node_obj) or (not self.data[node]:get(id)) then |
| 307 return false, "item-not-found"; | 288 return false, "item-not-found"; |
| 289 end | |
| 290 local ok = self.data[node]:set(id, nil); | |
| 291 if not ok then | |
| 292 return nil, "internal-server-error"; | |
| 308 end | 293 end |
| 309 self.events.fire_event("item-retracted", { node = node, actor = actor, id = id }); | 294 self.events.fire_event("item-retracted", { node = node, actor = actor, id = id }); |
| 310 remove_item_by_id(self.data[node], id); | |
| 311 if retract then | 295 if retract then |
| 312 self.config.broadcaster("items", node, node_obj.subscribers, retract); | 296 self.config.broadcaster("items", node, node_obj.subscribers, retract); |
| 313 end | 297 end |
| 314 return true | 298 return true |
| 315 end | 299 end |
| 322 -- | 306 -- |
| 323 local node_obj = self.nodes[node]; | 307 local node_obj = self.nodes[node]; |
| 324 if not node_obj then | 308 if not node_obj then |
| 325 return false, "item-not-found"; | 309 return false, "item-not-found"; |
| 326 end | 310 end |
| 327 self.data[node] = {}; -- Purge | 311 self.data[node] = self.config.itemstore(self.nodes[node].config); |
| 328 self.events.fire_event("node-purged", { node = node, actor = actor }); | 312 self.events.fire_event("node-purged", { node = node, actor = actor }); |
| 329 if notify then | 313 if notify then |
| 330 self.config.broadcaster("purge", node, node_obj.subscribers); | 314 self.config.broadcaster("purge", node, node_obj.subscribers); |
| 331 end | 315 end |
| 332 return true | 316 return true |
| 341 local node_obj = self.nodes[node]; | 325 local node_obj = self.nodes[node]; |
| 342 if not node_obj then | 326 if not node_obj then |
| 343 return false, "item-not-found"; | 327 return false, "item-not-found"; |
| 344 end | 328 end |
| 345 if id then -- Restrict results to a single specific item | 329 if id then -- Restrict results to a single specific item |
| 346 return true, { id, [id] = self.data[node][id] }; | 330 return true, { id, [id] = self.data[node]:get(id) }; |
| 347 else | 331 else |
| 348 return true, self.data[node]; | 332 local data = {} |
| 333 for key, value in self.data[node]:items() do | |
| 334 data[key] = value; | |
| 335 end | |
| 336 return true, data; | |
| 349 end | 337 end |
| 350 end | 338 end |
| 351 | 339 |
| 352 function service:get_nodes(actor) | 340 function service:get_nodes(actor) |
| 353 -- Access checking | 341 -- Access checking |
| 433 end | 421 end |
| 434 | 422 |
| 435 for k,v in pairs(new_config) do | 423 for k,v in pairs(new_config) do |
| 436 node_obj.config[k] = v; | 424 node_obj.config[k] = v; |
| 437 end | 425 end |
| 438 trim_items(self.data[node], node_obj.config["pubsub#max_items"]); | 426 local new_data = self.config.itemstore(self.nodes[node].config); |
| 439 | 427 for key, value in self.data[node]:items() do |
| 428 new_data:set(key, value); | |
| 429 end | |
| 430 self.data[node] = new_data; | |
| 440 return true; | 431 return true; |
| 441 end | 432 end |
| 442 | 433 |
| 443 return { | 434 return { |
| 444 new = new; | 435 new = new; |
