diff --git a/dht-node/jest.config.js b/dht-node/jest.config.js index 203d043cf..fa00ed868 100644 --- a/dht-node/jest.config.js +++ b/dht-node/jest.config.js @@ -6,7 +6,7 @@ module.exports = { collectCoverageFrom: ['src/**/*.ts', '!**/node_modules/**', '!src/seeds/**', '!build/**'], coverageThreshold: { global: { - lines: 78, + lines: 80, }, }, setupFiles: ['/test/testSetup.ts'], diff --git a/dht-node/src/dht_node/index.test.ts b/dht-node/src/dht_node/index.test.ts index d97b3737e..9f030f4e7 100644 --- a/dht-node/src/dht_node/index.test.ts +++ b/dht-node/src/dht_node/index.test.ts @@ -1,12 +1,19 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -import { startDHT } from './index' +import { + CommunityApi, + startDHT, + writeFederatedHomeCommunityEntries, + writeHomeCommunityEntry, +} from './index' import DHT from '@hyperswarm/dht' import CONFIG from '@/config' import { logger } from '@test/testSetup' +import { Community as DbCommunity } from '@entity/Community' import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' import { testEnvironment, cleanDB } from '@test/helpers' +import { validate as validateUUID, version as versionUUID } from 'uuid' CONFIG.FEDERATION_DHT_SEED = '64ebcb0e3ad547848fef4197c6e2332f' @@ -101,7 +108,7 @@ beforeAll(async () => { }) afterAll(async () => { - await cleanDB() + // await cleanDB() await con.close() }) @@ -155,6 +162,135 @@ describe('federation', () => { }) }) + describe('home community', () => { + it('one in communities', async () => { + const result = await DbCommunity.find({ foreign: false }) + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: expect.any(Number), + foreign: false, + url: CONFIG.FEDERATION_COMMUNITY_URL + '/api/', + publicKey: expect.any(Buffer), + communityUuid: expect.any(String), + authenticatedAt: null, + name: CONFIG.COMMUNITY_NAME, + description: CONFIG.COMMUNITY_DESCRIPTION, + creationDate: expect.any(Date), + createdAt: expect.any(Date), + updatedAt: null, + }), + ]), + ) + const valUUID = validateUUID( + result[0].communityUuid != null ? result[0].communityUuid : '', + ) + const verUUID = versionUUID( + result[0].communityUuid != null ? result[0].communityUuid : '', + ) + expect(valUUID).toEqual(true) + expect(verUUID).toEqual(4) + }) + it('update the one in communities', async () => { + const resultBefore = await DbCommunity.find({ foreign: false }) + expect(resultBefore).toHaveLength(1) + const modifiedCom = DbCommunity.create() + modifiedCom.communityUuid = resultBefore[0].communityUuid + modifiedCom.creationDate = resultBefore[0].creationDate + modifiedCom.description = 'updated description' + modifiedCom.foreign = resultBefore[0].foreign + modifiedCom.id = resultBefore[0].id + modifiedCom.name = 'update name' + modifiedCom.publicKey = Buffer.from( + '1234567891abcdef7892abcdef7893abcdef7894abcdef7895abcdef7896abcd1234567891abcdef7892abcdef7893abcdef7894abcdef7895abcdef7896abcd', + 'hex', + ) + modifiedCom.url = 'updated url' + await DbCommunity.update(modifiedCom, { id: resultBefore[0].id }) + + await writeHomeCommunityEntry(modifiedCom.publicKey.toString('hex')) + const resultAfter = await DbCommunity.find({ foreign: false }) + expect(resultAfter).toHaveLength(1) + expect(resultAfter).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: resultBefore[0].id, + foreign: false, + url: CONFIG.FEDERATION_COMMUNITY_URL + '/api/', + publicKey: modifiedCom.publicKey, + communityUuid: resultBefore[0].communityUuid, + authenticatedAt: null, + name: CONFIG.COMMUNITY_NAME, + description: CONFIG.COMMUNITY_DESCRIPTION, + creationDate: expect.any(Date), + createdAt: expect.any(Date), + updatedAt: expect.any(Date), + }), + ]), + ) + }) + }) + + describe('federated home community', () => { + it('three in federated_communities', async () => { + const homeApiVersions: CommunityApi[] = await writeFederatedHomeCommunityEntries( + keyPairMock.publicKey.toString('hex'), + ) + expect(homeApiVersions).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + api: '1_0', + url: CONFIG.FEDERATION_COMMUNITY_URL + '/api/', + }), + expect.objectContaining({ + api: '1_1', + url: CONFIG.FEDERATION_COMMUNITY_URL + '/api/', + }), + expect.objectContaining({ + api: '2_0', + url: CONFIG.FEDERATION_COMMUNITY_URL + '/api/', + }), + ]), + ) + const result = await DbFederatedCommunity.find({ foreign: false }) + expect(result).toHaveLength(3) + expect(result).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: expect.any(Number), + foreign: false, + publicKey: expect.any(Buffer), + apiVersion: '1_0', + endPoint: CONFIG.FEDERATION_COMMUNITY_URL + '/api/', + lastAnnouncedAt: null, + createdAt: expect.any(Date), + updatedAt: null, + }), + expect.objectContaining({ + id: expect.any(Number), + foreign: false, + publicKey: expect.any(Buffer), + apiVersion: '1_1', + endPoint: CONFIG.FEDERATION_COMMUNITY_URL + '/api/', + lastAnnouncedAt: null, + createdAt: expect.any(Date), + updatedAt: null, + }), + expect.objectContaining({ + id: expect.any(Number), + foreign: false, + publicKey: expect.any(Buffer), + apiVersion: '2_0', + endPoint: CONFIG.FEDERATION_COMMUNITY_URL + '/api/', + lastAnnouncedAt: null, + createdAt: expect.any(Date), + updatedAt: null, + }), + ]), + ) + }) + }) + describe('server connection event', () => { beforeEach(() => { serverEventMocks.connection({ diff --git a/dht-node/src/dht_node/index.ts b/dht-node/src/dht_node/index.ts index ca3cb6aab..cf8d211ae 100644 --- a/dht-node/src/dht_node/index.ts +++ b/dht-node/src/dht_node/index.ts @@ -8,6 +8,7 @@ import { Community as DbCommunity } from '@entity/Community' import DEVOP from '@/config/devop' import { setDevOpEnvValue } from '@/config/tools' import { v4 as uuidv4 } from 'uuid' +import { InsertResult } from '@dbTools/typeorm' const KEY_SECRET_SEEDBYTES = 32 const getSeed = (): Buffer | null => { @@ -30,7 +31,7 @@ enum ApiVersionType { V1_1 = '1_1', V2_0 = '2_0', } -type CommunityApi = { +export type CommunityApi = { api: string url: string } @@ -44,7 +45,7 @@ export const startDHT = async (topic: string): Promise => { // insert or update keyPair in .env.devop file setDevOpEnvValue('HOME_COMMUNITY_PUBLICKEY', keyPair.publicKey.toString('hex')) setDevOpEnvValue('HOME_COMMUNITY_PRIVATEKEY', keyPair.secretKey.toString('hex')) - await writeHomeCommunityEntry(keyPair.publicKey) + await writeHomeCommunityEntry(keyPair.publicKey.toString('hex')) const ownApiVersions = await writeFederatedHomeCommunityEntries(keyPair.publicKey) logger.info(`ApiList: ${JSON.stringify(ownApiVersions)}`) @@ -194,7 +195,7 @@ export const startDHT = async (topic: string): Promise => { } } -async function writeFederatedHomeCommunityEntries(pubKey: any): Promise { +export async function writeFederatedHomeCommunityEntries(pubKey: any): Promise { const homeApiVersions: CommunityApi[] = Object.values(ApiVersionType).map(function (apiEnum) { const comApi: CommunityApi = { api: apiEnum, @@ -205,48 +206,69 @@ async function writeFederatedHomeCommunityEntries(pubKey: any): Promise { +async function createFederatedCommunityEntity( + homeApi: CommunityApi, + pubKey: string, +): Promise { + let result: InsertResult + try { + const homeCom = DbFederatedCommunity.create() + homeCom.foreign = false + homeCom.apiVersion = homeApi.api + homeCom.endPoint = homeApi.url + homeCom.publicKey = Buffer.from(pubKey, 'hex') + + // this will NOT update the updatedAt column, to distingue between a normal update and the last announcement + result = await DbFederatedCommunity.insert(homeCom) + logger.info(`federation home-community inserted successfully: ${JSON.stringify(homeCom)}`) + console.log(`result: ${JSON.stringify(result)}`) + } catch (err) { + console.log('Error2:', err) + return false + } + return true +} + +export async function writeHomeCommunityEntry(pubKey: string): Promise { + console.log(`pubKey = `, pubKey) try { // check for existing homeCommunity entry - let homeCom = await DbCommunity.findOne({ foreign: false, publicKey: pubKey }) + let homeCom = await DbCommunity.findOne({ foreign: false, publicKey: Buffer.from(pubKey) }) if (!homeCom) { // check if a homecommunity with a different publicKey still exists homeCom = await DbCommunity.findOne({ foreign: false }) } if (homeCom) { // simply update the existing entry, but it MUST keep the ID and UUID because of possible relations - homeCom.publicKey = pubKey.toString('hex') - homeCom.url = CONFIG.FEDERATION_COMMUNITY_URL + homeCom.publicKey = Buffer.from(pubKey, 'hex') // pubKey.toString('hex') + homeCom.url = CONFIG.FEDERATION_COMMUNITY_URL + '/api/' homeCom.name = CONFIG.COMMUNITY_NAME homeCom.description = CONFIG.COMMUNITY_DESCRIPTION // this will NOT update the updatedAt column, to distingue between a normal update and the last announcement await DbCommunity.save(homeCom) logger.info(`home-community updated successfully: ${JSON.stringify(homeCom)}`) } else { - // insert a new homecommunity entry including a new ID and UUID + // insert a new homecommunity entry including a new ID and a new but ensured unique UUID homeCom = new DbCommunity() homeCom.foreign = false - homeCom.publicKey = pubKey.toString('hex') + homeCom.publicKey = Buffer.from(pubKey, 'hex') // pubKey.toString('hex') homeCom.communityUuid = await newCommunityUuid() - homeCom.url = CONFIG.FEDERATION_COMMUNITY_URL + homeCom.url = CONFIG.FEDERATION_COMMUNITY_URL + '/api/' homeCom.name = CONFIG.COMMUNITY_NAME homeCom.description = CONFIG.COMMUNITY_DESCRIPTION homeCom.creationDate = new Date() diff --git a/dht-node/test/helpers.ts b/dht-node/test/helpers.ts index aa7f94964..c5d6ce82b 100644 --- a/dht-node/test/helpers.ts +++ b/dht-node/test/helpers.ts @@ -22,8 +22,8 @@ const context = { export const cleanDB = async () => { // this only works as long we do not have foreign key constraints - for (let i = 0; i < entities.length; i++) { - await resetEntity(entities[i]) + for (const entity of entities) { + await resetEntity(entity) } }