Переглянути джерело

feat(room-metadata) add module for generic room metadata storage

factor2
Saúl Ibarra Corretgé 2 роки тому
джерело
коміт
11f138d28f

+ 6
- 0
doc/debian/jitsi-meet-prosody/prosody.cfg.lua-jvb.example Переглянути файл

@@ -65,10 +65,12 @@ VirtualHost "jitmeet.example.com"
65 65
         "muc_lobby_rooms";
66 66
         "muc_breakout_rooms";
67 67
         "av_moderation";
68
+        "room_metadata";
68 69
     }
69 70
     c2s_require_encryption = false
70 71
     lobby_muc = "lobby.jitmeet.example.com"
71 72
     breakout_rooms_muc = "breakout.jitmeet.example.com"
73
+    room_metadata_component = "metadata.jitmeet.example.com"
72 74
     main_muc = "conference.jitmeet.example.com"
73 75
     -- muc_lobby_whitelist = { "recorder.jitmeet.example.com" } -- Here we can whitelist jibri to enter lobby enabled rooms
74 76
 
@@ -140,3 +142,7 @@ Component "lobby.jitmeet.example.com" "muc"
140 142
         "muc_rate_limit";
141 143
         "polls";
142 144
     }
145
+
146
+Component "metadata.jitmeet.example.com" "room_metadata_component"
147
+    muc_component = "conference.jitmeet.example.com"
148
+    breakout_rooms_component = "breakout.jitmeet.example.com"

+ 8
- 0
resources/prosody-plugins/mod_room_metadata.lua Переглянути файл

@@ -0,0 +1,8 @@
1
+-- Generic room metadata
2
+-- See mod_room_metadata_component.lua
3
+
4
+local COMPONENT_IDENTITY_TYPE = 'room_metadata';
5
+local room_metadata_component_host = module:get_option_string('room_metadata_component', 'metadata.'..module.host);
6
+
7
+-- Advertise the component so clients can pick up the address and use it
8
+module:add_identity('component', COMPONENT_IDENTITY_TYPE, room_metadata_component_host);

+ 240
- 0
resources/prosody-plugins/mod_room_metadata_component.lua Переглянути файл

