Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 7 additions & 31 deletions src/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Module, NestModule, MiddlewareConsumer, RequestMethod } from '@nestjs/common';
import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { APP_FILTER } from '@nestjs/core';
import { AppController } from './app.controller';
import { AppService } from './app.service';
Expand All @@ -12,48 +12,24 @@ import { TokensModule } from './tokens/tokens.module';
import { AllExceptionsFilter } from './common/filters/all-exceptions.filter';
import { OgModule } from './og/og.module';
import { TradeModule } from './trade/trade.module';
import { WsModule } from './ws/ws.module';
import { ConfigModule } from '@nestjs/config';
import { MaintenanceMiddleware } from './common/middleware/maintenance.middleware';
import { RequestIdMiddleware } from './common/middleware/request-id.middleware';
import { RedisModule } from './common/redis/redis.module';

/**
* Root module of the application.
* Orchestrates the integration of all feature modules and global middleware.
*/
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true }),
RedisModule,
PrismaModule,
HealthModule,
RiskModule,
AuthModule,
AnalyticsModule,
SwapModule,
TokensModule,
OgModule,
TradeModule
RedisModule, PrismaModule, HealthModule, RiskModule,
AuthModule, AnalyticsModule, SwapModule, TokensModule,
OgModule, TradeModule, WsModule,
],
controllers: [AppController],
providers: [
AppService,
{
provide: APP_FILTER,
useClass: AllExceptionsFilter,
},
],
providers: [AppService, { provide: APP_FILTER, useClass: AllExceptionsFilter }],
})
export class AppModule implements NestModule {
/**
* Configures global middleware for the entire application.
* Currently applies RequestIdMiddleware and MaintenanceMiddleware to all routes.
*
* @param consumer - The middleware consumer to register middleware on.
*/
configure(consumer: MiddlewareConsumer) {
consumer
.apply(RequestIdMiddleware, MaintenanceMiddleware)
.forRoutes('*');
consumer.apply(RequestIdMiddleware, MaintenanceMiddleware).forRoutes('*');
}
}
33 changes: 15 additions & 18 deletions src/jobs/indexer.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,24 @@
import * as cron from 'node-cron';
import * as cron from 'node-cron';
import { RedisService } from '../common/redis/redis.service';

export class IndexerJob {
constructor() {
this.initializeJobs();
}
private redisService: RedisService;
constructor(redisService?: RedisService) { this.redisService = redisService; this.initializeJobs(); }

private initializeJobs() {
// Schedule a job to run every 5 minutes
cron.schedule('*/5 * * * *', () => {
console.log('Syncing Blockchain Data...');
this.syncBlockchainData();
});

console.log('Background indexer jobs initialized');
cron.schedule('*/1 * * * *', () => this.syncBlockchainData());
}

private syncBlockchainData() {
// Simulate blockchain data syncing
console.log(`[${new Date().toISOString()}] Starting blockchain data sync...`);

// Simulate some work
setTimeout(() => {
console.log(`[${new Date().toISOString()}] Blockchain data sync completed`);
}, 2000);
const events = [
{ event: 'InvoiceStatusChanged', data: { invoiceId: 'inv_001', status: 'FUNDED' } },
{ event: 'LiquidityPoolUpdated', data: { poolId: 'pool_001', liquidity: '150000' } },
{ event: 'YieldAccrued', data: { userId: 'user_001', yield: '0.05' } },
];
for (const ev of events) {
if (this.redisService) {
this.redisService.redisPublisher.publish('ws:events', JSON.stringify({ ...ev, room: 'room:global', timestamp: Date.now() }));
}
}
}
}
6 changes: 6 additions & 0 deletions src/ws/dto/ws-event.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export class WsEventPayload {
event: 'InvoiceStatusChanged' | 'LiquidityPoolUpdated' | 'YieldAccrued';
room: string;
data: Record<string, any>;
timestamp: number;
}
44 changes: 44 additions & 0 deletions src/ws/ws.gateway.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import {
WebSocketGateway, WebSocketServer, OnModuleInit,
SubscribeMessage, ConnectedSocket, MessageBody,
} from '@nestjs/websockets';
import { Server, Socket } from 'socket.io';
import { Logger } from '@nestjs/common';
import { RedisService } from '../common/redis/redis.service';

interface AuthenticatedSocket extends Socket { userId?: string; }

@WebSocketGateway({ cors: { origin: '*' }, namespace: '/ws' })
export class AppGateway implements OnModuleInit {
@WebSocketServer() server: Server;
private readonly logger = new Logger(AppGateway.name);

constructor(private readonly redisService: RedisService) {}

onModuleInit() {
this.logger.log('WebSocket Gateway initialized');
this.redisService.subscribe('ws:events', (message) => {
try {
const payload = JSON.parse(message);
this.server.to(payload.room).emit(payload.event, payload.data);
this.server.to('room:global').emit(payload.event, payload.data);
} catch (err) { this.logger.error('Failed to broadcast', err); }
});
}

handleConnection(client: AuthenticatedSocket) {
const token = client.handshake.auth?.token || client.handshake.query?.token;
if (!token) { client.disconnect(); return; }
try {
const payload = JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString());
client.userId = payload.sub || payload.userId;
if (client.userId) { client.join('room:user_' + client.userId); }
client.join('room:global');
} catch { client.disconnect(); }
}

@SubscribeMessage('subscribe')
handleSubscribe(@ConnectedSocket() client: AuthenticatedSocket, @MessageBody() room: string) {
if (client.userId && room === 'room:user_' + client.userId) client.join(room);
}
}
5 changes: 5 additions & 0 deletions src/ws/ws.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { Module } from '@nestjs/common';
import { AppGateway } from './ws.gateway';

@Module({ providers: [AppGateway], exports: [AppGateway] })
export class WsModule {}
Loading