mirror of
https://github.com/Qortal/Qortal-Hub.git
synced 2025-07-29 21:21:24 +00:00
fix parser
This commit is contained in:
@@ -33,7 +33,6 @@ function sbrk(size: number) {
|
||||
}
|
||||
|
||||
function processWaitingQueue() {
|
||||
console.log('Processing waiting queue...');
|
||||
let i = 0;
|
||||
while (i < waitingQueue.length) {
|
||||
const request = waitingQueue[i];
|
||||
@@ -98,25 +97,35 @@ function resetMemory() {
|
||||
}
|
||||
|
||||
function parseMessage(buffer: Buffer) {
|
||||
if (buffer.length < 17) return null;
|
||||
if (buffer.subarray(0, 4).toString('ascii') !== 'QORT') return null;
|
||||
const magic = buffer.subarray(0, 4).toString('ascii');
|
||||
if (magic !== 'QORT') return null;
|
||||
|
||||
const messageType = buffer.readUInt32BE(4);
|
||||
const payloadLength = buffer.readUInt32BE(9);
|
||||
const checksum = buffer.subarray(13, 17);
|
||||
const payload = buffer.subarray(17, 17 + payloadLength);
|
||||
const type = buffer.readUInt32BE(4); // bytes 4–7
|
||||
const hasId = buffer.readUInt8(8); // byte 8
|
||||
|
||||
const expectedChecksum = crypto
|
||||
.createHash('sha256')
|
||||
.update(payload)
|
||||
.digest()
|
||||
.subarray(0, 4);
|
||||
if (!checksum.equals(expectedChecksum)) return null;
|
||||
let offset = 9;
|
||||
let id = -1;
|
||||
if (hasId) {
|
||||
id = buffer.readUInt32BE(offset);
|
||||
offset += 4;
|
||||
}
|
||||
|
||||
const payloadLength = buffer.readUInt32BE(offset);
|
||||
offset += 4;
|
||||
|
||||
const checksum = buffer.subarray(offset, offset + 4);
|
||||
offset += 4;
|
||||
|
||||
const payload = buffer.subarray(offset, offset + payloadLength);
|
||||
offset += payloadLength;
|
||||
|
||||
const totalLength = offset;
|
||||
|
||||
return {
|
||||
messageType,
|
||||
messageType: type,
|
||||
id,
|
||||
payload,
|
||||
totalLength: 17 + payloadLength,
|
||||
totalLength,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -142,19 +151,37 @@ function createChallengePayload(
|
||||
return Buffer.concat([Buffer.from(publicKey), Buffer.from(challenge)]);
|
||||
}
|
||||
|
||||
function encodeFramedMessage(type: number, payload: Buffer): Buffer {
|
||||
const header = Buffer.from('QORT');
|
||||
function encodeFramedMessage(
|
||||
type: number,
|
||||
payload: Buffer,
|
||||
id: number
|
||||
): Buffer {
|
||||
const header = Buffer.from('QORT', 'ascii');
|
||||
const typeBuf = Buffer.alloc(4);
|
||||
typeBuf.writeUInt32BE(type);
|
||||
const hasId = Buffer.from([0]);
|
||||
|
||||
const hasId = Buffer.from([1]);
|
||||
const idBuf = Buffer.alloc(4);
|
||||
idBuf.writeUInt32BE(id);
|
||||
|
||||
const length = Buffer.alloc(4);
|
||||
length.writeUInt32BE(payload.length);
|
||||
|
||||
const checksum = crypto
|
||||
.createHash('sha256')
|
||||
.update(payload)
|
||||
.digest()
|
||||
.subarray(0, 4);
|
||||
return Buffer.concat([header, typeBuf, hasId, length, checksum, payload]);
|
||||
|
||||
return Buffer.concat([
|
||||
header,
|
||||
typeBuf,
|
||||
hasId,
|
||||
idBuf,
|
||||
length,
|
||||
checksum,
|
||||
payload,
|
||||
]);
|
||||
}
|
||||
|
||||
function ed25519ToX25519Private(edSeed: Uint8Array): Uint8Array {
|
||||
@@ -183,9 +210,15 @@ export class LiteNodeClient {
|
||||
private theirXPublicKey: Uint8Array | null = null;
|
||||
private theirChallenge: Uint8Array | null = null;
|
||||
private ourChallenge = crypto.randomBytes(32);
|
||||
private pingInterval: NodeJS.Timeout | null = null;
|
||||
private pendingPingIds = new Set<number>();
|
||||
|
||||
private alreadyResponded = false;
|
||||
|
||||
private messageQueue: Buffer[] = [];
|
||||
private isSending: boolean = false;
|
||||
private nextMessageId: number = 1;
|
||||
|
||||
constructor(
|
||||
private host: string,
|
||||
private port: number = 12392
|
||||
@@ -296,14 +329,37 @@ export class LiteNodeClient {
|
||||
|
||||
private async handleResponse(payload: Buffer) {
|
||||
this.startPinging();
|
||||
const nonce = payload.readUInt32BE(0);
|
||||
const responseHash = payload.subarray(4, 36);
|
||||
console.log('📩 Received RESPONSE from core:');
|
||||
console.log(' Nonce:', nonce);
|
||||
console.log(' Hash:', responseHash.toString('hex'));
|
||||
resetMemory();
|
||||
}
|
||||
|
||||
private lastHandledPingIds = new Set<number>();
|
||||
|
||||
private handlePing(id: number) {
|
||||
if (this.pendingPingIds.has(id)) {
|
||||
// This is a reply to our ping — success.
|
||||
this.pendingPingIds.delete(id);
|
||||
console.log('✅ Received PING reply for ID', id);
|
||||
return;
|
||||
}
|
||||
if (this.lastHandledPingIds.has(id)) {
|
||||
return; // Already replied to this ping
|
||||
}
|
||||
|
||||
const reply = encodeFramedMessage(
|
||||
MessageType.PING,
|
||||
Buffer.from([0x00]), // Required non-empty payload
|
||||
id
|
||||
);
|
||||
this.messageQueue.push(reply);
|
||||
this.flushMessageQueue();
|
||||
|
||||
this.lastHandledPingIds.add(id);
|
||||
console.log('🔁 Replied to PING with ID', id);
|
||||
|
||||
// Optionally clean up old IDs to avoid memory leak
|
||||
if (this.lastHandledPingIds.size > 1000) {
|
||||
this.lastHandledPingIds.clear();
|
||||
}
|
||||
}
|
||||
async connect(): Promise<void> {
|
||||
await this.init();
|
||||
|
||||
@@ -312,19 +368,20 @@ export class LiteNodeClient {
|
||||
{ host: this.host, port: this.port },
|
||||
() => {
|
||||
console.log(`✅ Connected to ${this.host}:${this.port}`);
|
||||
const helloPayload = createHelloPayload();
|
||||
this.sendMessage(MessageType.HELLO, helloPayload);
|
||||
this.sendMessage(MessageType.HELLO, createHelloPayload());
|
||||
|
||||
resolve();
|
||||
}
|
||||
);
|
||||
|
||||
this.socket.on('data', (data: Buffer) => {
|
||||
// console.log('📦 Raw data:', data.toString('hex'));
|
||||
this.buffer = Buffer.concat([this.buffer, data]);
|
||||
while (this.buffer.length >= 17) {
|
||||
while (true) {
|
||||
const parsed = parseMessage(this.buffer);
|
||||
if (!parsed) break;
|
||||
|
||||
const { messageType, payload, totalLength } = parsed;
|
||||
const { messageType, payload, totalLength, id } = parsed;
|
||||
this.buffer = this.buffer.subarray(totalLength);
|
||||
|
||||
switch (messageType) {
|
||||
@@ -340,6 +397,9 @@ export class LiteNodeClient {
|
||||
case MessageType.RESPONSE:
|
||||
this.handleResponse(payload);
|
||||
break;
|
||||
case MessageType.PING:
|
||||
this.handlePing(id);
|
||||
break;
|
||||
default:
|
||||
console.warn(`⚠️ Unhandled message type: ${messageType}`);
|
||||
}
|
||||
@@ -356,20 +416,58 @@ export class LiteNodeClient {
|
||||
});
|
||||
}
|
||||
|
||||
sendMessage(type: MessageType, payload: Buffer) {
|
||||
if (!this.socket) throw new Error('Socket not connected');
|
||||
const framed = encodeFramedMessage(type, payload);
|
||||
this.socket.write(framed);
|
||||
private flushMessageQueue() {
|
||||
if (
|
||||
this.isSending ||
|
||||
!this.socket ||
|
||||
this.socket.destroyed ||
|
||||
!this.socket.writable
|
||||
)
|
||||
return;
|
||||
|
||||
while (this.messageQueue.length > 0) {
|
||||
const message = this.messageQueue[0];
|
||||
const flushed = this.socket.write(message);
|
||||
if (!flushed) {
|
||||
this.isSending = true;
|
||||
this.socket.once('drain', () => {
|
||||
this.isSending = false;
|
||||
this.flushMessageQueue();
|
||||
});
|
||||
break;
|
||||
}
|
||||
this.messageQueue.shift();
|
||||
}
|
||||
}
|
||||
|
||||
private sendMessage(type: MessageType, payload: Buffer, id?: number) {
|
||||
const messageId = id ?? this.nextMessageId++;
|
||||
const framed = encodeFramedMessage(type, payload, messageId);
|
||||
console.log('🔐 Response hash:', framed.toString('hex'));
|
||||
this.messageQueue.push(framed);
|
||||
this.flushMessageQueue();
|
||||
}
|
||||
|
||||
startPinging(intervalMs: number = 5000) {
|
||||
setInterval(() => {
|
||||
try {
|
||||
this.sendMessage(MessageType.PING, Buffer.alloc(0));
|
||||
console.log('📡 Sent PING');
|
||||
} catch (err) {
|
||||
console.error('❌ Failed to send PING:', err);
|
||||
if (this.pingInterval) clearInterval(this.pingInterval);
|
||||
|
||||
this.pingInterval = setInterval(() => {
|
||||
if (!this.socket || this.socket.destroyed) {
|
||||
console.warn('⚠️ Skipping PING: socket not connected');
|
||||
return;
|
||||
}
|
||||
|
||||
const id = this.nextMessageId++;
|
||||
this.pendingPingIds.add(id);
|
||||
const pingMessage = encodeFramedMessage(
|
||||
MessageType.PING,
|
||||
Buffer.from([0x00]),
|
||||
id
|
||||
);
|
||||
this.messageQueue.push(pingMessage);
|
||||
this.flushMessageQueue();
|
||||
|
||||
console.log('📡 Sent PING with ID', id);
|
||||
}, intervalMs);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user