Comparison

plugins/mod_pep.lua @ 10036:045209b41b3a 0.11

mod_pep: Handle presence based subscription outside of util.pubsub (fixes #1372) Subscriptions were updated for each incoming presence stanza from contacts. Each subscription change triggered a configuration save, which would filter out the presence based subscriptions and usually end up replacing the existing data with identical data. With many subscribed nodes this adds up to a fair bit of IO bound work that is avoided by keeping them separate.
author Kim Alvefur <zash@zash.se>
date Thu, 30 May 2019 15:16:56 +0200
parent 9827:fd8aaab6669c
child 10037:e01f38acde74
child 10045:6714578cfd6e
comparison
equal deleted inserted replaced
10029:2c8f674b9243 10036:045209b41b3a
88 }; 88 };
89 end 89 end
90 return data, err; 90 return data, err;
91 end 91 end
92 function store:set(node, data) 92 function store:set(node, data)
93 if data then
94 -- Save the data without subscriptions
95 local subscribers = {};
96 for jid, sub in pairs(data.subscribers) do
97 if type(sub) ~= "table" or not sub.presence then
98 subscribers[jid] = sub;
99 end
100 end
101 data = {
102 name = data.name;
103 config = data.config;
104 affiliations = data.affiliations;
105 subscribers = subscribers;
106 };
107 end
108 return node_config:set(username, node, data); 93 return node_config:set(username, node, data);
109 end 94 end
110 function store:users() 95 function store:users()
111 return pairs(known_nodes:get(username) or {}); 96 return pairs(known_nodes:get(username) or {});
112 end 97 end
149 item:maptags(function () return nil; end); 134 item:maptags(function () return nil; end);
150 end 135 end
151 end 136 end
152 message:add_child(item); 137 message:add_child(item);
153 end 138 end
139
140 local broadcast_to = {};
154 for jid in pairs(jids) do 141 for jid in pairs(jids) do
142 broadcast_to[jid] = true;
143 end
144
145 local service_recipients = recipients[username];
146 if service_recipients then
147 local service = services[username];
148 for recipient, nodes in pairs(service_recipients) do
149 if nodes:contains(node) and service:may(node, recipient, "subscribe") then
150 broadcast_to[recipient] = true;
151 end
152 end
153 end
154
155 for jid in pairs(broadcast_to) do
155 module:log("debug", "Sending notification to %s from %s: %s", jid, user_bare, tostring(item)); 156 module:log("debug", "Sending notification to %s from %s: %s", jid, user_bare, tostring(item));
156 message.attr.to = jid; 157 message.attr.to = jid;
157 module:send(message); 158 module:send(message);
158 end 159 end
159 end 160 end
160 return simple_broadcast; 161 return simple_broadcast;
161 end 162 end
162 163
163 local function on_node_creation(event)
164 local service = event.service;
165 local node = event.node;
166 local username = service.config.pep_username;
167
168 local service_recipients = recipients[username];
169 if not service_recipients then return; end
170
171 for recipient, nodes in pairs(service_recipients) do
172 if nodes:contains(node) then
173 service:add_subscription(node, recipient, recipient, { presence = true });
174 end
175 end
176 end
177 164
178 function get_pep_service(username) 165 function get_pep_service(username)
179 module:log("debug", "get_pep_service(%q)", username); 166 module:log("debug", "get_pep_service(%q)", username);
180 local user_bare = jid_join(username, host); 167 local user_bare = jid_join(username, host);
181 local service = services[username]; 168 local service = services[username];
231 services[username] = service; 218 services[username] = service;
232 module:add_item("pep-service", { service = service, jid = user_bare }); 219 module:add_item("pep-service", { service = service, jid = user_bare });
233 return service; 220 return service;
234 end 221 end
235 222
236 module:hook("item-added/pep-service", function (event)
237 local service = event.item.service;
238 module:hook_object_event(service.events, "node-created", on_node_creation);
239 end);
240 223
241 function handle_pubsub_iq(event) 224 function handle_pubsub_iq(event)
242 local origin, stanza = event.origin, event.stanza; 225 local origin, stanza = event.origin, event.stanza;
243 local service_name = origin.username; 226 local service_name = origin.username;
244 if stanza.attr.to ~= nil then 227 if stanza.attr.to ~= nil then
301 if (current == empty_set or current:empty()) and (nodes == empty_set or nodes:empty()) then 284 if (current == empty_set or current:empty()) and (nodes == empty_set or nodes:empty()) then
302 return; 285 return;
303 end 286 end
304 287
305 local service = get_pep_service(service_name); 288 local service = get_pep_service(service_name);
306 for node in current - nodes do
307 service:remove_subscription(node, recipient, recipient);
308 end
309 289
310 for node in nodes - current do 290 for node in nodes - current do
311 if service:add_subscription(node, recipient, recipient, { presence = true }) then 291 if service:may(node, recipient, "subscribe") then
312 resend_last_item(recipient, node, service); 292 resend_last_item(recipient, node, service);
313 end 293 end
314 end 294 end
315 295
316 if nodes == empty_set or nodes:empty() then 296 if nodes == empty_set or nodes:empty() then