X-Git-Url: https://git.enpas.org/?a=blobdiff_plain;f=plugins%2Fmuc%2Fmod_muc.lua;h=657823383481f95abe63c31c45a746d331970ab2;hb=6efbd878b200c87080a4121283809df8f882bbba;hp=7ecd649051974b843f8ea710b90174706fa82d2a;hpb=987e2bf92d9d2ff695af42cfaf450ace1c511f6f;p=prosody.git diff --git a/plugins/muc/mod_muc.lua b/plugins/muc/mod_muc.lua index 7ecd6490..65782338 100644 --- a/plugins/muc/mod_muc.lua +++ b/plugins/muc/mod_muc.lua @@ -61,14 +61,12 @@ room_mt.send_history = history.send; room_mt.get_historylength = history.get_length; room_mt.set_historylength = history.set_length; -local iterators = require "util.iterators"; local jid_split = require "util.jid".split; local jid_bare = require "util.jid".bare; local st = require "util.stanza"; +local cache = require "util.cache"; local um_is_admin = require "core.usermanager".is_admin; -local rooms = module:shared "rooms"; - module:depends("disco"); module:add_identity("conference", "text", module:get_option_string("name", "Prosody Chatrooms")); module:add_feature("http://jabber.org/protocol/muc"); @@ -97,25 +95,27 @@ local persistent_rooms_storage = module:open_store("persistent"); local persistent_rooms = module:open_store("persistent", "map"); local room_configs = module:open_store("config"); +local room_items_cache = {}; + local function room_save(room, forced) local node = jid_split(room.jid); local is_persistent = persistent.get(room); - persistent_rooms:set(nil, room.jid, is_persistent); - if is_persistent then - local data = { - jid = room.jid; - _data = room._data; - _affiliations = room._affiliations; - }; - room_configs:set(node, data); - elseif forced then - room_configs:set(node, nil); - if not next(room._occupants) then -- Room empty - rooms[room.jid] = nil; - end + room_items_cache[room.jid] = room:get_public() and room:get_name() or nil; + if is_persistent or forced then + persistent_rooms:set(nil, room.jid, true); + local data = room:freeze(forced); + return room_configs:set(node, data); + else + persistent_rooms:set(nil, room.jid, nil); + return room_configs:set(node, nil); end end +local rooms = cache.new(module:get_option_number("muc_room_cache_size", 100), function (_, room) + module:log("debug", "%s evicted", room); + room_save(room, true); -- Force to disk +end); + -- Automatically destroy empty non-persistent rooms module:hook("muc-occupant-left",function(event) local room = event.room @@ -125,7 +125,7 @@ module:hook("muc-occupant-left",function(event) end); function track_room(room) - rooms[room.jid] = room; + rooms:set(room.jid, room); -- When room is created, over-ride 'save' method room.save = room_save; end @@ -134,59 +134,78 @@ local function restore_room(jid) local node = jid_split(jid); local data = room_configs:get(node); if data then - local room = muclib.new_room(jid); - room._data = data._data; - room._affiliations = data._affiliations; + local room = muclib.restore_room(data); track_room(room); return room; end end function forget_room(room) - local room_jid = room.jid; - local node = jid_split(room.jid); - rooms[room_jid] = nil; - room_configs:set(node, nil); - if persistent.get(room) then - persistent_rooms:set(nil, room_jid, nil); + module:log("debug", "Forgetting %s", room); + rooms.save = nil; + rooms:set(room.jid, nil); +end + +function delete_room(room) + module:log("debug", "Deleting %s", room); + room_configs:set(jid_split(room.jid), nil); + persistent_rooms:set(nil, room.jid, nil); + room_items_cache[room.jid] = nil; +end + +function module.unload() + for room in rooms:values() do + room:save(true); + forget_room(room); end end function get_room_from_jid(room_jid) - local room = rooms[room_jid]; - if room == nil then - -- Check if in persistent storage - if persistent_rooms:get(nil, room_jid) then - room = restore_room(room_jid); - if room == nil then - module:log("error", "Missing data for room '%s', removing from persistent room list", room_jid); - persistent_rooms:set(nil, room_jid, nil); - end - end + local room = rooms:get(room_jid); + if room then + rooms:set(room_jid, room); -- bump to top; + return room; end - return room + return restore_room(room_jid); end function each_room(local_only) - if not local_only then + if local_only then + return rooms:values(); + end + return coroutine.wrap(function () + local seen = {}; -- Don't iterate over persistent rooms twice + for room in rooms:values() do + coroutine.yield(room); + seen[room.jid] = true; + end for room_jid in pairs(persistent_rooms_storage:get(nil) or {}) do - if rooms[room_jid] == nil then -- Don't restore rooms that already exist + if not seen[room_jid] then local room = restore_room(room_jid); if room == nil then module:log("error", "Missing data for room '%s', omitting from iteration", room_jid); + else + coroutine.yield(room); end end end - end - return iterators.values(rooms); + end); end module:hook("host-disco-items", function(event) local reply = event.reply; module:log("debug", "host-disco-items called"); - for room in each_room() do - if not room:get_hidden() then - reply:tag("item", {jid=room.jid, name=room:get_name()}):up(); + if next(room_items_cache) ~= nil then + for jid, room_name in pairs(room_items_cache) do + reply:tag("item", { jid = jid, name = room_name }):up(); + end + else + for room in each_room() do + if not room:get_hidden() then + local jid, room_name = room.jid, room:get_name(); + room_items_cache[jid] = room_name; + reply:tag("item", { jid = jid, name = room_name }):up(); + end end end end); @@ -196,8 +215,10 @@ module:hook("muc-room-pre-create", function(event) end, -1000); module:hook("muc-room-destroyed",function(event) - return forget_room(event.room); -end) + local room = event.room; + forget_room(room); + delete_room(room); +end); do local restrict_room_creation = module:get_option("restrict_room_creation"); @@ -252,6 +273,7 @@ for event_name, method in pairs { -- Watch presence to create rooms if stanza.attr.type == nil and stanza.name == "presence" then room = muclib.new_room(room_jid); + return room:handle_first_presence(origin, stanza); elseif stanza.attr.type ~= "error" then origin.send(st.error_reply(stanza, "cancel", "not-allowed")); return true; @@ -264,10 +286,8 @@ for event_name, method in pairs { end function shutdown_component() - local x = st.stanza("x", {xmlns = "http://jabber.org/protocol/muc#user"}) - :tag("status", { code = "332"}):up(); for room in each_room(true) do - room:clear(x); + room:save(true); end end module:hook_global("server-stopping", shutdown_component);