Skip to content

Commit

Permalink
add cluster matching adapters
Browse files Browse the repository at this point in the history
  • Loading branch information
CarlosQ96 committed Oct 15, 2024
1 parent b20f60d commit d0b4b97
Show file tree
Hide file tree
Showing 11 changed files with 227 additions and 30 deletions.
32 changes: 16 additions & 16 deletions migration/1728554628004-AddEstimatedClusterMatching.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
import {MigrationInterface, QueryRunner} from "typeorm";
import { MigrationInterface, QueryRunner } from 'typeorm';

export class AddEstimatedClusterMatching1728554628004 implements MigrationInterface {

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
export class AddEstimatedClusterMatching1728554628004
implements MigrationInterface
{
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
CREATE TABLE estimated_cluster_matching (
id SERIAL PRIMARY KEY,
project_id INT NOT NULL,
qf_round_id INT NOT NULL,
matching DOUBLE PRECISION NOT NULL
);
`);
// Create indexes on the new table
await queryRunner.query(`

// Create indexes on the new table
await queryRunner.query(`
CREATE INDEX estimated_cluster_matching_project_id_qfround_id
ON estimated_cluster_matching (project_id, qf_round_id);
`);
await queryRunner.query(`

await queryRunner.query(`
CREATE INDEX estimated_cluster_matching_matching
ON estimated_cluster_matching (matching);
`);
}
}

public async down(queryRunner: QueryRunner): Promise<void> {
// Revert changes if necessary by dropping the table and restoring the view
await queryRunner.query(`
public async down(queryRunner: QueryRunner): Promise<void> {
// Revert changes if necessary by dropping the table and restoring the view
await queryRunner.query(`
DROP TABLE IF EXISTS estimated_cluster_matching;
`);
}

}
}
17 changes: 17 additions & 0 deletions src/adapters/adaptersFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ import { DonationSaveBackupMockAdapter } from './donationSaveBackup/DonationSave
import { SuperFluidAdapter } from './superFluid/superFluidAdapter';
import { SuperFluidMockAdapter } from './superFluid/superFluidMockAdapter';
import { SuperFluidAdapterInterface } from './superFluid/superFluidAdapterInterface';
import { CocmAdapter } from './cocmAdapter/cocmAdapter';
import { CocmMockAdapter } from './cocmAdapter/cocmMockAdapter';
import { CocmAdapterInterface } from './cocmAdapter/cocmAdapterInterface';

const discordAdapter = new DiscordAdapter();
const googleAdapter = new GoogleAdapter();
Expand Down Expand Up @@ -147,3 +150,17 @@ export const getSuperFluidAdapter = (): SuperFluidAdapterInterface => {
return superFluidMockAdapter;
}
};

const clusterMatchingAdapter = new CocmAdapter();
const clusterMatchingMockAdapter = new CocmMockAdapter();

export const getClusterMatchingAdapter = (): CocmAdapterInterface => {
switch (process.env.CLUSTER_MATCHING_ADAPTER) {
case 'clusterMatching':
return clusterMatchingAdapter;
case 'mock':
return clusterMatchingMockAdapter;
default:
return clusterMatchingMockAdapter;
}
};
46 changes: 46 additions & 0 deletions src/adapters/cocmAdapter/cocmAdapter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import axios from 'axios';
import {
CocmAdapterInterface,
EstimatedMatchingInput,
ProjectsEstimatedMatchings,
} from './cocmAdapterInterface';
import { logger } from '../../utils/logger';
import { i18n, translationErrorMessagesKeys } from '../../utils/errorMessages';

