File

mod_muc_eventsource/mod_muc_eventsource.lua @ 5160:8474a3b80200

mod_firewall: Fix 'is_admin' internal dependency rule #1797 (thanks diane) Looks like the boolean logic was inverted here. Instead, for now, simply check if is_admin is there. It is deprecated in trunk and was briefly removed before being brought back with a 'deprecated' warning as part of the new roles and permissions work. Making this dependency conditioned on the existence of the underlying function should make it work until it actually goes away for real.
author Kim Alvefur <zash@zash.se>
date Fri, 27 Jan 2023 23:06:25 +0100
parent 2897:39485b9bbdd6
line wrap: on
line source

module:depends("http");
local nodeprep = require "util.encodings".stringprep.nodeprep;

local jid_split = require "util.jid".split;
local json = require "util.json";

local streams = {};

function client_closed(response)
	local node = response._eventsource_node;
	module:log("debug", "Destroying client for %q", node);
	streams[node][response] = nil;
	if next(streams[node]) == nil then
		streams[node] = nil;
	end
end

function serve_stream(event, node)
	local response = event.response;

	node = nodeprep(node);
	if node == nil then
		return 400;
	end

	module:log("debug", "Client subscribed to: %s", node);

	response.on_destroy = client_closed;
	response._eventsource_node = node;

	response.conn:write(table.concat({
		"HTTP/1.1 200 OK";
		"Content-Type: text/event-stream";
		"Access-Control-Allow-Origin: *";
		"Access-Control-Allow-Methods: GET";
		"Access-Control-Max-Age: 7200";
		"";
		"";
	}, "\r\n"));

	local clientlist = streams[node];
	if not clientlist then
		clientlist = {};
		streams[node] = clientlist;
	end
	clientlist[response] = response.conn;

	return true;
end

function handle_message(event)
	local room, stanza = event.room, event.stanza;
	local node = (jid_split(event.room.jid));
	local clientlist = streams[node];
	if not clientlist then module:log("debug", "No clients for %q", node); return; end

	-- Extract body from message
	local body = event.stanza:get_child_text("body");
	if not body then
		return;
	end
	local nick = select(3, jid_split(stanza.attr.from));
	-- Encode body and broadcast to eventsource subscribers
	local json_data = json.encode({
		nick = nick;
		body = body;
	});
	local data = "data: "..json_data:gsub("\n", "\ndata: \n").."\n\n";
	for response, conn in pairs(clientlist) do
		conn:write(data);
	end
end

module:provides("http", {
	name = "eventsource";
	route = {
		["GET /*"] = serve_stream;
	};
});


module:hook("muc-broadcast-message", handle_message);