view mod_inotify_reload/mod_inotify_reload.lua @ 5186:fa3059e653fa

mod_http_oauth2: Implement the Implicit flow Everyone says this is insecure and bad, but it's also the only thing that makes sense for e.g. pure JavaScript clients, but hey implement this even more complicated thing instead!
author Kim Alvefur <zash@zash.se>
date Thu, 02 Mar 2023 22:06:50 +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);