export default class WetSock {
#config = undefined;
#server = undefined;
#clients = new Map();
#plugins = new Map();
constructor(config) {
this.#config = config;
this.#server = null;
}
start(server) {
this.#server = server;
registerPlugin(identifier, plugin) {
plugin.initialize(this);
this.#plugins.set(identifier, plugin);
getPlugin(identifier) {
return this.#plugins.get(identifier);
handleUpgrade(req) {
const clientId = Math.random().toString(36).substring(2);
const success = this.#server.upgrade(req, { data: { clientId } });
if (success) {
return undefined;
return Response.redirect('/', 302);
handleMessage(ws, message) {
const client = this.#clients.get(ws.data.clientId);
try {
const messageData = JSON.parse(message);
if(typeof(messageData) == 'object' && messageData.constructor.name == 'Object') {
message = messageData;
} catch (err) {}
for(const plugin of this.#plugins) {
if(plugin.onMessage(ws.data.clientId, message)) break; // plugin consumes message by returning a truthy value
handleOpen(ws) {
this.#plugins.forEach((plugin) => plugin.onOpen(ws.data.clientId));
handleClose(ws) {
this.#plugins.forEach((plugin) => plugin.onClose(ws.data.clientId));
this.#clients.delete(ws.data.clientId);
handleDrain(ws) {
// Handle socket drain event