annotate mod_http_roster_admin/mod_http_roster_admin.lua @ 2491:5fbca7de2088

mod_smacks: Send out more ack requests where needed Under some circumstances it was possible that more than "max_unacked_stanzas" where left in the outgoing stanza queue without forcing an ack. This could happen, when more stanzas entered the queue while the last ack request was still unanswered. Now the test "#queue > max_unacked_stanzas" is done upon receiving an ack as well as when sending out stanzas, which fixes this bug.
author tmolitor <thilo@eightysoft.de>
date Sun, 12 Feb 2017 19:27:50 +0100
parents 68ebc52222dc
children 7c3a1688e385
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
2161
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
1 -- mod_http_roster_admin
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
2 -- Description: Allow user rosters to be sourced from a remote HTTP API
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
3 --
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
4 -- Version: 1.0
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
5 -- Date: 2015-03-06
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
6 -- Author: Matthew Wild <matthew@prosody.im>
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
7 -- License: MPLv2
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
8 --
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
9 -- Requirements:
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
10 -- Prosody config:
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
11 -- storage = { roster = "memory" }
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
12 -- modules_disabled = { "roster" }
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
13 -- Dependencies:
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
14 -- Prosody 0.9
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
15 -- lua-cjson (Debian/Ubuntu/LuaRocks: lua-cjson)
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
16
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
17 local http = require "net.http";
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
18 local json = require "cjson";
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
19 local it = require "util.iterators";
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
20 local set = require "util.set";
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
21 local rm = require "core.rostermanager";
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
22 local st = require "util.stanza";
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
23 local array = require "util.array";
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
24
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
25 local host = module.host;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
26 local sessions = hosts[host].sessions;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
27
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
28 local roster_url = module:get_option_string("http_roster_url", "http://localhost/%s");
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
29
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
30 -- Send a roster push to the named user, with the given roster, for the specified
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
31 -- contact's roster entry. Used to notify clients of changes/removals.
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
32 local function roster_push(username, roster, contact_jid)
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
33 local stanza = st.iq({type="set"})
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
34 :tag("query", {xmlns = "jabber:iq:roster" });
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
35 local item = roster[contact_jid];
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
36 if item then
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
37 stanza:tag("item", {jid = contact_jid, subscription = item.subscription, name = item.name, ask = item.ask});
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
38 for group in pairs(item.groups) do
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
39 stanza:tag("group"):text(group):up();
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
40 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
41 else
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
42 stanza:tag("item", {jid = contact_jid, subscription = "remove"});
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
43 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
44 stanza:up():up(); -- move out from item
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
45 for _, session in pairs(hosts[host].sessions[username].sessions) do
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
46 if session.interested then
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
47 session.send(stanza);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
48 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
49 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
50 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
51
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
52 -- Send latest presence from the named local user to a contact.
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
53 local function send_presence(username, contact_jid, available)
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
54 module:log("debug", "Sending %savailable presence from %s to contact %s", (available and "" or "un"), username, contact_jid);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
55 for resource, session in pairs(sessions[username].sessions) do
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
56 local pres;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
57 if available then
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
58 pres = st.clone(session.presence);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
59 pres.attr.to = contact_jid;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
60 else
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
61 pres = st.presence({ to = contact_jid, from = session.full_jid, type = "unavailable" });
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
62 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
63 module:send(pres);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
64 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
65 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
66
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
67 -- Converts a 'friend' object from the API to a Prosody roster item object
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
68 local function friend_to_roster_item(friend)
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
69 return {
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
70 name = friend.name;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
71 subscription = "both";
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
72 groups = friend.groups or {};
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
73 };
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
74 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
75
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
76 -- Returns a handler function to consume the data returned from
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
77 -- the API, compare it to the user's current roster, and perform
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
78 -- any actions necessary (roster pushes, presence probes) to
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
79 -- synchronize them.
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
80 local function updated_friends_handler(username, cb)
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
81 return (function (ok, code, friends)
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
82 if not ok then
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
83 cb(false, code);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
84 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
85 local user = sessions[username];
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
86 local roster = user.roster;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
87 local old_contacts = set.new(array.collect(it.keys(roster)));
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
88 local new_contacts = set.new(array.collect(it.keys(friends)));
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
89
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
90 -- These two entries are not real contacts, ignore them
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
91 old_contacts:remove(false);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
92 old_contacts:remove("pending");
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
93
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
94 module:log("debug", "New friends list of %s: %s", username, json.encode(friends));
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
95
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
96 -- Calculate which contacts have been added/removed since
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
97 -- the last time we fetched the roster
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
98 local added_contacts = new_contacts - old_contacts;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
99 local removed_contacts = old_contacts - new_contacts;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
100
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
101 local added, removed = 0, 0;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
102
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
103 -- Add new contacts and notify connected clients
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
104 for contact_jid in added_contacts do
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
105 module:log("debug", "Processing new friend of %s: %s", username, contact_jid);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
106 roster[contact_jid] = friend_to_roster_item(friends[contact_jid]);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
107 roster_push(username, roster, contact_jid);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
108 send_presence(username, contact_jid, true);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
109 added = added + 1;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
110 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
111
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
112 -- Remove contacts and notify connected clients
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
113 for contact_jid in removed_contacts do
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
114 module:log("debug", "Processing removed friend of %s: %s", username, contact_jid);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
115 roster[contact_jid] = nil;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
116 roster_push(username, roster, contact_jid);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
117 send_presence(username, contact_jid, false);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
118 removed = removed + 1;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
119 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
120 module:log("debug", "User %s: added %d new contacts, removed %d contacts", username, added, removed);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
121 cb(true);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
122 end);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
123 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
124
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
125 -- Fetch the named user's roster from the API, call callback (cb)
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
126 -- with status and result (friends list) when received.
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
127 function fetch_roster(username, cb)
2210
126d79bf079b mod_http_roster_admin: Also log if the status error is 0 (Connection refused)
JC Brand <jcbrand@minddistrict.com>
parents: 2161
diff changeset
128 local x = {headers = {}};
126d79bf079b mod_http_roster_admin: Also log if the status error is 0 (Connection refused)
JC Brand <jcbrand@minddistrict.com>
parents: 2161
diff changeset
129 x["headers"]["ACCEPT"] = "application/json, text/plain, */*";
2441
68ebc52222dc Log URL called by http_roster_admin
JC Brand <jc@opkode.com>
parents: 2210
diff changeset
130 module:log("debug", "Fetching roster at URL: %s", roster_url:format(username));
2161
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
131 local ok, err = http.request(
2210
126d79bf079b mod_http_roster_admin: Also log if the status error is 0 (Connection refused)
JC Brand <jcbrand@minddistrict.com>
parents: 2161
diff changeset
132 roster_url:format(username),
126d79bf079b mod_http_roster_admin: Also log if the status error is 0 (Connection refused)
JC Brand <jcbrand@minddistrict.com>
parents: 2161
diff changeset
133 x,
126d79bf079b mod_http_roster_admin: Also log if the status error is 0 (Connection refused)
JC Brand <jcbrand@minddistrict.com>
parents: 2161
diff changeset
134 function (roster_data, code)
126d79bf079b mod_http_roster_admin: Also log if the status error is 0 (Connection refused)
JC Brand <jcbrand@minddistrict.com>
parents: 2161
diff changeset
135 if code ~= 200 then
126d79bf079b mod_http_roster_admin: Also log if the status error is 0 (Connection refused)
JC Brand <jcbrand@minddistrict.com>
parents: 2161
diff changeset
136 module:log("error", "Error fetching roster from %s (code %d): %s", roster_url:format(username), code, tostring(roster_data):sub(1, 40):match("^[^\r\n]+"));
126d79bf079b mod_http_roster_admin: Also log if the status error is 0 (Connection refused)
JC Brand <jcbrand@minddistrict.com>
parents: 2161
diff changeset
137 if code ~= 0 then
126d79bf079b mod_http_roster_admin: Also log if the status error is 0 (Connection refused)
JC Brand <jcbrand@minddistrict.com>
parents: 2161
diff changeset
138 cb(nil, code, roster_data);
126d79bf079b mod_http_roster_admin: Also log if the status error is 0 (Connection refused)
JC Brand <jcbrand@minddistrict.com>
parents: 2161
diff changeset
139 end
126d79bf079b mod_http_roster_admin: Also log if the status error is 0 (Connection refused)
JC Brand <jcbrand@minddistrict.com>
parents: 2161
diff changeset
140 return;
126d79bf079b mod_http_roster_admin: Also log if the status error is 0 (Connection refused)
JC Brand <jcbrand@minddistrict.com>
parents: 2161
diff changeset
141 end
126d79bf079b mod_http_roster_admin: Also log if the status error is 0 (Connection refused)
JC Brand <jcbrand@minddistrict.com>
parents: 2161
diff changeset
142 module:log("debug", "Successfully fetched roster for %s", username);
126d79bf079b mod_http_roster_admin: Also log if the status error is 0 (Connection refused)
JC Brand <jcbrand@minddistrict.com>
parents: 2161
diff changeset
143 module:log("debug", "The roster data is %s", roster_data);
126d79bf079b mod_http_roster_admin: Also log if the status error is 0 (Connection refused)
JC Brand <jcbrand@minddistrict.com>
parents: 2161
diff changeset
144 cb(true, code, json.decode(roster_data));
126d79bf079b mod_http_roster_admin: Also log if the status error is 0 (Connection refused)
JC Brand <jcbrand@minddistrict.com>
parents: 2161
diff changeset
145 end
126d79bf079b mod_http_roster_admin: Also log if the status error is 0 (Connection refused)
JC Brand <jcbrand@minddistrict.com>
parents: 2161
diff changeset
146 );
2161
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
147 if not ok then
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
148 module:log("error", "Failed to connect to roster API at %s: %s", roster_url:format(username), err);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
149 cb(false, 0, err);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
150 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
151 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
152
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
153 -- Fetch the named user's roster from the API, synchronize it with
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
154 -- the user's current roster. Notify callback (cb) with true/false
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
155 -- depending on success or failure.
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
156 function refresh_roster(username, cb)
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
157 local user = sessions[username];
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
158 if not (user and user.roster) then
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
159 module:log("debug", "User's (%q) roster updated, but they are not online - ignoring", username);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
160 cb(true);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
161 return;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
162 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
163 fetch_roster(username, updated_friends_handler(username, cb));
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
164 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
165
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
166 --- Roster protocol handling ---
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
167
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
168 -- Build a reply to a "roster get" request
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
169 local function build_roster_reply(stanza, roster_data)
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
170 local roster = st.reply(stanza)
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
171 :tag("query", { xmlns = "jabber:iq:roster" });
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
172
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
173 for jid, item in pairs(roster_data) do
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
174 if jid and jid ~= "pending" then
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
175 roster:tag("item", {
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
176 jid = jid,
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
177 subscription = item.subscription,
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
178 ask = item.ask,
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
179 name = item.name,
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
180 });
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
181 for group in pairs(item.groups) do
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
182 roster:tag("group"):text(group):up();
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
183 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
184 roster:up(); -- move out from item
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
185 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
186 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
187 return roster;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
188 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
189
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
190 -- Handle clients requesting their roster (generally at login)
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
191 -- This will not work if mod_roster is loaded (in 0.9).
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
192 module:hook("iq-get/self/jabber:iq:roster:query", function(event)
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
193 local session, stanza = event.origin, event.stanza;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
194
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
195 session.interested = true; -- resource is interested in roster updates
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
196
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
197 local roster = session.roster;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
198 if roster[false].downloaded then
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
199 return session.send(build_roster_reply(stanza, roster));
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
200 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
201
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
202 -- It's possible that we can call this more than once for a new roster
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
203 -- Should happen rarely (multiple clients of the same user request the
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
204 -- roster in the time it takes the API to respond). Currently we just
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
205 -- issue multiple requests, as it's harmless apart from the wasted
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
206 -- requests.
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
207 fetch_roster(session.username, function (ok, code, friends)
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
208 if not ok then
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
209 session.send(st.error_reply(stanza, "cancel", "internal-server-error"));
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
210 session:close("internal-server-error");
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
211 return;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
212 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
213
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
214 -- Are we the first callback to handle the downloaded roster?
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
215 local first = roster[false].downloaded == nil;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
216
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
217 if first then
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
218 -- Fill out new roster
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
219 for jid, friend in pairs(friends) do
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
220 roster[jid] = friend_to_roster_item(friend);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
221 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
222 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
223
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
224 -- Send full roster to client
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
225 session.send(build_roster_reply(stanza, roster));
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
226
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
227 if not first then
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
228 -- We already had a roster, make sure to handle any changes...
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
229 updated_friends_handler(session.username, nil)(ok, code, friends);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
230 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
231 end);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
232
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
233 return true;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
234 end);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
235
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
236 -- Prevent client from making changes to the roster. This will not
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
237 -- work if mod_roster is loaded (in 0.9).
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
238 module:hook("iq-set/self/jabber:iq:roster:query", function(event)
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
239 local session, stanza = event.origin, event.stanza;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
240 return session.send(st.error_reply(stanza, "cancel", "service-unavailable"));
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
241 end);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
242
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
243 --- HTTP endpoint to trigger roster refresh ---
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
244
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
245 -- Handles updating for a single user: GET /roster_admin/refresh/USERNAME
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
246 function handle_refresh_single(event, username)
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
247 refresh_roster(username, function (ok, code, err)
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
248 event.response.headers["Content-Type"] = "application/json";
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
249 event.response:send(json.encode({
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
250 status = ok and "ok" or "error";
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
251 message = err or "roster update complete";
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
252 }));
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
253 end);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
254 return true;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
255 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
256
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
257 -- Handles updating for multiple users: POST /roster_admin/refresh
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
258 -- Payload should be a JSON array of usernames, e.g. ["user1", "user2", "user3"]
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
259 function handle_refresh_multi(event)
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
260 local users = json.decode(event.request.body);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
261 if not users then
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
262 module:log("warn", "Multi-user refresh attempted with missing/invalid payload");
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
263 event.response:send(400);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
264 return true;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
265 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
266
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
267 local count, count_err = 0, 0;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
268
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
269 local function cb(ok)
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
270 count = count + 1;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
271 if not ok then
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
272 count_err = count_err + 1;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
273 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
274
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
275 if count == #users then
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
276 event.response.headers["Content-Type"] = "application/json";
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
277 event.response:send(json.encode({
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
278 status = "ok";
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
279 message = "roster update complete";
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
280 updated = count - count_err;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
281 errors = count_err;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
282 }));
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
283 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
284 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
285
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
286 for _, username in ipairs(users) do
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
287 refresh_roster(username, cb);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
288 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
289
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
290 return true;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
291 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
292
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
293
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
294 module:provides("http", {
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
295 route = {
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
296 ["POST /refresh"] = handle_refresh_multi;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
297 ["GET /refresh/*"] = handle_refresh_single;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
298 };
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
299 });