Mercurial > prosody-modules
comparison mod_pubsub_feed/mod_pubsub_feed.lua @ 403:fc62b26dfdf6
mod_pubsub_feed: Major cleanup, and use newer APIs. (Thanks Maranda)
| author | Kim Alvefur <zash@zash.se> |
|---|---|
| date | Thu, 25 Aug 2011 01:21:42 +0200 |
| parents | c92a37a72b25 |
| children | fe4fdba21a23 |
comparison
equal
deleted
inserted
replaced
| 402:c92a37a72b25 | 403:fc62b26dfdf6 |
|---|---|
| 24 | 24 |
| 25 local t_insert = table.insert; | 25 local t_insert = table.insert; |
| 26 local add_task = require "util.timer".add_task; | 26 local add_task = require "util.timer".add_task; |
| 27 local date, time = os.date, os.time; | 27 local date, time = os.date, os.time; |
| 28 local dt_parse, dt_datetime = require "util.datetime".parse, require "util.datetime".datetime; | 28 local dt_parse, dt_datetime = require "util.datetime".parse, require "util.datetime".datetime; |
| 29 local http = require "net.http"; | 29 local uuid = require "util.uuid".generate; |
| 30 local hmac_sha1 = require "util.hmac".sha1; | |
| 30 local parse_feed = require "feeds".feed_from_string; | 31 local parse_feed = require "feeds".feed_from_string; |
| 31 local st = require "util.stanza"; | 32 local st = require "util.stanza"; |
| 33 | |
| 34 local http = require "net.http"; | |
| 32 local httpserver = require "net.httpserver"; | 35 local httpserver = require "net.httpserver"; |
| 33 local formencode = require "net.http".formencode; | 36 local formdecode = http.formdecode; |
| 34 local dump = require "util.serialization".serialize; | 37 local formencode = http.formencode; |
| 35 local uuid = require "util.uuid".generate; | 38 local urldecode = http.urldecode; |
| 36 local hmac_sha1 = require "util.hmac".sha1; | 39 local urlencode = http.urlencode; |
| 37 | |
| 38 local urldecode = require "net.http".urldecode; | |
| 39 local urlencode = require "net.http".urlencode; | |
| 40 local urlparams = --require "net.http".getQueryParams or whatever MattJ names it, FIXME | |
| 41 function(s) | |
| 42 if not s:match("=") then return urldecode(s); end | |
| 43 local r = {} | |
| 44 s:gsub("([^=&]*)=([^&]*)", function(k,v) | |
| 45 r[ urldecode(k) ] = urldecode(v); | |
| 46 return nil | |
| 47 end) | |
| 48 return r | |
| 49 end; | |
| 50 | 40 |
| 51 local config = module:get_option("feeds") or { | 41 local config = module:get_option("feeds") or { |
| 52 planet_jabber = "http://planet.jabber.org/atom.xml"; | 42 planet_jabber = "http://planet.jabber.org/atom.xml"; |
| 53 prosody_blog = "http://blog.prosody.im/feed/atom.xml"; | 43 prosody_blog = "http://blog.prosody.im/feed/atom.xml"; |
| 54 }; | 44 }; |
| 55 local refresh_interval = module:get_option_number("feed_pull_interval", 15) * 60; | 45 local refresh_interval = module:get_option_number("feed_pull_interval", 15) * 60; |
| 56 local use_pubsubhubub = module:get_option_boolean("use_pubsubhubub", true); -- HTTP by default or not? | 46 local use_pubsubhubub = module:get_option_boolean("use_pubsubhubub", true); -- HTTP by default or not? |
| 57 local http_hostname = module:get_option_string("pubsubhubub_httphost", module.host); | 47 local httphost = module:get_option_string("pubsubhubub_httphost", module.host); -- If module.host IN A doesn't point to this server, use this to override. |
| 58 local feed_list = { } | 48 local feed_list = { } |
| 59 for node, url in pairs(config) do | 49 for node, url in pairs(config) do |
| 60 feed_list[node] = { url = url; node = node; last_update = 0 }; | 50 feed_list[node] = { url = url; node = node; last_update = 0 }; |
| 61 end | 51 end |
| 62 | 52 -- TODO module:hook("config-reloaded", above loop); |
| 63 local ports = module:get_option("feeds_ports") or { 5280 }; | 53 -- Also, keeping it somewhere persistent in order to avoid duplicated publishes? |
| 64 if not next(ports) then | 54 |
| 65 ports = { 5280 }; | 55 -- Thanks to Maranda for this |
| 66 end | 56 local port, base, ssl = 5280, "callback", false; |
| 67 local port_number, base_name, secure; | 57 local ports = module:get_option("feeds_ports") or { port = port, base = base, ssl = ssl }; |
| 68 for _, opts in ipairs(ports) do | 58 -- FIXME If ports isn't a table, this will cause an error |
| 69 if type(opts) == "number" then | 59 local _, first_port = next(ports); -- We base the callback URL on the first port config |
| 70 port_number, base_name = opts, "callback"; | 60 if first_port then |
| 71 elseif type(opts) == "table" then | 61 if type(first_port) == "number" then |
| 72 port_number, base_name, secure = opts.port or 5280, opts.path or "callback", opts.ssl or nil; | 62 port = first_port; |
| 73 elseif type(opts) == "string" then | 63 elseif type(first_port) == "table" then |
| 74 base_name, port_number = opts, 5280; | 64 port, base, ssl = |
| 65 first_port.port or port, | |
| 66 first_port.path or base, | |
| 67 first_port.ssl or ssl; | |
| 68 elseif type(first_port) == "string" then | |
| 69 base = first_port; | |
| 75 end | 70 end |
| 76 end | 71 end |
| 77 | 72 |
| 78 local response_codes = { | 73 local response_codes = { |
| 79 ["200"] = "OK"; | 74 ["200"] = "OK"; |
| 100 local feed = parse_feed(item.data); | 95 local feed = parse_feed(item.data); |
| 101 module:log("debug", "updating node %s", node); | 96 module:log("debug", "updating node %s", node); |
| 102 for _, entry in ipairs(feed) do | 97 for _, entry in ipairs(feed) do |
| 103 entry.attr.xmlns = "http://www.w3.org/2005/Atom"; | 98 entry.attr.xmlns = "http://www.w3.org/2005/Atom"; |
| 104 | 99 |
| 105 local e_published = entry:get_child("published"); | 100 local e_published = entry:get_child_text("published"); |
| 106 e_published = e_published and e_published:get_text(); | |
| 107 e_published = e_published and dt_parse(e_published); | 101 e_published = e_published and dt_parse(e_published); |
| 108 local e_updated = entry:get_child("updated"); | 102 local e_updated = entry:get_child_text("updated"); |
| 109 e_updated = e_updated and e_updated:get_text(); | |
| 110 e_updated = e_updated and dt_parse(e_updated); | 103 e_updated = e_updated and dt_parse(e_updated); |
| 111 | 104 |
| 112 local timestamp = e_updated or e_published or nil; | 105 local timestamp = e_updated or e_published or nil; |
| 113 --module:log("debug", "timestamp is %s, item.last_update is %s", tostring(timestamp), tostring(item.last_update)); | 106 --module:log("debug", "timestamp is %s, item.last_update is %s", tostring(timestamp), tostring(item.last_update)); |
| 114 if not timestamp or not item.last_update or timestamp > item.last_update then | 107 if not timestamp or not item.last_update or timestamp > item.last_update then |
| 115 local id = entry:get_child("id"); | 108 local id = entry:get_child_text("id"); |
| 116 id = id and id:get_text() or item.url.."#"..dt_datetime(timestamp); -- Missing id, so make one up | 109 id = id or item.url.."#"..dt_datetime(timestamp); -- Missing id, so make one up |
| 117 local xitem = st.stanza("item", { id = id }):add_child(entry); | 110 local xitem = st.stanza("item", { id = id }):add_child(entry); |
| 118 -- TODO Put data from /feed into item/source | 111 -- TODO Put data from /feed into item/source |
| 119 | 112 |
| 120 module:log("debug", "publishing to %s, id %s", node, id); | 113 module:log("debug", "publishing to %s, id %s", node, id); |
| 121 local ok, err = modules.pubsub.service:publish(node, actor, id, xitem); | 114 local ok, err = modules.pubsub.service:publish(node, actor, id, xitem); |
| 186 end | 179 end |
| 187 | 180 |
| 188 function subscribe(feed) | 181 function subscribe(feed) |
| 189 feed.token = uuid(); | 182 feed.token = uuid(); |
| 190 feed.secret = uuid(); | 183 feed.secret = uuid(); |
| 191 local _body, body = { | 184 local body = formencode{ |
| 192 ["hub.callback"] = format_url(secure, http_hostname, port_number, base_name, feed.node); | 185 ["hub.callback"] = format_url(ssl, httphost, port, base, feed.node); |
| 193 ["hub.mode"] = "subscribe"; --TODO unsubscribe | 186 ["hub.mode"] = "subscribe"; --TODO unsubscribe |
| 194 ["hub.topic"] = feed.url; | 187 ["hub.topic"] = feed.url; |
| 195 ["hub.verify"] = "async"; | 188 ["hub.verify"] = "async"; |
| 196 ["hub.verify_token"] = feed.token; | 189 ["hub.verify_token"] = feed.token; |
| 197 ["hub.secret"] = feed.secret; | 190 ["hub.secret"] = feed.secret; |
| 198 --["hub.lease_seconds"] = ""; | 191 --["hub.lease_seconds"] = ""; |
| 199 }, { }; | 192 }; |
| 200 for name, value in pairs(_body) do | |
| 201 t_insert(body, { name = name, value = value }); | |
| 202 end --FIXME Why do I have to do this? | |
| 203 body = formencode(body); | |
| 204 | 193 |
| 205 --module:log("debug", "subscription request, body: %s", body); | 194 --module:log("debug", "subscription request, body: %s", body); |
| 206 | 195 |
| 207 --FIXME The subscription states and related stuff | 196 --FIXME The subscription states and related stuff |
| 208 feed.subscription = "subscribe"; | 197 feed.subscription = "subscribe"; |
| 214 | 203 |
| 215 function handle_http_request(method, body, request) | 204 function handle_http_request(method, body, request) |
| 216 --module:log("debug", "%s request to %s%s with body %s", method, request.url.path, request.url.query and "?" .. request.url.query or "", #body > 0 and body or "empty"); | 205 --module:log("debug", "%s request to %s%s with body %s", method, request.url.path, request.url.query and "?" .. request.url.query or "", #body > 0 and body or "empty"); |
| 217 local query = request.url.query or {}; | 206 local query = request.url.query or {}; |
| 218 if query and type(query) == "string" then | 207 if query and type(query) == "string" then |
| 219 query = urlparams(query); | 208 query = formdecode(query); |
| 220 --module:log("debug", "GET data: %s", dump(query)); | 209 --module:log("debug", "GET data: %s", dump(query)); |
| 221 end | 210 end |
| 222 --module:log("debug", "Headers: %s", dump(request.headers)); | 211 --module:log("debug", "Headers: %s", dump(request.headers)); |
| 223 | 212 |
| 224 if method == "GET" then | 213 if method == "GET" then |
| 268 end | 257 end |
| 269 | 258 |
| 270 function init() | 259 function init() |
| 271 module:log("debug", "initiating", module.name); | 260 module:log("debug", "initiating", module.name); |
| 272 if use_pubsubhubub then | 261 if use_pubsubhubub then |
| 273 module:log("debug", "Starting http server on %s", format_url(secure, http_hostname, port_number, base_name, "NODE")); | 262 module:log("debug", "Starting http server on %s", format_url(ssl, httphost, port, base, "NODE")); |
| 274 --httpserver.new{ port = port_number, ssl = secure, type = (ssl and "ssl") or "tcp", base = base_name, handler = handle_http_request } | |
| 275 httpserver.new_from_config( ports, handle_http_request, { base = "callback" } ); | 263 httpserver.new_from_config( ports, handle_http_request, { base = "callback" } ); |
| 276 end | 264 end |
| 277 add_task(0, refresh_feeds); | 265 add_task(0, refresh_feeds); |
| 278 end | 266 end |
| 279 | 267 |
| 280 if prosody.start_time then -- already started | 268 if prosody.start_time then -- already started |
| 281 init(); | 269 init(); |
| 282 else | 270 else |
| 283 prosody.events.add_handler("server-started", init); | 271 module:hook_global("server-started", init); |
| 284 end | 272 end |
