From 5b6457caceba24fa1cd641ca7e6432e3a2348cd1 Mon Sep 17 00:00:00 2001 From: Marcos Defendi Date: Mon, 14 Jul 2025 13:19:24 -0300 Subject: [PATCH 1/2] fix: avoid to register routes every time the fn gets called --- .../federation-matrix/src/FederationMatrix.ts | 65 +++++++++++++++---- .../src/api/.well-known/server.ts | 13 ++-- .../src/api/_matrix/invite.ts | 13 ++-- .../src/api/_matrix/key/server.ts | 13 ++-- .../src/api/_matrix/profiles.ts | 23 ++++--- .../src/api/_matrix/rooms.ts | 15 ++--- .../src/api/_matrix/send-join.ts | 13 ++-- .../src/api/_matrix/transactions.ts | 13 ++-- .../src/api/_matrix/versions.ts | 8 +-- ee/packages/federation-matrix/src/api/api.ts | 31 --------- .../federation-matrix/src/setupContainers.ts | 41 ------------ 11 files changed, 106 insertions(+), 142 deletions(-) delete mode 100644 ee/packages/federation-matrix/src/api/api.ts delete mode 100644 ee/packages/federation-matrix/src/setupContainers.ts diff --git a/ee/packages/federation-matrix/src/FederationMatrix.ts b/ee/packages/federation-matrix/src/FederationMatrix.ts index 17ebf9fece781..399377660a86a 100644 --- a/ee/packages/federation-matrix/src/FederationMatrix.ts +++ b/ee/packages/federation-matrix/src/FederationMatrix.ts @@ -1,16 +1,24 @@ import 'reflect-metadata'; -import type { HomeserverEventSignatures, HomeserverServices, DependencyContainer } from '@hs/federation-sdk'; -import { getAllServices } from '@hs/federation-sdk'; +import { toUnpaddedBase64 } from '@hs/core'; +import { ConfigService, createFederationContainer, getAllServices } from '@hs/federation-sdk'; +import type { HomeserverEventSignatures, HomeserverServices, FederationContainerOptions } from '@hs/federation-sdk'; import { type IFederationMatrixService, ServiceClass, Settings } from '@rocket.chat/core-services'; import type { IMessage, IRoom, IUser } from '@rocket.chat/core-typings'; import { Emitter } from '@rocket.chat/emitter'; +import { Router } from '@rocket.chat/http-router'; import { Logger } from '@rocket.chat/logger'; import { MatrixBridgedUser, MatrixBridgedRoom, Users } from '@rocket.chat/models'; -import { getAllMatrixRoutes } from './api/api'; +import { getWellKnownRoutes } from './api/.well-known/server'; +import { getMatrixInviteRoutes } from './api/_matrix/invite'; +import { getKeyServerRoutes } from './api/_matrix/key/server'; +import { getMatrixProfilesRoutes } from './api/_matrix/profiles'; +import { getMatrixRoomsRoutes } from './api/_matrix/rooms'; +import { getMatrixSendJoinRoutes } from './api/_matrix/send-join'; +import { getMatrixTransactionsRoutes } from './api/_matrix/transactions'; +import { getFederationVersionsRoutes } from './api/_matrix/versions'; import { registerEvents } from './events'; -import { setup } from './setupContainers'; export class FederationMatrix extends ServiceClass implements IFederationMatrixService { protected name = 'federation-matrix'; @@ -21,10 +29,10 @@ export class FederationMatrix extends ServiceClass implements IFederationMatrixS private matrixDomain: string; - private diContainer: DependencyContainer; - private readonly logger = new Logger(this.name); + private httpRoutes: { matrix: Router<'/_matrix'>; wellKnown: Router<'/.well-known'> }; + private constructor(emitter?: Emitter) { super(); this.eventHandler = emitter || new Emitter(); @@ -32,11 +40,48 @@ export class FederationMatrix extends ServiceClass implements IFederationMatrixS static async create(emitter?: Emitter): Promise { const instance = new FederationMatrix(emitter); - instance.diContainer = await setup(instance.eventHandler); + const config = new ConfigService(); + const matrixConfig = config.getMatrixConfig(); + const serverConfig = config.getServerConfig(); + const signingKeys = await config.getSigningKey(); + const signingKey = signingKeys[0]; + + const containerOptions: FederationContainerOptions = { + emitter, + federationOptions: { + serverName: matrixConfig.serverName, + signingKey: toUnpaddedBase64(signingKey.privateKey), + signingKeyId: `ed25519:${signingKey.version}`, + timeout: 30000, + baseUrl: serverConfig.baseUrl, + }, + }; + + await createFederationContainer(containerOptions); + instance.homeserverServices = getAllServices(); + instance.buildMatrixHTTPRoutes(); return instance; } + private buildMatrixHTTPRoutes() { + const matrix = new Router('/_matrix'); + const wellKnown = new Router('/.well-known'); + + matrix + .use(getMatrixInviteRoutes(this.homeserverServices)) + .use(getMatrixProfilesRoutes(this.homeserverServices)) + .use(getMatrixRoomsRoutes(this.homeserverServices)) + .use(getMatrixSendJoinRoutes(this.homeserverServices)) + .use(getMatrixTransactionsRoutes(this.homeserverServices)) + .use(getKeyServerRoutes(this.homeserverServices)) + .use(getFederationVersionsRoutes()); + + wellKnown.use(getWellKnownRoutes(this.homeserverServices)); + + this.httpRoutes = { matrix, wellKnown }; + } + async created(): Promise { try { registerEvents(this.eventHandler); @@ -58,12 +103,8 @@ export class FederationMatrix extends ServiceClass implements IFederationMatrixS return this.matrixDomain; } - async started(): Promise { - this.homeserverServices = getAllServices(this.diContainer); - } - getAllRoutes() { - return getAllMatrixRoutes(); + return this.httpRoutes; } async createRoom(room: IRoom, owner: IUser, members: string[]): Promise { diff --git a/ee/packages/federation-matrix/src/api/.well-known/server.ts b/ee/packages/federation-matrix/src/api/.well-known/server.ts index 1deef06292e87..0ab75752a29ce 100644 --- a/ee/packages/federation-matrix/src/api/.well-known/server.ts +++ b/ee/packages/federation-matrix/src/api/.well-known/server.ts @@ -1,8 +1,9 @@ -import type { Router } from "@rocket.chat/http-router"; +import { Router } from "@rocket.chat/http-router"; import { ajv } from '@rocket.chat/rest-typings/dist/v1/Ajv'; -import { getAllServicesFromFederationSDK } from '../../setupContainers'; import { createHash } from 'node:crypto'; +import type { HomeserverServices } from '@hs/federation-sdk'; + const WellKnownServerResponseSchema = { type: 'object', properties: { @@ -16,10 +17,10 @@ const WellKnownServerResponseSchema = { const isWellKnownServerResponseProps = ajv.compile(WellKnownServerResponseSchema); -export const getWellKnownRoutes = (router: Router<'/.well-known'>) => { - const { wellKnown } = getAllServicesFromFederationSDK(); - - return router.get('/matrix/server', { +export const getWellKnownRoutes = (services: HomeserverServices) => { + const { wellKnown } = services; + + return new Router('/matrix').get('/server', { response: { 200: isWellKnownServerResponseProps }, diff --git a/ee/packages/federation-matrix/src/api/_matrix/invite.ts b/ee/packages/federation-matrix/src/api/_matrix/invite.ts index df4438bebd91a..6d957226cb8d8 100644 --- a/ee/packages/federation-matrix/src/api/_matrix/invite.ts +++ b/ee/packages/federation-matrix/src/api/_matrix/invite.ts @@ -1,8 +1,7 @@ -import type { Router } from '@rocket.chat/http-router'; +import type { HomeserverServices } from '@hs/federation-sdk'; +import { Router } from '@rocket.chat/http-router'; import { ajv } from '@rocket.chat/rest-typings/dist/v1/Ajv'; -import { getAllServicesFromFederationSDK } from '../../setupContainers'; - const EventBaseSchema = { type: 'object', properties: { @@ -127,11 +126,11 @@ const ProcessInviteResponseSchema = { const isProcessInviteResponseProps = ajv.compile(ProcessInviteResponseSchema); -export const getMatrixInviteRoutes = (router: Router<'/_matrix'>) => { - const { invite } = getAllServicesFromFederationSDK(); +export const getMatrixInviteRoutes = (services: HomeserverServices) => { + const { invite } = services; - return router.put( - '/federation/v2/invite/:roomId/:eventId', + return new Router('/federation').put( + '/v2/invite/:roomId/:eventId', { body: isProcessInviteBodyProps, params: isProcessInviteParamsProps, diff --git a/ee/packages/federation-matrix/src/api/_matrix/key/server.ts b/ee/packages/federation-matrix/src/api/_matrix/key/server.ts index af5c76de2e951..a24599cce396f 100644 --- a/ee/packages/federation-matrix/src/api/_matrix/key/server.ts +++ b/ee/packages/federation-matrix/src/api/_matrix/key/server.ts @@ -1,8 +1,7 @@ -import type { Router } from '@rocket.chat/http-router'; +import type { HomeserverServices } from '@hs/federation-sdk'; +import { Router } from '@rocket.chat/http-router'; import { ajv } from '@rocket.chat/rest-typings/dist/v1/Ajv'; -import { getAllServicesFromFederationSDK } from '../../../setupContainers'; - const ServerKeyResponseSchema = { type: 'object', properties: { @@ -33,11 +32,11 @@ const ServerKeyResponseSchema = { const isServerKeyResponseProps = ajv.compile(ServerKeyResponseSchema); -export const getKeyServerRoutes = (router: Router<'/_matrix'>) => { - const { server } = getAllServicesFromFederationSDK(); +export const getKeyServerRoutes = (services: HomeserverServices) => { + const { server } = services; - return router.get( - '/key/v2/server', + return new Router('/key').get( + '/v2/server', { response: { 200: isServerKeyResponseProps, diff --git a/ee/packages/federation-matrix/src/api/_matrix/profiles.ts b/ee/packages/federation-matrix/src/api/_matrix/profiles.ts index 400d412c59185..548991adbf71a 100644 --- a/ee/packages/federation-matrix/src/api/_matrix/profiles.ts +++ b/ee/packages/federation-matrix/src/api/_matrix/profiles.ts @@ -1,8 +1,7 @@ -import type { Router } from '@rocket.chat/http-router'; +import type { HomeserverServices } from '@hs/federation-sdk'; +import { Router } from '@rocket.chat/http-router'; import { ajv } from '@rocket.chat/rest-typings/dist/v1/Ajv'; -import { getAllServicesFromFederationSDK } from '../../setupContainers'; - const UsernameSchema = { type: 'string', pattern: '^@[A-Za-z0-9_=\\/.+-]+:(.+)$', @@ -330,12 +329,12 @@ const EventAuthResponseSchema = { const isEventAuthResponseProps = ajv.compile(EventAuthResponseSchema); -export const getMatrixProfilesRoutes = (router: Router<'/_matrix'>) => { - const { profile } = getAllServicesFromFederationSDK(); +export const getMatrixProfilesRoutes = (services: HomeserverServices) => { + const { profile } = services; - return router + return new Router('/federation') .get( - '/federation/v1/query/profile', + '/v1/query/profile', { query: isQueryProfileQueryProps, response: { @@ -356,7 +355,7 @@ export const getMatrixProfilesRoutes = (router: Router<'/_matrix'>) => { }, ) .post( - '/federation/v1/user/keys/query', + '/v1/user/keys/query', { body: isQueryKeysBodyProps, response: { @@ -377,7 +376,7 @@ export const getMatrixProfilesRoutes = (router: Router<'/_matrix'>) => { }, ) .get( - '/federation/v1/user/devices/:userId', + '/v1/user/devices/:userId', { params: isGetDevicesParamsProps, response: { @@ -398,7 +397,7 @@ export const getMatrixProfilesRoutes = (router: Router<'/_matrix'>) => { }, ) .get( - '/federation/v1/make_join/:roomId/:userId', + '/v1/make_join/:roomId/:userId', { params: isMakeJoinParamsProps, query: isMakeJoinQueryProps, @@ -438,7 +437,7 @@ export const getMatrixProfilesRoutes = (router: Router<'/_matrix'>) => { }, ) .post( - '/federation/v1/get_missing_events/:roomId', + '/v1/get_missing_events/:roomId', { params: isGetMissingEventsParamsProps, body: isGetMissingEventsBodyProps, @@ -461,7 +460,7 @@ export const getMatrixProfilesRoutes = (router: Router<'/_matrix'>) => { }, ) .get( - '/federation/v1/event_auth/:roomId/:eventId', + '/v1/event_auth/:roomId/:eventId', { params: isEventAuthParamsProps, response: { diff --git a/ee/packages/federation-matrix/src/api/_matrix/rooms.ts b/ee/packages/federation-matrix/src/api/_matrix/rooms.ts index 6670a08108d76..21bc9394b4afe 100644 --- a/ee/packages/federation-matrix/src/api/_matrix/rooms.ts +++ b/ee/packages/federation-matrix/src/api/_matrix/rooms.ts @@ -1,8 +1,7 @@ -import type { Router } from '@rocket.chat/http-router'; +import type { HomeserverServices } from '@hs/federation-sdk'; +import { Router } from '@rocket.chat/http-router'; import { ajv } from '@rocket.chat/rest-typings/dist/v1/Ajv'; -import { getAllServicesFromFederationSDK } from '../../setupContainers'; - const PublicRoomsQuerySchema = { type: 'object', properties: { @@ -122,12 +121,12 @@ const PublicRoomsPostBodySchema = { const isPublicRoomsPostBodyProps = ajv.compile(PublicRoomsPostBodySchema); -export const getMatrixRoomsRoutes = (router: Router<'/_matrix'>) => { - const { state } = getAllServicesFromFederationSDK(); +export const getMatrixRoomsRoutes = (services: HomeserverServices) => { + const { state } = services; - return router + return new Router('/federation') .get( - '/federation/v1/publicRooms', + '/v1/publicRooms', { query: isPublicRoomsQueryProps, response: { @@ -158,7 +157,7 @@ export const getMatrixRoomsRoutes = (router: Router<'/_matrix'>) => { }, ) .post( - '/federation/v1/publicRooms', + '/v1/publicRooms', { body: isPublicRoomsPostBodyProps, response: { diff --git a/ee/packages/federation-matrix/src/api/_matrix/send-join.ts b/ee/packages/federation-matrix/src/api/_matrix/send-join.ts index 9c5d38f77ccb4..842df90db8c5d 100644 --- a/ee/packages/federation-matrix/src/api/_matrix/send-join.ts +++ b/ee/packages/federation-matrix/src/api/_matrix/send-join.ts @@ -1,8 +1,7 @@ -import type { Router } from '@rocket.chat/http-router'; +import type { HomeserverServices } from '@hs/federation-sdk'; +import { Router } from '@rocket.chat/http-router'; import { ajv } from '@rocket.chat/rest-typings/dist/v1/Ajv'; -import { getAllServicesFromFederationSDK } from '../../setupContainers'; - const UsernameSchema = { type: 'string', pattern: '^@[A-Za-z0-9_=\\/.+-]+:(.+)$', @@ -216,11 +215,11 @@ const SendJoinResponseSchema = { const isSendJoinResponseProps = ajv.compile(SendJoinResponseSchema); -export const getMatrixSendJoinRoutes = (router: Router<'/_matrix'>) => { - const { sendJoin } = getAllServicesFromFederationSDK(); +export const getMatrixSendJoinRoutes = (services: HomeserverServices) => { + const { sendJoin } = services; - return router.put( - '/federation/v2/send_join/:roomId/:stateKey', + return new Router('/federation').put( + '/v2/send_join/:roomId/:stateKey', { params: isSendJoinParamsProps, body: isSendJoinEventProps, diff --git a/ee/packages/federation-matrix/src/api/_matrix/transactions.ts b/ee/packages/federation-matrix/src/api/_matrix/transactions.ts index 93d06bcf6ccf0..9fd59bd2312b4 100644 --- a/ee/packages/federation-matrix/src/api/_matrix/transactions.ts +++ b/ee/packages/federation-matrix/src/api/_matrix/transactions.ts @@ -1,8 +1,7 @@ -import type { Router } from '@rocket.chat/http-router'; +import type { HomeserverServices } from '@hs/federation-sdk'; +import { Router } from '@rocket.chat/http-router'; import { ajv } from '@rocket.chat/rest-typings/dist/v1/Ajv'; -import { getAllServicesFromFederationSDK } from '../../setupContainers'; - const SendTransactionParamsSchema = { type: 'object', properties: { @@ -155,11 +154,11 @@ const ErrorResponseSchema = { const isErrorResponseProps = ajv.compile(ErrorResponseSchema); -export const getMatrixTransactionsRoutes = (router: Router<'/_matrix'>) => { - const { event } = getAllServicesFromFederationSDK(); +export const getMatrixTransactionsRoutes = (services: HomeserverServices) => { + const { event } = services; - return router.put( - '/federation/v1/send/:txnId', + return new Router('/federation').put( + '/v1/send/:txnId', { params: isSendTransactionParamsProps, body: isSendTransactionBodyProps, diff --git a/ee/packages/federation-matrix/src/api/_matrix/versions.ts b/ee/packages/federation-matrix/src/api/_matrix/versions.ts index cb039856352bb..49cbce61f6d0c 100644 --- a/ee/packages/federation-matrix/src/api/_matrix/versions.ts +++ b/ee/packages/federation-matrix/src/api/_matrix/versions.ts @@ -1,5 +1,5 @@ import { ConfigService } from '@hs/federation-sdk'; -import type { Router } from '@rocket.chat/http-router'; +import { Router } from '@rocket.chat/http-router'; import { ajv } from '@rocket.chat/rest-typings/dist/v1/Ajv'; const GetVersionsResponseSchema = { @@ -25,11 +25,11 @@ const GetVersionsResponseSchema = { const isGetVersionsResponseProps = ajv.compile(GetVersionsResponseSchema); -export const getFederationVersionsRoutes = (router: Router<'/_matrix'>) => { +export const getFederationVersionsRoutes = () => { const configService = new ConfigService(); - return router.get( - '/federation/v1/version', + return new Router('/federation').get( + '/v1/version', { response: { 200: isGetVersionsResponseProps, diff --git a/ee/packages/federation-matrix/src/api/api.ts b/ee/packages/federation-matrix/src/api/api.ts deleted file mode 100644 index e61a602a8a4c1..0000000000000 --- a/ee/packages/federation-matrix/src/api/api.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Router } from '@rocket.chat/http-router'; - -import { getWellKnownRoutes } from './.well-known/server'; -import { getMatrixInviteRoutes } from './_matrix/invite'; -import { getKeyServerRoutes } from './_matrix/key/server'; -import { getMatrixProfilesRoutes } from './_matrix/profiles'; -import { getMatrixRoomsRoutes } from './_matrix/rooms'; -import { getMatrixSendJoinRoutes } from './_matrix/send-join'; -import { getMatrixTransactionsRoutes } from './_matrix/transactions'; -import { getFederationVersionsRoutes } from './_matrix/versions'; - -const matrix = new Router('/_matrix'); -const wellKnown = new Router('/.well-known'); - -export const getAllMatrixRoutes = () => { - matrix - .use(getMatrixInviteRoutes(matrix)) - .use(getMatrixProfilesRoutes(matrix)) - .use(getMatrixRoomsRoutes(matrix)) - .use(getMatrixSendJoinRoutes(matrix)) - .use(getMatrixTransactionsRoutes(matrix)) - .use(getFederationVersionsRoutes(matrix)) - .use(getKeyServerRoutes(matrix)); - - wellKnown.use(getWellKnownRoutes(wellKnown)); - - return { - matrix, - wellKnown, - }; -}; diff --git a/ee/packages/federation-matrix/src/setupContainers.ts b/ee/packages/federation-matrix/src/setupContainers.ts deleted file mode 100644 index 290f3da9d2db1..0000000000000 --- a/ee/packages/federation-matrix/src/setupContainers.ts +++ /dev/null @@ -1,41 +0,0 @@ -import 'reflect-metadata'; - -import { toUnpaddedBase64 } from '@hs/core'; -import { ConfigService, createFederationContainer, getAllServices } from '@hs/federation-sdk'; -import type { DependencyContainer, FederationContainerOptions, HomeserverEventSignatures, HomeserverServices } from '@hs/federation-sdk'; -import { Emitter } from '@rocket.chat/emitter'; - -let container: DependencyContainer | undefined; - -export async function setup( - emitter: Emitter = new Emitter(), -): Promise { - const config = new ConfigService(); - const matrixConfig = config.getMatrixConfig(); - const serverConfig = config.getServerConfig(); - const signingKeys = await config.getSigningKey(); - const signingKey = signingKeys[0]; - - const containerOptions: FederationContainerOptions = { - emitter, - federationOptions: { - serverName: matrixConfig.serverName, - signingKey: toUnpaddedBase64(signingKey.privateKey), - signingKeyId: `ed25519:${signingKey.version}`, - timeout: 30000, - baseUrl: serverConfig.baseUrl, - }, - }; - - container = createFederationContainer(containerOptions); - - return container; -} - -export function getAllServicesFromFederationSDK(): HomeserverServices { - if (!container) { - throw new Error('Federation container is not initialized. Call setup() first.'); - } - - return getAllServices(container); -} From eb5ef8b09150209b4a0343b644f75ea5b95315af Mon Sep 17 00:00:00 2001 From: Marcos Defendi Date: Mon, 14 Jul 2025 13:37:50 -0300 Subject: [PATCH 2/2] chore: remove old-way register routes leftovers --- apps/meteor/app/api/server/api.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/apps/meteor/app/api/server/api.ts b/apps/meteor/app/api/server/api.ts index 74f3ee477bcb8..dbafa020706f8 100644 --- a/apps/meteor/app/api/server/api.ts +++ b/apps/meteor/app/api/server/api.ts @@ -42,9 +42,6 @@ const createApi = function _createApi(options: { version?: string; useDefaultAut export const API: { api: Router<'/api', any, APIActionHandler>; v1: APIClass<'/v1'>; - _matrix: Router<'/_matrix', any, APIActionHandler>; - wellKnown: Router<'/.well-known', any, APIActionHandler>; - matrixInternal: Router<'/internal', any, APIActionHandler>; default: APIClass; ApiClass: typeof APIClass; channels?: { @@ -76,9 +73,6 @@ export const API: { version: 'v1', useDefaultAuth: true, }), - _matrix: new RocketChatAPIRouter('/_matrix'), - wellKnown: new RocketChatAPIRouter('/.well-known'), - matrixInternal: new RocketChatAPIRouter('/internal'), default: createApi({}), }; @@ -106,7 +100,6 @@ settings.watch('API_Enable_Rate_Limiter_Limit_Calls_Default', (value) => }); export const startRestAPI = () => { - // Register main API routes under /api prefix (WebApp.rawConnectHandlers as unknown as ReturnType).use( API.api .use(remoteAddressMiddleware)