diff --git a/package-lock.json b/package-lock.json index 1e39b567..cbee787b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "vscode-objectscript", - "version": "2.10.2-SNAPSHOT", + "version": "2.10.4-SNAPSHOT", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "vscode-objectscript", - "version": "2.10.2-SNAPSHOT", + "version": "2.10.4-SNAPSHOT", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -21,7 +21,7 @@ "node-fetch-cjs": "3.1.1", "vscode-cache": "^0.3.0", "vscode-extension-telemetry": "^0.1.6", - "ws": "^7.4.6" + "ws": "^8.14.2" }, "devDependencies": { "@types/glob": "^7.1.2", @@ -29,7 +29,7 @@ "@types/mocha": "^7.0.2", "@types/node": "^14.18.0", "@types/vscode": "1.75.0", - "@types/ws": "^7.2.5", + "@types/ws": "8.5.4", "@types/xmldom": "^0.1.29", "@typescript-eslint/eslint-plugin": "^4.32.0", "@typescript-eslint/parser": "^4.32.0", @@ -426,9 +426,9 @@ "dev": true }, "node_modules/@types/ws": { - "version": "7.4.7", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", - "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", + "version": "8.5.4", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", + "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==", "dev": true, "dependencies": { "@types/node": "*" @@ -5214,15 +5214,15 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "node_modules/ws": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.6.tgz", - "integrity": "sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA==", + "version": "8.14.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", + "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", "engines": { - "node": ">=8.3.0" + "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -5618,9 +5618,9 @@ "dev": true }, "@types/ws": { - "version": "7.4.7", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", - "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", + "version": "8.5.4", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", + "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==", "dev": true, "requires": { "@types/node": "*" @@ -9146,9 +9146,9 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "ws": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.6.tgz", - "integrity": "sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA==", + "version": "8.14.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", + "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", "requires": {} }, "y18n": { diff --git a/package.json b/package.json index b124a973..ca9f6fa3 100644 --- a/package.json +++ b/package.json @@ -1685,7 +1685,7 @@ "@types/mocha": "^7.0.2", "@types/node": "^14.18.0", "@types/vscode": "1.75.0", - "@types/ws": "^7.2.5", + "@types/ws": "8.5.4", "@types/xmldom": "^0.1.29", "@typescript-eslint/eslint-plugin": "^4.32.0", "@typescript-eslint/parser": "^4.32.0", @@ -1720,6 +1720,6 @@ "@vscode/debugadapter": "^1.61.0", "@vscode/debugprotocol": "^1.61.0", "vscode-extension-telemetry": "^0.1.6", - "ws": "^7.4.6" + "ws": "^8.14.2" } } diff --git a/src/debug/dbgp.ts b/src/debug/dbgp.ts index 0ff09345..2cb047bb 100644 --- a/src/debug/dbgp.ts +++ b/src/debug/dbgp.ts @@ -20,6 +20,8 @@ export class DbgpConnection extends EventEmitter { private _chunks: Buffer[]; private _dataLength: number; private _parser: DOMParser; + private _messages: Buffer[] = []; + private _processingMessages = false; public constructor(socket: WebSocket) { super(); @@ -27,7 +29,14 @@ export class DbgpConnection extends EventEmitter { this._parsingState = ParsingState.DataLength; this._chunksDataLength = 0; this._chunks = []; - socket.on("message", (data: string): void => this._handleDataChunk(Buffer.from(data))); + socket.on("message", (data: string): void => { + this._messages.push(Buffer.from(data)); + if (!this._processingMessages) { + this._processingMessages = true; + this._handleDataChunk(); + this._processingMessages = false; + } + }); socket.on("error", (error: Error): boolean => this.emit("error", error)); socket.on("close", (): boolean => this.emit("close")); this._parser = new DOMParser({ @@ -61,7 +70,9 @@ export class DbgpConnection extends EventEmitter { }); } - private _handleDataChunk(data: Buffer) { + private _handleDataChunk() { + if (!this._messages.length) return; // Shouldn't ever happen + const data: Buffer = this._messages.shift(); if (this._parsingState === ParsingState.DataLength) { // does data contain a NULL byte? const separatorIndex = data.indexOf("|"); @@ -80,11 +91,13 @@ export class DbgpConnection extends EventEmitter { if (data.length > separatorIndex + 1) { // handle the rest of the packet as part of the response const rest = data.slice(separatorIndex + 1, this._dataLength + separatorIndex + 1); - this._handleDataChunk(rest); + this._messages.unshift(rest); + this._handleDataChunk(); // more then one data chunk in one message const restData = data.slice(this._dataLength + separatorIndex + 1); if (restData.length) { - this._handleDataChunk(restData); + this._messages.unshift(restData); + this._handleDataChunk(); } } } else { @@ -99,7 +112,7 @@ export class DbgpConnection extends EventEmitter { // append the last piece of the response const lastResponsePiece = data.slice(0, this._dataLength - this._chunksDataLength); this._chunks.push(lastResponsePiece); - this._chunksDataLength += data.length; + this._chunksDataLength += lastResponsePiece.length; const response = Buffer.concat(this._chunks, this._chunksDataLength).toString("ascii"); // call response handler const xml = iconv.decode(Buffer.from(response, "base64"), ENCODING); @@ -110,11 +123,12 @@ export class DbgpConnection extends EventEmitter { this._chunksDataLength = 0; // switch to data length parsing state this._parsingState = ParsingState.DataLength; - // if data contains more info (except the NULL byte) - if (data.length > lastResponsePiece.length + 1) { - // handle the rest of the packet (after the NULL byte) as data length - const rest = data.slice(lastResponsePiece.length + 1); - this._handleDataChunk(rest); + // if data contains more info + if (data.length > lastResponsePiece.length) { + // handle the rest of the packet as data length + const rest = data.slice(lastResponsePiece.length); + this._messages.unshift(rest); + this._handleDataChunk(); } } else { // NO -> this is not the whole response yet. We buffer it and wait for the next data event. @@ -122,5 +136,6 @@ export class DbgpConnection extends EventEmitter { this._chunksDataLength += data.length; } } + while (this._messages.length) this._handleDataChunk(); } }