-
-
Notifications
You must be signed in to change notification settings - Fork 42
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WIP: Implement class Frame #477
base: master
Are you sure you want to change the base?
Conversation
lib/websocket.js
Outdated
this.#frame = Buffer.alloc(2); | ||
this.#frame[0] = 0x81; // FIN = 1, RSV = 0b000, opcode = 0b0001 (text frame) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this.#frame = Buffer.alloc(2); | |
this.#frame[0] = 0x81; // FIN = 1, RSV = 0b000, opcode = 0b0001 (text frame) | |
let meta = Buffer.alloc(2); | |
meta = 0x81; // FIN = 1, RSV = 0b000, opcode = 0b0001 (text frame) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better to name variables in a way that reflects their purpose, preserving code readability.
lib/websocket.js
Outdated
this.#frame[0] = 0x81; // FIN = 1, RSV = 0b000, opcode = 0b0001 (text frame) | ||
const length = data.length; | ||
if (length < LEN_16_BIT) { | ||
this.#frame[1] = length; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this.#frame[1] = length; | |
meta[1] = length; |
lib/websocket.js
Outdated
this.#frame[1] = LEN_16_BIT; | ||
this.#frame = Buffer.concat([this.#frame, len]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this.#frame[1] = LEN_16_BIT; | |
this.#frame = Buffer.concat([this.#frame, len]); | |
meta[1] = LEN_16_BIT; | |
meta = Buffer.concat([this.#frame, len]); |
lib/websocket.js
Outdated
this.#frame[1] = LEN_64_BIT; | ||
this.#frame = Buffer.concat([this.#frame, len]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this.#frame[1] = LEN_64_BIT; | |
this.#frame = Buffer.concat([this.#frame, len]); | |
meta[1] = LEN_64_BIT; | |
meta = Buffer.concat([this.#frame, len]); |
lib/websocket.js
Outdated
throw new Error('text value is too long to encode in one frame!'); | ||
} | ||
if (!this.#server) throw new Error('Unsupported'); | ||
this.#frame = Buffer.concat([this.#frame, data]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this.#frame = Buffer.concat([this.#frame, data]); | |
this.#frame = Buffer.concat([meta, data]); |
lib/websocket.js
Outdated
#server = false; | ||
|
||
constructor(data, options) { | ||
if (!Buffer.isBuffer(data) && typeof data !== 'string') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Always false. Because type of Buffer is object.
https://nodejs.org/dist/latest-v20.x/docs/api/buffer.html#static-method-bufferisbufferobj
> typeof Buffer.from('foo')
'object'
lib/websocket.js
Outdated
}; | ||
this.#server = opt.server; | ||
|
||
if (Buffer.isBuffer(data) && data.length !== 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Already checked isBuffer before
const xor = (cond1, cond2) => (cond1 || cond2) && !(cond1 && cond2); | ||
|
||
class Frame { | ||
#frame = null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#frame = null; | |
#data = null; |
lib/websocket.js
Outdated
#mask = null; | ||
#dataOffset = 6; | ||
#length = 0n; | ||
#server = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why server variable is required? The task was about refactoring, not about adding new features.
}; | ||
const xor = (cond1, cond2) => (cond1 || cond2) && !(cond1 && cond2); | ||
|
||
class Frame { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typically in a constructor you just assign some props for instance. Make some configuration. But you don't do some complex logic of how inputs should be mapped correctly to Frame class props. This is not the responsibility of the constructor. So we can create from
method that will take this responsibility. See in the example below. Also we should not handle encode or decode logic in constructor. Because when you create frame with string or buffer there is no difference. new Frame('1234')
and new Frame(buffer)
. Code becomes implicit and less readable. Instead you can do Frame.from(data).decode()
and Frame.from(data).decode()
. This makes clear what happens in this code. See in the example below. So, please use interface described in example below.
class Frame {
#buffer = null
constructor(buffer) {
this.#buffer = buffer
}
encode() {
...
}
decode() {
...
}
static from(data) {
if (Buffer.isBuffer(data)) {
return new Frame(data)
}
if (typeof data === 'string') {
return new Frame(Buffer.from(data))
}
throw new Error('Unsupported')
}
}
// USAGE
send(text) {
const frame = Frame.from(text).encode()
this.socket.write(frame.data);
}
receive(data) {
console.log('data: ', data[0], data.length);
if (data[0] !== OPCODE_SHORT) return;
const frame = Frame.from(data).decode()
const text = frame.toString();
this.send(`Echo "${text}"`);
console.log('Message:', text);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, with the factory, yeah, that's probably better. But creating a text frame of a protocol from a string and just saving the finished frame in a class field is not the same action. Then it is probably better to just accept a ready frame by constructor and create a protocol frame from input data by static method. Thanks.
Some tests failed |
These tests don't check the code I wrote. |
}; | ||
constructor(frame) { | ||
this.#frame = frame; | ||
const length = this.#frame[1] & 0x7f; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like new Frame()
will return error.
Uncaught TypeError: Cannot read properties of undefined (reading '1')
Is it ok here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because it doesn't have to work that way, pass a reference to the buffer with WebSocket frame to the constructor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or use static method 'from()' to create new instance
#473
npm t
)npm run fmt
)