135 lines
3.6 KiB
TypeScript
135 lines
3.6 KiB
TypeScript
import net from 'node:net'
|
|
import { cleanData } from '../ultils/helper.js'
|
|
|
|
interface LineConfig {
|
|
id: number
|
|
port: number
|
|
lineNumber: number
|
|
ip: string
|
|
stationId: number
|
|
apcName?: string
|
|
output: string
|
|
status: string
|
|
}
|
|
|
|
export default class LineConnection {
|
|
public client: net.Socket
|
|
public readonly config: LineConfig
|
|
public readonly socketIO: any
|
|
|
|
constructor(config: LineConfig, socketIO: any) {
|
|
this.config = config
|
|
this.socketIO = socketIO
|
|
this.client = new net.Socket()
|
|
}
|
|
|
|
connect(timeoutMs = 5000) {
|
|
return new Promise<void>((resolve, reject) => {
|
|
const { ip, port, lineNumber, id, stationId } = this.config
|
|
let resolvedOrRejected = false
|
|
// Set timeout
|
|
this.client.setTimeout(timeoutMs)
|
|
|
|
this.client.connect(port, ip, () => {
|
|
if (resolvedOrRejected) return
|
|
resolvedOrRejected = true
|
|
|
|
console.log(`✅ Connected to line ${lineNumber} (${ip}:${port})`)
|
|
this.config.status = 'connected'
|
|
this.socketIO.emit('line_connected', {
|
|
stationId,
|
|
lineId: id,
|
|
lineNumber,
|
|
status: 'connected',
|
|
})
|
|
resolve()
|
|
})
|
|
|
|
this.client.on('data', (data) => {
|
|
let message = data.toString()
|
|
// let output = cleanData(message)
|
|
// console.log(`📨 [${this.config.port}] ${message}`)
|
|
// Handle netOutput with backspace support
|
|
for (const char of message) {
|
|
if (char === '\x7F' || char === '\x08') {
|
|
this.config.output = this.config.output.slice(0, -1)
|
|
// message = message.slice(0, -1)
|
|
} else {
|
|
this.config.output += cleanData(char)
|
|
}
|
|
}
|
|
this.config.output = this.config.output.slice(-15000)
|
|
this.socketIO.emit('line_output', {
|
|
stationId,
|
|
lineId: id,
|
|
data: message,
|
|
})
|
|
})
|
|
|
|
this.client.on('error', (err) => {
|
|
if (resolvedOrRejected) return
|
|
resolvedOrRejected = true
|
|
console.error(`❌ Error line ${lineNumber}:`, err.message)
|
|
this.config.output += err.message
|
|
this.socketIO.emit('line_error', {
|
|
stationId,
|
|
lineId: id,
|
|
error: err.message,
|
|
})
|
|
reject(err)
|
|
})
|
|
|
|
this.client.on('close', () => {
|
|
console.log(`🔌 Line ${lineNumber} disconnected`)
|
|
this.config.status = 'disconnected'
|
|
this.socketIO.emit('line_disconnected', {
|
|
stationId,
|
|
lineId: id,
|
|
lineNumber,
|
|
status: 'disconnected',
|
|
})
|
|
})
|
|
|
|
this.client.on('timeout', () => {
|
|
if (resolvedOrRejected) return
|
|
resolvedOrRejected = true
|
|
|
|
console.log(`⏳ Connection timeout line ${lineNumber}`)
|
|
this.client.destroy()
|
|
reject(new Error('Connection timeout'))
|
|
})
|
|
})
|
|
}
|
|
|
|
sendCommand(cmd: string) {
|
|
if (this.client.destroyed) {
|
|
console.log(`⚠️ Cannot send, line ${this.config.lineNumber} is closed`)
|
|
return
|
|
}
|
|
// console.log(`➡️ [${this.config.apcName}] SEND:`, cmd)
|
|
this.client.write(`${cmd}\r\n`)
|
|
}
|
|
|
|
writeCommand(cmd: string) {
|
|
if (this.client.destroyed) {
|
|
console.log(`⚠️ Cannot send, line ${this.config.lineNumber} is closed`)
|
|
return
|
|
}
|
|
this.client.write(`${cmd}`)
|
|
}
|
|
|
|
disconnect() {
|
|
try {
|
|
this.client.destroy()
|
|
this.config.status = 'disconnected'
|
|
this.socketIO.emit('line_disconnected', {
|
|
...this.config,
|
|
status: 'disconnected',
|
|
})
|
|
console.log(`🔻 Closed connection to line ${this.config.lineNumber}`)
|
|
} catch (e) {
|
|
console.error('Error closing line:', e)
|
|
}
|
|
}
|
|
}
|