149 lines
3.8 KiB
TypeScript
149 lines
3.8 KiB
TypeScript
import { Server as SocketIOServer } from 'socket.io'
|
|
import http from 'node:http'
|
|
import LineConnection from '../app/services/line_connection.js'
|
|
import { ApplicationService } from '@adonisjs/core/types'
|
|
import env from '#start/env'
|
|
import { CustomServer, CustomSocket } from '../app/ultils/types.js'
|
|
|
|
interface Station {
|
|
id: number
|
|
name: string
|
|
ip: string
|
|
lines: any[]
|
|
}
|
|
|
|
export default class SocketIoProvider {
|
|
private static _io: CustomServer
|
|
constructor(protected app: ApplicationService) {}
|
|
|
|
/**
|
|
* Register bindings to the container
|
|
*/
|
|
register() {}
|
|
|
|
/**
|
|
* The container bindings have booted
|
|
*/
|
|
async boot() {}
|
|
|
|
/**
|
|
* The application has been booted
|
|
*/
|
|
async start() {}
|
|
|
|
/**
|
|
* The process has been started
|
|
*/
|
|
async ready() {
|
|
if (process.argv[1].includes('server.js')) {
|
|
const webSocket = new WebSocketIo(this.app)
|
|
SocketIoProvider._io = await webSocket.boot()
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Preparing to shutdown the app
|
|
*/
|
|
async shutdown() {}
|
|
|
|
public static get io() {
|
|
return this._io
|
|
}
|
|
}
|
|
|
|
export class WebSocketIo {
|
|
intervalMap: { [key: string]: NodeJS.Timeout } = {}
|
|
stationMap: Map<number, Station> = new Map()
|
|
lineMap: Map<number, LineConnection> = new Map() // key = lineId
|
|
|
|
constructor(protected app: ApplicationService) {}
|
|
|
|
async boot() {
|
|
const SOCKET_IO_PORT = env.get('SOCKET_PORT') || 8989
|
|
const FRONTEND_URL = env.get('FRONTEND_URL') || 'http://localhost:5173'
|
|
|
|
const socketServer = http.createServer()
|
|
const io = new SocketIOServer(socketServer, {
|
|
pingInterval: 25000, // 25s server gửi ping
|
|
pingTimeout: 20000, // chờ 20s không có pong thì disconnect
|
|
cors: {
|
|
origin: [FRONTEND_URL],
|
|
methods: ['GET', 'POST'],
|
|
credentials: true,
|
|
},
|
|
})
|
|
|
|
io.on('connection', (socket: CustomSocket) => {
|
|
console.log('Socket connected:', socket.id)
|
|
socket.connectionTime = new Date()
|
|
|
|
socket.on('disconnect', () => {
|
|
console.log(`🔴 FE disconnected: ${socket.id}`)
|
|
})
|
|
|
|
// FE gửi yêu cầu connect lines
|
|
socket.on('connect_lines', async (stationData: Station) => {
|
|
console.log('📡 Yêu cầu connect station:', stationData.name)
|
|
await this.connectStation(socket, stationData)
|
|
})
|
|
|
|
// FE gửi command đến line cụ thể
|
|
socket.on('send_command', (data) => {
|
|
const { lineId, command } = data
|
|
const line = this.lineMap.get(lineId)
|
|
if (line) {
|
|
line.sendCommand(command)
|
|
} else {
|
|
socket.emit('line_error', { lineId, error: 'Line not connected' })
|
|
}
|
|
})
|
|
|
|
// FE yêu cầu ngắt kết nối 1 station
|
|
socket.on('disconnect_station', (stationId) => {
|
|
this.disconnectStation(stationId)
|
|
})
|
|
})
|
|
|
|
socketServer.listen(SOCKET_IO_PORT, () => {
|
|
console.log(`Socket server is running on port ${SOCKET_IO_PORT}`)
|
|
})
|
|
|
|
return io
|
|
}
|
|
|
|
private async connectStation(socket, station: Station) {
|
|
this.stationMap.set(station.id, station)
|
|
for (const line of station.lines) {
|
|
const lineConn = new LineConnection(
|
|
{
|
|
id: line.id,
|
|
port: line.port,
|
|
ip: station.ip,
|
|
lineNumber: line.lineNumber,
|
|
stationId: station.id,
|
|
apcName: line.apcName,
|
|
},
|
|
this.io
|
|
)
|
|
await lineConn.connect()
|
|
this.lineMap.set(line.id, lineConn)
|
|
}
|
|
}
|
|
|
|
private disconnectStation(stationId: number) {
|
|
const station = this.stationMap.get(stationId)
|
|
if (!station) return
|
|
|
|
for (const line of station.lines) {
|
|
const conn = this.lineMap.get(line.id)
|
|
if (conn) {
|
|
conn.disconnect()
|
|
this.lineMap.delete(line.id)
|
|
}
|
|
}
|
|
|
|
this.stationMap.delete(stationId)
|
|
console.log(`🔻 Station ${station.name} disconnected`)
|
|
}
|
|
}
|