Skip to content
Open
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
1 change: 1 addition & 0 deletions ee/packages/federation-matrix/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"marked": "^16.1.2",
"mongodb": "6.16.0",
"pino": "^8.21.0",
"prom-client": "^15.1.3",
"reflect-metadata": "^0.2.2",
"sanitize-html": "~2.17.0",
"tsyringe": "^4.10.0",
Expand Down
236 changes: 184 additions & 52 deletions ee/packages/federation-matrix/src/FederationMatrix.ts

Large diffs are not rendered by default.

26 changes: 13 additions & 13 deletions ee/packages/federation-matrix/src/events/edu.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { api } from '@rocket.chat/core-services';
import { UserStatus } from '@rocket.chat/core-typings';
import { federationSDK } from '@rocket.chat/federation-sdk';
import { federationSDK, type HomeserverEventSignatures } from '@rocket.chat/federation-sdk';
import { Logger } from '@rocket.chat/logger';
import { Rooms, Users } from '@rocket.chat/models';

const logger = new Logger('federation-matrix:edu');

export const edus = async () => {
federationSDK.eventEmitterService.on('homeserver.matrix.typing', async (data) => {
try {
federationSDK.eventEmitterService.on(
'homeserver.matrix.typing',
async (data: HomeserverEventSignatures['homeserver.matrix.typing']) => {
const matrixRoom = await Rooms.findOne({ 'federation.mrid': data.room_id }, { projection: { _id: 1 } });
if (!matrixRoom) {
logger.debug({ msg: 'No bridged room found for Matrix room_id', roomId: data.room_id });
Expand All @@ -20,13 +21,13 @@ export const edus = async () => {
isTyping: data.typing,
roomId: matrixRoom._id,
});
} catch (err) {
logger.error({ msg: 'Error handling Matrix typing event', err });
}
});
},
(err: Error) => logger.error({ msg: 'Error handling Matrix typing event', err }),
);

federationSDK.eventEmitterService.on('homeserver.matrix.presence', async (data) => {
try {
federationSDK.eventEmitterService.on(
'homeserver.matrix.presence',
async (data: HomeserverEventSignatures['homeserver.matrix.presence']) => {
const matrixUser = await Users.findOneByUsername(data.user_id);
if (!matrixUser) {
logger.debug({ msg: 'No federated user found for Matrix user_id', userId: data.user_id });
Expand Down Expand Up @@ -67,8 +68,7 @@ export const edus = async () => {
previousStatus: undefined,
});
logger.debug({ msg: 'Updated presence for user from Matrix federation', userId: matrixUser._id, status });
} catch (err) {
logger.error({ msg: 'Error handling Matrix presence event', err });
}
});
},
(err: Error) => logger.error({ msg: 'Error handling Matrix presence event', err }),
);
};
14 changes: 7 additions & 7 deletions ee/packages/federation-matrix/src/events/member.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ async function getOrCreateFederatedRoom({
function getJoinRuleType(strippedState: PduForType<'m.room.join_rules'>[]): 'p' | 'c' | 'd' {
const joinRulesState = strippedState?.find((state: PduForType<'m.room.join_rules'>) => state.type === 'm.room.join_rules');

// as per the spec, users need to be invited to join a room, unless the rooms join rules state otherwise.
// as per the spec, users need to be invited to join a room, unless the room's join rules state otherwise.
if (!joinRulesState) {
return 'p';
}
Expand Down Expand Up @@ -255,8 +255,9 @@ async function handleLeave({
}

export function member() {
federationSDK.eventEmitterService.on('homeserver.matrix.membership', async ({ event }) => {
try {
federationSDK.eventEmitterService.on(
'homeserver.matrix.membership',
async ({ event }: HomeserverEventSignatures['homeserver.matrix.membership']) => {
switch (event.content.membership) {
case 'invite':
await handleInvite(event);
Expand All @@ -273,8 +274,7 @@ export function member() {
default:
logger.warn({ msg: 'Unknown membership type', membership: event.content.membership });
}
} catch (err) {
logger.error({ msg: 'Failed to process Matrix membership event', err });
}
});
},
(err: Error) => logger.error({ msg: 'Failed to process Matrix membership event', err }),
);
}
53 changes: 30 additions & 23 deletions ee/packages/federation-matrix/src/events/message.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import { FederationMatrix, Message, MeteorService } from '@rocket.chat/core-services';
import type { IUser, IRoom, FileAttachmentProps } from '@rocket.chat/core-typings';
import { type FileMessageType, type MessageType, type FileMessageContent, type EventID, federationSDK } from '@rocket.chat/federation-sdk';
import {
type FileMessageType,
type MessageType,
type FileMessageContent,
type EventID,
federationSDK,
type HomeserverEventSignatures,
} from '@rocket.chat/federation-sdk';
import { Logger } from '@rocket.chat/logger';
import { Users, Rooms, Messages } from '@rocket.chat/models';

Expand Down Expand Up @@ -111,8 +118,9 @@ async function handleMediaMessage(
}

export function message() {
federationSDK.eventEmitterService.on('homeserver.matrix.message', async ({ event, event_id: eventId }) => {
try {
federationSDK.eventEmitterService.on(
'homeserver.matrix.message',
async ({ event, event_id: eventId }: HomeserverEventSignatures['homeserver.matrix.message']) => {
const { msgtype, body } = event.content;
const messageBody = body.toString();

Expand All @@ -136,15 +144,15 @@ export function message() {

const relation = event.content['m.relates_to'];

// SPEC: For example, an m.thread relationship type denotes that the event is part of a thread of messages and should be rendered as such.
// SPEC: For example, an m.thread relationship type denotes that the event is part of a "thread" of messages and should be rendered as such.
const hasRelation = relation && 'rel_type' in relation;

const isThreadMessage = hasRelation && relation.rel_type === 'm.thread';

const threadRootEventId = isThreadMessage && relation.event_id;

// SPEC: Though rich replies form a relationship to another event, they do not use rel_type to create this relationship.
// Instead, a subkey named m.in_reply_to is used to describe the replys relationship,
// Instead, a subkey named m.in_reply_to is used to describe the reply's relationship,
const isRichReply = relation && !('rel_type' in relation) && 'm.in_reply_to' in relation;

const quoteMessageEventId = isRichReply && relation['m.in_reply_to']?.event_id;
Expand Down Expand Up @@ -261,13 +269,13 @@ export function message() {
ts: new Date(event.origin_server_ts),
});
}
} catch (err) {
logger.error({ msg: 'Error processing Matrix message', err });
}
});
},
(err: Error) => logger.error({ msg: 'Error processing Matrix message', err }),
);

federationSDK.eventEmitterService.on('homeserver.matrix.encrypted', async ({ event, event_id: eventId }) => {
try {
federationSDK.eventEmitterService.on(
'homeserver.matrix.encrypted',
async ({ event, event_id: eventId }: HomeserverEventSignatures['homeserver.matrix.encrypted']) => {
if (!event.content.ciphertext) {
logger.debug('No message content found in event');
return;
Expand All @@ -286,15 +294,15 @@ export function message() {

const relation = event.content['m.relates_to'];

// SPEC: For example, an m.thread relationship type denotes that the event is part of a thread of messages and should be rendered as such.
// SPEC: For example, an m.thread relationship type denotes that the event is part of a "thread" of messages and should be rendered as such.
const hasRelation = relation && 'rel_type' in relation;

const isThreadMessage = hasRelation && relation.rel_type === 'm.thread';

const threadRootEventId = isThreadMessage && relation.event_id;

// SPEC: Though rich replies form a relationship to another event, they do not use rel_type to create this relationship.
// Instead, a subkey named m.in_reply_to is used to describe the replys relationship,
// Instead, a subkey named m.in_reply_to is used to describe the reply's relationship,
const isRichReply = relation && !('rel_type' in relation) && 'm.in_reply_to' in relation;

const quoteMessageEventId = isRichReply && relation['m.in_reply_to']?.event_id;
Expand Down Expand Up @@ -377,13 +385,13 @@ export function message() {
thread,
ts: new Date(event.origin_server_ts),
});
} catch (err) {
logger.error({ msg: 'Error processing Matrix message', err });
}
});
},
(err: Error) => logger.error({ msg: 'Error processing Matrix message', err }),
);

federationSDK.eventEmitterService.on('homeserver.matrix.redaction', async ({ event }) => {
try {
federationSDK.eventEmitterService.on(
'homeserver.matrix.redaction',
async ({ event }: HomeserverEventSignatures['homeserver.matrix.redaction']) => {
const redactedEventId = event.redacts;
if (!redactedEventId) {
logger.debug('No redacts field in redaction event');
Expand All @@ -409,8 +417,7 @@ export function message() {
}

await Message.deleteMessage(user, rcMessage);
} catch (err) {
logger.error({ msg: 'Failed to process Matrix removal redaction', err });
}
});
},
(err: Error) => logger.error({ msg: 'Failed to process Matrix removal redaction', err }),
);
}
15 changes: 11 additions & 4 deletions ee/packages/federation-matrix/src/events/ping.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import { federationSDK } from '@rocket.chat/federation-sdk';
import { federationSDK, type HomeserverEventSignatures } from '@rocket.chat/federation-sdk';
import { Logger } from '@rocket.chat/logger';

const logger = new Logger('federation-matrix:ping');

export const ping = async () => {
federationSDK.eventEmitterService.on('homeserver.ping', async (data) => {
console.log('Message received from homeserver', data);
});
federationSDK.eventEmitterService.on(
'homeserver.ping',
async (data: HomeserverEventSignatures['homeserver.ping']) => {
logger.debug({ msg: 'Message received from homeserver', data });
},
(err: Error) => logger.error({ msg: 'Error handling homeserver ping', err }),
);
};
26 changes: 13 additions & 13 deletions ee/packages/federation-matrix/src/events/reaction.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { Message, FederationMatrix } from '@rocket.chat/core-services';
import { federationSDK } from '@rocket.chat/federation-sdk';
import { federationSDK, type HomeserverEventSignatures } from '@rocket.chat/federation-sdk';
import { Logger } from '@rocket.chat/logger';
import { Users, Messages } from '@rocket.chat/models'; // Rooms
import emojione from 'emojione';

const logger = new Logger('federation-matrix:reaction');

export function reaction() {
federationSDK.eventEmitterService.on('homeserver.matrix.reaction', async ({ event, event_id: eventId }) => {
try {
federationSDK.eventEmitterService.on(
'homeserver.matrix.reaction',
async ({ event, event_id: eventId }: HomeserverEventSignatures['homeserver.matrix.reaction']) => {
const isSetReaction = event.content?.['m.relates_to'];

const reactionTargetEventId = isSetReaction?.event_id;
Expand Down Expand Up @@ -41,13 +42,13 @@ export function reaction() {
const reactionEmoji = emojione.toShort(reactionKey);
await Message.reactToMessage(user._id, reactionEmoji, rcMessage._id, true);
await Messages.setFederationReactionEventId(internalUsername, rcMessage._id, reactionEmoji, eventId);
} catch (err) {
logger.error({ msg: 'Failed to process Matrix reaction', err });
}
});
},
(err: Error) => logger.error({ msg: 'Failed to process Matrix reaction', err }),
);

federationSDK.eventEmitterService.on('homeserver.matrix.redaction', async ({ event }) => {
try {
federationSDK.eventEmitterService.on(
'homeserver.matrix.redaction',
async ({ event }: HomeserverEventSignatures['homeserver.matrix.redaction']) => {
const redactedEventId = event.redacts;
if (!redactedEventId) {
logger.debug('No redacts field in redaction event');
Expand Down Expand Up @@ -85,8 +86,7 @@ export function reaction() {
const reactionEmoji = emojione.toShort(reactionKey);
await Message.reactToMessage(user._id, reactionEmoji, rcMessage._id, false);
await Messages.unsetFederationReactionEventId(redactedEventId, rcMessage._id, reactionEmoji);
} catch (err) {
logger.error({ msg: 'Failed to process Matrix reaction redaction', err });
}
});
},
(err: Error) => logger.error({ msg: 'Failed to process Matrix reaction redaction', err }),
);
}
Loading
Loading