Mercurial > prosody-hg
comparison core/moduleapi.lua @ 11200:bf8f2da84007
Merge 0.11->trunk
| author | Kim Alvefur <zash@zash.se> |
|---|---|
| date | Thu, 05 Nov 2020 22:31:25 +0100 |
| parents | 1dc49accb58e |
| children | 5f15ab7c6ae5 |
comparison
equal
deleted
inserted
replaced
| 11199:6c7c50a4de32 | 11200:bf8f2da84007 |
|---|---|
| 12 local logger = require "util.logger"; | 12 local logger = require "util.logger"; |
| 13 local pluginloader = require "util.pluginloader"; | 13 local pluginloader = require "util.pluginloader"; |
| 14 local timer = require "util.timer"; | 14 local timer = require "util.timer"; |
| 15 local resolve_relative_path = require"util.paths".resolve_relative_path; | 15 local resolve_relative_path = require"util.paths".resolve_relative_path; |
| 16 local st = require "util.stanza"; | 16 local st = require "util.stanza"; |
| 17 local cache = require "util.cache"; | |
| 18 local errors = require "util.error"; | |
| 19 local promise = require "util.promise"; | |
| 20 local time_now = require "util.time".now; | |
| 21 local format = require "util.format".format; | |
| 22 local jid_node = require "util.jid".node; | |
| 17 | 23 |
| 18 local t_insert, t_remove, t_concat = table.insert, table.remove, table.concat; | 24 local t_insert, t_remove, t_concat = table.insert, table.remove, table.concat; |
| 19 local error, setmetatable, type = error, setmetatable, type; | 25 local error, setmetatable, type = error, setmetatable, type; |
| 20 local ipairs, pairs, select = ipairs, pairs, select; | 26 local ipairs, pairs, select = ipairs, pairs, select; |
| 21 local tonumber, tostring = tonumber, tostring; | 27 local tonumber, tostring = tonumber, tostring; |
| 22 local require = require; | 28 local require = require; |
| 23 local pack = table.pack or function(...) return {n=select("#",...), ...}; end -- table.pack is only in 5.2 | 29 local pack = table.pack or require "util.table".pack; -- table.pack is only in 5.2 |
| 24 local unpack = table.unpack or unpack; --luacheck: ignore 113 -- renamed in 5.2 | 30 local unpack = table.unpack or unpack; --luacheck: ignore 113 -- renamed in 5.2 |
| 25 | 31 |
| 26 local prosody = prosody; | 32 local prosody = prosody; |
| 27 local hosts = prosody.hosts; | 33 local hosts = prosody.hosts; |
| 28 | 34 |
| 359 | 365 |
| 360 function api:send(stanza, origin) | 366 function api:send(stanza, origin) |
| 361 return core_post_stanza(origin or hosts[self.host], stanza); | 367 return core_post_stanza(origin or hosts[self.host], stanza); |
| 362 end | 368 end |
| 363 | 369 |
| 370 function api:send_iq(stanza, origin, timeout) | |
| 371 local iq_cache = self._iq_cache; | |
| 372 if not iq_cache then | |
| 373 iq_cache = cache.new(256, function (_, iq) | |
| 374 iq.reject(errors.new({ | |
| 375 type = "wait", condition = "resource-constraint", | |
| 376 text = "evicted from iq tracking cache" | |
| 377 })); | |
| 378 end); | |
| 379 self._iq_cache = iq_cache; | |
| 380 end | |
| 381 | |
| 382 local event_type; | |
| 383 if not jid_node(stanza.attr.from) then | |
| 384 event_type = "host"; | |
| 385 else -- assume bare since we can't hook full jids | |
| 386 event_type = "bare"; | |
| 387 end | |
| 388 local result_event = "iq-result/"..event_type.."/"..stanza.attr.id; | |
| 389 local error_event = "iq-error/"..event_type.."/"..stanza.attr.id; | |
| 390 local cache_key = event_type.."/"..stanza.attr.id; | |
| 391 | |
| 392 local p = promise.new(function (resolve, reject) | |
| 393 local function result_handler(event) | |
| 394 if event.stanza.attr.from == stanza.attr.to then | |
| 395 resolve(event); | |
| 396 return true; | |
| 397 end | |
| 398 end | |
| 399 | |
| 400 local function error_handler(event) | |
| 401 if event.stanza.attr.from == stanza.attr.to then | |
| 402 reject(errors.from_stanza(event.stanza, event)); | |
| 403 return true; | |
| 404 end | |
| 405 end | |
| 406 | |
| 407 if iq_cache:get(cache_key) then | |
| 408 reject(errors.new({ | |
| 409 type = "modify", condition = "conflict", | |
| 410 text = "IQ stanza id attribute already used", | |
| 411 })); | |
| 412 return; | |
| 413 end | |
| 414 | |
| 415 self:hook(result_event, result_handler); | |
| 416 self:hook(error_event, error_handler); | |
| 417 | |
| 418 local timeout_handle = self:add_timer(timeout or 120, function () | |
| 419 reject(errors.new({ | |
| 420 type = "wait", condition = "remote-server-timeout", | |
| 421 text = "IQ stanza timed out", | |
| 422 })); | |
| 423 end); | |
| 424 | |
| 425 local ok = iq_cache:set(cache_key, { | |
| 426 reject = reject, resolve = resolve, | |
| 427 timeout_handle = timeout_handle, | |
| 428 result_handler = result_handler, error_handler = error_handler; | |
| 429 }); | |
| 430 | |
| 431 if not ok then | |
| 432 reject(errors.new({ | |
| 433 type = "wait", condition = "internal-server-error", | |
| 434 text = "Could not store IQ tracking data" | |
| 435 })); | |
| 436 return; | |
| 437 end | |
| 438 | |
| 439 local wrapped_origin = setmetatable({ | |
| 440 -- XXX Needed in some cases for replies to work correctly when sending queries internally. | |
| 441 send = function (reply) | |
| 442 resolve({ stanza = reply }); | |
| 443 end; | |
| 444 }, { | |
| 445 __index = origin or hosts[self.host]; | |
| 446 }); | |
| 447 | |
| 448 self:send(stanza, wrapped_origin); | |
| 449 end); | |
| 450 | |
| 451 p:finally(function () | |
| 452 local iq = iq_cache:get(cache_key); | |
| 453 if iq then | |
| 454 self:unhook(result_event, iq.result_handler); | |
| 455 self:unhook(error_event, iq.error_handler); | |
| 456 iq.timeout_handle:stop(); | |
| 457 iq_cache:set(cache_key, nil); | |
| 458 end | |
| 459 end); | |
| 460 | |
| 461 return p; | |
| 462 end | |
| 463 | |
| 364 function api:broadcast(jids, stanza, iter) | 464 function api:broadcast(jids, stanza, iter) |
| 365 for jid in (iter or it.values)(jids) do | 465 for jid in (iter or it.values)(jids) do |
| 366 local new_stanza = st.clone(stanza); | 466 local new_stanza = st.clone(stanza); |
| 367 new_stanza.attr.to = jid; | 467 new_stanza.attr.to = jid; |
| 368 self:send(new_stanza); | 468 self:send(new_stanza); |
| 394 return setmetatable(t, timer_mt); | 494 return setmetatable(t, timer_mt); |
| 395 end | 495 end |
| 396 | 496 |
| 397 local path_sep = package.config:sub(1,1); | 497 local path_sep = package.config:sub(1,1); |
| 398 function api:get_directory() | 498 function api:get_directory() |
| 399 return self.path and (self.path:gsub("%"..path_sep.."[^"..path_sep.."]*$", "")) or nil; | 499 return self.resource_path or self.path and (self.path:gsub("%"..path_sep.."[^"..path_sep.."]*$", "")) or nil; |
| 400 end | 500 end |
| 401 | 501 |
| 402 function api:load_resource(path, mode) | 502 function api:load_resource(path, mode) |
| 403 path = resolve_relative_path(self:get_directory(), path); | 503 path = resolve_relative_path(self:get_directory(), path); |
| 404 return io.open(path, mode); | 504 return io.open(path, mode); |
| 406 | 506 |
| 407 function api:open_store(name, store_type) | 507 function api:open_store(name, store_type) |
| 408 return require"core.storagemanager".open(self.host, name or self.name, store_type); | 508 return require"core.storagemanager".open(self.host, name or self.name, store_type); |
| 409 end | 509 end |
| 410 | 510 |
| 411 function api:measure(name, stat_type) | 511 function api:measure(name, stat_type, conf) |
| 412 local measure = require "core.statsmanager".measure; | 512 local measure = require "core.statsmanager".measure; |
| 413 return measure(stat_type, "/"..self.host.."/mod_"..self.name.."/"..name); | 513 return measure(stat_type, "/"..self.host.."/mod_"..self.name.."/"..name, conf); |
| 414 end | 514 end |
| 415 | 515 |
| 416 function api:measure_object_event(events_object, event_name, stat_name) | 516 function api:measure_object_event(events_object, event_name, stat_name) |
| 417 local m = self:measure(stat_name or event_name, "times"); | 517 local m = self:measure(stat_name or event_name, "times"); |
| 418 local function handler(handlers, _event_name, _event_data) | 518 local function handler(handlers, _event_name, _event_data) |
| 430 | 530 |
| 431 function api:measure_global_event(event_name, stat_name) | 531 function api:measure_global_event(event_name, stat_name) |
| 432 return self:measure_object_event(prosody.events.wrappers, event_name, stat_name); | 532 return self:measure_object_event(prosody.events.wrappers, event_name, stat_name); |
| 433 end | 533 end |
| 434 | 534 |
| 535 local status_priorities = { error = 3, warn = 2, info = 1, core = 0 }; | |
| 536 | |
| 537 function api:set_status(status_type, status_message, override) | |
| 538 local priority = status_priorities[status_type]; | |
| 539 if not priority then | |
| 540 self:log("error", "set_status: Invalid status type '%s', assuming 'info'"); | |
| 541 status_type, priority = "info", status_priorities.info; | |
| 542 end | |
| 543 local current_priority = status_priorities[self.status_type] or 0; | |
| 544 -- By default an 'error' status can only be overwritten by another 'error' status | |
| 545 if (current_priority >= status_priorities.error and priority < current_priority and override ~= true) | |
| 546 or (override == false and current_priority > priority) then | |
| 547 self:log("debug", "moduleapi: ignoring status [prio %d override %s]: %s", priority, override, status_message); | |
| 548 return; | |
| 549 end | |
| 550 self.status_type, self.status_message, self.status_time = status_type, status_message, time_now(); | |
| 551 self:fire_event("module-status/updated", { name = self.name }); | |
| 552 end | |
| 553 | |
| 554 function api:log_status(level, msg, ...) | |
| 555 self:set_status(level, format(msg, ...)); | |
| 556 return self:log(level, msg, ...); | |
| 557 end | |
| 558 | |
| 559 function api:get_status() | |
| 560 return self.status_type, self.status_message, self.status_time; | |
| 561 end | |
| 562 | |
| 435 return api; | 563 return api; |
