X-Git-Url: https://git.enpas.org/?a=blobdiff_plain;f=util%2Fpubsub.lua;h=fc67cb1fda5767b492c4e4c02180ab5cb2ff2da1;hb=95dfe4b0aaaf26ee4651c09eb9757c56210a135a;hp=3beafab52c423f778af7e3d2729867b238834f9c;hpb=898fc1ff90e3c6244bbe8e88b5c533cde30bb588;p=prosody.git diff --git a/util/pubsub.lua b/util/pubsub.lua index 3beafab5..fc67cb1f 100644 --- a/util/pubsub.lua +++ b/util/pubsub.lua @@ -1,3 +1,6 @@ +local events = require "util.events"; +local t_remove = table.remove; + module("pubsub", package.seeall); local service = {}; @@ -16,6 +19,8 @@ function new(config) affiliations = {}; subscriptions = {}; nodes = {}; + data = {}; + events = events.new(); }, service_mt); end @@ -26,18 +31,15 @@ end function service:may(node, actor, action) if actor == true then return true; end - - + local node_obj = self.nodes[node]; local node_aff = node_obj and node_obj.affiliations[actor]; local service_aff = self.affiliations[actor] or self.config.get_affiliation(actor, node, action) or "none"; - + + -- Check if node allows/forbids it local node_capabilities = node_obj and node_obj.capabilities; - local service_capabilities = self.config.capabilities; - - -- Check if node allows/forbids it if node_capabilities then local caps = node_capabilities[node_aff or service_aff]; if caps then @@ -47,7 +49,9 @@ function service:may(node, actor, action) end end end + -- Check service-wide capabilities instead + local service_capabilities = self.config.capabilities; local caps = service_capabilities[node_aff or service_aff]; if caps then local can = caps[action]; @@ -55,7 +59,7 @@ function service:may(node, actor, action) return can; end end - + return false; end @@ -70,14 +74,14 @@ function service:set_affiliation(node, actor, jid, affiliation) return false, "item-not-found"; end node_obj.affiliations[jid] = affiliation; - local _, jid_sub = self:get_subscription(node, nil, jid); + local _, jid_sub = self:get_subscription(node, true, jid); if not jid_sub and not self:may(node, jid, "be_unsubscribed") then - local ok, err = self:add_subscription(node, nil, jid); + local ok, err = self:add_subscription(node, true, jid); if not ok then return ok, err; end elseif jid_sub and not self:may(node, jid, "be_subscribed") then - local ok, err = self:add_subscription(node, nil, jid); + local ok, err = self:add_subscription(node, true, jid); if not ok then return ok, err; end @@ -88,7 +92,7 @@ end function service:add_subscription(node, actor, jid, options) -- Access checking local cap; - if jid == actor or self:jids_equal(actor, jid) then + if actor == true or jid == actor or self:jids_equal(actor, jid) then cap = "subscribe"; else cap = "subscribe_other"; @@ -105,7 +109,7 @@ function service:add_subscription(node, actor, jid, options) if not self.config.autocreate_on_subscribe then return false, "item-not-found"; else - local ok, err = self:create(node, actor); + local ok, err = self:create(node, true); if not ok then return ok, err; end @@ -124,13 +128,14 @@ function service:add_subscription(node, actor, jid, options) else self.subscriptions[normal_jid] = { [jid] = { [node] = true } }; end + self.events.fire_event("subscription-added", { node = node, jid = jid, normalized_jid = normal_jid, options = options }); return true; end function service:remove_subscription(node, actor, jid) -- Access checking local cap; - if jid == actor or self:jids_equal(actor, jid) then + if actor == true or jid == actor or self:jids_equal(actor, jid) then cap = "unsubscribe"; else cap = "unsubscribe_other"; @@ -164,13 +169,26 @@ function service:remove_subscription(node, actor, jid) self.subscriptions[normal_jid] = nil; end end + self.events.fire_event("subscription-removed", { node = node, jid = jid, normalized_jid = normal_jid }); + return true; +end + +function service:remove_all_subscriptions(actor, jid) + local normal_jid = self.config.normalize_jid(jid); + local subs = self.subscriptions[normal_jid] + subs = subs and subs[jid]; + if subs then + for node in pairs(subs) do + self:remove_subscription(node, true, jid); + end + end return true; end function service:get_subscription(node, actor, jid) -- Access checking local cap; - if jid == actor or self:jids_equal(actor, jid) then + if actor == true or jid == actor or self:jids_equal(actor, jid) then cap = "get_subscription"; else cap = "get_subscription_other"; @@ -195,21 +213,52 @@ function service:create(node, actor) if self.nodes[node] then return false, "conflict"; end - + + self.data[node] = {}; self.nodes[node] = { name = node; subscribers = {}; config = {}; - data = {}; affiliations = {}; }; + setmetatable(self.nodes[node], { __index = { data = self.data[node] } }); -- COMPAT + self.events.fire_event("node-created", { node = node, actor = actor }); local ok, err = self:set_affiliation(node, true, actor, "owner"); if not ok then self.nodes[node] = nil; + self.data[node] = nil; end return ok, err; end +function service:delete(node, actor) + -- Access checking + if not self:may(node, actor, "delete") then + return false, "forbidden"; + end + -- + local node_obj = self.nodes[node]; + if not node_obj then + return false, "item-not-found"; + end + self.nodes[node] = nil; + self.data[node] = nil; + self.events.fire_event("node-deleted", { node = node, actor = actor }); + self.config.broadcaster("delete", node, node_obj.subscribers); + return true; +end + +local function remove_item_by_id(data, id) + if not data[id] then return end + data[id] = nil; + for i, _id in ipairs(data) do + if id == _id then + t_remove(data, i); + return i; + end + end +end + function service:publish(node, actor, id, item) -- Access checking if not self:may(node, actor, "publish") then @@ -221,14 +270,18 @@ function service:publish(node, actor, id, item) if not self.config.autocreate_on_publish then return false, "item-not-found"; end - local ok, err = self:create(node, actor); + local ok, err = self:create(node, true); if not ok then return ok, err; end node_obj = self.nodes[node]; end - node_obj.data[id] = item; - self.config.broadcaster(node, node_obj.subscribers, item); + local node_data = self.data[node]; + remove_item_by_id(node_data, id); + node_data[#self.data[node] + 1] = id; + node_data[id] = item; + self.events.fire_event("item-published", { node = node, actor = actor, id = id, item = item }); + self.config.broadcaster("items", node, node_obj.subscribers, item); return true; end @@ -239,12 +292,31 @@ function service:retract(node, actor, id, retract) end -- local node_obj = self.nodes[node]; - if (not node_obj) or (not node_obj.data[id]) then + if (not node_obj) or (not self.data[node][id]) then return false, "item-not-found"; end - node_obj.data[id] = nil; + self.events.fire_event("item-retracted", { node = node, actor = actor, id = id }); + remove_item_by_id(self.data[node], id); if retract then - self.config.broadcaster(node, node_obj.subscribers, retract); + self.config.broadcaster("items", node, node_obj.subscribers, retract); + end + return true +end + +function service:purge(node, actor, notify) + -- Access checking + if not self:may(node, actor, "retract") then + return false, "forbidden"; + end + -- + local node_obj = self.nodes[node]; + if not node_obj then + return false, "item-not-found"; + end + self.data[node] = {}; -- Purge + self.events.fire_event("node-purged", { node = node, actor = actor }); + if notify then + self.config.broadcaster("purge", node, node_obj.subscribers); end return true end @@ -260,9 +332,9 @@ function service:get_items(node, actor, id) return false, "item-not-found"; end if id then -- Restrict results to a single specific item - return true, { [id] = node_obj.data[id] }; + return true, { id, [id] = self.data[node][id] }; else - return true, node_obj.data; + return true, self.data[node]; end end @@ -278,7 +350,7 @@ end function service:get_subscriptions(node, actor, jid) -- Access checking local cap; - if jid == actor or self:jids_equal(actor, jid) then + if actor == true or jid == actor or self:jids_equal(actor, jid) then cap = "get_subscriptions"; else cap = "get_subscriptions_other"; @@ -304,7 +376,7 @@ function service:get_subscriptions(node, actor, jid) if node then -- Return only subscriptions to this node if subscribed_nodes[node] then ret[#ret+1] = { - node = subscribed_node; + node = node; jid = jid; subscription = node_obj.subscribers[jid]; };