Mercurial > 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 |
| parents | e609da067e9f |
| children | 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 |
