Comparison

plugins/muc/mod_muc.lua @ 7370:0ebc7ff1fff5

MUC: Switch to util.cache for storing rooms, store rooms to disk on eviction
author Kim Alvefur <zash@zash.se>
date Mon, 18 Apr 2016 19:18:37 +0200
parent 7367:2aef5e8b69e9
child 7371:d5ba0dec0c95
comparison
equal deleted inserted replaced
7369:c5cae59831d7 7370:0ebc7ff1fff5
59 local history = module:require "muc/history"; 59 local history = module:require "muc/history";
60 room_mt.send_history = history.send; 60 room_mt.send_history = history.send;
61 room_mt.get_historylength = history.get_length; 61 room_mt.get_historylength = history.get_length;
62 room_mt.set_historylength = history.set_length; 62 room_mt.set_historylength = history.set_length;
63 63
64 local iterators = require "util.iterators";
65 local jid_split = require "util.jid".split; 64 local jid_split = require "util.jid".split;
66 local jid_bare = require "util.jid".bare; 65 local jid_bare = require "util.jid".bare;
67 local st = require "util.stanza"; 66 local st = require "util.stanza";
67 local cache = require "util.cache";
68 local um_is_admin = require "core.usermanager".is_admin; 68 local um_is_admin = require "core.usermanager".is_admin;
69
70 local rooms = module:shared "rooms";
71 69
72 module:depends("disco"); 70 module:depends("disco");
73 module:add_identity("conference", "text", module:get_option_string("name", "Prosody Chatrooms")); 71 module:add_identity("conference", "text", module:get_option_string("name", "Prosody Chatrooms"));
74 module:add_feature("http://jabber.org/protocol/muc"); 72 module:add_feature("http://jabber.org/protocol/muc");
75 module:depends "muc_unique" 73 module:depends "muc_unique"
98 local room_configs = module:open_store("config"); 96 local room_configs = module:open_store("config");
99 97
100 local function room_save(room, forced) 98 local function room_save(room, forced)
101 local node = jid_split(room.jid); 99 local node = jid_split(room.jid);
102 local is_persistent = persistent.get(room); 100 local is_persistent = persistent.get(room);
103 persistent_rooms:set(nil, room.jid, is_persistent); 101 if is_persistent or forced then
104 if is_persistent then 102 persistent_rooms:set(nil, room.jid, true);
105 local data = room:freeze(); 103 local data = room:freeze(forced);
106 room_configs:set(node, data); 104 return room_configs:set(node, data);
107 elseif forced then 105 else
108 room_configs:set(node, nil); 106 persistent_rooms:set(nil, room.jid, nil);
109 if not next(room._occupants) then -- Room empty 107 return room_configs:set(node, nil);
110 rooms[room.jid] = nil; 108 end
111 end 109 end
112 end 110
113 end 111 local rooms = cache.new(module:get_option_number("muc_room_cache_size", 100), function (_, room)
112 module:log("debug", "%s evicted", room);
113 room_save(room, true); -- Force to disk
114 end);
114 115
115 -- Automatically destroy empty non-persistent rooms 116 -- Automatically destroy empty non-persistent rooms
116 module:hook("muc-occupant-left",function(event) 117 module:hook("muc-occupant-left",function(event)
117 local room = event.room 118 local room = event.room
118 if not room:has_occupant() and not persistent.get(room) then -- empty, non-persistent room 119 if not room:has_occupant() and not persistent.get(room) then -- empty, non-persistent room
119 module:fire_event("muc-room-destroyed", { room = room }); 120 module:fire_event("muc-room-destroyed", { room = room });
120 end 121 end
121 end); 122 end);
122 123
123 function track_room(room) 124 function track_room(room)
124 rooms[room.jid] = room; 125 rooms:set(room.jid, room);
125 -- When room is created, over-ride 'save' method 126 -- When room is created, over-ride 'save' method
126 room.save = room_save; 127 room.save = room_save;
127 end 128 end
128 129
129 local function restore_room(jid) 130 local function restore_room(jid)
135 return room; 136 return room;
136 end 137 end
137 end 138 end
138 139
139 function forget_room(room) 140 function forget_room(room)
140 local room_jid = room.jid; 141 module:log("debug", "Forgetting %s", room);
141 local node = jid_split(room.jid); 142 rooms.save = nil;
142 rooms[room_jid] = nil; 143 rooms:set(room.jid, nil);
143 room_configs:set(node, nil); 144 end
144 if persistent.get(room) then 145
145 persistent_rooms:set(nil, room_jid, nil); 146 function delete_room(room)
147 module:log("debug", "Deleting %s", room);
148 room_configs:set(jid_split(room.jid), nil);
149 persistent_rooms:set(nil, room.jid, nil);
150 end
151
152 function module.unload()
153 for room in rooms:values() do
154 room:save(true);
155 forget_room(room);
146 end 156 end
147 end 157 end
148 158
149 function get_room_from_jid(room_jid) 159 function get_room_from_jid(room_jid)
150 local room = rooms[room_jid]; 160 local room = rooms:get(room_jid);
151 if room == nil then 161 if room then
152 -- Check if in persistent storage 162 rooms:set(room_jid, room); -- bump to top;
153 if persistent_rooms:get(nil, room_jid) then 163 return room;
154 room = restore_room(room_jid); 164 end
155 if room == nil then 165 return restore_room(room_jid);
156 module:log("error", "Missing data for room '%s', removing from persistent room list", room_jid);
157 persistent_rooms:set(nil, room_jid, nil);
158 end
159 end
160 end
161 return room
162 end 166 end
163 167
164 function each_room(local_only) 168 function each_room(local_only)
165 if not local_only then 169 if local_only then
170 return rooms:values();
171 end
172 return coroutine.wrap(function ()
173 local seen = {}; -- Don't iterate over persistent rooms twice
174 for room in rooms:values() do
175 coroutine.yield(room);
176 seen[room.jid] = true;
177 end
166 for room_jid in pairs(persistent_rooms_storage:get(nil) or {}) do 178 for room_jid in pairs(persistent_rooms_storage:get(nil) or {}) do
167 if rooms[room_jid] == nil then -- Don't restore rooms that already exist 179 if seen[room_jid] then
168 local room = restore_room(room_jid); 180 local room = restore_room(room_jid);
169 if room == nil then 181 if room == nil then
170 module:log("error", "Missing data for room '%s', omitting from iteration", room_jid); 182 module:log("error", "Missing data for room '%s', omitting from iteration", room_jid);
183 else
184 coroutine.yield(room);
171 end 185 end
172 end 186 end
173 end 187 end
174 end 188 end);
175 return iterators.values(rooms);
176 end 189 end
177 190
178 module:hook("host-disco-items", function(event) 191 module:hook("host-disco-items", function(event)
179 local reply = event.reply; 192 local reply = event.reply;
180 module:log("debug", "host-disco-items called"); 193 module:log("debug", "host-disco-items called");
188 module:hook("muc-room-pre-create", function(event) 201 module:hook("muc-room-pre-create", function(event)
189 track_room(event.room); 202 track_room(event.room);
190 end, -1000); 203 end, -1000);
191 204
192 module:hook("muc-room-destroyed",function(event) 205 module:hook("muc-room-destroyed",function(event)
193 return forget_room(event.room); 206 local room = event.room;
194 end) 207 forget_room(room);
208 delete_room(room);
209 end);
195 210
196 do 211 do
197 local restrict_room_creation = module:get_option("restrict_room_creation"); 212 local restrict_room_creation = module:get_option("restrict_room_creation");
198 if restrict_room_creation == true then 213 if restrict_room_creation == true then
199 restrict_room_creation = "admin"; 214 restrict_room_creation = "admin";