rjweb-server
Version:
Easy and Robust Way to create a Web Server with Many Easy-to-use Features in NodeJS
210 lines (209 loc) • 5.78 kB
JavaScript
import Base from "./Base";
import parseContent from "../../functions/parseContent";
class WSConnect extends Base {
/**
* Initializes a new Instance of a Web Context
* @since 7.0.0
*/
constructor(controller, localContext, ws) {
super(controller, localContext);
/**
* The Type of this Request
* @since 5.7.0
*/
this.type = "connect";
this.rawWs = ws;
}
/**
* Close the Socket and send a Code + Message to the Client (automatically Formatted)
*
* This will instantly close the socket connection with a status code and
* message of choice, after calling and successfully closing the `.onClose()`
* callback will be called to finish the task.
* @example
* ```
* ctr.close(401, {
* message: 'this is json!'
* })
*
* // or
*
* ctr.close(401, 'this is text!')
* ```
* @since 5.4.0
*/
close(code, message) {
this.ctx.continueSend = false;
{
(async () => {
let result;
try {
result = await parseContent(message, false, this.ctg.logger);
} catch (err) {
this.ctx.handleError(err);
return true;
}
try {
this.rawWs.cork(() => this.rawWs.end(code, result.content));
} catch {
}
return true;
})();
}
return this;
}
/**
* Print a Message to the Client (automatically Formatted)
*
* This will send a new websocket message to the client as soon
* as the event loop allows it to execute the async task of parsing
* the message content.
* @example
* ```
* ctr.print({
* message: 'this is json!'
* })
*
* // or
*
* ctr.print('this is text!')
* ```
* @since 5.4.0
*/
print(message, options = {}) {
const prettify = options?.prettify ?? false;
{
(async () => {
let result;
try {
result = await parseContent(message, prettify, this.ctg.logger);
} catch (err) {
this.ctx.handleError(err);
return true;
}
try {
this.rawWs.cork(() => this.rawWs.send(result.content));
this.ctg.webSockets.messages.outgoing.increase();
this.ctg.data.outgoing.increase(result.content.byteLength);
} catch {
}
return true;
})();
}
return this;
}
/**
* Print a references value every time it changes
*
* This will print when the provided reference changes state similarly
* to the `.printStream()` method which listen to a streams `data` event.
* @example
* ```
* const ref = new Reference('Hello')
*
* ctr.printRef(ref)
*
* ref.set('Ok')
* ```
* @since 7.2.0
*/
printRef(reference, options = {}) {
const prettify = options?.prettify ?? false;
const ref = reference["onChange"](async (value) => {
let data;
try {
data = (await parseContent(value, prettify, this.ctg.logger)).content;
} catch (err) {
return this.ctx.handleError(err);
}
try {
this.rawWs.send(data);
this.ctg.webSockets.messages.outgoing.increase();
this.ctg.data.outgoing.increase(data.byteLength);
} catch {
}
});
this.ctx.refListeners.push({
ref: reference,
refListener: ref
});
return this;
}
/**
* Remove a reference subscription
*
* This will remove the listener of a reference from the
* current socket. May be slow when having many references
* attached to the socket.
* @example
* ```
* const ref = new Reference('Hello')
*
* ctr.printRef(ref)
*
* ref.set('Ok')
*
* ctr.removeRef(ref)
* ```
* @since 7.2.0
*/
removeRef(reference) {
const index = this.ctx.refListeners.findIndex(({ ref }) => Object.is(ref, reference));
if (index >= 0) {
reference["removeOnChange"](this.ctx.refListeners[index].refListener);
this.ctx.refListeners.splice(index, 1);
}
return this;
}
/**
* Print the `data` event of a Stream to the Client
*
* This will print the `data` event of a stream to the client
* in real time. This shouldnt be used over `.printRef()` but is
* useful when working with something like a `fs.ReadStream` for
* some reason.
* @example
* ```
* const fileStream = fs.createReadStream('./profile.png')
* ctr.printStream(fileStream)
* ```
* @since 5.4.0
*/
printStream(stream, options = {}) {
const prettify = options?.prettify ?? false;
const destroyAbort = options?.destroyAbort ?? true;
const destroyStream = () => {
stream.destroy();
};
const dataListener = async (data) => {
try {
data = (await parseContent(data, prettify, this.ctg.logger)).content;
} catch (err) {
return this.ctx.handleError(err);
}
try {
this.rawWs.send(data);
this.ctg.webSockets.messages.outgoing.increase();
this.ctg.data.outgoing.increase(data.byteLength);
} catch {
}
}, closeListener = () => {
if (destroyAbort)
this.ctx.events.unlist("requestAborted", destroyStream);
}, errorListener = (error) => {
this.ctx.handleError(error);
stream.removeListener("data", dataListener).removeListener("close", closeListener).removeListener("error", errorListener);
};
if (destroyAbort)
this.ctx.events.listen("requestAborted", destroyStream);
stream.on("data", dataListener).once("close", closeListener).once("error", errorListener);
this.ctx.events.listen(
"requestAborted",
() => stream.removeListener("data", dataListener).removeListener("close", closeListener).removeListener("error", errorListener)
);
return this;
}
}
export {
WSConnect as default
};