Mercurial > prosody-modules
comparison mod_xml_status/mod_xml_status.lua @ 524:ff3ea8735d61
mod_xml_status: initial commit. Expose server status in xml format to be used on external webapps.
| author | Marco Cirillo <maranda@lightwitch.org> |
|---|---|
| date | Fri, 06 Jan 2012 23:15:51 +0000 |
| parents | |
| children | a9cd75cc9563 |
comparison
equal
deleted
inserted
replaced
| 523:eff140d53b83 | 524:ff3ea8735d61 |
|---|---|
| 1 -- (C) 2011, Marco Cirillo (LW.Org) | |
| 2 -- Display server stats in readable XML format | |
| 3 | |
| 4 module:set_global() | |
| 5 | |
| 6 local ports = module:get_option_array("xml_status_http_ports", {{ port = 5280 }}) | |
| 7 local show_hosts = module:get_option_array("xml_status_show_hosts", nil) | |
| 8 local show_comps = module:get_option_array("xml_status_show_comps", nil) | |
| 9 | |
| 10 local httpserver = require "net.httpserver" | |
| 11 | |
| 12 -- code begin | |
| 13 | |
| 14 if not prosody.stanza_counter and not show_hosts and not show_comps then | |
| 15 module:log ("error", "mod_xml_status requires at least one of the following things:") | |
| 16 module:log ("error", "mod_stanza_counter loaded, or either xml_status_show_hosts or xml_status_show_comps configuration values set.") | |
| 17 module:log ("error", "check the module wiki at: http://code.google.com/p/prosody-modules/wiki/mod_xml_status") | |
| 18 return false | |
| 19 end | |
| 20 | |
| 21 local r_err = "\n<html>\n<head>\n<title>Prosody's XML Status - Error %s</title>\n<meta name=\"robots\" content=\"noindex, nofollow\" />\n</head>\n\n<body>\n<h3>%s</h3>\n</body>\n\n</html>\n" | |
| 22 | |
| 23 local response_table = {} | |
| 24 response_table.header = '<?xml version="1.0" encoding="UTF-8" ?>' | |
| 25 response_table.doc_header = '<document>' | |
| 26 response_table.doc_closure = '</document>' | |
| 27 response_table.stanzas = { | |
| 28 elem_header = ' <stanzas>', elem_closure = ' </stanzas>', | |
| 29 incoming = ' <incoming iq="%d" message="%d" presence="%d" />', | |
| 30 outgoing = ' <outgoing iq="%d" message="%d" presence="%d" />' | |
| 31 } | |
| 32 response_table.hosts = { | |
| 33 elem_header = ' <hosts>', elem_closure = ' </hosts>', | |
| 34 status = ' <status name="%s" current="%s" />' | |
| 35 } | |
| 36 response_table.comps = { | |
| 37 elem_header = ' <components>', elem_closure = ' </components>', | |
| 38 status = ' <status name="%s" current="%s" />' | |
| 39 } | |
| 40 | |
| 41 local function forge_response() | |
| 42 local hosts_s = {}; local components = {}; local stats = {}; local hosts_stats = {}; local comps_stats = {} | |
| 43 | |
| 44 -- add headers | |
| 45 local result = {}; result[#result+1] = response_table.header; result[#result+1] = response_table.doc_header | |
| 46 | |
| 47 if show_hosts then for _, name in ipairs(show_hosts) do hosts_s[#hosts_s+1] = name end end | |
| 48 if show_comps then for _, name in ipairs(show_comps) do components[#components+1] = name end end | |
| 49 | |
| 50 -- build stanza stats if there | |
| 51 if prosody.stanza_counter then | |
| 52 stats[1] = response_table.stanzas.elem_header | |
| 53 stats[2] = response_table.stanzas.incoming:format(prosody.stanza_counter.iq["incoming"], | |
| 54 prosody.stanza_counter.message["incoming"], | |
| 55 prosody.stanza_counter.presence["incoming"]) | |
| 56 stats[3] = response_table.stanzas.outgoing:format(prosody.stanza_counter.iq["outgoing"], | |
| 57 prosody.stanza_counter.message["outgoing"], | |
| 58 prosody.stanza_counter.presence["outgoing"]) | |
| 59 stats[4] = response_table.stanzas.elem_closure | |
| 60 end | |
| 61 | |
| 62 -- build hosts stats if there | |
| 63 if hosts_s[1] then | |
| 64 hosts_stats[1] = response_table.hosts.elem_header | |
| 65 for _, name in ipairs(hosts_s) do | |
| 66 hosts_stats[#hosts_stats+1] = response_table.hosts.status:format( | |
| 67 name, hosts[name] and "online" or "offline") | |
| 68 end | |
| 69 hosts_stats[#hosts_stats+1] = response_table.hosts.elem_closure | |
| 70 end | |
| 71 | |
| 72 -- build components stats if there | |
| 73 if components[1] then | |
| 74 comps_stats[1] = response_table.comps.elem_header | |
| 75 for _, name in ipairs(components) do | |
| 76 comps_stats[#comps_stats+1] = response_table.comps.status:format( | |
| 77 name, hosts[name].modules.component and hosts[name].modules.component.connected and "online" or | |
| 78 hosts[name] and hosts[name].modules.component == nil and "online" or "offline") | |
| 79 end | |
| 80 comps_stats[#comps_stats+1] = response_table.comps.elem_closure | |
| 81 end | |
| 82 | |
| 83 -- finish building xml stats document | |
| 84 for _, bstring in ipairs(stats) do result[#result+1] = bstring end | |
| 85 for _, bstring in ipairs(hosts_stats) do result[#result+1] = bstring end | |
| 86 for _, bstring in ipairs(comps_stats) do result[#result+1] = bstring end | |
| 87 result[#result+1] = response_table.doc_closure | |
| 88 | |
| 89 return table.concat(result, "\n") | |
| 90 end | |
| 91 | |
| 92 -- http handlers | |
| 93 | |
| 94 local function response(code, r, h) | |
| 95 local response = { | |
| 96 status = code; | |
| 97 body = r; | |
| 98 } | |
| 99 | |
| 100 if h then response.headers = h; end | |
| 101 return response | |
| 102 end | |
| 103 | |
| 104 local function request(method, body, request) | |
| 105 if not prosody.stanza_counter then | |
| 106 local err500 = r_err:format("500", "Internal server error") | |
| 107 return response(500, err500) end | |
| 108 if method == "GET" then | |
| 109 return response(200, forge_response()) | |
| 110 else | |
| 111 local err405 = r_err:format("405", "Only GET is supported") | |
| 112 return response(405, err405, {["Allow"] = "GET"}) | |
| 113 end | |
| 114 end | |
| 115 | |
| 116 -- initialization. | |
| 117 -- init http interface | |
| 118 local function setup() | |
| 119 httpserver.new_from_config(ports, request, { base = "xml-status" }) | |
| 120 end | |
| 121 | |
| 122 if prosody.start_time then | |
| 123 setup(); | |
| 124 else | |
| 125 module:hook("server-started", setup); | |
| 126 end |
