Software /
code /
prosody-modules
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 folder = "/opt/local/var/log/prosody/rooms";<br /> | 93 folder = "/opt/local/var/log/prosody/rooms";<br /> |
91 http_port = "/opt/local/var/log/prosody/rooms";<br /> | 94 http_port = "/opt/local/var/log/prosody/rooms";<br /> |
92 }<br /> | 95 }<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 |