# HG changeset patch
# User Kim Alvefur <zash@zash.se>
# Date 1716116815 -7200
# Node ID cf367ab36fcc3d2f91c35588931f992b00e3adbe
# Parent  6f840763fc73c384eebc77def84f9cfc5b71bfdd
util.prosodyctl: Use notify socket to wait for Prosody to be ready

Previously, prosodyctl only waits for the pidfile to appear, which does
not necessarily mean that Prosody is fully ready to receive traffic.

By waiting until Prosody says it's ready via the systemd notify socket
we know for sure that Prosody is really ready.

Notably this should ensure that when running `make integration-test`
Prosody is really ready when Scansion starts running tests.

Not sure if this timeout handling is optimal.

diff -r 6f840763fc73 -r cf367ab36fcc util/prosodyctl.lua
--- a/util/prosodyctl.lua	Tue May 14 17:07:47 2024 +0200
+++ b/util/prosodyctl.lua	Sun May 19 13:06:55 2024 +0200
@@ -15,9 +15,13 @@
 local interpolation = require "prosody.util.interpolation";
 local signal = require "prosody.util.signal";
 local set = require "prosody.util.set";
+local path = require"prosody.util.paths";
 local lfs = require "lfs";
 local type = type;
 
+local have_socket_unix, socket_unix = pcall(require, "socket.unix");
+have_socket_unix = have_socket_unix and type(socket_unix) == "table"; -- was a function in older LuaSocket
+
 local nodeprep, nameprep = stringprep.nodeprep, stringprep.nameprep;
 
 local io, os = io, os;
@@ -177,11 +181,31 @@
 	if ret then
 		return false, "already-running";
 	end
+	local notify_socket;
+	if have_socket_unix then
+		local notify_path = path.join(prosody.paths.data, "notify.sock");
+		os.remove(notify_path);
+		lua = string.format("NOTIFY_SOCKET=%q %s", notify_path, lua);
+		notify_socket = socket_unix.dgram();
+		local ok = notify_socket:setsockname(notify_path);
+		if not ok then return false, "notify-failed"; end
+	end
 	if not source_dir then
 		os.execute(lua .. "./prosody -D");
 	else
 		os.execute(lua .. source_dir.."/../../bin/prosody -D");
 	end
+
+	if notify_socket then
+		for i = 1, 5 do
+			notify_socket:settimeout(i);
+			if notify_socket:receivefrom() == "READY=1" then
+				return true;
+			end
+		end
+		return false, "not-ready";
+	end
+
 	return true;
 end