rjweb-server
Version:
Easy and Robust Way to create a Web Server with Many Easy-to-use Features in NodeJS
178 lines (177 loc) • 5.67 kB
JavaScript
import Route from "../Route";
import RateLimit from "./RateLimit";
import { as, object } from "@rjweb/utils";
export default class Ws {
/**
* Create a new HTTP Route Builder
* @since 7.0.0
*/ constructor(path, ratelimit) {
this.route = new Route('ws', 'GET', path, {});
if (ratelimit)
this.route.ratelimit = ratelimit;
}
/**
* Add OpenAPI Documentation to all HTTP Endpoints in this Path (and all children)
* @since 9.0.0
*/ document(item) {
this.route.openApi = object.deepMerge(this.route.openApi, item);
return this;
}
/**
* Add a Ratelimit to this Endpoint
*
* When a User requests this Endpoint, that will count against their hit count, if
* the hits exceeds the `<maxHits>` in `<timeWindow>ms`, they wont be able to access
* the route for `<penalty>ms`.
* @example
* ```
* import { time } from "@rjweb/utils"
* const server = new Server(...)
*
* server.path('/', (path) => path
* .ws('/hello', (ws) => ws
* .ratelimit((limit) => limit
* .hits(5)
* .timeWindow(time(20).s())
* .penalty(0)
* ) // This will allow 5 messages every 20 seconds
* .onOpen((ctr) => {
* ctr.print('Hello bro!')
* })
* .onMessage((ctr) => {
* ctr.print('Nice bro!')
* })
* .onClose((ctr) => {
* console.log('Bye bro!')
* })
* )
* )
*
* server.rateLimit('wsMessage', (ctr) => {
* ctr.print(`Please wait ${ctr.getRateLimit()?.resetIn}ms!!!!!`)
* })
* ```
* @since 8.6.0
*/ ratelimit(callback) {
const limit = new RateLimit();
if (this.route.ratelimit)
limit['data'] = Object.assign({}, this.route.ratelimit);
callback(limit);
this.route.ratelimit = limit['data'];
return as(this);
}
/**
* Add additional Context to this Endpoint
*
* This will add additional context to this Endpoint, which will be available in the
* `ctr` object when the Endpoint is executed.
* @since 7.0.0
*/ context() {
return as(this);
}
/**
* Use a Validator on this Endpoint
*
* This will attach a Validator to this Endpoint, which will be run before the
* Endpoint is executed. If the Validator fails, the Endpoint will not be executed.
* @since 9.0.0
*/ validate(validator) {
this.route.validators.push(validator);
this.route.openApi = object.deepMerge(this.route.openApi, validator.openApi);
return as(this);
}
/**
* Attach a Callback for when someone makes an HTTP request to upgrade to a WebSocket
*
* This will attach a callback for when the server recieves a http request and
* finishes parsing it for the user. This Handler is not required to be set, but
* if you want to do additional checks before upgrading to a WebSocket, you can
* attach this handler.
* @example
* ```
* const server = new Server(...)
*
* server.path('/', (path) => path
* .ws('/hello', (http) => http
* .onUpgrade((ctr, end) => {
* if (!ctr.queries.has('gay')) return end(ctr.status(ctr.$status.BAD_REQUEST).print('No Gay query'))
* })
* )
* )
* ```
* @since 5.10.0
*/ onUpgrade(callback) {
this.route.data.onUpgrade = callback;
return as(this);
}
/**
* Attach a Callback for when someone Establishes a connection to the Socket
*
* This will attach a callback for when the websocket connection is established
* and ready for use. This callback will commonly be used to attach references using
* `.printRef()` or similar.
* @example
* ```
* const server = new Server(...)
*
* server.path('/', (path) => path
* .ws('/ws', (ws) => ws
* .onOpen((ctr) => {
* console.log('Connected to Client')
* })
* )
* )
* ```
* @since 5.4.0
*/ onOpen(callback) {
this.route.data.onOpen = callback;
return as(this);
}
/**
* Attach a Callback for when someone sends a Message to the Socket
*
* This will attach a callback for when the server recieves a message from
* the Client. This event can be disabled completely by setting `message.enabled`
* to false in the initial Server Options.
* @example
* ```
* const server = new Server(...)
*
* server.path('/', (path) => path
* .ws('/ws', (ws) => ws
* .onMessage((ctr) => {
* ctr.print(ctr.message)
* })
* )
* )
* ```
* @since 5.4.0
*/ onMessage(callback) {
this.route.data.onMessage = callback;
return as(this);
}
/**
* Attach a Callback for when the Socket closes
*
* This will attach a callback for when the Socket is closed in any way
* that should trigger this (basically all). In this callback `.message`
* will be the message the client sent as reason for the close or just empty
* when the client didnt send a reason or the server closed the socket.
* @example
* ```
* const controller = new Server({ })
*
* controller.path('/', (path) => path
* .ws('/ws', (ws) => ws
* .onClose((ctr) => {
* console.log('Closed Client Connection')
* })
* )
* )
* ```
* @since 5.4.0
*/ onClose(callback) {
this.route.data.onClose = callback;
return as(this);
}
}