This commit is contained in:
Amirhossein Mahmoodi
2024-07-29 16:03:34 +03:30
parent 0ad17d2c8c
commit d09567d9d5
19 changed files with 9443 additions and 194 deletions

View File

@@ -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 {}

View File

@@ -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();

View File

@@ -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);
}
}
}

View File

@@ -1,5 +0,0 @@
export class NotificationInterface {
call_id: number;
telephone_id: string;
phone_number: string;
}

View File

@@ -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',
});
}
}
}

View File

@@ -0,0 +1,6 @@
export class ClientConnectionDto {
client_id: string;
socket_id: string;
event: string;
description?: string;
}

View File

@@ -0,0 +1,5 @@
export class SendMessageDto {
auth: string[];
data: any;
event: string;
}

View 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;
}

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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 {}

View File

@@ -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!',
});
});
}
}