Skip to content

Commit

Permalink
Merge branch 'master' into node21
Browse files Browse the repository at this point in the history
  • Loading branch information
tshemsedinov authored Oct 30, 2023
2 parents ee0857a + 73272f9 commit 3978b43
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 4 deletions.
3 changes: 3 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,8 @@
},
"parserOptions": {
"ecmaVersion": "latest"
},
"globals": {
"BigInt": true
}
}
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## [Unreleased][unreleased]

## [3.1.2][] - 2023-10-22

- Fix: proc timeout reached error detection

## [3.1.1][] - 2023-10-09

- Fix: do not serve API over http and ws on balancing port
Expand Down Expand Up @@ -249,7 +253,8 @@ Module stub v0.0.0 and all before 1.0.0 are experiments with syntactic and
binary structures and multiple different ideas originated from JSTP and old
protocols like USP and CLEAR.

[unreleased]: https://github.com/metarhia/metacom/compare/v3.1.1...HEAD
[unreleased]: https://github.com/metarhia/metacom/compare/v3.1.2...HEAD
[3.1.2]: https://github.com/metarhia/metacom/compare/v3.1.1...v3.1.2
[3.1.1]: https://github.com/metarhia/metacom/compare/v3.1.0...v3.1.1
[3.1.0]: https://github.com/metarhia/metacom/compare/v3.0.6...v3.1.0
[3.0.6]: https://github.com/metarhia/metacom/compare/v3.0.5...v3.0.6
Expand Down
98 changes: 98 additions & 0 deletions lib/websocket.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
'use strict';

const crypto = require('node:crypto');

const EOL = '\r\n';
const UPGRADE = [
'HTTP/1.1 101 Switching Protocols',
'Upgrade: websocket',
'Connection: Upgrade',
].join(EOL);
const MAGIC = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
const MASK_LENGTH = 4;
const PING_TIMEOUT = 5000;
const PING = Buffer.from([0x89, 0]);
const OPCODE_SHORT = 0x81;
const LEN_16_BIT = 126;
const MAX_16_BIT = 65536;
const LEN_64_BIT = 127;

const acceptKey = (key) => {
const hash = crypto.createHash('sha1');
hash.update(key + MAGIC);
return hash.digest('base64');
};

const calcOffset = (frame, length) => {
if (length < LEN_16_BIT) return [2, 6];
if (length === LEN_16_BIT) return [4, 8];
return [10, 14];
};

const parseFrame = (frame) => {
const length = frame[1] ^ 0x80;
const [maskOffset, dataOffset] = calcOffset(frame, length);
const mask = frame.subarray(maskOffset, maskOffset + MASK_LENGTH);
const data = frame.subarray(dataOffset);
return { mask, data };
};

const sendMessage = (socket, text) => {
const data = Buffer.from(text);
let meta = Buffer.alloc(2);
const length = data.length;
meta[0] = OPCODE_SHORT;
if (length < LEN_16_BIT) {
meta[1] = length;
} else if (length < MAX_16_BIT) {
const len = Buffer.from([(length & 0xff00) >> 8, length & 0x00ff]);
meta = Buffer.concat([meta, len]);
meta[1] = LEN_16_BIT;
} else {
const len = Buffer.alloc(8);
len.writeBigInt64BE(BigInt(length), 0);
meta = Buffer.concat([meta, len]);
meta[1] = LEN_64_BIT;
}
const frame = Buffer.concat([meta, data]);
socket.write(frame);
};

const unmask = (buffer, mask) => {
const data = Buffer.allocUnsafe(buffer.length);
buffer.copy(data);
for (let i = 0; i < data.length; i++) {
data[i] ^= mask[i & 3];
}
return data;
};

const init = (server) => {
server.on('upgrade', (req, socket, head) => {
const receive = (data) => {
if (data[0] !== OPCODE_SHORT) return;
const frame = parseFrame(data);
const msg = unmask(frame.data, frame.mask);
const text = msg.toString();
sendMessage(socket, `Echo "${text}"`);
};

const key = req.headers['sec-websocket-key'];
const accept = acceptKey(key);
const packet = UPGRADE + EOL + `Sec-WebSocket-Accept: ${accept}`;
socket.write(packet + EOL + EOL);
receive(head);

socket.on('data', receive);

socket.on('error', (error) => {
console.log(error.code);
});

setInterval(() => {
socket.write(PING);
}, PING_TIMEOUT);
});
};

module.exports = { init };
13 changes: 11 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "metacom",
"version": "3.1.1",
"version": "3.1.2",
"author": "Timur Shemsedinov <[email protected]>",
"description": "Communication protocol for Metarhia stack with rpc, events, binary streams, memory and db access",
"license": "MIT",
Expand Down

0 comments on commit 3978b43

Please sign in to comment.