Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
805494f
MEX-748 Implement Claim Rewards notifications in xPortal
EmanuelMiron Mar 28, 2025
bc73efe
MEX-748 Fix issue on failed req
EmanuelMiron Mar 28, 2025
e33d070
MEX-748 Make the module more generic
EmanuelMiron Apr 11, 2025
c726d97
MEX-748 Added push_notifications_aip_url in env.example
EmanuelMiron Apr 11, 2025
5701b74
MEX-748 Moved options to config from env
EmanuelMiron Apr 11, 2025
9daa642
MEX-748 Use ApiService instead of axios directly
EmanuelMiron Apr 11, 2025
c9f750a
MEX-748 Added Fixes after review
EmanuelMiron Apr 16, 2025
7454f00
MEX-748 Fix feesCollector startEpoch logic
EmanuelMiron Apr 16, 2025
49f1ca4
MEX-748 Fix Cron interval for feesCollector Rewards Notifications
EmanuelMiron Apr 17, 2025
ff38557
MEX-748 Added Logs to PushNotification Service
EmanuelMiron Apr 30, 2025
7084897
MEX-748 Added try catch block for the sendPushNotifications
EmanuelMiron Apr 30, 2025
c534c44
MEX-748 Implement RedLock for Push Notifications as a decorator
EmanuelMiron Apr 30, 2025
ff5aee7
Merge branch 'development' into MEX-748-push-notifications
EmanuelMiron Apr 30, 2025
3f19dad
MEX-748 Added Logs back
EmanuelMiron May 6, 2025
5f3c8f1
MEX-748 Added error logging on sendPushNotifications
EmanuelMiron May 6, 2025
6ea6bdd
MEX-748 Moved withLockAndRetry to generic utils
EmanuelMiron May 6, 2025
171b388
MEX-748: Removed redundant try/catch blocks
EmanuelMiron May 6, 2025
47aa1ca
MEX-748 Moved LockAndRetry decorator
EmanuelMiron May 6, 2025
934afbc
MEX-748 Other small fixes
EmanuelMiron May 6, 2025
945d960
MEX-748 Place failedNotifications on the common redis instance
EmanuelMiron May 6, 2025
dc8e57b
MEX-748 Fix srem issue
EmanuelMiron May 6, 2025
9a2131e
MEX-748 Integrate devnet energy snapshot index
EmanuelMiron May 14, 2025
e8d35ca
Merge branch 'development' into MEX-748-push-notifications
EmanuelMiron May 14, 2025
afcd632
MEX-748 Dynamic Cron based on environment
EmanuelMiron May 14, 2025
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
8 changes: 8 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ ENABLE_CACHE_WARMER=true
ENABLE_EVENTS_NOTIFIER=false
ENABLE_TRACER=false
ENABLE_COMPLEXITY=true
ENABLE_PUSH_NOTIFICATIONS=true

#Log filename to use for file logging. Optional
LOG_FILE=
Expand Down Expand Up @@ -74,3 +75,10 @@ OPEN_EXCHANGE_RATES_URL=https://openexchangerates.org/api
# AWS Timestream
AWS_TIMESTREAM_READ=false
AWS_TIMESTREAM_WRITE=false

# Notification Service Configuration
PUSH_NOTIFICATIONS_API_URL=
PUSH_NOTIFICATIONS_API_KEY=
PUSH_NOTIFICATIONS_BATCH_SIZE=100
PUSH_NOTIFICATIONS_MAX_RETRIES=3
PUSH_NOTIFICATIONS_CHAIN_ID=508 # 508 for devnet
54 changes: 54 additions & 0 deletions src/helpers/api.config.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,50 @@ export class ApiConfigService {
return mongoDBPassword;
}

getNotificationsApiUrl(): string {
const apiUrl = this.configService.get<string>('PUSH_NOTIFICATIONS_API_URL');
if (!apiUrl) {
throw new Error('No push notifications API url present');
}
return apiUrl;
}

getNotificationsApiKey(): string {
const apiKey = this.configService.get<string>('PUSH_NOTIFICATIONS_API_KEY');
if (!apiKey) {
throw new Error('No push notifications API key present');
}
return apiKey;
}

