-- Measure the number of messages used in a meeting. Sends amplitude event. -- Needs to be activated under the muc component where the limit needs to be applied (main muc and breakout muc) -- Copyright (C) 2023-present 8x8, Inc. local jid = require 'util.jid'; local http = require 'net.http'; local cjson_safe = require 'cjson.safe' local amplitude_endpoint = module:get_option_string('amplitude_endpoint', 'https://api2.amplitude.com/2/httpapi'); local amplitude_api_key = module:get_option_string('amplitude_api_key'); if not amplitude_api_key then module:log("warn", "No 'amplitude_api_key' option set, disabling amplitude reporting"); return end local muc_domain_base = module:get_option_string('muc_mapper_domain_base'); local isBreakoutRoom = module.host == 'breakout.' .. muc_domain_base; local util = module:require 'util'; local is_healthcheck_room = util.is_healthcheck_room; local extract_subdomain = util.extract_subdomain; module:log('info', 'Loading measure message count'); local shard_name = module:context(muc_domain_base):get_option_string('shard_name'); local region_name = module:context(muc_domain_base):get_option_string('region_name'); local release_number = module:context(muc_domain_base):get_option_string('release_number'); local http_headers = { ['User-Agent'] = 'Prosody ('..prosody.version..'; '..prosody.platform..')', ['Content-Type'] = 'application/json' }; local inspect = require "inspect" function table.clone(t) return {table.unpack(t)} end local function event_cb(content_, code_, response_, request_) if code_ == 200 or code_ == 204 then module:log('debug', 'URL Callback: Code %s, Content %s, Request (host %s, path %s, body %s), Response: %s', code_, content_, request_.host, request_.path, inspect(request_.body), inspect(response_)); else module:log('warn', 'URL Callback non successful: Code %s, Content %s, Request (%s), Response: %s', code_, content_, inspect(request_), inspect(response_)); end end function send_event(room) local user_properties = { shard_name = shard_name; region_name = region_name; release_number = release_number; }; local node = jid.split(room.jid); local subdomain, room_name = extract_subdomain(node); user_properties.tenant = subdomain or '/'; user_properties.conference_name = room_name or node; local event_properties = { messages_count = room._muc_messages_count or 0; polls_count = room._muc_polls_count or 0; tenant_mismatch = room.jitsi_meet_tenant_mismatch or false; }; if room.created_timestamp then event_properties.duration = (os.time() * 1000 - room.created_timestamp) / 1000; end local event = { api_key = amplitude_api_key; events = { { user_id = room._data.meetingId; device_id = room._data.meetingId; event_type = 'conference_ended'; event_properties = event_properties; user_properties = user_properties; } }; }; local request = http.request(amplitude_endpoint, { headers = http_headers, method = "POST", body = cjson_safe.encode(event) }, event_cb); end function on_message(event) local stanza = event.stanza; local body = stanza:get_child('body'); if not body then -- we ignore messages without body - lobby, polls ... return; end local session = event.origin; if not session or not session.jitsi_web_query_room then return; end -- get room name with tenant and find room. local room = get_room_by_name_and_subdomain(session.jitsi_web_query_room, session.jitsi_web_query_prefix); if not room then module:log('warn', 'No room found found for %s/%s', session.jitsi_web_query_prefix, session.jitsi_web_query_room); return; end if not room._muc_messages_count then room._muc_messages_count = 0; end room._muc_messages_count = room._muc_messages_count + 1; end -- Conference ended, send stats function room_destroyed(event) local room, session = event.room, event.origin; if is_healthcheck_room(room.jid) then return; end if isBreakoutRoom then return; end send_event(room); end function poll_created(event) local session = event.event.origin; -- get room name with tenant and find room. local room = get_room_by_name_and_subdomain(session.jitsi_web_query_room, session.jitsi_web_query_prefix); if not room then module:log('warn', 'No room found found for %s/%s', session.jitsi_web_query_prefix, session.jitsi_web_query_room); return false; end if not room._muc_polls_count then room._muc_polls_count = 0; end room._muc_polls_count = room._muc_polls_count + 1; end module:hook('message/full', on_message); -- private messages module:hook('message/bare', on_message); -- room messages module:hook('muc-room-destroyed', room_destroyed, -1); module:hook("muc-occupant-left", function(event) local occupant, room = event.occupant, event.room; local session = event.origin; if session and session.jitsi_meet_tenant_mismatch then room.jitsi_meet_tenant_mismatch = true; end end); module:hook('poll-created', poll_created);