export class CocmAdapter implements CocmAdapterInterface {
private ClusterMatchingURL;

constructor() {
this.ClusterMatchingURL =
process.env.CLUSTER_MATCHING_API_URL || 'localhost';
}

async fetchEstimatedClusterMatchings(
matchingDataInput: EstimatedMatchingInput,
): Promise<ProjectsEstimatedMatchings> {
try {
const result = await axios.post(
this.ClusterMatchingURL,
matchingDataInput,
{
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
},
);
if (result?.data?.error !== null) {
logger.error('clusterMatchingApi error', result.data.error);
throw new Error(
i18n.__(translationErrorMessagesKeys.CLUSTER_MATCHING_API_ERROR),
);
}
return result.data;
} catch (e) {
logger.error('clusterMatchingApi error', e);
throw new Error(
i18n.__(translationErrorMessagesKeys.CLUSTER_MATCHING_API_ERROR),
);
}
}
}
49 changes: 49 additions & 0 deletions src/adapters/cocmAdapter/cocmAdapterInterface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Example Data
// {
// "matching_data": [
// {
// "matching_amount": 83.25,
// "matching_percent": 50.0,
// "project_name": "Test1",
// "strategy": "COCM"
// },
// {
// "matching_amount": 83.25,
// "matching_percent": 50.0,
// "project_name": "Test3",
// "strategy": "COCM"
// }
// ]
// }

export interface ProjectsEstimatedMatchings {
matching_data: {
matching_amount: number;
matching_percent: number;
project_name: string;
strategy: string;
}[];
}

export interface EstimatedMatchingInput {
votes_data: [
{
voter: string;
payoutAddress: string;
amountUSD: number;
project_name: string;
score: number;
},
];
strategy: string;
min_donation_threshold_amount: number;
matching_cap_amount: number;
matching_amount: number;
passport_threshold: number;
}

export interface CocmAdapterInterface {
fetchEstimatedClusterMatchings(
matchingDataInput: EstimatedMatchingInput,
): Promise<ProjectsEstimatedMatchings>;
}
30 changes: 30 additions & 0 deletions src/adapters/cocmAdapter/cocmMockAdapter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import axios from 'axios';

Check failure on line 1 in src/adapters/cocmAdapter/cocmMockAdapter.ts

View workflow job for this annotation

GitHub Actions / test

'axios' is defined but never used

Check failure on line 1 in src/adapters/cocmAdapter/cocmMockAdapter.ts

View workflow job for this annotation

GitHub Actions / test

'axios' is defined but never used
import {
CocmAdapterInterface,
ProjectsEstimatedMatchings,
} from './cocmAdapterInterface';
import { i18n, translationErrorMessagesKeys } from '../../utils/errorMessages';

Check failure on line 6 in src/adapters/cocmAdapter/cocmMockAdapter.ts

View workflow job for this annotation

GitHub Actions / test

'i18n' is defined but never used

Check failure on line 6 in src/adapters/cocmAdapter/cocmMockAdapter.ts

View workflow job for this annotation

GitHub Actions / test

'i18n' is defined but never used

Check failure on line 6 in src/adapters/cocmAdapter/cocmMockAdapter.ts

View workflow job for this annotation

GitHub Actions / test

'translationErrorMessagesKeys' is defined but never used

Check failure on line 6 in src/adapters/cocmAdapter/cocmMockAdapter.ts

View workflow job for this annotation

GitHub Actions / test

'translationErrorMessagesKeys' is defined but never used
import { logger } from '../../utils/logger';

Check failure on line 7 in src/adapters/cocmAdapter/cocmMockAdapter.ts

View workflow job for this annotation

GitHub Actions / test

'logger' is defined but never used

Check failure on line 7 in src/adapters/cocmAdapter/cocmMockAdapter.ts

View workflow job for this annotation

GitHub Actions / test

'logger' is defined but never used

export class CocmMockAdapter implements CocmAdapterInterface {
async fetchEstimatedClusterMatchings(
_matchingDataInput,
): Promise<ProjectsEstimatedMatchings> {
return {
matching_data: [
{
matching_amount: 83.25,
matching_percent: 50.0,
project_name: 'Test1',
strategy: 'COCM',
},
{
matching_amount: 83.25,
matching_percent: 50.0,
project_name: 'Test3',
strategy: 'COCM',
},
],
};
}
}
14 changes: 0 additions & 14 deletions src/server/bootstrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -339,20 +339,6 @@ export async function bootstrap() {
logger.error('Enabling power boosting snapshot ', e);
}
}

