Skip to content
This repository was archived by the owner on Nov 5, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 32 additions & 3 deletions deno-runtime/handlers/listener/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { RoomBuilder } from '../../lib/accessors/builders/RoomBuilder.ts';
import { AppAccessors, AppAccessorsInstance } from '../../lib/accessors/mod.ts';
import { require } from '../../lib/require.ts';
import createRoom from '../../lib/roomFactory.ts';
import { Room } from "../../lib/room.ts";

const { AppsEngineException } = require('@rocket.chat/apps-engine/definition/exceptions/AppsEngineException.js') as {
AppsEngineException: typeof _AppsEngineException;
Expand Down Expand Up @@ -46,6 +47,7 @@ export default async function handleListener(evtInterface: string, params: unkno

return JsonRpcError.internalError({ message: e.message });
}

}

export function parseArgs(deps: { AppAccessorsInstance: AppAccessors }, evtMethod: string, params: unknown[]): unknown[] {
Expand All @@ -62,7 +64,9 @@ export function parseArgs(deps: { AppAccessorsInstance: AppAccessors }, evtMetho

let context = param1;

if (evtMethod.endsWith('RoomUserJoined') || evtMethod.endsWith('RoomUserLeave')) {
if (evtMethod.includes('Message')) {
context = hydrateMessageObjects(context) as Record<string, unknown>;
} else if (evtMethod.endsWith('RoomUserJoined') || evtMethod.endsWith('RoomUserLeave')) {
(context as Record<string, unknown>).room = createRoom((context as Record<string, unknown>).room as IRoom, AppAccessorsInstance.getSenderFn());
} else if (evtMethod.includes('PreRoom')) {
context = createRoom(context as IRoom, AppAccessorsInstance.getSenderFn());
Expand All @@ -74,7 +78,7 @@ export function parseArgs(deps: { AppAccessorsInstance: AppAccessors }, evtMetho
if (evtMethod.startsWith('check')) {
// "checkPostMessageDeleted" has an extra param - (context, reader, http, extraContext)
if (param2) {
args.push(param2);
args.push(hydrateMessageObjects(param2));
}

return args;
Expand Down Expand Up @@ -114,8 +118,33 @@ export function parseArgs(deps: { AppAccessorsInstance: AppAccessors }, evtMetho
throw JsonRpcError.invalidParams(null);
}

args.push(param2);
args.push(hydrateMessageObjects(param2));
}

return args;
}

/**
* Hydrate the context object with the correct IMessage
*
* Some information is lost upon serializing the data from listeners through the pipes,
* so here we hydrate the complete object as necessary
*/
function hydrateMessageObjects(context: unknown): unknown {
if (objectIsRawMessage(context)) {
context.room = createRoom(context.room as IRoom, AppAccessorsInstance.getSenderFn());
} else if ((context as Record<string, unknown>)?.message) {
(context as Record<string, unknown>).message = hydrateMessageObjects((context as Record<string, unknown>).message);
}

return context;
}

function objectIsRawMessage(value: unknown): value is IMessage {
if (!value) return false;

const { id, room, sender, createdAt } = value as Record<string, unknown>;

// Check if we have the fields of a message and the room hasn't already been hydrated
return !!(id && room && sender && createdAt) && !(room instanceof Room);
}
59 changes: 56 additions & 3 deletions deno-runtime/handlers/tests/listener-handler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,15 @@ describe('handlers > listeners', () => {
it('correctly parses the arguments for a request to trigger the "checkPreRoomCreateExtend" method', () => {
const evtMethod = 'checkPreRoomCreateExtend';
// For the 'checkPreRoomCreateExtend' method, the context will be a room in a real scenario
const evtArgs = [{ __type: 'context' }];
const evtArgs = [
{
id: 'fake',
type: 'fake',
slugifiedName: 'fake',
creator: 'fake',
createdAt: Date.now(),
},
];

const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs);

Expand Down Expand Up @@ -136,7 +144,15 @@ describe('handlers > listeners', () => {
it('correctly parses the arguments for a request to trigger the "executePostRoomUserJoined" method', () => {
const evtMethod = 'executePostRoomUserJoined';
// For the 'executePostRoomUserJoined' method, the context will be a room in a real scenario
const evtArgs = [{ __type: 'context', room: { __type: 'room' } }];
const room = {
id: 'fake',
type: 'fake',
slugifiedName: 'fake',
creator: 'fake',
createdAt: Date.now(),
};

const evtArgs = [{ __type: 'context', room }];

const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs);

Expand All @@ -151,7 +167,15 @@ describe('handlers > listeners', () => {
it('correctly parses the arguments for a request to trigger the "executePostRoomUserLeave" method', () => {
const evtMethod = 'executePostRoomUserLeave';
// For the 'executePostRoomUserLeave' method, the context will be a room in a real scenario
const evtArgs = [{ __type: 'context', room: { __type: 'room' } }];
const room = {
id: 'fake',
type: 'fake',
slugifiedName: 'fake',
creator: 'fake',
createdAt: Date.now(),
};

const evtArgs = [{ __type: 'context', room }];

const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs);

Expand All @@ -178,4 +202,33 @@ describe('handlers > listeners', () => {
assertEquals(params[4], { __type: 'modifier' });
assertEquals(params[5], { __type: 'extraContext' });
});

it('correctly parses the arguments for a request to trigger the "executePostMessageSent" method', () => {
const evtMethod = 'executePostMessageSent';
// For the 'executePostMessageDeleted' method, the context will be a message in a real scenario
const evtArgs = [
{
id: 'fake',
sender: 'fake',
createdAt: Date.now(),
room: {
id: 'fake-room',
type: 'fake',
slugifiedName: 'fake',
creator: 'fake',
createdAt: Date.now(),
},
},
];

const params = parseArgs({ AppAccessorsInstance: mockAppAccessors }, evtMethod, evtArgs);

assertEquals(params.length, 5);
assertObjectMatch((params[0] as Record<string, unknown>), { id: 'fake' });
assertInstanceOf((params[0] as any).room, Room);
assertEquals(params[1], { __type: 'reader' });
assertEquals(params[2], { __type: 'http' });
assertEquals(params[3], { __type: 'persistence' });
assertEquals(params[4], { __type: 'modifier' });
});
});