Working fix for socket read for large response. Going to try another fix.

This commit is contained in:
Daniel Scalzi 2020-08-27 20:45:11 -04:00
parent 3838729da7
commit 27f95235f8
No known key found for this signature in database
GPG Key ID: D18EA3FB4B142A57

View File

@ -124,6 +124,10 @@ class ClientBoundPacket {
this.buffer = [...buffer] this.buffer = [...buffer]
} }
public append(buffer: Buffer): void {
this.buffer.push(...buffer)
}
public readByte(): number { public readByte(): number {
return this.buffer.shift()! return this.buffer.shift()!
} }
@ -169,6 +173,18 @@ class ClientBoundPacket {
} }
export function getVarIntSize(value: number): number {
let size = 0
do {
value >>>= 7
size++
} while (value != 0)
return size
}
/** /**
* Get the handshake packet. * Get the handshake packet.
* *
@ -201,6 +217,15 @@ function getRequestPacket(): Buffer {
.toBuffer() .toBuffer()
} }
function unifyStatusResponse(resp: ServerStatus): ServerStatus {
if(typeof resp.description === 'string') {
resp.description = {
text: resp.description
}
}
return resp
}
export function getServerStatus(protocol: number, address: string, port = 25565): Promise<ServerStatus | null> { export function getServerStatus(protocol: number, address: string, port = 25565): Promise<ServerStatus | null> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -210,19 +235,41 @@ export function getServerStatus(protocol: number, address: string, port = 25565)
socket.write(getRequestPacket()) socket.write(getRequestPacket())
}) })
socket.setTimeout(2500, () => { socket.setTimeout(10000, () => {
socket.destroy() socket.destroy()
logger.error(`Server Status Socket timed out (${address}:${port})`) logger.error(`Server Status Socket timed out (${address}:${port})`)
reject(new Error(`Server Status Socket timed out (${address}:${port})`)) reject(new Error(`Server Status Socket timed out (${address}:${port})`))
}) })
const maxTries = 2
let iterations = 0
let inboundPacket!: ClientBoundPacket
let packetLength = 0
let bytesLeft = -1
socket.on('data', (data) => { socket.on('data', (data) => {
const inboundPacket = new ClientBoundPacket(data) if(iterations > maxTries) {
socket.destroy()
reject(new Error(`Data read from ${address}:${port} exceeded ${maxTries} iterations, closing connection.`))
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars let doAppend = true
const packetLength = inboundPacket.readVarInt() // First VarInt is packet length.
const packetType = inboundPacket.readVarInt() // Second VarInt is packet type. // First delivery
if(bytesLeft == -1) {
inboundPacket = new ClientBoundPacket(data)
// First VarInt is packet length.
// Length of Packet ID + Data
packetLength = inboundPacket.readVarInt()
// Second VarInt is packet type.
const packetType = inboundPacket.readVarInt()
console.log(packetType, packetLength)
if(packetType !== 0x00) { if(packetType !== 0x00) {
// TODO // TODO
@ -231,10 +278,39 @@ export function getServerStatus(protocol: number, address: string, port = 25565)
return return
} }
const res = inboundPacket.readString() // Remainder of Buffer is the server status json. bytesLeft = packetLength + getVarIntSize(packetLength)
doAppend = false
}
if(bytesLeft > 0) {
++iterations
bytesLeft -= data.length
if(doAppend) {
inboundPacket.append(data)
}
console.log(bytesLeft, data.toString('utf-8'))
}
if(bytesLeft === 0) {
// Remainder of Buffer is the server status json.
const result = inboundPacket.readString()
try {
const parsed = JSON.parse(result)
socket.end() socket.end()
resolve(JSON.parse(res)) resolve(unifyStatusResponse(parsed))
} catch(err) {
socket.destroy()
logger.error('Failed to parse server status JSON', err)
console.log(result)
reject(new Error('Failed to parse server status JSON'))
}
}
}) })
socket.on('error', (err: NodeJS.ErrnoException) => { socket.on('error', (err: NodeJS.ErrnoException) => {
@ -251,7 +327,7 @@ export function getServerStatus(protocol: number, address: string, port = 25565)
resolve(null) resolve(null)
return return
} else { } else {
logger.error(`Error trying to pull server status (${address}:${port}})`, err) logger.error(`Error trying to pull server status (${address}:${port})`, err)
resolve(null) resolve(null)
return return
} }