openvibers/openvibe.chat Commits

Elements: a chat command reaches Live on the existing chat-message effect (#533)

OP OpenVibers committed 2 days ago · e0c85399f8 · 2 files, +37 −0

Changes

ddiff --git a/server/chat/chat-server.js b/server/chat/chat-server.js
iindex 98fc895..bb58273 100644
---- a/server/chat/chat-server.js
++++ b/server/chat/chat-server.js
@@@ -1514,6 +1514,20 @@ class ChatServer {
const parts = text.trim().split(/\s+/);
const cmd = parts[0].toLowerCase();
++ // A !command may be an Element trigger (Elements, stage 1). Commands bypass the normal chat
++ // line path, so this is the one place they reach Live's existing chat-message effect; Live runs
++ // an element only if its library listens for that command, and a signed-in person is required.
++ if (client.channelUserId && client.user?.id) {
++ try {
++ ctx.effects.chatMessage({
++ element: true, element_command: true,
++ stream_id: client.streamId || null, channel_user_id: client.channelUserId,
++ user_id: client.user.id, username: client.user.display_name || client.user.username,
++ message: text,
++ }).catch(() => { /* the element trigger is not worth a user-visible error */ });
++ } catch { /* non-critical */ }
++ }
++
// Arena: !hype / !beef / !arena (Live server/arena/arena-chat.js) — chat can only hype; the Arena
// is pure mic. Live runs the command. When Live delivers through Chat's ingress (LIVE_CHAT_INGRESS)
// the sender-only replies come back in the effect response and this socket sends them; on the old
ddiff --git a/test/ws-protocol.test.js b/test/ws-protocol.test.js
iindex 7863f6c..42cba2b 100644
---- a/test/ws-protocol.test.js
++++ b/test/ws-protocol.test.js
@@@ -138,6 +138,29 @@ t('chat into a stream room: room delivery, global cross-feed, persistence, outbo
assert.strictEqual(reaction.body.powerchat_chat.externalChatterId, `u${alice.id}`);
});
++t('a chat command is marked for Elements on the existing chat-message effect', async () => {
++ const carol = h.addUser('carol', { subject: 'usr_01J9CCCCCCCCCCCCCCCCCCCCCC' });
++ const ws = await h.ws({ ip: '198.51.100.22', token: carol.token, stream: streamId });
++ ws.sendJson({ type: 'join', streamId, token: carol.token });
++ await ws.next((m) => m.type === 'auth');
++ ws.sendJson({ type: 'chat', message: '!dance please' });
++ let fx = null;
++ for (let i = 0; i < 60 && !fx; i++) {
++ fx = h.live.effects.find((e) => e.name === 'chat-message' && e.body.message === '!dance please');
++ if (!fx) await h.sleep(25);
++ }
++ assert.ok(fx, 'the command reaches Live on the one chat-message effect');
++ assert.strictEqual(fx.body.element_command, true);
++ assert.strictEqual(fx.body.element, true);
++ assert.strictEqual(fx.body.channel_user_id, streamer.id);
++ assert.strictEqual(fx.body.user_id, carol.id);
++ assert.strictEqual(fx.body.award, undefined, 'a command does not carry the coin bonus');
++ // A normal line goes the ordinary path; its effect is not an element command.
++ const plain = h.live.effects.find((e) => e.name === 'chat-message' && e.body.message === 'hello stream');
++ assert.strictEqual(plain.body.element_command, undefined, 'a normal line is not an element trigger');
++ ws.close();
++});
++
t('a message that could not be saved is not broadcast; the sender is told', async () => {
const orig = h.db.saveChatMessage;
h.db.saveChatMessage = () => { throw new Error('disk full'); };