@@ -0,0 +1,240 @@
1
+-- This module implements a generic metadata storage system for rooms.
2
+--
3
+-- VirtualHost "jitmeet.example.com"
4
+--     modules_enabled = {
5
+--         "room_metadata"
6
+--     }
7
+--     room_metadata_component = "metadata.jitmeet.example.com"
8
+--     main_muc = "conference.jitmeet.example.com"
9
+--
10
+-- Component "metadata.jitmeet.example.com" "room_metadata_component"
11
+--      muc_component = "conference.jitmeet.example.com"
12
+--      breakout_rooms_component = "breakout.jitmeet.example.com"
13
+
14
+local jid_node = require 'util.jid'.node;
15
+local json = require 'util.json';
16
+local st = require 'util.stanza';
17
+
18
+local util = module:require 'util';
19
+local is_healthcheck_room = util.is_healthcheck_room;
20
+local get_room_from_jid = util.get_room_from_jid;
21
+local room_jid_match_rewrite = util.room_jid_match_rewrite;
22
+
23
+local COMPONENT_IDENTITY_TYPE = 'room_metadata';
24
+local FORM_KEY = 'muc#roominfo_jitsimetadata';
25
+
26
+local muc_component_host = module:get_option_string('muc_component');
27
+
28
+if muc_component_host == nil then
29
+    module:log("error", "No muc_component specified. No muc to operate on!");
30
+    return;
31
+end
32
+
33
+local breakout_rooms_component_host = module:get_option_string('breakout_rooms_component');
34
+
35
+module:log("info", "Starting room metadata for %s", muc_component_host);
36
+
37
+
38
+-- Utility functions
39
+
40
+function getMetadataJSON(room)
41
+    return json.encode({
42
+        type = COMPONENT_IDENTITY_TYPE,
43
+        metadata = room.jitsiMetadata or {}
44
+    });
45
+end
46
+
47
+-- Putting the information on the config form / disco-info allows us to save
48
+-- an extra message to users who join later.
49
+function getFormData(room)
50
+    return {
51
+        name = FORM_KEY;
52
+        type = 'text-multi';
53
+        label = 'Room metadata';
54
+        value = getMetadataJSON(room);
55
+    };
56
+end
57
+
58
+function broadcastMetadata(room)
59
+    local json_msg = getMetadataJSON(room);
60
+
61
+    for _, occupant in room:each_occupant() do
62
+        if jid_node(occupant.jid) ~= 'focus' then
63
+            send_json_msg(occupant.jid, json_msg)
64
+        end
65
+    end
66
+end
67
+
68
+function send_json_msg(to_jid, json_msg)
69
+    local stanza = st.message({ from = module.host; to = to_jid; })
70
+         :tag('json-message', { xmlns = 'http://jitsi.org/jitmeet' }):text(json_msg):up();
71
+    module:send(stanza);
72
+end
73
+
74
+-- Handling events
75
+
76
+function room_created(event)
77
+    local room = event.room;
78
+
79
+    if is_healthcheck_room(room.jid) then
80
+        return ;
81
+    end
82
+
83
+    room.jitsiMetadata = {};
84
+end
85
+
86
+function on_message(event)
87
+    local session = event.origin;
88
+
89
+    -- Check the type of the incoming stanza to avoid loops:
90
+    if event.stanza.attr.type == 'error' then
91
+        return; -- We do not want to reply to these, so leave.
92
+    end
93
+
94
+    if not session or not session.jitsi_web_query_room then
95
+        return false;
96
+    end
97
+
98
+    local message = event.stanza:get_child(COMPONENT_IDENTITY_TYPE, 'http://jitsi.org/jitmeet');
99
+    local messageText = message:get_text();
100
+
101
+    if not message or not messageText then
102
+        return false;
103
+    end
104
+
105
+    local roomJid = message.attr.room;
106
+    local room = get_room_from_jid(room_jid_match_rewrite(roomJid));
107
+
108
+    if not room then
109
+        module:log('warn', 'No room found found for %s/%s',
110
+                session.jitsi_web_query_prefix, session.jitsi_web_query_room);
111
+        return false;
112
+    end
113
+
114
+    -- check that the participant requesting is a moderator and is an occupant in the room
115
+    local from = event.stanza.attr.from;
116
+    local occupant = room:get_occupant_by_real_jid(from);
117
+
118
+    if not occupant then
119
+        module:log('warn', 'No occupant %s found for %s', from, room.jid);
120
+        return false;
121
+    end
122
+
123
+    if occupant.role ~= 'moderator' then
124
+        module:log('warn', 'Occupant %s is not moderator and not allowed this operation for %s', from, room.jid);
125
+        return false;
126
+    end
127
+
128
+    local jsonData = json.decode(messageText);
129
+    if jsonData == nil then -- invalid JSON
130
+        module:log("error", "Invalid JSON message: %s", messageText);
131
+        return false;
132
+    end
133
+
134
+    if jsonData.key == nil or jsonData.data == nil then
135
+        module:log("error", "Invalid JSON payload, key or data are missing: %s", messageText);
136
+        return false;
137
+    end
138
+
139
+    room.jitsiMetadata[jsonData.key] = jsonData.data;
140
+
141
+    broadcastMetadata(room);
142
+
143
+    return true;
144
+end
145
+
146
+-- Module operations
147
+
148
+-- process a host module directly if loaded or hooks to wait for its load
149
+function process_host_module(name, callback)
150
+    local function process_host(host)
151
+        if host == name then
152
+            callback(module:context(host), host);
153
+        end
154
+    end
155
+
156
+    if prosody.hosts[name] == nil then
157
+        module:log('debug', 'No host/component found, will wait for it: %s', name)
158
+
159
+        -- when a host or component is added
160
+        prosody.events.add_handler('host-activated', process_host);
161
+    else
162
+        process_host(name);
163
+    end
164
+end
165
+
166
+-- handle messages to this component
167
+module:hook("message/host", on_message);
168
+
169
+-- operates on already loaded main muc module
170
+function process_main_muc_loaded(main_muc, host_module)
171
+    module:log('debug', 'Main muc loaded');
172
+    module:log("info", "Hook to muc events on %s", muc_component_host);
173
+
174
+    host_module:hook("muc-room-created", room_created, -1);
175
+
176
+    host_module:hook('muc-disco#info', function (event)
177
+        local room = event.room;
178
+
179
+        table.insert(event.form, getFormData(room));
180
+    end);
181
+
182
+    host_module:hook("muc-config-form", function(event)
183
+        local room = event.room;
184
+
185
+        table.insert(event.form, getFormData(room));
186
+    end);
187
+end
188
+
189
+-- process or waits to process the main muc component
190
+process_host_module(muc_component_host, function(host_module, host)
191
+    local muc_module = prosody.hosts[host].modules.muc;
192
+
193
+    if muc_module then
194
+        process_main_muc_loaded(muc_module, host_module);
195
+    else
196
+        module:log('debug', 'Will wait for muc to be available');
197
+        prosody.hosts[host].events.add_handler('module-loaded', function(event)
198
+            if (event.module == 'muc') then
199
+                process_main_muc_loaded(prosody.hosts[host].modules.muc, host_module);
200
+            end
201
+        end);
202
+    end
203
+end);
204
+
205
+-- breakout rooms support
206
+function process_breakout_muc_loaded(breakout_muc, host_module)
207
+    module:log('debug', 'Breakout rooms muc loaded');
208
+    module:log("info", "Hook to muc events on %s", breakout_rooms_component_host);
209
+
210
+    host_module:hook("muc-room-created", room_created, -1);
211
+
212
+    host_module:hook('muc-disco#info', function (event)
213
+        local room = event.room;
214
+
215
+        table.insert(event.form, getFormData(room));
216
+    end);
217
+
218
+    host_module:hook("muc-config-form", function(event)
219
+        local room = event.room;
220
+
221
+        table.insert(event.form, getFormData(room));
222
+    end);
223
+end
224
+
225
+if breakout_rooms_component_host then
226
+    process_host_module(breakout_rooms_component_host, function(host_module, host)
227
+        local muc_module = prosody.hosts[host].modules.muc;
228
+
229
+        if muc_module then
230
+            process_breakout_muc_loaded(muc_module, host_module);
231
+        else
232
+            module:log('debug', 'Will wait for muc to be available');
233
+            prosody.hosts[host].events.add_handler('module-loaded', function(event)
234
+                if (event.module == 'muc') then
235
+                    process_breakout_muc_loaded(prosody.hosts[host].modules.muc, host_module);
236
+                end
237
+            end);
238
+        end
239
+    end);
240
+end

Завантаження…
Відмінити
Зберегти