getNotificationsBatchSize(): number {
const batchSize = this.configService.get<number>(
'PUSH_NOTIFICATIONS_BATCH_SIZE',
);
if (!batchSize) {
throw new Error('No push notifications batch size present');
}
return batchSize;
}

getNotificationsMaxRetries(): number {
const maxRetries = this.configService.get<number>(
'PUSH_NOTIFICATIONS_MAX_RETRIES',
);
if (!maxRetries) {
throw new Error('No push notifications max retries present');
}
return maxRetries;
}

getChainId(): number {
const chainId = this.configService.get<number>('PUSH_NOTIFICATIONS_CHAIN_ID');
if (!chainId) {
throw new Error('No push notifications chainId present');
}
return chainId;
}

getJwtSecret(): string {
const secret = this.configService.get<string>('JWT_SECRET');
if (!secret) {
Expand Down Expand Up @@ -352,4 +396,14 @@ export class ApiConfigService {
getRateLimiterSecret(): string | undefined {
return this.configService.get<string>('RATE_LIMITER_SECRET');
}

isNotificationsModuleActive(): boolean {
const notificationsModuleActive = this.configService.get<string>(
'ENABLE_PUSH_NOTIFICATIONS',
);
if (!notificationsModuleActive) {
return false;
}
return notificationsModuleActive === 'true';
}
}
6 changes: 6 additions & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import cookieParser from 'cookie-parser';
import { WINSTON_MODULE_NEST_PROVIDER } from 'nest-winston';
import { LoggerService } from '@nestjs/common';
import { NestExpressApplication } from '@nestjs/platform-express';
import { PushNotificationsModule } from './modules/push-notifications/push.notifications.module';

async function bootstrap() {
BigNumber.config({ EXPONENTIAL_AT: [-30, 30] });
Expand Down Expand Up @@ -90,5 +91,10 @@ async function bootstrap() {
await rabbitMqService.getFilterAddresses();
await eventsNotifierApp.listen(5673, '0.0.0.0');
}

if (apiConfigService.isNotificationsModuleActive()) {
const pushNotificationsApp = await NestFactory.create(PushNotificationsModule);
await pushNotificationsApp.listen(5674, '0.0.0.0');
}
}
bootstrap();
47 changes: 47 additions & 0 deletions src/modules/push-notifications/models/push.notifications.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
export interface EnergyDetailsType {
lastUpdateEpoch: number;
amount: string;
totalLockedTokens: string;
}

export interface AccountType {
address: string;
nonce: number;
balance: string;
balanceNum: number;
totalBalanceWithStake: string;
totalBalanceWithStakeNum: number;
timestamp: number;
shardID: number;
totalStake: string;
energy: string;
energyNum: number;
energyDetails: EnergyDetailsType;
totalUnDelegate: string;
}

export interface ContractKeysRaw {
data: {
blockInfo: {
hash: string;
nonce: number;
rootHash: string;
};
pairs: Record<string, string>;
};
code: string;
}

export interface UserEnergyAddress {
address: string;
notificationSent: boolean;
}

export interface NotificationPayload {
addresses: string[];
chainId: number;
title: string;
body: string;
route: string;
iconUrl: string;
}
31 changes: 31 additions & 0 deletions src/modules/push-notifications/push.notifications.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Module } from '@nestjs/common';
import { ScheduleModule } from '@nestjs/schedule';
import { PushNotificationsService } from './push.notifications.service';
import { PushNotificationsSetterService } from './services/push.notifications.setter.service';
import { CommonAppModule } from '../../common.app.module';
import { MXCommunicationModule } from '../../services/multiversx-communication/mx.communication.module';
import { ElasticSearchModule } from '../../services/elastic-search/elastic.search.module';
import { ContextModule } from '../../services/context/context.module';
import { CacheModule } from '../../services/caching/cache.module';
import { EnergyModule } from '../energy/energy.module';

@Module({
imports: [
CommonAppModule,
ScheduleModule.forRoot(),
MXCommunicationModule,
ElasticSearchModule,
ContextModule,
CacheModule,
EnergyModule,
],
providers: [
PushNotificationsService,
PushNotificationsSetterService,
],
exports: [
PushNotificationsService,
PushNotificationsSetterService,
],
})
export class PushNotificationsModule {}
Loading
Loading