if (!isTestEnv) {
// They will fail in test env, because we run migrations after bootstrap so refreshing them will cause this error
// relation "project_estimated_matching_view" does not exist
logger.debug(
'continueDbSetup() before refreshProjectEstimatedMatchingView() ',
new Date(),
);
await refreshProjectEstimatedMatchingView();
logger.debug(
'continueDbSetup() after refreshProjectEstimatedMatchingView() ',
new Date(),
);
}
logger.debug('continueDbSetup() end of function', new Date());
}

Expand Down
Empty file.
50 changes: 50 additions & 0 deletions src/services/cronJobs/syncEstimatedClusterMatchingJob.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { schedule } from 'node-cron';
import { spawn, Worker, Thread } from 'threads';
import config from '../../config';
import { logger } from '../../utils/logger';
import {
findActiveQfRound,
findUsersWithoutMBDScoreInActiveAround,
} from '../../repositories/qfRoundRepository';
import { findUserById } from '../../repositories/userRepository';
import { UserQfRoundModelScore } from '../../entities/userQfRoundModelScore';

const cronJobTime =
(config.get('SYNC_ESTIMATED_CLUSTED_MATCHING_CRONJOB_EXPRESSION') as string) ||
'0 * * * * *';

export const runSyncEstimatedClusterMatchingCronjob = () => {
logger.debug(
'runSyncEstimatedClusterMatchingCronjob() has been called, cronJobTime',
cronJobTime,
);
schedule(cronJobTime, async () => {
await fetchAndUpdateClusterEstimatedMatching();
});
};

export const fetchAndUpdateClusterEstimatedMatching = async () => {
const fetchWorker = await spawn(
new Worker('../../workers/cocm/fetchEstimatedClusterMtchingWorker'),
);

const updateWorker = await spawn(
new Worker('../../workers/cocm/updateProjectsEstimatedClusterMatchingWorker')
);
const activeQfRoundId =
(await findActiveQfRound())?.id;
if (!activeQfRoundId || activeQfRoundId === 0) return;

for (const projectId of []) {
try {

// const userScore = await worker.syncUserScore({
// userWallet: user?.walletAddress,
// });
} catch (e) {
logger.info(`User with Id ${1} did not sync MBD score this batch`);
}
}
await Thread.terminate(fetchWorker);
await Thread.terminate(updateWorker);
};
2 changes: 2 additions & 0 deletions src/utils/errorMessages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const setI18nLocaleForRequest = async (req, _res, next) => {
};

export const errorMessages = {
CLUSTER_MATCHING_API_ERROR: 'Error in the cluster matching api, check logs',
FIAT_DONATION_ALREADY_EXISTS: 'Onramper donation already exists',
CAMPAIGN_NOT_FOUND: 'Campaign not found',
QF_ROUND_NOT_FOUND: 'qf round not found',
Expand Down Expand Up @@ -208,6 +209,7 @@ export const errorMessages = {
};

export const translationErrorMessagesKeys = {
CLUSTER_MATCHING_API_ERROR: 'CLUSTER_MATCHING_API_ERROR',
GITCOIN_ERROR_FETCHING_DATA: 'GITCOIN_ERROR_FETCHING_DATA',
TX_NOT_FOUND: 'TX_NOT_FOUND',
INVALID_PROJECT_ID: 'INVALID_PROJECT_ID',
Expand Down
17 changes: 17 additions & 0 deletions src/workers/cocm/fetchEstimatedClusterMatchingWorker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// workers/auth.js
import { expose } from 'threads/worker';
import { WorkerModule } from 'threads/dist/types/worker';
import { getClusterMatchingAdapter } from '../../adapters/adaptersFactory';

type FetchEstimatedClusterMatchingWorkerFunctions = 'fetchEstimatedClusterMatching';

export type FetchEstimatedClusterMatchingWorker =
WorkerModule<FetchEstimatedClusterMatchingWorkerFunctions>;

const worker: FetchEstimatedClusterMatchingWorker = {
async fetchEstimatedClusterMatching(matchingDataInput: any) {
return await getClusterMatchingAdapter().fetchEstimatedClusterMatchings(matchingDataInput);
},
};

expose(worker);
Empty file.

0 comments on commit d0b4b97

Please sign in to comment.