Skip to content

Custom websocket#515

Open
MarhiievHE wants to merge 10 commits intometarhia:masterfrom
MarhiievHE:custom_websocket
Open

Custom websocket#515
MarhiievHE wants to merge 10 commits intometarhia:masterfrom
MarhiievHE:custom_websocket

Conversation

@MarhiievHE
Copy link
Member

#476

  • tests and linter show no problems (npm t)
  • tests are added/updated for bug fixes and new features
  • code is properly formatted (npm run fix)
  • description of changes is added in CHANGELOG.md
  • update .d.ts typings

lib/server.js Outdated

if (balancer) return;
this.wsServer = new ws.Server({ server: this.httpServer });
this.wsServer = new WebsocketServer(this.httpServer);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd propose to be compatible with ws:

Suggested change
this.wsServer = new WebsocketServer(this.httpServer);
this.wsServer = new WebsocketServer({ server: this.httpServer });

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment on lines +88 to +94
GOING_AWAY: {
reason: 'Going away',
buf: Buffer.from([
0x88, 0xc, 0x3, 0xe9, 0x47, 0x6f, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x77,
0x61, 0x79,
]),
},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's hold strings as ascii strings and all unprintable as hex, for example:

Suggested change
GOING_AWAY: {
reason: 'Going away',
buf: Buffer.from([
0x88, 0xc, 0x3, 0xe9, 0x47, 0x6f, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x77,
0x61, 0x79,
]),
},
GOING_AWAY: {
reason: 'Going away',
buf: Buffer.concat([
Buffer.from([0x88, 0x0c, 0x03, 0xe9]),
Buffer.from('Going away', 'utf8'),
]),
},

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

CLOSE_CODES,
TWO_32,
} = require('./constants');
const { Result } = require('./utils/result');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Always add extensions in require

Suggested change
const { Result } = require('./utils/result');
const { Result } = require('./utils/result.js');

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also done

Comment on lines +205 to +207
module.exports = {
Frame,
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
module.exports = {
Frame,
};
module.exports = { Frame };

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And it's done

Comment on lines +268 to +275
on(event, cb) {
if (event === 'open') this._openCb = cb;
else if (event === 'message') this._messageCb = (buf) => cb(buf);
else if (event === 'frame') this._frameCb = cb;
else if (event === 'ping') this._pingCb = (buf) => cb(buf);
else if (event === 'pong') this._pongCb = (buf) => cb(buf);
else if (event === 'close') this._closeCb = cb;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can just use EventEmitter

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that’s a good idea — much cleaner than mocking everything. Done

// Methods: send(data), sendFrame(opcode, payload, { fin=true, mask=true }),
// sendText, sendBinary, ping, close
class ProtocolClient {
constructor(url) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wery long constructor, maybe we can decompose, for example, extracting collection:
{ [opcode]: [handler] }

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, done

@@ -0,0 +1,35 @@
'use strict';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be moved to metautil

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I move the Result class to metautil, or do you think it would be better to introduce an algebraic data types?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, please find an issue there or just create new in metautil and PR

@tshemsedinov tshemsedinov changed the title WIP: Custom websocket Custom websocket Jan 8, 2026
@@ -0,0 +1,35 @@
'use strict';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, please find an issue there or just create new in metautil and PR

Comment on lines +162 to +171
this.emit(
'error',
new Error('Protocol error: Unexpected CONTINUATION without start'),
);
return void this.#close(
Frame.protocolErrorClose(
PROTOCOL_ERROR_SUBTYPES.COMMON,
this.#isClient,
),
);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use intermediate variables here and in other places

Suggested change
this.emit(
'error',
new Error('Protocol error: Unexpected CONTINUATION without start'),
);
return void this.#close(
Frame.protocolErrorClose(
PROTOCOL_ERROR_SUBTYPES.COMMON,
this.#isClient,
),
);
const error = new Error('Protocol error: Unexpected CONTINUATION without start');
this.emit('error', error);
const frame = Frame.protocolErrorClose(
PROTOCOL_ERROR_SUBTYPES.COMMON,
this.#isClient,
);
return void this.#close(frame);

static close(code = 1000, reason = '') {
if (code === null || code === undefined) {
const payload = Buffer.alloc(0);
return new this(true, OPCODES.CLOSE, false, payload, null);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return new this(true, OPCODES.CLOSE, false, payload, null);
return new Frame(true, OPCODES.CLOSE, false, payload, null);

Comment on lines +63 to +67
static emptyPingBuffer(isClient = false) {
const buf = isClient ? Buffer.from(CLIENT_EMPTY_PING) : EMPTY_PING;
if (isClient) crypto.randomBytes(4).copy(buf, 2);
return buf;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like we can preallocate this buffer to avoid calling method

} = require('./constants.js');
const { Result } = require('./utils/result.js');

class Frame {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Think about naming improvement for this class static methods, it looks like all those methods are factories, so createPong will be better and createCloseError will be better than errorClose

Comment on lines +6 to +13
const { Connection } = require('../../../lib/websocket/connection.js');
const { Frame } = require('../../../lib/websocket/frame.js');
const {
OPCODES,
CLOSE_TIMEOUT,
} = require('../../../lib/websocket/constants.js');
const { FrameParser } = require('../../../lib/websocket/frameParser.js');
const { MockSocket } = require('../utils/mockSocket.js');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Such long /../ constructions are not ok, let's find alternative way

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be better require('../../../metacom.js'); but I'll propose something better later, need a time to clone and check repo locally

omelchenko

This comment was marked as off-topic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants