Skip to content
Merged
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
2 changes: 2 additions & 0 deletions apps/triggers/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
"@lib/database": "workspace:*",
"@lib/dhm-adapter": "workspace:*",
"@lib/glofas-adapter": "workspace:*",
"@lib/gfh-adapter": "workspace:*",
"@nestjs/event-emitter": "3.0.0",
"@nestjs/mapped-types": "*",
"@rumsan/connect": "^1.0.6",
"@rumsan/sdk": "^0.0.47",
Expand Down
32 changes: 32 additions & 0 deletions apps/triggers/src/sources-data/schedule-sources-data.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
RainfallStationData,
} from '@lib/dhm-adapter';
import { GlofasAdapter, GlofasServices } from '@lib/glofas-adapter';
import { GfhAdapter, GfhService } from '@lib/gfh-adapter';
import {
Indicator,
isErr,
Expand All @@ -34,15 +35,18 @@ export class ScheduleSourcesDataService
private dhmWaterMonitored: HealthMonitoredAdapter<undefined>;
private dhmRainfallMonitored: HealthMonitoredAdapter<undefined>;
private glofasMonitored: HealthMonitoredAdapter<null>;
private gfhMonitored: HealthMonitoredAdapter<undefined>;

constructor(
@Inject(HealthCacheService)
private readonly healthCacheService: HealthCacheService,
private readonly dhmWaterLevelAdapter: DhmWaterLevelAdapter,
private readonly dhmRainfallLevelAdapter: DhmRainfallAdapter,
private readonly glofasAdapter: GlofasAdapter,
private readonly gfhAdapter: GfhAdapter,
private readonly dhmService: DhmService,
private readonly glofasServices: GlofasServices,
private readonly gfhService: GfhService,
private readonly healthService: HealthMonitoringService,
) {
this.dhmWaterMonitored = this.wrapWithHealthMonitoring(
Expand All @@ -52,6 +56,7 @@ export class ScheduleSourcesDataService
this.dhmRainfallLevelAdapter,
);
this.glofasMonitored = this.wrapWithHealthMonitoring(this.glofasAdapter);
this.gfhMonitored = this.wrapWithHealthMonitoring(this.gfhAdapter);
}

onModuleInit() {
Expand All @@ -60,13 +65,15 @@ export class ScheduleSourcesDataService
this.dhmWaterLevelAdapter,
this.dhmRainfallLevelAdapter,
this.glofasAdapter,
this.gfhAdapter,
].forEach((adapter) => adapter.setHealthService(this.healthService));
}

onApplicationBootstrap() {
this.syncRiverWaterData();
this.syncRainfallData();
this.synchronizeGlofas();
this.syncGfhData();
}

private wrapWithHealthMonitoring<T>(
Expand Down Expand Up @@ -255,4 +262,29 @@ export class ScheduleSourcesDataService
);
});
}

//run every 24 hours
@Cron('0 0 * * *')
async syncGfhData() {
const gfhResult = await this.gfhMonitored.execute();

if (isErr<Indicator[]>(gfhResult)) {
this.logger.warn(gfhResult.details);
if (gfhResult.details instanceof AxiosError) {
const errorMessage = `HTTP Error: ${gfhResult.details.response?.status} ${gfhResult.details.response?.statusText} - Data: ${JSON.stringify(gfhResult.details.response?.data)} - Config: ${JSON.stringify(gfhResult.details.response?.config)}`;
this.logger.warn(errorMessage);
} else {
this.logger.warn(gfhResult.details);
}
return;
}

gfhResult.data.forEach(async (indicator) => {
await this.gfhService.saveDataInGfh(
SourceType.WATER_LEVEL,
(indicator.location as any).basinId,
indicator,
);
});
}
}
4 changes: 3 additions & 1 deletion apps/triggers/src/sources-data/sources-data.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ import { GlofasService } from './glofas.service';
import { ConfigService } from '@nestjs/config';
import { BullModule } from '@nestjs/bull';
import { BQUEUE } from 'src/constant';
import { GfhService } from './gfh.service';
import Redis from 'ioredis';
import { DataSourceEventsListener } from './data-source-events.listener';
import { HealthMonitoringService, HealthCacheService } from '@lib/core';
import { GlofasModule, GlofasServices } from '@lib/glofas-adapter';
import { GfhModule, GfhService } from '@lib/gfh-adapter';

