Comparison

mod_muc_log/mod_muc_log.lua @ 62:0dfd65bfedb0

mod_muc_log: using datamanager to store the logging.
author Thilo Cestonaro <thilo@cestona.ro>
date Sun, 25 Oct 2009 14:21:30 +0100
parent 61:e609da067e9f
child 80:bed9a6b40fae
comparison
equal deleted inserted replaced
61:e609da067e9f 62:0dfd65bfedb0
7 local splitJid = require "util.jid".split; 7 local splitJid = require "util.jid".split;
8 local bareJid = require "util.jid".bare; 8 local bareJid = require "util.jid".bare;
9 local config_get = require "core.configmanager".get; 9 local config_get = require "core.configmanager".get;
10 local httpserver = require "net.httpserver"; 10 local httpserver = require "net.httpserver";
11 local serialize = require "util.serialization".serialize; 11 local serialize = require "util.serialization".serialize;
12 local datamanager = require "util.datamanager";
13 local data_load, data_store, data_getpath = datamanager.load, datamanager.store, datamanager.getpath;
14 local datastore = "muc_log";
12 local config = {}; 15 local config = {};
13 16
14 17
15 --[[ LuaFileSystem 18 --[[ LuaFileSystem
16 * URL: http://www.keplerproject.org/luafilesystem/index.html 19 * URL: http://www.keplerproject.org/luafilesystem/index.html
90 &nbsp;&nbsp;&nbsp;&nbsp;folder = "/opt/local/var/log/prosody/rooms";<br /> 93 &nbsp;&nbsp;&nbsp;&nbsp;folder = "/opt/local/var/log/prosody/rooms";<br />
91 &nbsp;&nbsp;&nbsp;&nbsp;http_port = "/opt/local/var/log/prosody/rooms";<br /> 94 &nbsp;&nbsp;&nbsp;&nbsp;http_port = "/opt/local/var/log/prosody/rooms";<br />
92 &nbsp;&nbsp;}<br /> 95 &nbsp;&nbsp;}<br />
93 ]]; 96 ]];
94 97
95 function validateLogFolder() 98 local function ensureDatastorePathExists(node, host, today)
96 if config.folder == nil then 99 local path = data_getpath(node, host, datastore, "dat", true);
97 module:log("warn", "muc_log folder isn't configured. configure it please!"); 100 path = path:gsub("/[^/]*$", "");
101
102 -- check existance
103 local attributes = lfs.attributes(path);
104 if attributes.mode ~= "directory" then
105 module:log("warn", "muc_log folder isn't a folder: %s", path);
98 return false; 106 return false;
99 end 107 end
100 108
101 -- check existance 109 attributes = lfs.attributes(path .. "/" .. today);
102 local attributes = lfs.attributes(config.folder);
103 if attributes == nil then 110 if attributes == nil then
104 module:log("warn", "muc_log folder doesn't exist. create it please!"); 111 return lfs.mkdir(path .. "/" .. today);
105 return false; 112 elseif attributes.mode == "directory" then
106 elseif attributes.mode ~= "directory" then 113 return true;
107 module:log("warn", "muc_log folder isn't a folder, it's a %s. change this please!", attributes.mode); 114 end
108 return false; 115 return false;
109 end --TODO: check for write rights!
110
111 return true;
112 end 116 end
113 117
114 function logIfNeeded(e) 118 function logIfNeeded(e)
115 local stanza, origin = e.stanza, e.origin; 119 local stanza, origin = e.stanza, e.origin;
116 if validateLogFolder() == false then
117 return;
118 end
119 120
120 if (stanza.name == "presence") or 121 if (stanza.name == "presence") or
121 (stanza.name == "iq") or 122 (stanza.name == "iq") or
122 (stanza.name == "message" and tostring(stanza.attr.type) == "groupchat") 123 (stanza.name == "message" and tostring(stanza.attr.type) == "groupchat")
123 then 124 then
126 local bare = node .. "@" .. host; 127 local bare = node .. "@" .. host;
127 if prosody.hosts[host] ~= nil and prosody.hosts[host].muc ~= nil and prosody.hosts[host].muc.rooms[bare] ~= nil then 128 if prosody.hosts[host] ~= nil and prosody.hosts[host].muc ~= nil and prosody.hosts[host].muc.rooms[bare] ~= nil then
128 local room = prosody.hosts[host].muc.rooms[bare] 129 local room = prosody.hosts[host].muc.rooms[bare]
129 local today = os.date("%y%m%d"); 130 local today = os.date("%y%m%d");
130 local now = os.date("%X") 131 local now = os.date("%X")
131 local fn = config.folder .. "/" .. today .. "_" .. bare .. ".log";
132 local mucTo = nil 132 local mucTo = nil
133 local mucFrom = nil; 133 local mucFrom = nil;
134 local alreadyJoined = false; 134 local alreadyJoined = false;
135 135
136 if stanza.name == "presence" and stanza.attr.type == nil then 136 if stanza.name == "presence" and stanza.attr.type == nil then
143 if stanza.tags[1] ~= nil and stanza.tags[1].name == "query" then 143 if stanza.tags[1] ~= nil and stanza.tags[1].name == "query" then
144 local tmp = stanza.tags[1]; 144 local tmp = stanza.tags[1];
145 if tmp.tags[1] ~= nil and tmp.tags[1].name == "item" and tmp.tags[1].attr.nick ~= nil then 145 if tmp.tags[1] ~= nil and tmp.tags[1].name == "item" and tmp.tags[1].attr.nick ~= nil then
146 tmp = tmp.tags[1]; 146 tmp = tmp.tags[1];
147 for jid, nick in pairs(room._jid_nick) do 147 for jid, nick in pairs(room._jid_nick) do
148 module:log("debug", "%s == %s", nick, stanza.attr.to .. "/" .. tmp.attr.nick)
149 if nick == stanza.attr.to .. "/" .. tmp.attr.nick then 148 if nick == stanza.attr.to .. "/" .. tmp.attr.nick then
150 mucTo = nick; 149 mucTo = nick;
151 break; 150 break;
152 end 151 end
153 end 152 end
160 break; 159 break;
161 end 160 end
162 end 161 end
163 end 162 end
164 163
165 if mucFrom ~= nil or mucTo ~= nil then 164 if (mucFrom ~= nil or mucTo ~= nil) and ensureDatastorePathExists(node, host, today) then
166 module:log("debug", "try to open room log: %s", fn); 165 local data = data_load(node, host, datastore .. "/" .. today);
167 local f = assert(io.open(fn, "a"));
168 local realFrom = stanza.attr.from; 166 local realFrom = stanza.attr.from;
169 local realTo = stanza.attr.to; 167 local realTo = stanza.attr.to;
168
169 if data == nil then
170 data = {};
171 end
172
170 stanza.attr.from = mucFrom; 173 stanza.attr.from = mucFrom;
171 stanza.attr.to = mucTo; 174 stanza.attr.to = mucTo;
172 f:write("<stanza time=\"".. now .. "\">" .. tostring(stanza) .. "</stanza>\n"); 175 data[#data + 1] = "<stanza time=\"".. now .. "\">" .. tostring(stanza) .. "</stanza>\n";
173 stanza.attr.from = realFrom; 176 stanza.attr.from = realFrom;
174 stanza.attr.to = realTo; 177 stanza.attr.to = realTo;
175 if alreadyJoined == true then 178 if alreadyJoined == true then
176 if stanza[#stanza].name == "alreadyJoined" then -- normaly the faked element should be the last, remove it when it is the last 179 if stanza[#stanza].name == "alreadyJoined" then -- normaly the faked element should be the last, remove it when it is the last
177 stanza[#stanza] = nil; 180 stanza[#stanza] = nil;
182 break; 185 break;
183 end 186 end
184 end 187 end
185 end 188 end
186 end 189 end
187 f:close() 190 data_store(node, host, datastore .. "/" .. today, data);
188 end 191 end
189 end 192 end
190 end 193 end
191 else
192 module:log("debug", serialize(stanza));
193 end 194 end
194 return; 195 return;
195 end 196 end
196 197
197 function createDoc(body) 198 function createDoc(body)
258 end 259 end
259 260
260 local function generateDayListSiteContentByRoom(bareRoomJid) 261 local function generateDayListSiteContentByRoom(bareRoomJid)
261 local days = ""; 262 local days = "";
262 local tmp; 263 local tmp;
263 264 local node, host, resource = splitJid(bareRoomJid);
264 for file in lfs.dir(config.folder) do 265 local path = data_getpath(node, host, datastore);
265 local year, month, day = file:match("^(%d%d)(%d%d)(%d%d)_" .. bareRoomJid .. ".log"); 266 path = path:gsub("/[^/]*$", "");
267 for file in lfs.dir(path) do
268 local year, month, day = file:match("^(%d%d)(%d%d)(%d%d)");
266 if year ~= nil and month ~= nil and day ~= nil and 269 if year ~= nil and month ~= nil and day ~= nil and
267 year ~= "" and month ~= "" and day ~= "" 270 year ~= "" and month ~= "" and day ~= ""
268 then 271 then
269 tmp = html.days.bit; 272 tmp = html.days.bit;
270 tmp = tmp:gsub("###JID###", bareRoomJid); 273 tmp = tmp:gsub("###JID###", bareRoomJid);
280 end 283 end
281 end 284 end
282 285
283 local function parseIqStanza(stanza, timeStuff, nick) 286 local function parseIqStanza(stanza, timeStuff, nick)
284 local text = nil; 287 local text = nil;
285 -- module:log("debug", serialize(stanza));
286 for _,tag in ipairs(stanza) do 288 for _,tag in ipairs(stanza) do
287 if tag.tag == "query" then 289 if tag.tag == "query" then
288 for _,item in ipairs(tag) do 290 for _,item in ipairs(tag) do
289 if item.tag == "item" then 291 if item.tag == "item" then
290 for _,reason in ipairs(item) do 292 for _,reason in ipairs(item) do
375 local ret = ""; 377 local ret = "";
376 local year; 378 local year;
377 local month; 379 local month;
378 local day; 380 local day;
379 local tmp; 381 local tmp;
382 local node, host, resource = splitJid(bareRoomJid);
380 383
381 if query.year ~= nil and query.month ~= nil and query.day ~= nil then 384 if query.year ~= nil and query.month ~= nil and query.day ~= nil then
382 local file = config.folder .. "/" .. query.year .. query.month .. query.day .. "_" .. bareRoomJid .. ".log"; 385 local data = data_load(node, host, datastore .. "/" .. query.year .. query.month .. query.day);
383 local f, err = io.open(file, "r"); 386 if data ~= nil then
384 if f ~= nil then 387 for i=1, #data, 1 do
385 local content = f:read("*a"); 388 local stanza = lom.parse(data[i]);
386 local parsed = lom.parse("<xml>" .. content .. "</xml>"); 389 if stanza ~= nil and stanza.attr ~= nil and stanza.attr.time ~= nil then
387 f:close(); 390 local timeStuff = html.day.time:gsub("###TIME###", stanza.attr.time);
388 if parsed ~= nil then 391 if stanza[1] ~= nil then
389 for _,stanza in ipairs(parsed) do 392 local nick;
390 if stanza.attr ~= nil and stanza.attr.time ~= nil then 393
391 local timeStuff = html.day.time:gsub("###TIME###", stanza.attr.time); 394 -- grep nick from "from" resource
392 if stanza[1] ~= nil then 395 if stanza[1].attr.from ~= nil then -- presence and messages
393 local nick; 396 nick = htmlEscape(stanza[1].attr.from:match("/(.+)$"));
394 397 elseif stanza[1].attr.to ~= nil then -- iq
395 -- grep nick from "from" resource 398 nick = htmlEscape(stanza[1].attr.to:match("/(.+)$"));
396 if stanza[1].attr.from ~= nil then -- presence and messages 399 end
397 nick = htmlEscape(stanza[1].attr.from:match("/(.+)$")); 400
398 elseif stanza[1].attr.to ~= nil then -- iq 401 if stanza[1].tag == "presence" and nick ~= nil then
399 nick = htmlEscape(stanza[1].attr.to:match("/(.+)$")); 402 ret = ret .. parsePresenceStanza(stanza[1], timeStuff, nick);
400 end 403 elseif stanza[1].tag == "message" then
401 404 ret = ret .. parseMessageStanza(stanza[1], timeStuff, nick);
402 if stanza[1].tag == "presence" and nick ~= nil then 405 elseif stanza[1].tag == "iq" then
403 ret = ret .. parsePresenceStanza(stanza[1], timeStuff, nick); 406 ret = ret .. parseIqStanza(stanza[1], timeStuff, nick);
404 elseif stanza[1].tag == "message" then 407 else
405 ret = ret .. parseMessageStanza(stanza[1], timeStuff, nick); 408 module:log("info", "unknown stanza subtag in log found. room: %s; day: %s", bareRoomJid, query.year .. "/" .. query.month .. "/" .. query.day);
406 elseif stanza[1].tag == "iq" then
407 ret = ret .. parseIqStanza(stanza[1], timeStuff, nick);
408 else
409 module:log("info", "unknown stanza subtag in log found. room: %s; day: %s", bareRoomJid, query.year .. "/" .. query.month .. "/" .. query.day);
410 end
411 end 409 end
412 end 410 end
413 end 411 end
414 else
415 module:log("warn", "could not parse room log. room: %s; day: %s", bareRoomJid, query.year .. "/" .. query.month .. "/" .. query.day);
416 end 412 end
417 else 413 else
418 return generateDayListSiteContentByRoom(bareRoomJid); -- fallback 414 return generateDayListSiteContentByRoom(bareRoomJid); -- fallback
419 end 415 end
420 tmp = html.day.body:gsub("###DAY_STUFF###", ret):gsub("###JID###", bareRoomJid); 416 tmp = html.day.body:gsub("###DAY_STUFF###", ret):gsub("###JID###", bareRoomJid);
428 424
429 function handle_request(method, body, request) 425 function handle_request(method, body, request)
430 local query = splitQuery(request.url.query); 426 local query = splitQuery(request.url.query);
431 local node, host = grepRoomJid(request.url.path); 427 local node, host = grepRoomJid(request.url.path);
432 428
433 if validateLogFolder() == false then
434 return createDoc(html.help);
435 end
436 if node ~= nil and host ~= nil then 429 if node ~= nil and host ~= nil then
437 local bare = node .. "@" .. host; 430 local bare = node .. "@" .. host;
438 if prosody.hosts[host] ~= nil and prosody.hosts[host].muc ~= nil and prosody.hosts[host].muc.rooms[bare] ~= nil then 431 if prosody.hosts[host] ~= nil and prosody.hosts[host].muc ~= nil and prosody.hosts[host].muc.rooms[bare] ~= nil then
439 local room = prosody.hosts[host].muc.rooms[bare]; 432 local room = prosody.hosts[host].muc.rooms[bare];
440 if request.url.query == nil then 433 if request.url.query == nil then