view mod_inotify_reload/mod_inotify_reload.lua @ 5173:460f78654864

mod_muc_rtbl: also filter messages This was a bit tricky because we don't want to run the JIDs through SHA256 on each message. Took a while to come up with this simple plan of just caching the SHA256 of the JIDs on the occupants. This will leave some dirt in the occupants after unloading the module, but that should be ok; once they cycle the room, the hashes will be gone. This is direly needed, otherwise, there is a tight race between the moderation activities and the actors joining the room.
author Jonas Schäfer <jonas@wielicki.name>
date Tue, 21 Feb 2023 21:37:27 +0100
parents ab988e98a9f9
children 82207f936f1f
line wrap: on
line source

-- mod_inotify_reload
-- Reloads modules when their files change
-- Depends on linotify: https://github.com/hoelzro/linotify

module:set_global();

local inotify = require "inotify";
local modulemanager = require "core.modulemanager";

local inh = inotify.init();

local watches = {};
local watch_ids = {};

-- Fake socket object around inotify
local inh_conn = {
	getfd = function () return inh:fileno(); end;
	dirty = function (self) return false; end;
	settimeout = function () end;
	send = function (_, d) return #d, 0; end;
	close = function () end;
	receive = function ()
		local events = inh:read();
		for _, event in ipairs(events) do
			local mod = watches[watch_ids[event.wd]];
			if mod then
				local host, name = mod.host, mod.name;
				module:log("debug", "Reloading changed module mod_%s on %s", name, host);
				modulemanager.reload(host, name);
			else
				module:log("warn", "no watch for %d", event.wd);
			end
		end
		return "";
	end
};
require "net.server".wrapclient(inh_conn, "inotify", inh:fileno(), {
	onincoming = function () end, ondisconnect = function () end
}, "*a");

function watch_module(name, host, path)
	local id, err = inh:addwatch(path, inotify.IN_CLOSE_WRITE);
	if not id then return nil, err; end
	local k = host.."\0"..name;
	watches[k] = { id = id, path = path, name = name, host = host };
	watch_ids[id] = k;
	module:log("debug", "Watching %s:%s with id %d", name, host, id);
	return true;
end

function unwatch_module(name, host)
	local k = host.."\0"..name;
	if not watches[k] then
		module:log("warn", "Not watching %s:%s", name, host);
		return nil, "not-watching";
	end
	local id = watches[k].id;
	local ok, err = inh:rmwatch(id);
	module:log("info", "Removed watch %d", id);
	watches[k] = nil;
	watch_ids[id] = nil;
	return ok, err;
end

function module_loaded(event)
	local host, name = event.host, event.module;
	local path = modulemanager.get_module(host, name).module.path;
	if not path then
		module:log("warn", "Couldn't watch mod_%s, no path", name);
		return;
	end
	if watch_module(name, host, path) then
		module:log("debug", "Watching mod_%s", name);
	end
end

function module_unloaded(event)
	unwatch_module(event.module, event.host);
end

function module.add_host(module)
	module:hook("module-loaded", module_loaded);
	module:hook("module-unloaded", module_unloaded);
end

module:hook("module-loaded", module_loaded);
module:hook("module-unloaded", module_unloaded);