File

mod_http_host_status_check/mod_http_host_status_check.lua @ 6302:06fbbd45ba75

mod_cloud_notify: Readme: fix links and labels that were removed in the last commit diff --git a/mod_cloud_notify/README.md b/mod_cloud_notify/README.md --- a/mod_cloud_notify/README.md +++ b/mod_cloud_notify/README.md @@ -1,3 +1,9 @@ +---- +-labels: +-- 'Stage-Beta' +-summary: 'XEP-0357: Cloud push notifications' +---- + # Introduction This module enables support for sending "push notifications" to clients @@ -32,15 +38,15 @@ notification to your device. When your d it will display it or wake up the app so it can connect to XMPP and receive any pending messages. -This protocol is described for developers in \[XEP-0357: Push -Notifications\]. +This protocol is described for developers in [XEP-0357: Push +Notifications]. -For this module to work reliably, you must have \[mod_smacks\], -\[mod_mam\] and \[mod_carbons\] also enabled on your server. +For this module to work reliably, you must have [mod_smacks], +[mod_mam] and [mod_carbons] also enabled on your server. Some clients, notably Siskin and Snikket iOS need some additional extensions that are not currently defined in a standard XEP. To support -these clients, see \[mod_cloud_notify_extensions\]. +these clients, see [mod_cloud_notify_extensions]. # Configuration @@ -58,18 +64,18 @@ these clients, see \[mod_cloud_notify_ex # Internal design notes App servers are notified about offline messages, messages stored by -\[mod_mam\] or messages waiting in the smacks queue. The business rules +[mod_mam] or messages waiting in the smacks queue. The business rules outlined [here](//mail.jabber.org/pipermail/standards/2016-February/030925.html) are all honored[^2]. -To cooperate with \[mod_smacks\] this module consumes some events: +To cooperate with [mod_smacks] this module consumes some events: `smacks-ack-delayed`, `smacks-hibernation-start` and `smacks-hibernation-end`. These events allow this module to send out notifications for messages received while the session is hibernated by -\[mod_smacks\] or even when smacks acknowledgements for messages are +[mod_smacks] or even when smacks acknowledgements for messages are delayed by a certain amount of seconds configurable with the -\[mod_smacks\] setting `smacks_max_ack_delay`. +[mod_smacks] setting `smacks_max_ack_delay`. The `smacks_max_ack_delay` setting allows to send out notifications to clients which aren't already in smacks hibernation state (because the
author Menel <menel@snikket.de>
date Fri, 13 Jun 2025 10:44:37 +0200
parent 2765:85cf9a8b4020
line wrap: on
line source

local heartbeats = module:shared("/*/host_status_check/heartbeats");
local events = module:shared("/*/host_status_check/connection_events");
local host_status_ok = module:shared("host_status_ok");

local time = require "socket".gettime;
local template = require "util.interpolation".new("%b{}", function (s) return s end)

module:depends "http"

local threshold = module:get_option_number("status_check_heartbeat_threshold", 10);

local function status_string(status, duration, comment)
	local string_timestamp;
	if duration then
		string_timestamp = ("(%0.2fs%s)"):format(duration, comment or "");
	elseif comment then
		string_timestamp = ("(%s)"):format(comment);
	else
		return status and "UP" or "DOWN";
	end
	return (status and "UP " or "DOWN ")..string_timestamp;
end

local function string_pad(s, len)
	return s..(" "):rep(len-#s);
end

local status_page_template = [[
STATUS {status}
{host_statuses%HOST {item} {idx}
}]];

function status_page()
	local host_statuses = {};
	local current_time = time();

	local all_ok = true;
	local failed_hosts = {};

	for host in pairs(hosts) do
		local last_heartbeat_time = heartbeats[host];
		
		local ok, status_text = true;
		
		local is_component = hosts[host].type == "component" and hosts[host].modules.component;
		
		if is_component then
			local current_status = hosts[host].modules.component.connected;
			if events[host] then
				local tracked_status = events[host].connected;
				if tracked_status == current_status then
					status_text = status_string(current_status, time() - events[host].timestamp);
				else
					status_text = status_string(current_status, nil, "!");
				end
			else
				status_text = status_string(current_status, nil, "?");
			end
			if not current_status then
				ok = false;
			end
		else
			local event_info = events[host];
			local connected = true;
			if event_info then
				connected = event_info.connected;
			end
			status_text = status_string(connected, event_info and (time() - events[host].timestamp), not event_info and "?");
		end

		if last_heartbeat_time then
			local time_since_heartbeat = current_time - last_heartbeat_time;
			if ok then
				if time_since_heartbeat > threshold then
					status_text = ("TIMEOUT (%0.2fs)"):format(time_since_heartbeat);
					ok = false;
				else
					status_text = status_text:gsub("^%S+", "GOOD");
				end
			end
		end

		if not ok then
			all_ok = false;
			table.insert(failed_hosts, host);
		end
		
		if not ok or is_component or last_heartbeat_time then
			host_statuses[host] = string_pad(status_text, 20);
		end
		local last_ok = host_status_ok[host];
		if last_ok ~= ok then
			if last_ok ~= nil then
				module:log("warn", "Host status check %s (%s)", ok and "OK" or "FAILED", status_text);
			end
			host_status_ok[host] = ok;
		end
	end
	local page = template(status_page_template, {
		status = all_ok and "OK" or ("FAIL: "..table.concat(failed_hosts, ", "));
		host_statuses = host_statuses;
	});
	return page;
end

module:provides("http", {
	route = {
		GET = status_page;
	};
})