@Module({
imports: [
Expand All @@ -23,6 +23,7 @@ import { GlofasModule, GlofasServices } from '@lib/glofas-adapter';
}),
DhmModule.forRoot(),
GlofasModule.forRoot(),
GfhModule.forRoot(),
],
controllers: [SourcesDataController],
providers: [
Expand All @@ -37,6 +38,7 @@ import { GlofasModule, GlofasServices } from '@lib/glofas-adapter';
HealthMonitoringService,
DhmServiceLib,
GlofasServices,
GfhService,
{
provide: 'REDIS_CLIENT',
useFactory: (configService: ConfigService) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/types/indicator.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export interface Indicator<T = any> {
kind: 'OBSERVATION' | 'FORECAST';
indicator: IndicatorType;
value: number;
info?: T[];
info?: T | T[];
units: string;
issuedAt: string;
location: LocationType;
Expand Down
20 changes: 11 additions & 9 deletions packages/core/src/types/result.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@ export type Result<T> =
executionContext?: ExecutionContext;
};

export function Ok<T>(
data: T,
executionContext?: ExecutionContext,
): Result<T> {
export function Ok<T>(data: T, executionContext?: ExecutionContext): Result<T> {
return { success: true, data, executionContext };
}

Expand All @@ -24,9 +21,7 @@ export function Err<T>(
return { success: false, error, details, executionContext };
}

export function isErr<T>(
result: Result<T>,
): result is {
export function isErr<T>(result: Result<T>): result is {
success: false;
error: string;
details?: unknown;
Expand Down Expand Up @@ -60,13 +55,20 @@ export function chain<T, U>(

export async function chainAsync<T, U>(
result: Result<T> | Promise<Result<T>>,
fn: (data: T) => Promise<Result<U>> | Result<U>,
fn: (
data: T,
executionContext?: ExecutionContext,
) => Promise<Result<U>> | Result<U>,
): Promise<Result<U>> {
const resolvedResult = await result;
if (!resolvedResult.success) {
return resolvedResult;
}
const nextResult = await fn(resolvedResult.data);

const nextResult = await fn(
resolvedResult.data,
resolvedResult.executionContext,
);
if (nextResult.success && resolvedResult.executionContext) {
return {
...nextResult,
Expand Down
69 changes: 69 additions & 0 deletions packages/database/prisma/seeds/seed-gfh-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { PrismaClient } from '../../generated/prisma';
import { GfhApiKeyType } from '../../src/nestjs';

const prisma = new PrismaClient();
const config: GfhApiKeyType = {
name: 'GFHAPIKEY',
value: {
API_KEY: 'AIzaSyC_5LUv3k3A',
},
isPrivate: false,
};

const main = async () => {
console.log('#'.repeat(30));
console.log('Seeding GFH API KEY');
console.log('#'.repeat(30));

try {
const gfhApiKey = await prisma.setting.findUnique({
where: { name: config.name },
});

if (gfhApiKey) {
console.log('GFH API KEY already exists');
await prisma.setting.delete({
where: { name: config.name },
});
console.log('Old GFH API KEY deleted');
}

await prisma.setting.create({
data: {
name: config.name,
value: config.value,
isPrivate: config.isPrivate,
dataType: 'OBJECT',
requiredFields: [],
isReadOnly: false,
},
});

console.log('GFH API KEY seeded successfully');
} catch (error: any) {
console.error('Error seeding GFH API KEY:', error);
await prisma.setting.create({
data: {
name: config.name,
value: config.value,
isPrivate: config.isPrivate,
dataType: 'OBJECT',
requiredFields: [],
isReadOnly: false,
},
});
}
};

main()
.then(async () => {})
.catch(async (error) => {
console.log(error);
})
.finally(async () => {
console.log('#'.repeat(30));
console.log('Seeding completed');
console.log('#'.repeat(30));
console.log('\n');
await prisma.$disconnect();
});
2 changes: 1 addition & 1 deletion packages/database/prisma/seeds/seed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ const config: DataSourceType = {
{
STATION_NAME: 'Sarda River Basin',
RIVER_NAME: 'doda',
STATION_ID: 'G10165',
STATION_ID: 'G10166',
POINT_ID: 'SI002576',
LISFLOOD_DRAINAGE_AREA: 432,
'LISFLOOD_X_(DEG)': 80.422917,
Expand Down
7 changes: 7 additions & 0 deletions packages/database/src/nestjs/types/gfh-apiKey.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export interface GfhApiKeyType {
name: string;
value: {
API_KEY: string;
};
isPrivate: boolean;
}
1 change: 1 addition & 0 deletions packages/database/src/nestjs/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './datasource.type';
export * from './datasource-config.type';
export * from './gfh-apiKey.type';
5 changes: 5 additions & 0 deletions packages/gfh-adapter/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/** @type {import("eslint").Linter.Config[]} */

import { nestjs } from "@workspace/eslint-config/nest-js";

export default [...nestjs];
1 change: 1 addition & 0 deletions packages/gfh-adapter/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./src";
27 changes: 27 additions & 0 deletions packages/gfh-adapter/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"name": "@lib/gfh-adapter",
"version": "1.0.0",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"scripts": {
"build": "tsc",
"test": "jest"
},
"dependencies": {
"@lib/core": "workspace:*",
"@lib/database": "workspace:*",
"axios": "^1.12.2",
"@nestjs/axios": "^4.0.1",
"cheerio": "^1.1.2"
},
"devDependencies": {
"@types/jest": "^27.0.2",
"@workspace/eslint-config": "workspace:*",
"@workspace/typescript-config": "workspace:*",
"jest": "^27.0.6",
"typescript": "5.9.2"
},
"exports": {
".": "./dist/index.js"
}
}
Loading