Преглед на файлове

A poltergeist module.

Thanks to Matthew Wild for the initial help of creating these.
Module with REST interface to create poltergeist participants and change their statuses.
When user with same id joins the room, the poltergeist is removed.  We also make sure that that user uses same username when authenticates. This way we are sure that user will join the room with the same nick as the poltergeist.
j8
damencho преди 7 години
родител
ревизия
58d06fe7e6
променени са 2 файла, в които са добавени 261 реда и са изтрити 0 реда
  1. 240
    0
      resources/prosody-plugins/mod_muc_poltergeist.lua
  2. 21
    0
      resources/prosody-plugins/mod_poltergeist_component.lua

+ 240
- 0
resources/prosody-plugins/mod_muc_poltergeist.lua Целия файл

@@ -0,0 +1,240 @@
1
+local bare = require "util.jid".bare;
2
+local generate_uuid = require "util.uuid".generate;
3
+local jid = require "util.jid";
4
+local neturl = require "net.url";
5
+local parse = neturl.parseQuery;
6
+local st = require "util.stanza";
7
+local get_room_from_jid = module:require "util".get_room_from_jid;
8
+
9
+-- Options
10
+local poltergeist_component
11
+    = module:get_option_string("poltergeist_component", module.host);
12
+
13
+-- table to store all poltergeists we create
14
+local poltergeists = {};
15
+
16
+-- poltergaist management functions
17
+
18
+-- Returns the room if available, work and in multidomain mode
19
+-- @param room_name the name of the room
20
+-- @param group name of the group (optional)
21
+-- @return returns room if found or nil
22
+function get_room(room_name, group)
23
+    local room_address = jid.join(room_name, module:get_host());
24
+    -- if there is a group we are in multidomain mode
25
+    if group and group ~= "" then
26
+        room_address = "["..group.."]"..room_address;
27
+    end
28
+
29
+    return get_room_from_jid(room_address);
30
+end
31
+
32
+-- Stores the username in the table where we store poltergeist usernames
33
+-- based on their room names
34
+-- @param room the room instance
35
+-- @param user_id the user id
36
+-- @param username the username to store
37
+function store_username(room, user_id, username)
38
+    local room_name = jid.node(room.jid);
39
+
40
+    -- we store in poltergeist user ids for room names
41
+    if (not poltergeists[room_name]) then
42
+        poltergeists[room_name] = {};
43
+    end
44
+    poltergeists[room_name][user_id] = username;
45
+    log("debug", "stored in session: %s", username);
46
+end
47
+
48
+-- Retrieve the username for a user
49
+-- @param room the room instance
50
+-- @param user_id the user id
51
+-- @return returns the stored username for user or nil
52
+function get_username(room, user_id)
53
+    local room_name = jid.node(room.jid);
54
+
55
+    if (not poltergeists[room_name]) then
56
+        return nil;
57
+    end
58
+
59
+    return poltergeists[room_name][user_id];
60
+end
61
+
62
+-- if we found that a session for a user with id has a poltergiest already
63
+-- created, retrieve its jid and return it to the authentication
64
+-- so we can reuse it and we that real user will replace the poltergiest
65
+prosody.events.add_handler("pre-jitsi-authentication", function(session)
66
+
67
+    if (session.jitsi_meet_context_user) then
68
+        local room = get_room(
69
+            session.jitsi_bosh_query_room,
70
+            session.jitsi_meet_context_group);
71
+
72
+        if (not room) then
73
+            return nil;
74
+        end
75
+
76
+        local username
77
+            = get_username(room, session.jitsi_meet_context_user["id"]);
78
+
79
+        if (not username) then
80
+            return nil;
81
+        end
82
+
83
+        log("debug", "Found predefined username %s", username);
84
+
85
+        -- let's find the room and if the poltergeist occupant is there
86
+        -- lets remove him before the real participant joins
87
+        -- when we see the unavailable presence to go out the server
88
+        -- we will mark it with ignore tag
89
+        local nick = string.sub(username, 0, 8);
90
+        if (have_poltergeist_occupant(room, nick)) then
91
+            remove_poltergeist_occupant(room, nick);
92
+        end
93
+
94
+        return username;
95
+    end
96
+
97
+    return nil;
98
+end);
99
+
100
+-- Creates poltergeist occupant
101
+-- @param room the room instance where we create the occupant
102
+-- @param nick the nick to use for the new occupant
103
+-- @param name the display name fot the occupant (optional)
104
+-- @param avatar the avatar to use for the new occupant (optional)
105
+function create_poltergeist_occupant(room, nick, name, avatar)
106
+    log("debug", "create_poltergeist_occupant %s:", nick);
107
+    -- Join poltergeist occupant to room, with the invited JID as their nick
108
+    local join_presence = st.presence({
109
+        to = room.jid.."/"..nick,
110
+        from = poltergeist_component.."/"..nick
111
+    }):tag("x", { xmlns = "http://jabber.org/protocol/muc" }):up();
112
+
113
+    if (name) then
114
+        join_presence:tag(
115
+            "nick",
116
+            { xmlns = "http://jabber.org/protocol/nick" }):text(name):up();
117
+    end
118
+    if (avatar) then
119
+        join_presence:tag("avatar-url"):text(avatar):up();
120
+    end
121
+
122
+    room:handle_first_presence(
123
+        prosody.hosts[poltergeist_component], join_presence);
124
+end
125
+
126
+-- Removes poltergeist occupant
127
+-- @param room the room instance where to remove the occupant
128
+-- @param nick the nick of the occupant to remove
129
+function remove_poltergeist_occupant(room, nick)
130
+    log("debug", "remove_poltergeist_occupant %s", nick);
131
+    local leave_presence = st.presence({
132
+        to = room.jid.."/"..nick,
133
+        from = poltergeist_component.."/"..nick,
134
+        type = "unavailable" });
135
+    room:handle_normal_presence(
136
+        prosody.hosts[poltergeist_component], leave_presence);
137
+end
138
+
139
+-- Checks for existance of a poltergeist occupant
140
+-- @param room the room instance where to check for occupant
141
+-- @param nick the nick of the occupant
142
+-- @return true if occupant is found, false otherwise
143
+function have_poltergeist_occupant(room, nick)
144
+	-- Find out if we have a poltergeist occupant in the room for this JID
145
+	return not not room:get_occupant_jid(poltergeist_component.."/"..nick);
146
+end
147
+
148
+-- Event handlers
149
+
150
+--- Note: mod_muc and some of its sub-modules add event handlers between 0 and -100,
151
+--- e.g. to check for banned users, etc.. Hence adding these handlers at priority -100.
152
+module:hook("muc-decline", function (event)
153
+	remove_poltergeist_occupant(event.room, bare(event.stanza.attr.from));
154
+end, -100);
155
+-- before sending the presence for a poltergeist leaving add ignore tag
156
+-- as poltergeist is leaving just before the real user joins and in the client
157
+-- we ignore this presence to avoid leaving/joining experience and the real
158
+-- user will reuse all currently created UI components for the same nick
159
+module:hook("muc-broadcast-presence", function (event)
160
+    if (bare(event.occupant.jid) == poltergeist_component) then
161
+        if(event.stanza.attr.type == "unavailable") then
162
+            event.stanza:tag(
163
+                "ignore", { xmlns = "http://jitsi.org/jitmeet/" }):up();
164
+        end
165
+    end
166
+end, -100);
167
+
168
+--- Handles request for creating/managing poltergeists
169
+-- @param event the http event, holds the request query
170
+-- @return GET response, containing a json with response details
171
+function handle_create_poltergeist (event)
172
+    local params = parse(event.request.url.query);
173
+    local user_id = params["user"];
174
+    local room_name = params["room"];
175
+    local group = params["group"];
176
+    local name = params["name"];
177
+    local avatar = params["avatar"];
178
+
179
+    local room = get_room(room_name, group);
180
+    if (not room) then
181
+        log("error", "no room found %s", room_address);
182
+        return 404;
183
+    end
184
+
185
+    local username = generate_uuid();
186
+    store_username(room, user_id, username)
187
+
188
+    create_poltergeist_occupant(room, string.sub(username,0,8), name, avatar);
189
+
190
+    return 200;
191
+end
192
+
193
+--- Handles request for updating poltergeists status
194
+-- @param event the http event, holds the request query
195
+-- @return GET response, containing a json with response details
196
+function handle_update_poltergeist (event)
197
+    local params = parse(event.request.url.query);
198
+    local user_id = params["user"];
199
+    local room_name = params["room"];
200
+    local group = params["group"];
201
+    local status = params["status"];
202
+
203
+    local room = get_room(room_name, group);
204
+    if (not room) then
205
+        log("error", "no room found %s", room_address);
206
+        return 404;
207
+    end
208
+
209
+    local username = get_username(room, user_id);
210
+    if (not username) then
211
+        return 404;
212
+    end
213
+
214
+    local nick = string.sub(username, 0, 8);
215
+    if (have_poltergeist_occupant(room, nick)) then
216
+        local update_presence = st.presence({
217
+            to = room.jid.."/"..nick,
218
+            from = poltergeist_component.."/"..nick
219
+        }):tag("status"):text(status):up();
220
+
221
+        room:handle_normal_presence(
222
+            prosody.hosts[poltergeist_component], update_presence);
223
+
224
+        return 200;
225
+    else
226
+        return 404;
227
+    end
228
+end
229
+
230
+
231
+log("info", "Loading poltergeist service");
232
+module:depends("http");
233
+module:provides("http", {
234
+    default_path = "/";
235
+    name = "poltergeist";
236
+    route = {
237
+        ["GET /poltergeist/create"] = handle_create_poltergeist;
238
+        ["GET /poltergeist/update"] = handle_update_poltergeist;
239
+    };
240
+});

+ 21
- 0
resources/prosody-plugins/mod_poltergeist_component.lua Целия файл

@@ -0,0 +1,21 @@
1
+local st = require "util.stanza";
2
+
3
+-- A component which we use to receive all stanzas for the created poltergeists
4
+-- replays with error if an iq is sent
5
+function no_action()
6
+	return true;
7
+end
8
+
9
+function error_reply(event)
10
+	module:send(st.error_reply(event.stanza, "cancel", "service-unavailable"));
11
+	return true;
12
+end
13
+
14
+module:hook("presence/host", no_action);
15
+module:hook("message/host", no_action);
16
+module:hook("presence/full", no_action);
17
+module:hook("message/full", no_action);
18
+
19
+module:hook("iq/host", error_reply);
20
+module:hook("iq/full", error_reply);
21
+module:hook("iq/bare", error_reply);

Loading…
Отказ
Запис