diff --git a/README.md b/README.md index 00a13b1..70d770a 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,6 @@ -

- Nest Logo -

- -[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456 -[circleci-url]: https://circleci.com/gh/nestjs/nest - -

A progressive Node.js framework for building efficient and scalable server-side applications.

-

-NPM Version -Package License -NPM Downloads -CircleCI -Coverage -Discord -Backers on Open Collective -Sponsors on Open Collective - - Support us - -

- - ## Description -[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository. +[LeyuChat](https://dev.leyuchat.com/) A Message Automation tool ## Installation @@ -32,42 +8,19 @@ $ npm install ``` -## Running the app +## Running Mini App ```bash # development $ npm run start -# watch mode -$ npm run start:dev +# run database consumer +$ pm2 start dist/src/apps/consumers/database-consumer/main.js --no-daemon -# production mode -$ npm run start:prod +# run chat consumer +$ pm2 start dist/src/apps/consumers/chat-consumer/main.js --no-daemon ``` -## Test - -```bash -# unit tests -$ npm run test - -# e2e tests -$ npm run test:e2e - -# test coverage -$ npm run test:cov -``` - -## Support - -Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support). - -## Stay in touch - -- Author - [Kamil Myƛliwiec](https://kamilmysliwiec.com) -- Website - [https://nestjs.com](https://nestjs.com/) -- Twitter - [@nestframework](https://twitter.com/nestframework) - ## License -Nest is [MIT licensed](LICENSE). +LeyuChat is [MIT licensed](LICENSE). diff --git a/docker-compose.yml b/docker-compose.yml index dc7d514..eb7880a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -51,6 +51,22 @@ services: environment: RABBITMQ_DEFAULT_USER: user RABBITMQ_DEFAULT_PASS: password + + chat-consumer: + build: + context: . + platform: linux/amd64 + environment: + - RABBITMQ_URL=${RABBITMQ_URL} + command: ["node", "dist/src/apps/consumers/chat-consumer/main.js"] + + database-consumer: + build: + context: . + platform: linux/amd64 + environment: + - RABBITMQ_URL=${RABBITMQ_URL} + command: ["node", "dist/src/apps/consumers/database-consumer/main.js"] volumes: postgres_data: diff --git a/package-lock.json b/package-lock.json index 9763a7e..5329e8f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,6 +25,7 @@ "@nestjs/websockets": "^10.4.15", "@prisma/client": "^5.22.0", "@types/ioredis": "^4.28.10", + "amqp-connection-manager": "^4.1.14", "amqplib": "^0.10.5", "bcryptjs": "^2.4.3", "class-transformer": "^0.5.1", @@ -3778,6 +3779,22 @@ "node": ">=0.10.0" } }, + "node_modules/amqp-connection-manager": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/amqp-connection-manager/-/amqp-connection-manager-4.1.14.tgz", + "integrity": "sha512-1km47dIvEr0HhMUazqovSvNwIlSvDX2APdUpULaINtHpiki1O+cLRaTeXb/jav4OLtH+k6GBXx5gsKOT9kcGKQ==", + "license": "MIT", + "dependencies": { + "promise-breaker": "^6.0.0" + }, + "engines": { + "node": ">=10.0.0", + "npm": ">5.0.0" + }, + "peerDependencies": { + "amqplib": "*" + } + }, "node_modules/amqplib": { "version": "0.10.5", "resolved": "https://registry.npmjs.org/amqplib/-/amqplib-0.10.5.tgz", @@ -11045,6 +11062,12 @@ "asap": "~2.0.3" } }, + "node_modules/promise-breaker": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/promise-breaker/-/promise-breaker-6.0.0.tgz", + "integrity": "sha512-BthzO9yTPswGf7etOBiHCVuugs2N01/Q/94dIPls48z2zCmrnDptUUZzfIb+41xq0MnYZ/BzmOd6ikDR4ibNZA==", + "license": "MIT" + }, "node_modules/prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", diff --git a/package.json b/package.json index c505937..d09aaaf 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "@nestjs/websockets": "^10.4.15", "@prisma/client": "^5.22.0", "@types/ioredis": "^4.28.10", + "amqp-connection-manager": "^4.1.14", "amqplib": "^0.10.5", "bcryptjs": "^2.4.3", "class-transformer": "^0.5.1", diff --git a/src/apps/consumers/chat-consumer/chat-consumer.controller.spec.ts b/src/apps/consumers/chat-consumer/chat-consumer.controller.spec.ts new file mode 100644 index 0000000..6dad5f0 --- /dev/null +++ b/src/apps/consumers/chat-consumer/chat-consumer.controller.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { ChatConsumerController } from './chat-consumer.controller'; + +describe('ChatConsumerController', () => { + let controller: ChatConsumerController; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [ChatConsumerController], + }).compile(); + + controller = module.get(ChatConsumerController); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); +}); diff --git a/src/apps/consumers/chat-consumer/chat-consumer.controller.ts b/src/apps/consumers/chat-consumer/chat-consumer.controller.ts new file mode 100644 index 0000000..cc767ea --- /dev/null +++ b/src/apps/consumers/chat-consumer/chat-consumer.controller.ts @@ -0,0 +1,4 @@ +import { Controller } from '@nestjs/common'; + +@Controller('chat-consumer') +export class ChatConsumerController {} diff --git a/src/apps/consumers/chat-consumer/chat-consumer.module.ts b/src/apps/consumers/chat-consumer/chat-consumer.module.ts new file mode 100644 index 0000000..83b52ac --- /dev/null +++ b/src/apps/consumers/chat-consumer/chat-consumer.module.ts @@ -0,0 +1,18 @@ +import { Module } from '@nestjs/common'; +import { ChatConsumerController } from './chat-consumer.controller'; +import { ChatConsumerService } from './chat-consumer.service'; +import { ConfigModule } from '@nestjs/config'; +import { PrismaModule } from 'src/modules/prisma/prisma.module'; + +@Module({ + imports: [ + ConfigModule.forRoot({ + isGlobal: true, + envFilePath: '.env', + }), + PrismaModule, + ], + controllers: [ChatConsumerController], + providers: [ChatConsumerService], +}) +export class ChatConsumerModule {} diff --git a/src/apps/consumers/chat-consumer/chat-consumer.service.spec.ts b/src/apps/consumers/chat-consumer/chat-consumer.service.spec.ts new file mode 100644 index 0000000..c0ea396 --- /dev/null +++ b/src/apps/consumers/chat-consumer/chat-consumer.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { ChatConsumerService } from './chat-consumer.service'; + +describe('ChatConsumerService', () => { + let service: ChatConsumerService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ChatConsumerService], + }).compile(); + + service = module.get(ChatConsumerService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/src/apps/consumers/chat-consumer/chat-consumer.service.ts b/src/apps/consumers/chat-consumer/chat-consumer.service.ts new file mode 100644 index 0000000..c4753b1 --- /dev/null +++ b/src/apps/consumers/chat-consumer/chat-consumer.service.ts @@ -0,0 +1,4 @@ +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class ChatConsumerService {} diff --git a/src/apps/consumers/chat-consumer/main.ts b/src/apps/consumers/chat-consumer/main.ts new file mode 100644 index 0000000..44ac168 --- /dev/null +++ b/src/apps/consumers/chat-consumer/main.ts @@ -0,0 +1,26 @@ +import { NestFactory } from '@nestjs/core'; +import { MicroserviceOptions, Transport } from '@nestjs/microservices'; +import { ChatConsumerModule } from './chat-consumer.module'; + +async function bootstrap() { + const app = await NestFactory.createMicroservice( + ChatConsumerModule, + { + transport: Transport.RMQ, + options: { + urls: [process.env.RABBITMQ_URL], + queue: 'chat', + queueOptions: { + durable: true, + messageTtl: 60000, + deadLetterExchange: 'message', + deadLetterRoutingKey: 'dead', + }, + noAck: false, + prefetchCount: 1, + }, + }, + ); + await app.listen(); +} +bootstrap(); diff --git a/src/apps/consumers/database-consumer/database-consumer.controller.spec.ts b/src/apps/consumers/database-consumer/database-consumer.controller.spec.ts new file mode 100644 index 0000000..b5f898e --- /dev/null +++ b/src/apps/consumers/database-consumer/database-consumer.controller.spec.ts @@ -0,0 +1,20 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { DatabaseConsumerController } from './database-consumer.controller'; + +describe('DatabaseConsumerController', () => { + let controller: DatabaseConsumerController; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [DatabaseConsumerController], + }).compile(); + + controller = module.get( + DatabaseConsumerController, + ); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); +}); diff --git a/src/apps/consumers/database-consumer/database-consumer.controller.ts b/src/apps/consumers/database-consumer/database-consumer.controller.ts new file mode 100644 index 0000000..6e65260 --- /dev/null +++ b/src/apps/consumers/database-consumer/database-consumer.controller.ts @@ -0,0 +1,16 @@ +import { Controller } from '@nestjs/common'; +import { Ctx, EventPattern, Payload, RmqContext } from '@nestjs/microservices'; +import { MessagePayload } from 'src/types/message'; +import { DatabaseConsumerService } from './database-consumer.service'; + +@Controller('database-consumer') +export class DatabaseConsumerController { + constructor(private readonly databaseService: DatabaseConsumerService) {} + @EventPattern() + async handleMessage( + @Payload() data: MessagePayload, + @Ctx() context: RmqContext, + ) { + this.databaseService.handleMessage(data, context); + } +} diff --git a/src/apps/consumers/database-consumer/database-consumer.module.ts b/src/apps/consumers/database-consumer/database-consumer.module.ts new file mode 100644 index 0000000..75af18a --- /dev/null +++ b/src/apps/consumers/database-consumer/database-consumer.module.ts @@ -0,0 +1,18 @@ +import { Module } from '@nestjs/common'; +import { DatabaseConsumerController } from './database-consumer.controller'; +import { DatabaseConsumerService } from './database-consumer.service'; +import { ConfigModule } from '@nestjs/config'; +import { PrismaModule } from 'src/modules/prisma/prisma.module'; + +@Module({ + imports: [ + ConfigModule.forRoot({ + isGlobal: true, + envFilePath: '.env', + }), + PrismaModule, + ], + controllers: [DatabaseConsumerController], + providers: [DatabaseConsumerService], +}) +export class DatabaseConsumerModule {} diff --git a/src/apps/consumers/database-consumer/database-consumer.service.spec.ts b/src/apps/consumers/database-consumer/database-consumer.service.spec.ts new file mode 100644 index 0000000..915e605 --- /dev/null +++ b/src/apps/consumers/database-consumer/database-consumer.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { DatabaseConsumerService } from './database-consumer.service'; + +describe('DatabaseConsumerService', () => { + let service: DatabaseConsumerService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [DatabaseConsumerService], + }).compile(); + + service = module.get(DatabaseConsumerService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/src/apps/consumers/database-consumer/database-consumer.service.ts b/src/apps/consumers/database-consumer/database-consumer.service.ts new file mode 100644 index 0000000..c31c1c1 --- /dev/null +++ b/src/apps/consumers/database-consumer/database-consumer.service.ts @@ -0,0 +1,11 @@ +import { Injectable } from '@nestjs/common'; +import { RmqContext } from '@nestjs/microservices'; +import { MessagePayload } from 'src/types/message'; + +@Injectable() +export class DatabaseConsumerService { + async handleMessage(data: MessagePayload, context: RmqContext) { + console.log(data); + console.log(context); + } +} diff --git a/src/apps/consumers/database-consumer/main.ts b/src/apps/consumers/database-consumer/main.ts new file mode 100644 index 0000000..bafadfd --- /dev/null +++ b/src/apps/consumers/database-consumer/main.ts @@ -0,0 +1,26 @@ +import { NestFactory } from '@nestjs/core'; +import { MicroserviceOptions, Transport } from '@nestjs/microservices'; +import { DatabaseConsumerModule } from './database-consumer.module'; + +async function bootstrap() { + const app = await NestFactory.createMicroservice( + DatabaseConsumerModule, + { + transport: Transport.RMQ, + options: { + urls: [process.env.RABBITMQ_URL], + queue: 'database', + queueOptions: { + durable: true, + messageTtl: 60000, + deadLetterExchange: 'message', + deadLetterRoutingKey: 'dead', + }, + noAck: false, + prefetchCount: 1, + }, + }, + ); + await app.listen(); +} +bootstrap(); diff --git a/src/types/message.ts b/src/types/message.ts new file mode 100644 index 0000000..c7979a8 --- /dev/null +++ b/src/types/message.ts @@ -0,0 +1,7 @@ +import { Message } from '@prisma/client'; + +export interface MessagePayload { + type?: string; + metadata?: Record; + payload?: Message; +}