From 7f3286bec50f9ff47311e36b9f120e39229837d2 Mon Sep 17 00:00:00 2001 From: Meriem-BM Date: Thu, 22 Aug 2024 09:56:52 +0100 Subject: [PATCH 1/3] fix: reduce timer to 15 mins & update renew draft donation expiration date --- package-lock.json | 114 ++++++++++++++---- package.json | 3 +- src/resolvers/draftDonationResolver.ts | 14 ++- src/server/bootstrap.ts | 7 ++ .../cronJobs/checkQRTransactionJob.ts | 6 + src/services/ws/webSocketServer.ts | 51 ++++++++ 6 files changed, 164 insertions(+), 31 deletions(-) create mode 100644 src/services/ws/webSocketServer.ts diff --git a/package-lock.json b/package-lock.json index 54152c452..d615618d4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -75,7 +75,8 @@ "twitter-api-sdk": "^1.0.9", "type-graphql": "2.0.0-beta.1", "typedi": "0.8.0", - "typeorm": "0.3.20" + "typeorm": "0.3.20", + "ws": "^8.18.0" }, "devDependencies": { "@types/axios": "^0.14.0", @@ -3197,6 +3198,26 @@ "ws": "7.4.6" } }, + "node_modules/@ethersproject/providers/node_modules/ws": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/@ethersproject/random": { "version": "5.7.0", "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.7.0.tgz", @@ -12567,6 +12588,27 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "peer": true }, + "node_modules/hardhat/node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "peer": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/has-bigints": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", @@ -13831,6 +13873,26 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" }, + "node_modules/jayson/node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/jest-worker": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", @@ -17129,6 +17191,26 @@ "node": ">=8" } }, + "node_modules/puppeteer/node_modules/ws": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/qs": { "version": "6.11.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", @@ -17924,26 +18006,6 @@ "utf-8-validate": "^5.0.2" } }, - "node_modules/rpc-websockets/node_modules/ws": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.15.0.tgz", - "integrity": "sha512-H/Z3H55mrcrgjFwI+5jKavgXvwQLtfPCUEp6pi35VhoB0pfcHnSoyuTzkBEZpzq49g1193CUEwIvmsjcotenYw==", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -21217,15 +21279,15 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/ws": { - "version": "7.4.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", - "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "engines": { - "node": ">=8.3.0" + "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { diff --git a/package.json b/package.json index edcb23176..8366ab74b 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,8 @@ "twitter-api-sdk": "^1.0.9", "type-graphql": "2.0.0-beta.1", "typedi": "0.8.0", - "typeorm": "0.3.20" + "typeorm": "0.3.20", + "ws": "^8.18.0" }, "lint-staged": { "*.ts": [ diff --git a/src/resolvers/draftDonationResolver.ts b/src/resolvers/draftDonationResolver.ts index 08f313bc7..9ccc85f22 100644 --- a/src/resolvers/draftDonationResolver.ts +++ b/src/resolvers/draftDonationResolver.ts @@ -168,7 +168,7 @@ export class DraftDonationResolver { : fromAddress.toLowerCase(); const expiresAt = isQRDonation - ? new Date(Date.now() + 30 * 60 * 1000) + ? new Date(Date.now() + 15 * 60 * 1000) : undefined; const draftDonationId = await DraftDonation.createQueryBuilder( @@ -418,6 +418,12 @@ export class DraftDonationResolver { { status: DRAFT_DONATION_STATUS.FAILED }, ); + // Notify clients of new donation + (global as any).notifyDraftDonationFailed({ + draftDonationId: id, + expiresAt: draftDonation.expiresAt, + }); + return true; } catch (e) { logger.error( @@ -432,7 +438,7 @@ export class DraftDonationResolver { @Arg('id', _type => Int) id: number, ): Promise { try { - const expiresAt = new Date(Date.now() + 30 * 60 * 1000); + const expiresAt = new Date(Date.now() + 15 * 60 * 1000); const draftDonation = await DraftDonation.createQueryBuilder( 'draftDonation', ) @@ -440,8 +446,8 @@ export class DraftDonationResolver { .andWhere('draftDonation.isQRDonation = :isQRDonation', { isQRDonation: true, }) - .andWhere('draftDonation.status = :status', { - status: DRAFT_DONATION_STATUS.PENDING, + .andWhere('draftDonation.status != :status', { + status: DRAFT_DONATION_STATUS.MATCHED, }) .getOne(); diff --git a/src/server/bootstrap.ts b/src/server/bootstrap.ts index e74525e64..21a1ca581 100644 --- a/src/server/bootstrap.ts +++ b/src/server/bootstrap.ts @@ -68,6 +68,7 @@ import { runDraftDonationMatchWorkerJob } from '../services/cronJobs/draftDonati import { runCheckUserSuperTokenBalancesJob } from '../services/cronJobs/checkUserSuperTokenBalancesJob'; import { runCheckPendingRecurringDonationsCronJob } from '../services/cronJobs/syncRecurringDonationsWithNetwork'; import { runCheckQRTransactionJob } from '../services/cronJobs/checkQRTransactionJob'; +import { startWebSocketServer } from '../services/ws/webSocketServer'; Resource.validate = validate; @@ -291,6 +292,12 @@ export async function bootstrap() { const httpServer = http.createServer(app); + // Start WebSocket server + const { notifyDonationAdded, notifyDraftDonationFailed } = + startWebSocketServer(httpServer); + (global as any).notifyDonationAdded = notifyDonationAdded; + (global as any).notifyDraftDonationFailed = notifyDraftDonationFailed; + await new Promise((resolve, reject) => { httpServer .listen({ port: 4000 }, () => { diff --git a/src/services/cronJobs/checkQRTransactionJob.ts b/src/services/cronJobs/checkQRTransactionJob.ts index 5e6bfa541..6b465a4a0 100644 --- a/src/services/cronJobs/checkQRTransactionJob.ts +++ b/src/services/cronJobs/checkQRTransactionJob.ts @@ -181,6 +181,12 @@ export async function checkTransactions( donationId: returnedDonation.id, }); + // Notify clients of new donation + (global as any).notifyDonationAdded({ + donationId: returnedDonation.id, + draftDonationId: donation.id, + }); + return; } } diff --git a/src/services/ws/webSocketServer.ts b/src/services/ws/webSocketServer.ts new file mode 100644 index 000000000..7014488dd --- /dev/null +++ b/src/services/ws/webSocketServer.ts @@ -0,0 +1,51 @@ +import WebSocket from 'ws'; + +export function startWebSocketServer(server) { + const wss = new WebSocket.Server({ server }); + + // Handle WebSocket connections + wss.on('connection', ws => { + console.log('New client connected'); + + ws.on('message', message => { + console.log('Received:', message); + }); + + ws.on('close', () => { + console.log('Client disconnected'); + }); + }); + + // Broadcast a message to all connected clients + function broadcastMessage(message) { + wss.clients.forEach(client => { + if (client.readyState === WebSocket.OPEN) { + client.send(message); + } + }); + } + + // Exported function to be called from cron job + function notifyDonationAdded(donation) { + const message = JSON.stringify({ + type: 'new-donation', + data: donation, + }); + broadcastMessage(message); + } + + // Exported function to to be called when marking draft donation as failed + function notifyDraftDonationFailed(donation) { + const message = JSON.stringify({ + type: 'draft-donation-failed', + data: donation, + }); + broadcastMessage(message); + } + + // Export the notifyDonationAdded function so it can be used externally + return { + notifyDonationAdded, + notifyDraftDonationFailed, + }; +} From bf37bc778a4a344b569b806f7b32e8247c41adec Mon Sep 17 00:00:00 2001 From: Meriem-BM Date: Thu, 22 Aug 2024 10:23:02 +0100 Subject: [PATCH 2/3] fix: remove console logs --- src/services/ws/webSocketServer.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/services/ws/webSocketServer.ts b/src/services/ws/webSocketServer.ts index 7014488dd..cea49d97a 100644 --- a/src/services/ws/webSocketServer.ts +++ b/src/services/ws/webSocketServer.ts @@ -5,15 +5,9 @@ export function startWebSocketServer(server) { // Handle WebSocket connections wss.on('connection', ws => { - console.log('New client connected'); - ws.on('message', message => { console.log('Received:', message); }); - - ws.on('close', () => { - console.log('Client disconnected'); - }); }); // Broadcast a message to all connected clients From 97b0cec64a2e96f6880aba6ec9df47c4e0cdec02 Mon Sep 17 00:00:00 2001 From: Meriem-BM Date: Thu, 22 Aug 2024 10:42:30 +0100 Subject: [PATCH 3/3] fix: replace console log with logger --- src/services/ws/webSocketServer.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/services/ws/webSocketServer.ts b/src/services/ws/webSocketServer.ts index cea49d97a..16568a2b2 100644 --- a/src/services/ws/webSocketServer.ts +++ b/src/services/ws/webSocketServer.ts @@ -1,4 +1,5 @@ import WebSocket from 'ws'; +import { logger } from '../../utils/logger'; export function startWebSocketServer(server) { const wss = new WebSocket.Server({ server }); @@ -6,7 +7,7 @@ export function startWebSocketServer(server) { // Handle WebSocket connections wss.on('connection', ws => { ws.on('message', message => { - console.log('Received:', message); + logger.info(`Received message: ${message}`); }); });