diff --git a/prodsody/.env b/prodsody/.env new file mode 100644 index 0000000..0154b4c --- /dev/null +++ b/prodsody/.env @@ -0,0 +1,220 @@ +# shellcheck disable=SC2034 + +################################################################################ +################################################################################ +# Welcome to the Jitsi Meet Docker setup! +# +# This sample .env file contains some basic options to get you started. +# The full options reference can be found here: +# https://jitsi.github.io/handbook/docs/devops-guide/devops-guide-docker +################################################################################ +################################################################################ + + +# +# Basic configuration options +# + +# Directory where all configuration will be stored +# custom +CONFIG=./jitsi-meet-cfg + +# Exposed HTTP port +HTTP_PORT=8000 + +# Exposed HTTPS port +HTTPS_PORT=8443 + +# System time zone +TZ=UTC + +# Public URL for the web service (required) +#PUBLIC_URL=https://meet.example.com + +# Media IP addresses to advertise by the JVB +# This setting deprecates DOCKER_HOST_ADDRESS, and supports a comma separated list of IPs +# See the "Running behind NAT or on a LAN environment" section in the Handbook: +# https://jitsi.github.io/handbook/docs/devops-guide/devops-guide-docker#running-behind-nat-or-on-a-lan-environment +#JVB_ADVERTISE_IPS=192.168.1.1,1.2.3.4 + + +# +# JaaS Components (beta) +# https://jaas.8x8.vc +# + +# Enable JaaS Components (hosted Jigasi) +# NOTE: if Let's Encrypt is enabled a JaaS account will be automatically created, using the provided email in LETSENCRYPT_EMAIL +#ENABLE_JAAS_COMPONENTS=0 + +# +# Let's Encrypt configuration +# + +# Enable Let's Encrypt certificate generation +#ENABLE_LETSENCRYPT=1 + +# Domain for which to generate the certificate +#LETSENCRYPT_DOMAIN=meet.example.com + +# E-Mail for receiving important account notifications (mandatory) +#LETSENCRYPT_EMAIL=alice@atlanta.net + +# Use the staging server (for avoiding rate limits while testing) +#LETSENCRYPT_USE_STAGING=1 + + +# +# Etherpad integration (for document sharing) +# + +# Set etherpad-lite URL in docker local network (uncomment to enable) +#ETHERPAD_URL_BASE=http://etherpad.meet.jitsi:9001 + +# Set etherpad-lite public URL, including /p/ pad path fragment (uncomment to enable) +#ETHERPAD_PUBLIC_URL=https://etherpad.my.domain/p/ + +# Name your etherpad instance! +ETHERPAD_TITLE=Video Chat + +# The default text of a pad +ETHERPAD_DEFAULT_PAD_TEXT="Welcome to Web Chat!\n\n" + +# Name of the skin for etherpad +ETHERPAD_SKIN_NAME=colibris + +# Skin variants for etherpad +ETHERPAD_SKIN_VARIANTS="super-light-toolbar super-light-editor light-background full-width-editor" + + +# +# Basic Jigasi configuration options (needed for SIP gateway support) +# + +# SIP URI for incoming / outgoing calls +#JIGASI_SIP_URI=test@sip2sip.info + +# Password for the specified SIP account as a clear text +#JIGASI_SIP_PASSWORD=passw0rd + +# SIP server (use the SIP account domain if in doubt) +#JIGASI_SIP_SERVER=sip2sip.info + +# SIP server port +#JIGASI_SIP_PORT=5060 + +# SIP server transport +#JIGASI_SIP_TRANSPORT=UDP + + +# +# Authentication configuration (see handbook for details) +# + +# Enable authentication +#ENABLE_AUTH=1 + +# Enable guest access +#ENABLE_GUESTS=1 + +# Select authentication type: internal, jwt, ldap or matrix +#AUTH_TYPE=internal + +# JWT authentication +# + +# Application identifier +#JWT_APP_ID=my_jitsi_app_id + +# Application secret known only to your token generator +#JWT_APP_SECRET=my_jitsi_app_secret + +# (Optional) Set asap_accepted_issuers as a comma separated list +#JWT_ACCEPTED_ISSUERS=my_web_client,my_app_client + +# (Optional) Set asap_accepted_audiences as a comma separated list +#JWT_ACCEPTED_AUDIENCES=my_server1,my_server2 + +# LDAP authentication (for more information see the Cyrus SASL saslauthd.conf man page) +# + +# LDAP url for connection +#LDAP_URL=ldaps://ldap.domain.com/ + +# LDAP base DN. Can be empty +#LDAP_BASE=DC=example,DC=domain,DC=com + +# LDAP user DN. Do not specify this parameter for the anonymous bind +#LDAP_BINDDN=CN=binduser,OU=users,DC=example,DC=domain,DC=com + +# LDAP user password. Do not specify this parameter for the anonymous bind +#LDAP_BINDPW=LdapUserPassw0rd + +# LDAP filter. Tokens example: +# %1-9 - if the input key is user@mail.domain.com, then %1 is com, %2 is domain and %3 is mail +# %s - %s is replaced by the complete service string +# %r - %r is replaced by the complete realm string +#LDAP_FILTER=(sAMAccountName=%u) + +# LDAP authentication method +#LDAP_AUTH_METHOD=bind + +# LDAP version +#LDAP_VERSION=3 + +# LDAP TLS using +#LDAP_USE_TLS=1 + +# List of SSL/TLS ciphers to allow +#LDAP_TLS_CIPHERS=SECURE256:SECURE128:!AES-128-CBC:!ARCFOUR-128:!CAMELLIA-128-CBC:!3DES-CBC:!CAMELLIA-128-CBC + +# Require and verify server certificate +#LDAP_TLS_CHECK_PEER=1 + +# Path to CA cert file. Used when server certificate verify is enabled +#LDAP_TLS_CACERT_FILE=/etc/ssl/certs/ca-certificates.crt + +# Path to CA certs directory. Used when server certificate verify is enabled +#LDAP_TLS_CACERT_DIR=/etc/ssl/certs + +# Wether to use starttls, implies LDAPv3 and requires ldap:// instead of ldaps:// +# LDAP_START_TLS=1 + + +# +# Security +# +# Set these to strong passwords to avoid intruders from impersonating a service account +# The service(s) won't start unless these are specified +# Running ./gen-passwords.sh will update .env with strong passwords +# You may skip the Jigasi and Jibri passwords if you are not using those +# DO NOT reuse passwords +# + +# XMPP password for Jicofo client connections +JICOFO_AUTH_PASSWORD=f38025966d68dbfa2ce9e4b1b73985a3 + +# XMPP password for JVB client connections +JVB_AUTH_PASSWORD=b690c0555f116fea238dcdf4421d69f6 + +# XMPP password for Jigasi MUC client connections +JIGASI_XMPP_PASSWORD=f262def4ac4fdaf3878ff0dd1b70b2fd + +# XMPP recorder password for Jibri client connections +JIBRI_RECORDER_PASSWORD=9c393fecbca7ae6d6631192833ebf50d + +# XMPP password for Jibri client connections +JIBRI_XMPP_PASSWORD=662f13288a07ca64afb4b9b97b4feed6 + +# +# Docker Compose options +# + +# Container restart policy +#RESTART_POLICY=unless-stopped + +# Jitsi image version (useful for local development) +#JITSI_IMAGE_VERSION=latest +#custom +XMPP_MODULES=jitsi_rooms +LOG_LEVEL=debug diff --git a/prodsody/.gitignore b/prodsody/.gitignore new file mode 100644 index 0000000..18b504b --- /dev/null +++ b/prodsody/.gitignore @@ -0,0 +1,12 @@ +jitsi-meet-cfg/jicofo/jicofo.conf +jitsi-meet-cfg/jicofo/logging.properties +jitsi-meet-cfg/jvb/jvb.conf +jitsi-meet-cfg/jvb/logging.properties +jitsi-meet-cfg/prosody/config/certs/ +jitsi-meet-cfg/prosody/config/conf.d/ +jitsi-meet-cfg/prosody/config/prosody.cfg.lua +jitsi-meet-cfg/prosody/config/saslauthd.conf +jitsi-meet-cfg/web/config.js +jitsi-meet-cfg/web/interface_config.js +jitsi-meet-cfg/web/keys/ +jitsi-meet-cfg/web/nginx/ diff --git a/prodsody/Readme.md b/prodsody/Readme.md new file mode 100644 index 0000000..65ebf87 --- /dev/null +++ b/prodsody/Readme.md @@ -0,0 +1,21 @@ +# Jitsi rooms prosody plugin + +## Development + +### Requirements + +- Docker & docker-compose +- entr for dev mode + +### Get started + +- run `./run_dev.sh` +- open [https://localhost:8443/](https://localhost:8443/) +- make changes to mod_jitsi_rooms.lua and save the file +- prosody will be restarted +- join a room in jitsi +- run `curl localhost:5280/jitsi_rooms` to test the rest endpoint + +## Deploying + +- all required changes to the [jitsi meet docker setup](https://github.com/jitsi/docker-jitsi-meet) are marked with a "custom" comment diff --git a/prodsody/docker-compose.yml b/prodsody/docker-compose.yml new file mode 100644 index 0000000..5535060 --- /dev/null +++ b/prodsody/docker-compose.yml @@ -0,0 +1,349 @@ +version: "3.5" + +services: + # Frontend + web: + image: jitsi/web:${JITSI_IMAGE_VERSION:-stable-8218} + restart: ${RESTART_POLICY:-unless-stopped} + ports: + - "${HTTP_PORT}:80" + - "${HTTPS_PORT}:443" + volumes: + - ${CONFIG}/web:/config:Z + - ${CONFIG}/web/crontabs:/var/spool/cron/crontabs:Z + - ${CONFIG}/transcripts:/usr/share/jitsi-meet/transcripts:Z + environment: + - AMPLITUDE_ID + - ANALYTICS_SCRIPT_URLS + - ANALYTICS_WHITELISTED_EVENTS + - AUDIO_QUALITY_OPUS_BITRATE + - AUTO_CAPTION_ON_RECORD + - BRANDING_DATA_URL + - CALLSTATS_CUSTOM_SCRIPT_URL + - CALLSTATS_ID + - CALLSTATS_SECRET + - CHROME_EXTENSION_BANNER_JSON + - CONFCODE_URL + - CONFIG_EXTERNAL_CONNECT + - DEFAULT_LANGUAGE + - DEPLOYMENTINFO_ENVIRONMENT + - DEPLOYMENTINFO_ENVIRONMENT_TYPE + - DEPLOYMENTINFO_REGION + - DEPLOYMENTINFO_SHARD + - DEPLOYMENTINFO_USERREGION + - DESKTOP_SHARING_FRAMERATE_MIN + - DESKTOP_SHARING_FRAMERATE_MAX + - DIALIN_NUMBERS_URL + - DIALOUT_AUTH_URL + - DIALOUT_CODES_URL + - DISABLE_AUDIO_LEVELS + - DISABLE_DEEP_LINKING + - DISABLE_GRANT_MODERATOR + - DISABLE_HTTPS + - DISABLE_KICKOUT + - DISABLE_LOCAL_RECORDING + - DISABLE_POLLS + - DISABLE_PRIVATE_CHAT + - DISABLE_PROFILE + - DISABLE_REACTIONS + - DISABLE_REMOTE_VIDEO_MENU + - DISABLE_START_FOR_ALL + - DROPBOX_APPKEY + - DROPBOX_REDIRECT_URI + - DYNAMIC_BRANDING_URL + - ENABLE_AUDIO_PROCESSING + - ENABLE_AUTH + - ENABLE_BREAKOUT_ROOMS + - ENABLE_CALENDAR + - ENABLE_COLIBRI_WEBSOCKET + - ENABLE_E2EPING + - ENABLE_FILE_RECORDING_SHARING + - ENABLE_GUESTS + - ENABLE_HSTS + - ENABLE_HTTP_REDIRECT + - ENABLE_IPV6 + - ENABLE_LETSENCRYPT + - ENABLE_LIPSYNC + - ENABLE_NO_AUDIO_DETECTION + - ENABLE_NOISY_MIC_DETECTION + - ENABLE_OCTO + - ENABLE_OPUS_RED + - ENABLE_PREJOIN_PAGE + - ENABLE_P2P + - ENABLE_WELCOME_PAGE + - ENABLE_CLOSE_PAGE + - ENABLE_LIVESTREAMING + - ENABLE_LOCAL_RECORDING_NOTIFY_ALL_PARTICIPANT + - ENABLE_LOCAL_RECORDING_SELF_START + - ENABLE_RECORDING + - ENABLE_REMB + - ENABLE_REQUIRE_DISPLAY_NAME + - ENABLE_SERVICE_RECORDING + - ENABLE_SIMULCAST + - ENABLE_STATS_ID + - ENABLE_STEREO + - ENABLE_SUBDOMAINS + - ENABLE_TALK_WHILE_MUTED + - ENABLE_TCC + - ENABLE_TRANSCRIPTIONS + - ENABLE_XMPP_WEBSOCKET + - ENABLE_JAAS_COMPONENTS + - ETHERPAD_PUBLIC_URL + - ETHERPAD_URL_BASE + - E2EPING_NUM_REQUESTS + - E2EPING_MAX_CONFERENCE_SIZE + - E2EPING_MAX_MESSAGE_PER_SECOND + - GOOGLE_ANALYTICS_ID + - GOOGLE_API_APP_CLIENT_ID + - HIDE_PREMEETING_BUTTONS + - HIDE_PREJOIN_DISPLAY_NAME + - HIDE_PREJOIN_EXTRA_BUTTONS + - INVITE_SERVICE_URL + - LETSENCRYPT_DOMAIN + - LETSENCRYPT_EMAIL + - LETSENCRYPT_USE_STAGING + - MATOMO_ENDPOINT + - MATOMO_SITE_ID + - MICROSOFT_API_APP_CLIENT_ID + - NGINX_RESOLVER + - NGINX_WORKER_PROCESSES + - NGINX_WORKER_CONNECTIONS + - PEOPLE_SEARCH_URL + - PREFERRED_LANGUAGE + - PUBLIC_URL + - P2P_PREFERRED_CODEC + - RESOLUTION + - RESOLUTION_MIN + - RESOLUTION_WIDTH + - RESOLUTION_WIDTH_MIN + - START_AUDIO_MUTED + - START_AUDIO_ONLY + - START_BITRATE + - START_SILENT + - START_WITH_AUDIO_MUTED + - START_VIDEO_MUTED + - START_WITH_VIDEO_MUTED + - TESTING_CAP_SCREENSHARE_BITRATE + - TESTING_OCTO_PROBABILITY + - TOKEN_AUTH_URL + - TOOLBAR_BUTTONS + - TRANSLATION_LANGUAGES + - TRANSLATION_LANGUAGES_HEAD + - TZ + - USE_APP_LANGUAGE + - VIDEOQUALITY_BITRATE_H264_LOW + - VIDEOQUALITY_BITRATE_H264_STANDARD + - VIDEOQUALITY_BITRATE_H264_HIGH + - VIDEOQUALITY_BITRATE_VP8_LOW + - VIDEOQUALITY_BITRATE_VP8_STANDARD + - VIDEOQUALITY_BITRATE_VP8_HIGH + - VIDEOQUALITY_BITRATE_VP9_LOW + - VIDEOQUALITY_BITRATE_VP9_STANDARD + - VIDEOQUALITY_BITRATE_VP9_HIGH + - VIDEOQUALITY_ENFORCE_PREFERRED_CODEC + - VIDEOQUALITY_PREFERRED_CODEC + - XMPP_AUTH_DOMAIN + - XMPP_BOSH_URL_BASE + - XMPP_DOMAIN + - XMPP_GUEST_DOMAIN + - XMPP_MUC_DOMAIN + - XMPP_RECORDER_DOMAIN + - XMPP_PORT + - WHITEBOARD_ENABLED + - WHITEBOARD_COLLAB_SERVER_BASE_URL + networks: + meet.jitsi: + + # XMPP server + prosody: + image: jitsi/prosody:${JITSI_IMAGE_VERSION:-stable-8218} + restart: ${RESTART_POLICY:-unless-stopped} + expose: + - "${XMPP_PORT:-5222}" + - "5347" + - "5280" + # custom + ports: + - 5280:5280 + volumes: + - ${CONFIG}/prosody/config:/config:Z + - ${CONFIG}/prosody/prosody-plugins-custom:/prosody-plugins-custom:Z + environment: + - AUTH_TYPE + - DISABLE_POLLS + - ENABLE_AUTH + - ENABLE_AV_MODERATION + - ENABLE_BREAKOUT_ROOMS + - ENABLE_END_CONFERENCE + - ENABLE_GUESTS + - ENABLE_IPV6 + - ENABLE_LOBBY + - ENABLE_RECORDING + - ENABLE_XMPP_WEBSOCKET + - ENABLE_JAAS_COMPONENTS + - GC_TYPE + - GC_INC_TH + - GC_INC_SPEED + - GC_INC_STEP_SIZE + - GC_GEN_MIN_TH + - GC_GEN_MAX_TH + - GLOBAL_CONFIG + - GLOBAL_MODULES + - JIBRI_RECORDER_USER + - JIBRI_RECORDER_PASSWORD + - JIBRI_XMPP_USER + - JIBRI_XMPP_PASSWORD + - JICOFO_AUTH_PASSWORD + - JICOFO_COMPONENT_SECRET + - JIGASI_XMPP_USER + - JIGASI_XMPP_PASSWORD + - JVB_AUTH_USER + - JVB_AUTH_PASSWORD + - JWT_APP_ID + - JWT_APP_SECRET + - JWT_ACCEPTED_ISSUERS + - JWT_ACCEPTED_AUDIENCES + - JWT_ASAP_KEYSERVER + - JWT_ALLOW_EMPTY + - JWT_AUTH_TYPE + - JWT_ENABLE_DOMAIN_VERIFICATION + - JWT_TOKEN_AUTH_MODULE + - MATRIX_UVS_URL + - MATRIX_UVS_ISSUER + - MATRIX_UVS_AUTH_TOKEN + - MATRIX_UVS_SYNC_POWER_LEVELS + - LOG_LEVEL + - LDAP_AUTH_METHOD + - LDAP_BASE + - LDAP_BINDDN + - LDAP_BINDPW + - LDAP_FILTER + - LDAP_VERSION + - LDAP_TLS_CIPHERS + - LDAP_TLS_CHECK_PEER + - LDAP_TLS_CACERT_FILE + - LDAP_TLS_CACERT_DIR + - LDAP_START_TLS + - LDAP_URL + - LDAP_USE_TLS + - MAX_PARTICIPANTS + - PROSODY_RESERVATION_ENABLED + - PROSODY_RESERVATION_REST_BASE_URL + - PUBLIC_URL + - TURN_CREDENTIALS + - TURN_HOST + - TURNS_HOST + - TURN_PORT + - TURNS_PORT + - TURN_TRANSPORT + - TZ + - XMPP_DOMAIN + - XMPP_AUTH_DOMAIN + - XMPP_GUEST_DOMAIN + - XMPP_MUC_DOMAIN + - XMPP_INTERNAL_MUC_DOMAIN + - XMPP_MODULES + - XMPP_MUC_MODULES + - XMPP_MUC_CONFIGURATION + - XMPP_INTERNAL_MUC_MODULES + - XMPP_RECORDER_DOMAIN + - XMPP_PORT + networks: + meet.jitsi: + aliases: + - ${XMPP_SERVER:-xmpp.meet.jitsi} + + # Focus component + jicofo: + image: jitsi/jicofo:${JITSI_IMAGE_VERSION:-stable-8218} + restart: ${RESTART_POLICY:-unless-stopped} + volumes: + - ${CONFIG}/jicofo:/config:Z + environment: + - AUTH_TYPE + - BRIDGE_AVG_PARTICIPANT_STRESS + - BRIDGE_STRESS_THRESHOLD + - ENABLE_AUTH + - ENABLE_AUTO_OWNER + - ENABLE_CODEC_VP8 + - ENABLE_CODEC_VP9 + - ENABLE_CODEC_H264 + - ENABLE_OCTO + - ENABLE_RECORDING + - ENABLE_SCTP + - ENABLE_AUTO_LOGIN + - JICOFO_AUTH_PASSWORD + - JICOFO_ENABLE_BRIDGE_HEALTH_CHECKS + - JICOFO_CONF_INITIAL_PARTICIPANT_WAIT_TIMEOUT + - JICOFO_CONF_SINGLE_PARTICIPANT_TIMEOUT + - JICOFO_ENABLE_HEALTH_CHECKS + - JIBRI_BREWERY_MUC + - JIBRI_REQUEST_RETRIES + - JIBRI_PENDING_TIMEOUT + - JIGASI_BREWERY_MUC + - JIGASI_SIP_URI + - JVB_BREWERY_MUC + - MAX_BRIDGE_PARTICIPANTS + - OCTO_BRIDGE_SELECTION_STRATEGY + - SENTRY_DSN="${JICOFO_SENTRY_DSN:-0}" + - SENTRY_ENVIRONMENT + - SENTRY_RELEASE + - TZ + - XMPP_DOMAIN + - XMPP_AUTH_DOMAIN + - XMPP_INTERNAL_MUC_DOMAIN + - XMPP_MUC_DOMAIN + - XMPP_RECORDER_DOMAIN + - XMPP_SERVER + - XMPP_PORT + depends_on: + - prosody + networks: + meet.jitsi: + + # Video bridge + jvb: + image: jitsi/jvb:${JITSI_IMAGE_VERSION:-stable-8218} + restart: ${RESTART_POLICY:-unless-stopped} + ports: + - "${JVB_PORT:-10000}:${JVB_PORT:-10000}/udp" + - "127.0.0.1:${JVB_COLIBRI_PORT:-8080}:8080" + volumes: + - ${CONFIG}/jvb:/config:Z + environment: + - DOCKER_HOST_ADDRESS + - ENABLE_COLIBRI_WEBSOCKET + - ENABLE_OCTO + - JVB_ADVERTISE_IPS + - JVB_ADVERTISE_PRIVATE_CANDIDATES + - JVB_AUTH_USER + - JVB_AUTH_PASSWORD + - JVB_BREWERY_MUC + - JVB_DISABLE_STUN + - JVB_PORT + - JVB_MUC_NICKNAME + - JVB_STUN_SERVERS + - JVB_OCTO_BIND_ADDRESS + - JVB_OCTO_REGION + - JVB_OCTO_RELAY_ID + - JVB_WS_DOMAIN + - JVB_WS_SERVER_ID + - PUBLIC_URL + - SENTRY_DSN="${JVB_SENTRY_DSN:-0}" + - SENTRY_ENVIRONMENT + - SENTRY_RELEASE + - COLIBRI_REST_ENABLED + - SHUTDOWN_REST_ENABLED + - TZ + - XMPP_AUTH_DOMAIN + - XMPP_INTERNAL_MUC_DOMAIN + - XMPP_SERVER + - XMPP_PORT + depends_on: + - prosody + networks: + meet.jitsi: + +# Custom network so all services can communicate using a FQDN +networks: + meet.jitsi: diff --git a/prodsody/jitsi-meet-cfg/jibri/.gitkeep b/prodsody/jitsi-meet-cfg/jibri/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/prodsody/jitsi-meet-cfg/jigasi/.gitkeep b/prodsody/jitsi-meet-cfg/jigasi/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/prodsody/jitsi-meet-cfg/prosody/prosody-plugins-custom/.gitkeep b/prodsody/jitsi-meet-cfg/prosody/prosody-plugins-custom/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/prodsody/jitsi-meet-cfg/prosody/prosody-plugins-custom/mod_jitsi_rooms.lua b/prodsody/jitsi-meet-cfg/prosody/prosody-plugins-custom/mod_jitsi_rooms.lua new file mode 100644 index 0000000..f517a63 --- /dev/null +++ b/prodsody/jitsi-meet-cfg/prosody/prosody-plugins-custom/mod_jitsi_rooms.lua @@ -0,0 +1,204 @@ +---@diagnostic disable: deprecated +local it = require "util.iterators"; +local json = require "util.json"; +local array = require "util.array"; +local iterators = require "util.iterators"; +local jid = require "util.jid"; + +local async_handler_wrapper = module:require "util".async_handler_wrapper; +local get_room_from_jid = module:require "util".get_room_from_jid; +local muc_domain_prefix = module:get_option_string("muc_mapper_domain_prefix", "conference"); +local domain_name = "meet.jitsi" + + +function get_participants_for_room(room_name) + + local room_address = jid.join(room_name, muc_domain_prefix .. "." .. domain_name); + local room = get_room_from_jid(room_address); + local occupants_json = array(); + if room then + local occupants = room._occupants; + if occupants then + participant_count = iterators.count(room:each_occupant()); + for _, occupant in room:each_occupant() do + -- filter focus as we keep it as hidden participant + if string.sub(occupant.nick, -string.len("/focus")) ~= "/focus" then + for _, pr in occupant:each_session() do + local nick = pr:get_child_text("nick", "http://jabber.org/protocol/nick") or ""; + local email = pr:get_child_text("email") or ""; + local avatarURL = pr:get_child_text("avatarURL") or "" -- does not work :( + occupants_json:push({ + jid = tostring(occupant.nick), + email = tostring(email), + display_name = tostring(nick), + avatarURL = tostring(avatarURL) + }); + end + end + end + end + log("debug", + "there are %s occupants in room", tostring(participant_count)); + return occupants_json + else + log("debug", "no such room exists"); + end + return occupants_json +end + +function get_all_rooms_with_participants() + + local sessions = prosody.full_sessions; + + local someTable = (it.join(it.keys(sessions))); + local actual_rooms = someTable[1][2] + + local roomNames = {} + for _, v in pairs(actual_rooms) do + table.insert(roomNames, v["jitsi_web_query_room"]) + end + + local rooms_with_participants = {} + for _, room_name in pairs(roomNames) do + rooms_with_participants[room_name] = get_participants_for_room(room_name) + end + return json.encode(rooms_with_participants) +end + +--- Handles request for retrieving the room participants details +-- @param event the http event, holds the request query +-- @return GET response, containing a json with participants details +function handle_get_sessions(event) + handle_room_event() + return { status_code = 200; body = get_all_rooms_with_participants() }; +end + +function module.load() + -- Ensure that mod_http is loaded: + -- + module:depends("http"); + + -- Now publish our HTTP 'app': + module:log("info", "Hello! You can reach me at: %s", module:http_url()); + module:provides("http", { + route = { + ["GET"] = function(event) return async_handler_wrapper(event, handle_get_sessions) end; + + }; + }); +end + +-------- event stuff +-- +-- +-- +-- +-- +-- +-- +-- +-- + +local http = require "net.http"; +local is_healthcheck_room = module:require "util".is_healthcheck_room; +--- Start non-blocking HTTP call +-- @param url URL to call +-- @param options options table as expected by net.http where we provide optional headers, body or method. +local function async_http_request(url, options) + local completed = false; + local timed_out = false; + + local function cb_(response_body, response_code) + if not timed_out then -- request completed before timeout + completed = true; + + module:log("debug", "%s %s returned code %s", options.method, url, response_code); + end + end + + http.request(url, options, cb_); +end + +--- Checks if event is triggered by healthchecks or focus user. +function is_system_event(event) + + if event == nil or event.room == nil or event.room.jid == nil then + return true; + end + + if is_healthcheck_room(event.room.jid) then + return true; + end + + if event.occupant and jid.node(event.occupant.jid) == "focus" then + return true; + end + + return false; +end + +function handle_room_event(event) + module:log('info', "hallo irgendwas ist passiert"); + if is_system_event(event) then + return; + end + + async_http_request("https://www.toptal.com/developers/postbin/1673793686086-1283829133026", + { + method = "POST", + body = get_all_rooms_with_participants() + }) + +end + +--Helper function to wait till a component is loaded before running the given callback +function run_when_component_loaded(component_host_name, callback) + local function trigger_callback() + module:log('info', 'Component loaded %s', component_host_name); + callback(module:context(component_host_name), component_host_name); + end + + if prosody.hosts[component_host_name] == nil then + module:log('debug', 'Host %s not yet loaded. Will trigger when it is loaded.', component_host_name); + prosody.events.add_handler('host-activated', function(host) + if host == component_host_name then + trigger_callback(); + end + end); + else + trigger_callback(); + end +end + +-- Helper function to wait till a component's muc module is loaded before running the given callback +function run_when_muc_module_loaded(component_host_module, component_host_name, callback) + local function trigger_callback() + module:log('info', 'MUC module loaded for %s', component_host_name); + callback(prosody.hosts[component_host_name].modules.muc, component_host_module); + end + + if prosody.hosts[component_host_name].modules.muc == nil then + module:log('debug', 'MUC module for %s not yet loaded. Will trigger when it is loaded.', component_host_name); + prosody.hosts[component_host_name].events.add_handler('module-loaded', function(event) + if (event.module == 'muc') then + trigger_callback(); + end + end); + else + trigger_callback() + end +end + +local main_muc_component_host = muc_domain_prefix .. "." .. domain_name +-- Handle events on main muc module +run_when_component_loaded(main_muc_component_host, function(host_module, host_name) + run_when_muc_module_loaded(host_module, host_name, function(main_muc, main_module) + main_muc_service = main_muc; -- so it can be accessed from breakout muc event handlers + + -- the following must run after speakerstats (priority -1) + main_module:hook("muc-room-created", handle_room_event, -3); -- must run after handle_main_room_created + main_module:hook("muc-occupant-joined", handle_room_event, -2); + main_module:hook("muc-occupant-left", handle_room_event, -2); + main_module:hook("muc-room-destroyed", handle_room_event, -2); + end); +end); diff --git a/prodsody/jitsi-meet-cfg/transcripts/.gitkeep b/prodsody/jitsi-meet-cfg/transcripts/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/prodsody/jitsi-meet-cfg/web/.gitkeep b/prodsody/jitsi-meet-cfg/web/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/prodsody/mod_jitsi_rooms.lua b/prodsody/mod_jitsi_rooms.lua index 968d5a8..f517a63 100644 --- a/prodsody/mod_jitsi_rooms.lua +++ b/prodsody/mod_jitsi_rooms.lua @@ -10,26 +10,6 @@ local get_room_from_jid = module:require "util".get_room_from_jid; local muc_domain_prefix = module:get_option_string("muc_mapper_domain_prefix", "conference"); local domain_name = "meet.jitsi" -function debug_table_recursive(aTable, depth) - if (depth > 5) then - return "" - end - local result = {} - for key, value in pairs(aTable) do - --log("debug", key); - if (type(value) == "table") - then - table.insert(result, string.format("\"%s\":%s", tostring(key), debug_table_recursive(value, depth + 1))) - elseif (type(value) == "function") - then - --table.insert(result, string.format("\"%s\":%s", tostring(key), debug_table_recursive(it.join(value)))) - else - table.insert(result, string.format("\"%s\":\"%s\"", tostring(key), tostring(value))) - --log("debug", key); - end - end - return "{" .. table.concat(result, ",") .. "}" -end function get_participants_for_room(room_name) @@ -141,6 +121,11 @@ end --- Checks if event is triggered by healthchecks or focus user. function is_system_event(event) + + if event == nil or event.room == nil or event.room.jid == nil then + return true; + end + if is_healthcheck_room(event.room.jid) then return true; end diff --git a/prodsody/run_dev.sh b/prodsody/run_dev.sh new file mode 100755 index 0000000..638a05b --- /dev/null +++ b/prodsody/run_dev.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + + +docker-compose up -d + +open https://localhost:8443/test + + +ls *.lua | entr sh -c 'cp mod_jitsi_rooms.lua jitsi-meet-cfg/prosody/prosody-plugins-custom && docker-compose restart prosody'