diff --git a/backend/package.json b/backend/package.json index b198d54..cd5d025 100644 --- a/backend/package.json +++ b/backend/package.json @@ -26,6 +26,7 @@ "@fastify/multipart": "^7.2.0", "@fastify/reply-from": "^8.3.0", "@fastify/static": "^6.5.0", + "@nestjs/bull": "^0.6.1", "@nestjs/common": "^9.0.11", "@nestjs/config": "^2.2.0", "@nestjs/core": "^9.0.11", @@ -40,6 +41,7 @@ "@nestjs/websockets": "^9.0.11", "bcrypt": "^5.0.1", "bmp-img": "^1.2.1", + "bull": "^4.9.0", "cors": "^2.8.5", "file-type": "^18.0.0", "is-docker": "^3.0.0", @@ -69,6 +71,7 @@ "@nestjs/schematics": "^9.0.3", "@nestjs/testing": "^9.0.11", "@types/bcrypt": "^5.0.0", + "@types/bull": "^3.15.9", "@types/cors": "^2.8.12", "@types/multer": "^1.4.7", "@types/node": "^18.7.18", diff --git a/backend/src/app.module.ts b/backend/src/app.module.ts index 2db11b0..ef4cfb9 100644 --- a/backend/src/app.module.ts +++ b/backend/src/app.module.ts @@ -1,10 +1,13 @@ +import { BullModule } from '@nestjs/bull'; import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common'; import { ScheduleModule } from '@nestjs/schedule'; import { ServeStaticModule } from '@nestjs/serve-static'; import cors from 'cors'; import { IncomingMessage, ServerResponse } from 'http'; +import { BullConfigService } from './config/early/bull.config.service'; import { EarlyConfigModule } from './config/early/early-config.module'; import { ServeStaticConfigService } from './config/early/serve-static.config.service'; +import { ConsumersModule } from './consumers/consumers.module'; import { DatabaseModule } from './database/database.module'; import { PicsurLayersModule } from './layers/PicsurLayers.module'; import { PicsurLoggerModule } from './logger/logger.module'; @@ -45,12 +48,18 @@ const imageCorsOverride = ( imports: [EarlyConfigModule], }), ScheduleModule.forRoot(), + BullModule.forRootAsync({ + useExisting: BullConfigService, + imports: [EarlyConfigModule], + }), + DatabaseModule, AuthManagerModule, UsageManagerModule, DemoManagerModule, PicsurRoutesModule, PicsurLayersModule, + ConsumersModule, ], }) export class AppModule implements NestModule { diff --git a/backend/src/collections/ingress-file-db/ingress-file-db.module.ts b/backend/src/collections/ingress-file-db/ingress-file-db.module.ts new file mode 100644 index 0000000..6131318 --- /dev/null +++ b/backend/src/collections/ingress-file-db/ingress-file-db.module.ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { EIngressFileBackend } from '../../database/entities/ingress-file.entity'; +import { IngressFileDbService } from './ingress-file-db.service'; + +@Module({ + imports: [TypeOrmModule.forFeature([EIngressFileBackend])], + providers: [IngressFileDbService], + exports: [IngressFileDbService], +}) +export class IngressFileDbModule {} diff --git a/backend/src/collections/ingress-file-db/ingress-file-db.service.ts b/backend/src/collections/ingress-file-db/ingress-file-db.service.ts new file mode 100644 index 0000000..bb4b24d --- /dev/null +++ b/backend/src/collections/ingress-file-db/ingress-file-db.service.ts @@ -0,0 +1,14 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; +import { EIngressFileBackend } from '../../database/entities/ingress-file.entity'; + +@Injectable() +export class IngressFileDbService { + private readonly logger = new Logger(IngressFileDbService.name); + + constructor( + @InjectRepository(EIngressFileBackend) + private readonly ingressFileRepo: Repository, + ) {} +} diff --git a/backend/src/config/early/bull.config.service.ts b/backend/src/config/early/bull.config.service.ts new file mode 100644 index 0000000..079c7b5 --- /dev/null +++ b/backend/src/config/early/bull.config.service.ts @@ -0,0 +1,25 @@ +import { + BullRootModuleOptions, + SharedBullConfigurationFactory +} from '@nestjs/bull'; +import { Injectable } from '@nestjs/common'; +import { RedisConfigService } from './redis.config.service'; + +@Injectable() +export class BullConfigService implements SharedBullConfigurationFactory { + constructor(private readonly redisConfig: RedisConfigService) {} + + async createSharedConfiguration(): Promise { + const options: BullRootModuleOptions = { + url: this.redisConfig.getRedisUrl(), + redis: { + lazyConnect: false, + }, + defaultJobOptions: { + attempts: 3, + removeOnFail: true, + }, + }; + return options; + } +} diff --git a/backend/src/config/early/early-config.module.ts b/backend/src/config/early/early-config.module.ts index 7e40d3f..a7fb961 100644 --- a/backend/src/config/early/early-config.module.ts +++ b/backend/src/config/early/early-config.module.ts @@ -1,9 +1,11 @@ import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import { AuthConfigService } from './auth.config.service'; +import { BullConfigService } from './bull.config.service'; import { EarlyJwtConfigService } from './early-jwt.config.service'; import { HostConfigService } from './host.config.service'; import { MultipartConfigService } from './multipart.config.service'; +import { RedisConfigService } from './redis.config.service'; import { ServeStaticConfigService } from './serve-static.config.service'; import { TypeOrmConfigService } from './type-orm.config.service'; @@ -21,6 +23,8 @@ import { TypeOrmConfigService } from './type-orm.config.service'; HostConfigService, AuthConfigService, MultipartConfigService, + RedisConfigService, + BullConfigService, ], exports: [ ConfigModule, @@ -30,6 +34,8 @@ import { TypeOrmConfigService } from './type-orm.config.service'; HostConfigService, AuthConfigService, MultipartConfigService, + RedisConfigService, + BullConfigService, ], }) export class EarlyConfigModule {} diff --git a/backend/src/config/early/redis.config.service.ts b/backend/src/config/early/redis.config.service.ts new file mode 100644 index 0000000..e0e07e0 --- /dev/null +++ b/backend/src/config/early/redis.config.service.ts @@ -0,0 +1,20 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { ParseString } from 'picsur-shared/dist/util/parse-simple'; +import { EnvPrefix } from '../config.static'; + +@Injectable() +export class RedisConfigService { + private readonly logger = new Logger(RedisConfigService.name); + + constructor(private readonly configService: ConfigService) { + this.logger.log('Redis URL: ' + this.getRedisUrl()); + } + + public getRedisUrl(): string { + return ParseString( + this.configService.get(`${EnvPrefix}REDIS_URL`), + 'redis://localhost:6379', + ); + } +} diff --git a/backend/src/config/early/type-orm.config.service.ts b/backend/src/config/early/type-orm.config.service.ts index da8e9b2..e411adb 100644 --- a/backend/src/config/early/type-orm.config.service.ts +++ b/backend/src/config/early/type-orm.config.service.ts @@ -6,6 +6,7 @@ import { EntityList } from '../../database/entities'; import { MigrationList } from '../../database/migrations'; import { DefaultName, EnvPrefix } from '../config.static'; import { HostConfigService } from './host.config.service'; +import { RedisConfigService } from './redis.config.service'; @Injectable() export class TypeOrmConfigService implements TypeOrmOptionsFactory { @@ -14,6 +15,7 @@ export class TypeOrmConfigService implements TypeOrmOptionsFactory { constructor( private readonly configService: ConfigService, private readonly hostService: HostConfigService, + private readonly redisConfig: RedisConfigService, ) { const varOptions = this.getTypeOrmServerOptions(); @@ -66,6 +68,12 @@ export class TypeOrmConfigService implements TypeOrmOptionsFactory { entitiesDir: 'src/database/entities', }, + cache: { + duration: 60000, + type: 'ioredis', + options: this.redisConfig.getRedisUrl(), + }, + ...varOptions, } as TypeOrmModuleOptions; } diff --git a/backend/src/consumers/consumers.module.ts b/backend/src/consumers/consumers.module.ts new file mode 100644 index 0000000..0a98916 --- /dev/null +++ b/backend/src/consumers/consumers.module.ts @@ -0,0 +1,14 @@ +import { BullModule } from '@nestjs/bull'; +import { Module } from '@nestjs/common'; +import { IngestConsumer } from './ingest.consumer'; + +@Module({ + imports: [ + BullModule.registerQueue({ + name: 'image-ingest', + }), + ], + providers: [IngestConsumer], + exports: [BullModule], +}) +export class ConsumersModule {} diff --git a/backend/src/consumers/ingest.consumer.ts b/backend/src/consumers/ingest.consumer.ts new file mode 100644 index 0000000..0e984bf --- /dev/null +++ b/backend/src/consumers/ingest.consumer.ts @@ -0,0 +1,18 @@ +import { OnQueueError, Process, Processor } from '@nestjs/bull'; +import { Logger } from '@nestjs/common'; +import type { Job } from 'bull'; + +@Processor('image-ingest') +export class IngestConsumer { + private readonly logger = new Logger(IngestConsumer.name); + + @Process() + async processJob(job: Job) { + console.log('processJob', job); + } + + @OnQueueError() + async handleError(error: any) { + this.logger.error(error); + } +} diff --git a/backend/src/database/entities/index.ts b/backend/src/database/entities/index.ts index 9515ac2..c34d063 100644 --- a/backend/src/database/entities/index.ts +++ b/backend/src/database/entities/index.ts @@ -2,6 +2,7 @@ import { EApiKeyBackend } from './apikey.entity'; import { EImageDerivativeBackend } from './images/image-derivative.entity'; import { EImageFileBackend } from './images/image-file.entity'; import { EImageBackend } from './images/image.entity'; +import { EIngressFileBackend } from './ingress-file.entity'; import { ESysPreferenceBackend } from './system/sys-preference.entity'; import { ESystemStateBackend } from './system/system-state.entity'; import { EUsrPreferenceBackend } from './system/usr-preference.entity'; @@ -18,4 +19,5 @@ export const EntityList = [ EUsrPreferenceBackend, EApiKeyBackend, ESystemStateBackend, + EIngressFileBackend, ]; diff --git a/backend/src/database/entities/ingress-file.entity.ts b/backend/src/database/entities/ingress-file.entity.ts new file mode 100644 index 0000000..3e6ef88 --- /dev/null +++ b/backend/src/database/entities/ingress-file.entity.ts @@ -0,0 +1,16 @@ +import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm'; + +@Entity() +export class EIngressFileBackend { + @PrimaryGeneratedColumn('uuid') + id: string; + + @Column({ nullable: false }) + filename: string; + + @Column({ type: 'bytea', nullable: false }) + data: Buffer; + + @Column({ nullable: false, default: false }) + in_use: boolean; +} diff --git a/backend/src/routes/api/experiment/experiment.controller.ts b/backend/src/routes/api/experiment/experiment.controller.ts index e7d8e2d..6c4cb6b 100644 --- a/backend/src/routes/api/experiment/experiment.controller.ts +++ b/backend/src/routes/api/experiment/experiment.controller.ts @@ -1,20 +1,23 @@ -import { WebSocketGateway } from '@nestjs/websockets'; +import { InjectQueue } from '@nestjs/bull'; +import { Controller, Get } from '@nestjs/common'; +import type { Queue } from 'bull'; +import { NoPermissions } from '../../../decorators/permissions.decorator'; +import { ReturnsAnything } from '../../../decorators/returns.decorator'; - -@WebSocketGateway({ - namespace: 'experiment', -}) +@Controller('api/experiment') +@NoPermissions() export class ExperimentController { - constructor() { - console.log('ExperimentController created'); - } + constructor( - // @SubscribeMessage('test') - // async testRoute(@MessageBody() data: any): Promise { - // console.log('testRoute', data); - // return Promise.resolve({ - // event: 'test', - // data: Buffer.from('Hello'), - // }) - // } + @InjectQueue('image-ingest') private readonly ingestQueue: Queue, + ) {} + + @Get() + @ReturnsAnything() + async testRoute(): Promise { + this.ingestQueue.add({ foo: Buffer.from("aaaaaheleool") }); + + + return 'ok'; + } } diff --git a/backend/src/routes/api/experiment/experiment.module.ts b/backend/src/routes/api/experiment/experiment.module.ts index 727993b..e6fc381 100644 --- a/backend/src/routes/api/experiment/experiment.module.ts +++ b/backend/src/routes/api/experiment/experiment.module.ts @@ -1,11 +1,12 @@ import { Module } from '@nestjs/common'; +import { ConsumersModule } from '../../../consumers/consumers.module'; import { ExperimentController } from './experiment.controller'; // This is comletely useless module, but is used for testing // TODO: remove when out of beta @Module({ - imports: [], - providers: [ExperimentController] + imports: [ConsumersModule], + controllers: [ExperimentController] }) export class ExperimentModule {} diff --git a/support/dev.docker-compose.yml b/support/dev.docker-compose.yml index 50062c9..bb32153 100644 --- a/support/dev.docker-compose.yml +++ b/support/dev.docker-compose.yml @@ -11,6 +11,14 @@ services: restart: unless-stopped volumes: - db-data:/var/lib/postgresql/data + devredis: + image: redis:7-alpine + ports: + - '6379:6379' + restart: unless-stopped + volumes: + - redis-data:/data volumes: db-data: + redis-data: diff --git a/yarn.lock b/yarn.lock index d2f34cd..06a5bd0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2382,6 +2382,74 @@ __metadata: languageName: node linkType: hard +"@msgpackr-extract/msgpackr-extract-darwin-arm64@npm:2.1.2": + version: 2.1.2 + resolution: "@msgpackr-extract/msgpackr-extract-darwin-arm64@npm:2.1.2" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@msgpackr-extract/msgpackr-extract-darwin-x64@npm:2.1.2": + version: 2.1.2 + resolution: "@msgpackr-extract/msgpackr-extract-darwin-x64@npm:2.1.2" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@msgpackr-extract/msgpackr-extract-linux-arm64@npm:2.1.2": + version: 2.1.2 + resolution: "@msgpackr-extract/msgpackr-extract-linux-arm64@npm:2.1.2" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + +"@msgpackr-extract/msgpackr-extract-linux-arm@npm:2.1.2": + version: 2.1.2 + resolution: "@msgpackr-extract/msgpackr-extract-linux-arm@npm:2.1.2" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@msgpackr-extract/msgpackr-extract-linux-x64@npm:2.1.2": + version: 2.1.2 + resolution: "@msgpackr-extract/msgpackr-extract-linux-x64@npm:2.1.2" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + +"@msgpackr-extract/msgpackr-extract-win32-x64@npm:2.1.2": + version: 2.1.2 + resolution: "@msgpackr-extract/msgpackr-extract-win32-x64@npm:2.1.2" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@nestjs/bull-shared@npm:^0.1.1": + version: 0.1.1 + resolution: "@nestjs/bull-shared@npm:0.1.1" + dependencies: + tslib: 2.4.0 + peerDependencies: + "@nestjs/common": ^6.10.11 || ^7.0.0 || ^8.0.0 || ^9.0.0 + "@nestjs/core": ^6.10.11 || ^7.0.0 || ^8.0.0 || ^9.0.0 + checksum: cdedeebd541393718c416b2c45bccc6bd148079827a3bb675510bd3a54b5a7f49164ec830df183fcaead9e1cad3a3da07202e38cbb45ee5b511de0fb60084f78 + languageName: node + linkType: hard + +"@nestjs/bull@npm:^0.6.1": + version: 0.6.1 + resolution: "@nestjs/bull@npm:0.6.1" + dependencies: + "@nestjs/bull-shared": ^0.1.1 + tslib: 2.4.0 + peerDependencies: + "@nestjs/common": ^6.10.11 || ^7.0.0 || ^8.0.0 || ^9.0.0 + "@nestjs/core": ^6.10.11 || ^7.0.0 || ^8.0.0 || ^9.0.0 + bull: ^3.3 || ^4.0.0 + checksum: 053a0eea1acfb6bd6fc9e996d47e7c5a4b845c1d9667df3f9639e34cf2afd9ff2cbbe511b5b91a9db71e1480b3e13f2f262f9a04deca50809a1b9cdc4116ccc9 + languageName: node + linkType: hard + "@nestjs/cli@npm:^9.1.3": version: 9.1.3 resolution: "@nestjs/cli@npm:9.1.3" @@ -2938,6 +3006,16 @@ __metadata: languageName: node linkType: hard +"@types/bull@npm:^3.15.9": + version: 3.15.9 + resolution: "@types/bull@npm:3.15.9" + dependencies: + "@types/ioredis": "*" + "@types/redis": ^2.8.0 + checksum: 060a274e2939ca70f6ddd89842a5a0e46101a5adaba3fcdc6899e7e64382d01513a954dc5dabfa73993ce584e9a74b3c85b30dcd38362cfcf6eee1416bbf7463 + languageName: node + linkType: hard + "@types/component-emitter@npm:^1.2.10": version: 1.2.11 resolution: "@types/component-emitter@npm:1.2.11" @@ -3051,6 +3129,15 @@ __metadata: languageName: node linkType: hard +"@types/ioredis@npm:*": + version: 4.28.10 + resolution: "@types/ioredis@npm:4.28.10" + dependencies: + "@types/node": "*" + checksum: 0f2788cf25f490d3b345db8c5f8b8ce3f6c92cc99abcf744c8f974f02b9b3875233b3d22098614c462a0d6c41c523bd655509418ea88eb6249db6652290ce7cf + languageName: node + linkType: hard + "@types/json-schema@npm:*, @types/json-schema@npm:^7.0.5, @types/json-schema@npm:^7.0.8, @types/json-schema@npm:^7.0.9": version: 7.0.11 resolution: "@types/json-schema@npm:7.0.11" @@ -3166,6 +3253,15 @@ __metadata: languageName: node linkType: hard +"@types/redis@npm:^2.8.0": + version: 2.8.32 + resolution: "@types/redis@npm:2.8.32" + dependencies: + "@types/node": "*" + checksum: 2b12103e05977941870c9a248f6ea51f4b7ad7e0f16a7403799c2ed1b3e63b60f693c39f9186be0ea02776934c4595ddcd2a5bde41e530aaad42d26449f6a669 + languageName: node + linkType: hard + "@types/resize-observer-browser@npm:^0.1.7": version: 0.1.7 resolution: "@types/resize-observer-browser@npm:0.1.7" @@ -4207,6 +4303,23 @@ __metadata: languageName: node linkType: hard +"bull@npm:^4.9.0": + version: 4.9.0 + resolution: "bull@npm:4.9.0" + dependencies: + cron-parser: ^4.2.1 + debuglog: ^1.0.0 + get-port: ^5.1.1 + ioredis: ^4.28.5 + lodash: ^4.17.21 + msgpackr: ^1.5.2 + p-timeout: ^3.2.0 + semver: ^7.3.2 + uuid: ^8.3.0 + checksum: 6f100feb753a9100ab2653f67a525f42de3f4c137bdc1b5659b1154d37fd8371e23834a7b36271b54e13bd3a7ac4e534414ecd8b13e26c73e9fc425a28b70a8e + languageName: node + linkType: hard + "bytes@npm:3.0.0": version: 3.0.0 resolution: "bytes@npm:3.0.0" @@ -4451,6 +4564,13 @@ __metadata: languageName: node linkType: hard +"cluster-key-slot@npm:^1.1.0": + version: 1.1.0 + resolution: "cluster-key-slot@npm:1.1.0" + checksum: fc953c75209b1ef9088081bab4e40a0b2586491c974ab93460569c014515ca5a2e31c043f185285e177007162fc353d07836d98f570c171dbe055775430e495b + languageName: node + linkType: hard + "color-convert@npm:^1.9.0": version: 1.9.3 resolution: "color-convert@npm:1.9.3" @@ -4731,6 +4851,15 @@ __metadata: languageName: node linkType: hard +"cron-parser@npm:^4.2.1": + version: 4.6.0 + resolution: "cron-parser@npm:4.6.0" + dependencies: + luxon: ^3.0.1 + checksum: cef63dee396732a8247c2c55d99512db7ad39797459f4bfd534ce5c18efdbf88b16ae8265c3b2abc40cdfadf8930bb1be6778e6ae664ae70e4ed7f206487d0cd + languageName: node + linkType: hard + "cron@npm:2.0.0": version: 2.0.0 resolution: "cron@npm:2.0.0" @@ -4872,7 +5001,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:4.3.4, debug@npm:^4.0.0, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.2, debug@npm:^4.3.3, debug@npm:^4.3.4, debug@npm:~4.3.1, debug@npm:~4.3.2": +"debug@npm:4, debug@npm:4.3.4, debug@npm:^4.0.0, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.3, debug@npm:^4.3.4, debug@npm:~4.3.1, debug@npm:~4.3.2": version: 4.3.4 resolution: "debug@npm:4.3.4" dependencies: @@ -4893,6 +5022,13 @@ __metadata: languageName: node linkType: hard +"debuglog@npm:^1.0.0": + version: 1.0.1 + resolution: "debuglog@npm:1.0.1" + checksum: 970679f2eb7a73867e04d45b52583e7ec6dee1f33c058e9147702e72a665a9647f9c3d6e7c2f66f6bf18510b23eb5ded1b617e48ac1db23603809c5ddbbb9763 + languageName: node + linkType: hard + "decompress-response@npm:^6.0.0": version: 6.0.0 resolution: "decompress-response@npm:6.0.0" @@ -4965,6 +5101,13 @@ __metadata: languageName: node linkType: hard +"denque@npm:^1.1.0": + version: 1.5.1 + resolution: "denque@npm:1.5.1" + checksum: 4375ad19d5cea99f90effa82a8cecdaa10f4eb261fbcd7e47cd753ff2737f037aac8f7f4e031cc77f3966314c491c86a0d3b20c128aeee57f791b4662c45108e + languageName: node + linkType: hard + "depd@npm:2.0.0": version: 2.0.0 resolution: "depd@npm:2.0.0" @@ -6317,6 +6460,13 @@ __metadata: languageName: node linkType: hard +"get-port@npm:^5.1.1": + version: 5.1.1 + resolution: "get-port@npm:5.1.1" + checksum: 0162663ffe5c09e748cd79d97b74cd70e5a5c84b760a475ce5767b357fb2a57cb821cee412d646aa8a156ed39b78aab88974eddaa9e5ee926173c036c0713787 + languageName: node + linkType: hard + "get-stream@npm:^5.0.0": version: 5.2.0 resolution: "get-stream@npm:5.2.0" @@ -6888,6 +7038,25 @@ __metadata: languageName: node linkType: hard +"ioredis@npm:^4.28.5": + version: 4.28.5 + resolution: "ioredis@npm:4.28.5" + dependencies: + cluster-key-slot: ^1.1.0 + debug: ^4.3.1 + denque: ^1.1.0 + lodash.defaults: ^4.2.0 + lodash.flatten: ^4.4.0 + lodash.isarguments: ^3.1.0 + p-map: ^2.1.0 + redis-commands: 1.7.0 + redis-errors: ^1.2.0 + redis-parser: ^3.0.0 + standard-as-callback: ^2.1.0 + checksum: a8793c3324cd69fa55b4baacbda118ce6724e574260157761276b31411dd3e168c75490f7155c6ce34d79e01488efa98e0cdb162991970fd56da7cbcdafb8fb8 + languageName: node + linkType: hard + "ip@npm:^1.1.5": version: 1.1.8 resolution: "ip@npm:1.1.8" @@ -7471,6 +7640,20 @@ __metadata: languageName: node linkType: hard +"lodash.defaults@npm:^4.2.0": + version: 4.2.0 + resolution: "lodash.defaults@npm:4.2.0" + checksum: 84923258235592c8886e29de5491946ff8c2ae5c82a7ac5cddd2e3cb697e6fbdfbbb6efcca015795c86eec2bb953a5a2ee4016e3735a3f02720428a40efbb8f1 + languageName: node + linkType: hard + +"lodash.flatten@npm:^4.4.0": + version: 4.4.0 + resolution: "lodash.flatten@npm:4.4.0" + checksum: 0ac34a393d4b795d4b7421153d27c13ae67e08786c9cbb60ff5b732210d46f833598eee3fb3844bb10070e8488efe390ea53bb567377e0cb47e9e630bf0811cb + languageName: node + linkType: hard + "lodash.includes@npm:^4.3.0": version: 4.3.0 resolution: "lodash.includes@npm:4.3.0" @@ -7478,6 +7661,13 @@ __metadata: languageName: node linkType: hard +"lodash.isarguments@npm:^3.1.0": + version: 3.1.0 + resolution: "lodash.isarguments@npm:3.1.0" + checksum: ae1526f3eb5c61c77944b101b1f655f846ecbedcb9e6b073526eba6890dc0f13f09f72e11ffbf6540b602caee319af9ac363d6cdd6be41f4ee453436f04f13b5 + languageName: node + linkType: hard + "lodash.isboolean@npm:^3.0.3": version: 3.0.3 resolution: "lodash.isboolean@npm:3.0.3" @@ -7567,6 +7757,13 @@ __metadata: languageName: node linkType: hard +"luxon@npm:^3.0.1": + version: 3.0.3 + resolution: "luxon@npm:3.0.3" + checksum: 67d143f102f520761c4202086579a5cf30b230ea299da27cacb31e9f9d372cadef90f14cbe7e2621b70825b267fe00128b8176ed8b7172b48f77a403a662d5aa + languageName: node + linkType: hard + "macos-release@npm:^2.5.0": version: 2.5.0 resolution: "macos-release@npm:2.5.0" @@ -7906,6 +8103,49 @@ __metadata: languageName: node linkType: hard +"msgpackr-extract@npm:^2.0.2": + version: 2.1.2 + resolution: "msgpackr-extract@npm:2.1.2" + dependencies: + "@msgpackr-extract/msgpackr-extract-darwin-arm64": 2.1.2 + "@msgpackr-extract/msgpackr-extract-darwin-x64": 2.1.2 + "@msgpackr-extract/msgpackr-extract-linux-arm": 2.1.2 + "@msgpackr-extract/msgpackr-extract-linux-arm64": 2.1.2 + "@msgpackr-extract/msgpackr-extract-linux-x64": 2.1.2 + "@msgpackr-extract/msgpackr-extract-win32-x64": 2.1.2 + node-gyp: latest + node-gyp-build-optional-packages: 5.0.3 + dependenciesMeta: + "@msgpackr-extract/msgpackr-extract-darwin-arm64": + optional: true + "@msgpackr-extract/msgpackr-extract-darwin-x64": + optional: true + "@msgpackr-extract/msgpackr-extract-linux-arm": + optional: true + "@msgpackr-extract/msgpackr-extract-linux-arm64": + optional: true + "@msgpackr-extract/msgpackr-extract-linux-x64": + optional: true + "@msgpackr-extract/msgpackr-extract-win32-x64": + optional: true + bin: + download-msgpackr-prebuilds: bin/download-prebuilds.js + checksum: bf068baa690d3e5c5609c10aa363901ac43d3f32b9d89f9dfb77293afa866eb1b943482338da6c38d50790a66c966fd7e0fbc9187b2a35f40f253931f649f97f + languageName: node + linkType: hard + +"msgpackr@npm:^1.5.2": + version: 1.6.3 + resolution: "msgpackr@npm:1.6.3" + dependencies: + msgpackr-extract: ^2.0.2 + dependenciesMeta: + msgpackr-extract: + optional: true + checksum: e784d25f68e6e323c64a2677032c3c303ad78acc618b6d25511dc7ece130e43d825143ed53d509d75ed12bdd7e3c4d33c888545378561239cc464796e882cd45 + languageName: node + linkType: hard + "multicast-dns@npm:^7.2.5": version: 7.2.5 resolution: "multicast-dns@npm:7.2.5" @@ -8134,6 +8374,17 @@ __metadata: languageName: node linkType: hard +"node-gyp-build-optional-packages@npm:5.0.3": + version: 5.0.3 + resolution: "node-gyp-build-optional-packages@npm:5.0.3" + bin: + node-gyp-build-optional-packages: bin.js + node-gyp-build-optional-packages-optional: optional.js + node-gyp-build-optional-packages-test: build-test.js + checksum: be3f0235925c8361e5bc1a03848f5e24815b0df8aa90bd13f1eac91cd86264bbb8b7689ca6cd083b02c8099c7b54f9fb83066c7bb77c2389dc4eceab921f084f + languageName: node + linkType: hard + "node-gyp-build@npm:^4.2.2": version: 4.4.0 resolution: "node-gyp-build@npm:4.4.0" @@ -8499,6 +8750,13 @@ __metadata: languageName: node linkType: hard +"p-finally@npm:^1.0.0": + version: 1.0.0 + resolution: "p-finally@npm:1.0.0" + checksum: 93a654c53dc805dd5b5891bab16eb0ea46db8f66c4bfd99336ae929323b1af2b70a8b0654f8f1eae924b2b73d037031366d645f1fd18b3d30cbd15950cc4b1d4 + languageName: node + linkType: hard + "p-limit@npm:^2.2.0": version: 2.3.0 resolution: "p-limit@npm:2.3.0" @@ -8535,6 +8793,13 @@ __metadata: languageName: node linkType: hard +"p-map@npm:^2.1.0": + version: 2.1.0 + resolution: "p-map@npm:2.1.0" + checksum: 9e3ad3c9f6d75a5b5661bcad78c91f3a63849189737cd75e4f1225bf9ac205194e5c44aac2ef6f09562b1facdb9bd1425584d7ac375bfaa17b3f1a142dab936d + languageName: node + linkType: hard + "p-map@npm:^4.0.0": version: 4.0.0 resolution: "p-map@npm:4.0.0" @@ -8554,6 +8819,15 @@ __metadata: languageName: node linkType: hard +"p-timeout@npm:^3.2.0": + version: 3.2.0 + resolution: "p-timeout@npm:3.2.0" + dependencies: + p-finally: ^1.0.0 + checksum: 3dd0eaa048780a6f23e5855df3dd45c7beacff1f820476c1d0d1bcd6648e3298752ba2c877aa1c92f6453c7dd23faaf13d9f5149fc14c0598a142e2c5e8d649c + languageName: node + linkType: hard + "p-timeout@npm:^6.0.0": version: 6.0.0 resolution: "p-timeout@npm:6.0.0" @@ -8917,6 +9191,7 @@ __metadata: "@fastify/multipart": ^7.2.0 "@fastify/reply-from": ^8.3.0 "@fastify/static": ^6.5.0 + "@nestjs/bull": ^0.6.1 "@nestjs/cli": ^9.1.3 "@nestjs/common": ^9.0.11 "@nestjs/config": ^2.2.0 @@ -8933,6 +9208,7 @@ __metadata: "@nestjs/typeorm": ^9.0.1 "@nestjs/websockets": ^9.0.11 "@types/bcrypt": ^5.0.0 + "@types/bull": ^3.15.9 "@types/cors": ^2.8.12 "@types/multer": ^1.4.7 "@types/node": ^18.7.18 @@ -8945,6 +9221,7 @@ __metadata: "@typescript-eslint/parser": ^5.37.0 bcrypt: ^5.0.1 bmp-img: ^1.2.1 + bull: ^4.9.0 cors: ^2.8.5 eslint: ^8.23.1 eslint-config-prettier: ^8.5.0 @@ -9946,6 +10223,29 @@ __metadata: languageName: node linkType: hard +"redis-commands@npm:1.7.0": + version: 1.7.0 + resolution: "redis-commands@npm:1.7.0" + checksum: d1ff7fbcb5e54768c77f731f1d49679d2a62c3899522c28addb4e2e5813aea8bcac3f22519d71d330224c3f2937f935dfc3d8dc65e90db0f5fe22dc2c1515aa7 + languageName: node + linkType: hard + +"redis-errors@npm:^1.0.0, redis-errors@npm:^1.2.0": + version: 1.2.0 + resolution: "redis-errors@npm:1.2.0" + checksum: f28ac2692113f6f9c222670735aa58aeae413464fd58ccf3fce3f700cae7262606300840c802c64f2b53f19f65993da24dc918afc277e9e33ac1ff09edb394f4 + languageName: node + linkType: hard + +"redis-parser@npm:^3.0.0": + version: 3.0.0 + resolution: "redis-parser@npm:3.0.0" + dependencies: + redis-errors: ^1.0.0 + checksum: 89290ae530332f2ae37577647fa18208d10308a1a6ba750b9d9a093e7398f5e5253f19855b64c98757f7129cccce958e4af2573fdc33bad41405f87f1943459a + languageName: node + linkType: hard + "reflect-metadata@npm:^0.1.13, reflect-metadata@npm:^0.1.2": version: 0.1.13 resolution: "reflect-metadata@npm:0.1.13" @@ -10352,7 +10652,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:7.3.7, semver@npm:^7.0.0, semver@npm:^7.1.1, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.7": +"semver@npm:7.3.7, semver@npm:^7.0.0, semver@npm:^7.1.1, semver@npm:^7.3.2, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.7": version: 7.3.7 resolution: "semver@npm:7.3.7" dependencies: @@ -10825,6 +11125,13 @@ __metadata: languageName: node linkType: hard +"standard-as-callback@npm:^2.1.0": + version: 2.1.0 + resolution: "standard-as-callback@npm:2.1.0" + checksum: 88bec83ee220687c72d94fd86a98d5272c91d37ec64b66d830dbc0d79b62bfa6e47f53b71646011835fc9ce7fae62739545d13124262b53be4fbb3e2ebad551c + languageName: node + linkType: hard + "statuses@npm:2.0.1": version: 2.0.1 resolution: "statuses@npm:2.0.1" @@ -11644,7 +11951,7 @@ __metadata: languageName: node linkType: hard -"uuid@npm:8.3.2, uuid@npm:^8.3.2": +"uuid@npm:8.3.2, uuid@npm:^8.3.0, uuid@npm:^8.3.2": version: 8.3.2 resolution: "uuid@npm:8.3.2" bin: