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 |