diff --git a/backend/src/federation/client/1_0/FederationClient.ts b/backend/src/federation/client/1_0/FederationClient.ts deleted file mode 100644 index 743d17348..000000000 --- a/backend/src/federation/client/1_0/FederationClient.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-return */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ -import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' -import { gql } from 'graphql-request' - -import { GraphQLGetClient } from '@/federation/client/GraphQLGetClient' -import { LogError } from '@/server/LogError' -import { backendLogger as logger } from '@/server/logger' - -export async function requestGetPublicKey( - dbCom: DbFederatedCommunity, -): Promise { - let endpoint = dbCom.endPoint.endsWith('/') ? dbCom.endPoint : dbCom.endPoint + '/' - endpoint = `${endpoint}${dbCom.apiVersion}/` - logger.info(`requestGetPublicKey with endpoint='${endpoint}'...`) - - const graphQLClient = GraphQLGetClient.getInstance(endpoint) - logger.debug(`graphQLClient=${JSON.stringify(graphQLClient)}`) - const query = gql` - query { - getPublicKey { - publicKey - } - } - ` - const variables = {} - - try { - const { data, errors, extensions, headers, status } = await graphQLClient.rawRequest( - query, - variables, - ) - logger.debug(`Response-Data:`, data, errors, extensions, headers, status) - if (data) { - logger.debug(`Response-PublicKey:`, data.getPublicKey.publicKey) - logger.info(`requestGetPublicKey processed successfully`) - return data.getPublicKey.publicKey - } - logger.warn(`requestGetPublicKey processed without response data`) - } catch (err) { - throw new LogError(`Request-Error:`, err) - } -} diff --git a/backend/src/federation/client/1_1/FederationClient.ts b/backend/src/federation/client/1_1/FederationClient.ts deleted file mode 100644 index 35c88bf3b..000000000 --- a/backend/src/federation/client/1_1/FederationClient.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unsafe-return */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' -import { gql } from 'graphql-request' - -import { GraphQLGetClient } from '@/federation/client/GraphQLGetClient' -import { LogError } from '@/server/LogError' -import { backendLogger as logger } from '@/server/logger' - -export async function requestGetPublicKey( - dbCom: DbFederatedCommunity, -): Promise { - let endpoint = dbCom.endPoint.endsWith('/') ? dbCom.endPoint : dbCom.endPoint + '/' - endpoint = `${endpoint}${dbCom.apiVersion}/` - logger.info(`requestGetPublicKey with endpoint='${endpoint}'...`) - - const graphQLClient = GraphQLGetClient.getInstance(endpoint) - logger.debug(`graphQLClient=${JSON.stringify(graphQLClient)}`) - const query = gql` - query { - getPublicKey { - publicKey - } - } - ` - const variables = {} - - try { - const { data, errors, extensions, headers, status } = await graphQLClient.rawRequest( - query, - variables, - ) - logger.debug(`Response-Data:`, data, errors, extensions, headers, status) - if (data) { - logger.debug(`Response-PublicKey:`, data.getPublicKey.publicKey) - logger.info(`requestGetPublicKey processed successfully`) - return data.getPublicKey.publicKey - } - logger.warn(`requestGetPublicKey processed without response data`) - } catch (err) { - throw new LogError(`Request-Error:`, err) - } -} diff --git a/backend/src/federation/client/Client.ts b/backend/src/federation/client/Client.ts new file mode 100644 index 000000000..98f63c127 --- /dev/null +++ b/backend/src/federation/client/Client.ts @@ -0,0 +1,58 @@ +import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' + +import { ApiVersionType } from '@/federation/enum/apiVersionType' + +// eslint-disable-next-line camelcase +import { Client_1_0 } from './Client_1_0' +// eslint-disable-next-line camelcase +import { Client_1_1 } from './Client_1_1' + +// eslint-disable-next-line camelcase +type FederationClient = Client_1_0 | Client_1_1 + +interface ClientInstance { + id: number + // eslint-disable-next-line no-use-before-define + client: FederationClient +} + +// eslint-disable-next-line @typescript-eslint/no-extraneous-class +export class Client { + private static instanceArray: ClientInstance[] = [] + + /** + * The Singleton's constructor should always be private to prevent direct + * construction calls with the `new` operator. + */ + // eslint-disable-next-line no-useless-constructor, @typescript-eslint/no-empty-function + private constructor() {} + + private static createFederationClient = (dbCom: DbFederatedCommunity) => { + switch (dbCom.apiVersion) { + case ApiVersionType.V1_0: + return new Client_1_0(dbCom) + case ApiVersionType.V1_1: + return new Client_1_1(dbCom) + default: + return null + } + } + + /** + * The static method that controls the access to the singleton instance. + * + * This implementation let you subclass the Singleton class while keeping + * just one instance of each subclass around. + */ + public static getInstance(dbCom: DbFederatedCommunity): FederationClient | null { + const instance = Client.instanceArray.find((instance) => instance.id === dbCom.id) + if (instance) { + return instance.client + } + const client = Client.createFederationClient(dbCom) + if (client) { + Client.instanceArray.push({ id: dbCom.id, client } as ClientInstance) + } + return client + } +} diff --git a/backend/src/federation/client/Client_1_0.ts b/backend/src/federation/client/Client_1_0.ts new file mode 100644 index 000000000..fd2f941a3 --- /dev/null +++ b/backend/src/federation/client/Client_1_0.ts @@ -0,0 +1,46 @@ +import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' +import { GraphQLClient } from 'graphql-request' + +import { getPublicKey } from '@/federation/query/getPublicKey' +import { LogError } from '@/server/LogError' +import { backendLogger as logger } from '@/server/logger' + +// eslint-disable-next-line camelcase +export class Client_1_0 { + dbCom: DbFederatedCommunity + endpoint: string + client: GraphQLClient + + constructor(dbCom: DbFederatedCommunity) { + this.dbCom = dbCom + this.endpoint = `${dbCom.endPoint.endsWith('/') ? dbCom.endPoint : dbCom.endPoint + '/'}${ + dbCom.apiVersion + }/` + this.client = new GraphQLClient(this.endpoint, { + method: 'GET', + jsonSerializer: { + parse: JSON.parse, + stringify: JSON.stringify, + }, + }) + } + + getPublicKey = async (): Promise => { + logger.info(`requestGetPublicKey with endpoint='${this.endpoint}'...`) + try { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const { data, errors, headers, status } = await this.client.rawRequest(getPublicKey, {}) + logger.debug('Response-Data:', data, errors, headers, status) + if (data) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + logger.debug('Response-PublicKey:', data.getPublicKey.publicKey) + logger.info(`requestGetPublicKey processed successfully`) + // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access + return data.getPublicKey.publicKey + } + logger.warn(`requestGetPublicKey processed without response data`) + } catch (err) { + throw new LogError(`Request-Error:`, err) + } + } +} diff --git a/backend/src/federation/client/Client_1_1.ts b/backend/src/federation/client/Client_1_1.ts new file mode 100644 index 000000000..8525acc5d --- /dev/null +++ b/backend/src/federation/client/Client_1_1.ts @@ -0,0 +1,5 @@ +// eslint-disable-next-line camelcase +import { Client_1_0 } from './Client_1_0' + +// eslint-disable-next-line camelcase +export class Client_1_1 extends Client_1_0 {} diff --git a/backend/src/federation/client/GraphQLGetClient.ts b/backend/src/federation/client/GraphQLGetClient.ts deleted file mode 100644 index e2d3e6ed3..000000000 --- a/backend/src/federation/client/GraphQLGetClient.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { GraphQLClient } from 'graphql-request' -import { PatchedRequestInit } from 'graphql-request/dist/types' - -interface ClientInstance { - url: string - // eslint-disable-next-line no-use-before-define - client: GraphQLGetClient -} - -export class GraphQLGetClient extends GraphQLClient { - private static instanceArray: ClientInstance[] = [] - - /** - * The Singleton's constructor should always be private to prevent direct - * construction calls with the `new` operator. - */ - // eslint-disable-next-line no-useless-constructor - private constructor(url: string, options?: PatchedRequestInit) { - super(url, options) - } - - /** - * The static method that controls the access to the singleton instance. - * - * This implementation let you subclass the Singleton class while keeping - * just one instance of each subclass around. - */ - public static getInstance(url: string): GraphQLGetClient { - const instance = GraphQLGetClient.instanceArray.find((instance) => instance.url === url) - if (instance) { - return instance.client - } - const client = new GraphQLGetClient(url, { - method: 'GET', - jsonSerializer: { - parse: JSON.parse, - stringify: JSON.stringify, - }, - }) - GraphQLGetClient.instanceArray.push({ url, client } as ClientInstance) - return client - } -} diff --git a/backend/src/federation/query/getPublicKey.ts b/backend/src/federation/query/getPublicKey.ts new file mode 100644 index 000000000..a772a0cf1 --- /dev/null +++ b/backend/src/federation/query/getPublicKey.ts @@ -0,0 +1,9 @@ +import { gql } from 'graphql-request' + +export const getPublicKey = gql` + query { + getPublicKey { + publicKey + } + } +` diff --git a/backend/src/federation/validateCommunities.ts b/backend/src/federation/validateCommunities.ts index 073a8eded..c0a8036a0 100644 --- a/backend/src/federation/validateCommunities.ts +++ b/backend/src/federation/validateCommunities.ts @@ -6,10 +6,7 @@ import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCom import { LogError } from '@/server/LogError' import { backendLogger as logger } from '@/server/logger' -// eslint-disable-next-line camelcase -import { requestGetPublicKey as v1_0_requestGetPublicKey } from './client/1_0/FederationClient' -// eslint-disable-next-line camelcase -import { requestGetPublicKey as v1_1_requestGetPublicKey } from './client/1_1/FederationClient' +import { Client } from './client/Client' import { ApiVersionType } from './enum/apiVersionType' export function startValidateCommunities(timerInterval: number): void { @@ -41,7 +38,7 @@ export async function validateCommunities(): Promise { `Federation: validate publicKey for dbCom: ${dbCom.id} with apiVersion=${dbCom.apiVersion}`, ) try { - const pubKey = await invokeVersionedRequestGetPublicKey(dbCom) + const pubKey = await Client.getInstance(dbCom)?.getPublicKey() logger.info( 'Federation: received publicKey from endpoint', pubKey, @@ -60,7 +57,7 @@ export async function validateCommunities(): Promise { // DbCommunity.delete({ id: dbCom.id }) } } catch (err) { - if (!isLogError(err)) { + if (!(err instanceof LogError)) { logger.error(`Error:`, err) } } @@ -72,20 +69,3 @@ export async function validateCommunities(): Promise { } } } - -function isLogError(err: unknown) { - return err instanceof LogError -} - -async function invokeVersionedRequestGetPublicKey( - dbCom: DbFederatedCommunity, -): Promise { - switch (dbCom.apiVersion) { - case ApiVersionType.V1_0: - return v1_0_requestGetPublicKey(dbCom) - case ApiVersionType.V1_1: - return v1_1_requestGetPublicKey(dbCom) - default: - return undefined - } -} diff --git a/federation/src/server/plugins.ts b/federation/src/server/plugins.ts index 541c68ca2..38fdfbe9f 100644 --- a/federation/src/server/plugins.ts +++ b/federation/src/server/plugins.ts @@ -23,8 +23,8 @@ const setHeadersPlugin = { const filterVariables = (variables: any) => { const vars = clonedeep(variables) - if (vars.password) vars.password = '***' - if (vars.passwordNew) vars.passwordNew = '***' + if (vars && vars.password) vars.password = '***' + if (vars && vars.passwordNew) vars.passwordNew = '***' return vars }