update
This commit is contained in:
21
.eslintrc.js
21
.eslintrc.js
@@ -1,24 +1,25 @@
|
||||
module.exports = {
|
||||
parser: "@typescript-eslint/parser",
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
project: "tsconfig.json",
|
||||
project: 'tsconfig.json',
|
||||
tsconfigRootDir: __dirname,
|
||||
sourceType: "module",
|
||||
sourceType: 'module',
|
||||
},
|
||||
plugins: ["@typescript-eslint/eslint-plugin"],
|
||||
plugins: ['@typescript-eslint/eslint-plugin'],
|
||||
extends: [
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:prettier/recommended',
|
||||
],
|
||||
root: true,
|
||||
env: {
|
||||
node: true,
|
||||
jest: true,
|
||||
},
|
||||
ignorePatterns: [".eslintrc.js"],
|
||||
ignorePatterns: ['.eslintrc.js'],
|
||||
rules: {
|
||||
"@typescript-eslint/interface-name-prefix": "off",
|
||||
"@typescript-eslint/explicit-function-return-type": "off",
|
||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
'@typescript-eslint/interface-name-prefix': 'off',
|
||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
},
|
||||
};
|
||||
|
||||
26
.gitignore
vendored
26
.gitignore
vendored
@@ -1,9 +1,7 @@
|
||||
# compiled output
|
||||
/dist
|
||||
/node_modules
|
||||
.env
|
||||
package-lock.json
|
||||
ecosystem.config.js
|
||||
/build
|
||||
|
||||
# Logs
|
||||
logs
|
||||
@@ -35,4 +33,24 @@ lerna-debug.log*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
!.vscode/extensions.json
|
||||
|
||||
# dotenv environment variable files
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
# temp directory
|
||||
.temp
|
||||
.tmp
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"singleQuote": false,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all"
|
||||
}
|
||||
9234
package-lock.json
generated
Normal file
9234
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
29
package.json
29
package.json
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "notification-server",
|
||||
"name": "notification_server",
|
||||
"version": "0.0.1",
|
||||
"description": "",
|
||||
"author": "",
|
||||
@@ -21,20 +21,18 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "^10.0.0",
|
||||
"@nestjs/config": "^3.1.1",
|
||||
"@nestjs/config": "^3.2.3",
|
||||
"@nestjs/core": "^10.0.0",
|
||||
"@nestjs/platform-express": "^10.0.0",
|
||||
"@nestjs/platform-socket.io": "^10.2.7",
|
||||
"@nestjs/sequelize": "^10.0.0",
|
||||
"@nestjs/websockets": "^10.2.7",
|
||||
"@nestjs/platform-socket.io": "^10.3.10",
|
||||
"@nestjs/typeorm": "^10.0.2",
|
||||
"@nestjs/websockets": "^10.3.10",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.14.0",
|
||||
"mysql2": "^3.6.2",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"class-validator": "^0.14.1",
|
||||
"pg": "^8.12.0",
|
||||
"reflect-metadata": "^0.2.0",
|
||||
"rxjs": "^7.8.1",
|
||||
"sequelize": "^6.33.0",
|
||||
"sequelize-typescript": "^2.1.5",
|
||||
"socket.io": "^4.7.2"
|
||||
"typeorm": "^0.3.20"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cli": "^10.0.0",
|
||||
@@ -43,17 +41,16 @@
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/jest": "^29.5.2",
|
||||
"@types/node": "^20.3.1",
|
||||
"@types/sequelize": "^4.28.17",
|
||||
"@types/supertest": "^2.0.12",
|
||||
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
||||
"@typescript-eslint/parser": "^6.0.0",
|
||||
"@types/supertest": "^6.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^7.0.0",
|
||||
"@typescript-eslint/parser": "^7.0.0",
|
||||
"eslint": "^8.42.0",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-plugin-prettier": "^5.0.0",
|
||||
"jest": "^29.5.0",
|
||||
"prettier": "^3.0.0",
|
||||
"source-map-support": "^0.5.21",
|
||||
"supertest": "^6.3.3",
|
||||
"supertest": "^7.0.0",
|
||||
"ts-jest": "^29.1.0",
|
||||
"ts-loader": "^9.4.3",
|
||||
"ts-node": "^10.9.1",
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
import { Module } from "@nestjs/common";
|
||||
import { NotificationModule } from "./notifications/notification.module";
|
||||
import { SequelizeModule } from "@nestjs/sequelize";
|
||||
import { ConfigModule } from "@nestjs/config";
|
||||
import { SocketModule } from "./socket/socket.module";
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { SocketModule } from './socket/socket.module';
|
||||
import { NotificationModule } from './notifications/notification.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
ConfigModule.forRoot(),
|
||||
SequelizeModule.forRoot({
|
||||
dialect: "mysql",
|
||||
host: process.env.DB_HOST,
|
||||
port: parseInt(process.env.DB_PORT),
|
||||
username: process.env.DB_USERNAME,
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_NAME,
|
||||
autoLoadModels: true,
|
||||
synchronize: true,
|
||||
TypeOrmModule.forRoot({
|
||||
type: 'postgres',
|
||||
host: process.env.POSTGRES_HOST,
|
||||
port: 5432,
|
||||
ssl: process.env.POSTGRES_SSL === 'true',
|
||||
username: process.env.POSTGRES_USER,
|
||||
password: process.env.POSTGRES_PASSWORD,
|
||||
database: process.env.POSTGRES_DATABASE,
|
||||
entities: [__dirname + '/**/*.entity{.ts,.js}'],
|
||||
synchronize: process.env.DB_SYNC === 'true',
|
||||
}),
|
||||
NotificationModule,
|
||||
SocketModule,
|
||||
NotificationModule,
|
||||
],
|
||||
})
|
||||
export class AppModule {
|
||||
}
|
||||
export class AppModule {}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { NestFactory } from "@nestjs/core";
|
||||
import { AppModule } from "./app.module";
|
||||
import { ValidationPipe } from "@nestjs/common";
|
||||
import { IoAdapter } from "@nestjs/platform-socket.io";
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import { AppModule } from './app.module';
|
||||
import { ValidationPipe } from '@nestjs/common';
|
||||
import { IoAdapter } from '@nestjs/platform-socket.io';
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(AppModule);
|
||||
@@ -9,5 +9,4 @@ async function bootstrap() {
|
||||
app.useWebSocketAdapter(new IoAdapter(app));
|
||||
await app.listen(parseInt(process.env.PORT));
|
||||
}
|
||||
|
||||
bootstrap();
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
import { Body, Controller, Post } from "@nestjs/common";
|
||||
import { NotificationDto } from "./notification.dto";
|
||||
import { NotificationService } from "./notification.service";
|
||||
import { Body, Controller, Post } from '@nestjs/common';
|
||||
import { NotificationDto } from './notification.dto';
|
||||
import { NotificationService } from './notification.service';
|
||||
|
||||
@Controller("notifications")
|
||||
@Controller('notifications')
|
||||
export class NotificationController {
|
||||
constructor(private notificationService: NotificationService) {}
|
||||
|
||||
constructor(private notificationService: NotificationService) {
|
||||
}
|
||||
|
||||
|
||||
@Post("send")
|
||||
@Post('send')
|
||||
async sendNotification(@Body() notificationData: NotificationDto) {
|
||||
return await this.notificationService.sendNotification(notificationData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
export class NotificationInterface {
|
||||
call_id: number;
|
||||
telephone_id: string;
|
||||
phone_number: string;
|
||||
}
|
||||
@@ -1,15 +1,18 @@
|
||||
import { Injectable } from "@nestjs/common";
|
||||
import { SocketGateway } from "../socket/socket.gateway";
|
||||
import { NotificationInterface } from "./notification.interface";
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { SocketGateway } from '../socket/socket.gateway';
|
||||
import { NotificationDto } from './notification.dto';
|
||||
|
||||
@Injectable()
|
||||
export class NotificationService {
|
||||
constructor(
|
||||
private socketGateway: SocketGateway,
|
||||
) {
|
||||
}
|
||||
constructor(private socketGateway: SocketGateway) {}
|
||||
|
||||
async sendNotification(notificationData: NotificationInterface) {
|
||||
return await this.socketGateway.handleSendNotification(notificationData);
|
||||
async sendNotification(notificationData: NotificationDto) {
|
||||
const auth: string[] = [];
|
||||
auth.push(notificationData.telephone_id);
|
||||
return await this.socketGateway.handleSendMessage({
|
||||
auth,
|
||||
data: notificationData,
|
||||
event: 'answer',
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
6
src/socket/dto/clientConnection.dto.ts
Normal file
6
src/socket/dto/clientConnection.dto.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export class ClientConnectionDto {
|
||||
client_id: string;
|
||||
socket_id: string;
|
||||
event: string;
|
||||
description?: string;
|
||||
}
|
||||
5
src/socket/dto/sendMessage.dto.ts
Normal file
5
src/socket/dto/sendMessage.dto.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export class SendMessageDto {
|
||||
auth: string[];
|
||||
data: any;
|
||||
event: string;
|
||||
}
|
||||
19
src/socket/socket.entity.ts
Normal file
19
src/socket/socket.entity.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
|
||||
|
||||
@Entity()
|
||||
export class SocketConnection {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
client_id: string;
|
||||
|
||||
@Column()
|
||||
socket_id: string;
|
||||
|
||||
@Column()
|
||||
event: string;
|
||||
|
||||
@Column({ nullable: true })
|
||||
description: string;
|
||||
}
|
||||
@@ -1,35 +1,61 @@
|
||||
import { OnGatewayConnection, SubscribeMessage, WebSocketGateway, WebSocketServer } from "@nestjs/websockets";
|
||||
import { Server, Socket } from "socket.io";
|
||||
import { NotificationInterface } from "../notifications/notification.interface";
|
||||
import { SocketService } from "./socket.service";
|
||||
import {
|
||||
OnGatewayConnection,
|
||||
SubscribeMessage,
|
||||
WebSocketGateway,
|
||||
WebSocketServer,
|
||||
} from '@nestjs/websockets';
|
||||
import { Server, Socket } from 'socket.io';
|
||||
import { SocketService } from './socket.service';
|
||||
import { SendMessageDto } from './dto/sendMessage.dto';
|
||||
|
||||
@WebSocketGateway()
|
||||
export class SocketGateway implements OnGatewayConnection {
|
||||
@WebSocketServer() server: Server;
|
||||
|
||||
constructor(
|
||||
private socketService: SocketService,
|
||||
) {
|
||||
}
|
||||
constructor(private socketService: SocketService) {}
|
||||
|
||||
handleConnection(client: Socket) {
|
||||
this.socketService.ClientConnection({
|
||||
async handleConnection(client: Socket) {
|
||||
await this.socketService.ClientConnection({
|
||||
client_id: client.handshake.auth.token,
|
||||
socket_id: client.id,
|
||||
event: "connected",
|
||||
event: 'connected',
|
||||
});
|
||||
client.on("disconnect", (reason) => {
|
||||
this.socketService.ClientConnection({
|
||||
client.on('disconnect', async (reason) => {
|
||||
await this.socketService.ClientConnection({
|
||||
client_id: client.handshake.auth.token,
|
||||
socket_id: client.id,
|
||||
event: "disconnected",
|
||||
event: 'disconnected',
|
||||
description: reason,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@SubscribeMessage("sendNotificationToClients")
|
||||
handleSendNotification(notificationData: NotificationInterface) {
|
||||
return this.socketService.sendNotificationToClients(this.server, notificationData);
|
||||
@SubscribeMessage('sendMessageToClients')
|
||||
handleSendMessage(sendMessageDto: SendMessageDto) {
|
||||
const clients = this.getConnectedClients(sendMessageDto.auth);
|
||||
if (clients.length === 0) {
|
||||
return {
|
||||
status: 0,
|
||||
message: 'Failed to find the clients!',
|
||||
};
|
||||
}
|
||||
return this.socketService.sendMessageToClients(
|
||||
clients,
|
||||
sendMessageDto.data,
|
||||
sendMessageDto.event,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
getConnectedClients(auth: string[]): Socket[] {
|
||||
const connectedClients = this.server.sockets.sockets;
|
||||
|
||||
const clients = [];
|
||||
for (const connectedClient of connectedClients) {
|
||||
if (auth.includes(connectedClient[1].handshake.auth.token)) {
|
||||
clients.push(connectedClient[1]);
|
||||
}
|
||||
}
|
||||
|
||||
return clients;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
import { Column, DataType, Model, Table } from "sequelize-typescript";
|
||||
|
||||
@Table({ updatedAt: false, tableName: "notifications" })
|
||||
export class SocketModel extends Model {
|
||||
@Column({
|
||||
type: DataType.BIGINT,
|
||||
allowNull: false,
|
||||
autoIncrement: true,
|
||||
primaryKey: true,
|
||||
})
|
||||
id: number;
|
||||
|
||||
@Column({ allowNull: false })
|
||||
client_id: string;
|
||||
|
||||
@Column({ allowNull: false })
|
||||
socket_id: string;
|
||||
|
||||
@Column({ allowNull: false })
|
||||
event: string;
|
||||
|
||||
@Column
|
||||
description: string;
|
||||
}
|
||||
@@ -1,13 +1,12 @@
|
||||
import { Module } from "@nestjs/common";
|
||||
import { SocketGateway } from "./socket.gateway";
|
||||
import { SocketService } from "./socket.service";
|
||||
import { SequelizeModule } from "@nestjs/sequelize";
|
||||
import { SocketModel } from "./socket.model";
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { SocketConnection } from './socket.entity';
|
||||
import { SocketGateway } from './socket.gateway';
|
||||
import { SocketService } from './socket.service';
|
||||
|
||||
@Module({
|
||||
imports: [SequelizeModule.forFeature([SocketModel])],
|
||||
imports: [TypeOrmModule.forFeature([SocketConnection])],
|
||||
providers: [SocketGateway, SocketService],
|
||||
exports: [SocketGateway],
|
||||
})
|
||||
export class SocketModule {
|
||||
}
|
||||
export class SocketModule {}
|
||||
|
||||
@@ -1,53 +1,60 @@
|
||||
import { Injectable } from "@nestjs/common";
|
||||
import { InjectModel } from "@nestjs/sequelize";
|
||||
import { SocketModel } from "./socket.model";
|
||||
import { Server } from "socket.io";
|
||||
import { NotificationInterface } from "../notifications/notification.interface";
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Socket } from 'socket.io';
|
||||
import { Repository } from 'typeorm';
|
||||
import { ClientConnectionDto } from './dto/clientConnection.dto';
|
||||
import { SocketConnection } from './socket.entity';
|
||||
|
||||
@Injectable()
|
||||
export class SocketService {
|
||||
constructor(
|
||||
@InjectModel(SocketModel)
|
||||
private socketModel: typeof SocketModel,
|
||||
) {
|
||||
@InjectRepository(SocketConnection)
|
||||
private socketConnectionRepository: Repository<SocketConnection>,
|
||||
) {}
|
||||
|
||||
async ClientConnection(data: ClientConnectionDto) {
|
||||
const client = this.socketConnectionRepository.create(data);
|
||||
await this.socketConnectionRepository.save(client);
|
||||
}
|
||||
|
||||
ClientConnection(data: any) {
|
||||
this.socketModel.create(data);
|
||||
}
|
||||
|
||||
sendNotificationToClients(server: Server, notificationData: NotificationInterface) {
|
||||
sendMessageToClients(clients: Socket[], data: any, event: string) {
|
||||
return new Promise(async (resolveHandlerSend) => {
|
||||
const connectedClients = server.sockets.sockets;
|
||||
let sent: boolean = false;
|
||||
|
||||
if (connectedClients.size === 0) {
|
||||
resolveHandlerSend({ status: 1, message: "Failed to find the clients!" });
|
||||
return;
|
||||
}
|
||||
|
||||
let sent: any = false;
|
||||
|
||||
for (const connectedClient of connectedClients) {
|
||||
if (connectedClient[1].handshake.auth.token == notificationData.telephone_id) {
|
||||
try {
|
||||
for (const client of clients) {
|
||||
sent = await new Promise((resolveSend) => {
|
||||
connectedClient[1].timeout(2000).emit("answer", JSON.stringify(notificationData), (err: any) => {
|
||||
if (err) {
|
||||
resolveSend(false);
|
||||
} else {
|
||||
resolveSend(true);
|
||||
}
|
||||
});
|
||||
client
|
||||
.timeout(2000)
|
||||
.emit(event, JSON.stringify(data), (err: any) => {
|
||||
if (err) {
|
||||
resolveSend(false);
|
||||
} else {
|
||||
resolveSend(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
resolveHandlerSend({
|
||||
status: 0,
|
||||
message: 'Failed to send to the clients!',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sent) {
|
||||
resolveHandlerSend({ status: 2, message: "Failed to send to the clients!" });
|
||||
resolveHandlerSend({
|
||||
status: 0,
|
||||
message: 'Failed to send to the clients!',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
resolveHandlerSend({ status: 0, message: "Success in sending to the clients!" });
|
||||
resolveHandlerSend({
|
||||
status: 1,
|
||||
message: 'Success in sending to the clients!',
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import * as request from 'supertest';
|
||||
import { AppModule } from './../src/app.module';
|
||||
|
||||
describe('AppController (e2e)', () => {
|
||||
let app: INestApplication;
|
||||
|
||||
beforeEach(async () => {
|
||||
const moduleFixture: TestingModule = await Test.createTestingModule({
|
||||
imports: [AppModule],
|
||||
}).compile();
|
||||
|
||||
app = moduleFixture.createNestApplication();
|
||||
await app.init();
|
||||
});
|
||||
|
||||
it('/ (GET)', () => {
|
||||
return request(app.getHttpServer())
|
||||
.get('/')
|
||||
.expect(200)
|
||||
.expect('Hello World!');
|
||||
});
|
||||
});
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"moduleFileExtensions": ["js", "json", "ts"],
|
||||
"rootDir": ".",
|
||||
"testEnvironment": "node",
|
||||
"testRegex": ".e2e-spec.ts$",
|
||||
"transform": {
|
||||
"^.+\\.(t|j)s$": "ts-jest"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user