This repository has been archived on 2025-03-10. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
wetsock/lib/WetSock/WetSock.js

195 lines
5.4 KiB
JavaScript
Raw Permalink Normal View History

import SocketClient from './SocketClient';
import Message from './Message';
/**
* WetSock class represents the main server class for handling WebSocket connections and plugins.
*/
2024-04-02 15:57:41 +00:00
export default class WetSock {
#config = undefined;
#server = undefined;
#clients = new Map();
#plugins = new Map();
#listeners = new Map();
/**
* Create a new instance of WetSock.
* @param {Object} config - The configuration object for the server.
*/
2024-04-02 15:57:41 +00:00
constructor(config) {
2024-04-02 23:30:37 +00:00
this.#config = config;
this.#server = null;
2024-04-02 15:57:41 +00:00
}
/**
* Start the server with the provided server instance.
* @param {Object} server - The server instance to start.
*/
2024-04-02 15:57:41 +00:00
start(server) {
this.#server = server;
}
/**
* Register a plugin with the specified identifier and priority.
* @param {string} identifier - The identifier for the plugin.
* @param {Object} plugin - The plugin instance to register.
* @param {number} priority - The priority of the plugin (default: 0).
*/
registerPlugin(identifier, plugin, priority = 0) {
2024-04-02 15:57:41 +00:00
plugin.initialize(this);
this.#plugins.set(identifier, { plugin, priority });
2024-04-02 15:57:41 +00:00
}
/**
* Get the plugin with the specified identifier.
* @param {string} identifier - The identifier of the plugin.
* @returns {Object} The plugin instance.
*/
2024-04-02 15:57:41 +00:00
getPlugin(identifier) {
return this.#plugins.get(identifier);
}
/**
* Handle the WebSocket upgrade request.
* @param {Object} req - The upgrade request object.
* @returns {Response} The response to send back.
*/
2024-04-02 15:57:41 +00:00
handleUpgrade(req) {
const clientId = Math.random().toString(36).substring(2);
const success = this.#server.upgrade(req, { data: { clientId } });
if (success) {
this.#clients.set(clientId, { id: clientId });
2024-04-02 15:57:41 +00:00
return undefined;
}
return Response.redirect('/', 302);
}
/**
* Handle the opening of a WebSocket connection.
* @param {WebSocket} ws - The WebSocket connection.
*/
handleOpen(ws) {
const client = new SocketClient(ws.data.clientId, ws);
this.#clients.set(client.id, client);
const plugins = [...this.#plugins.keys()].filter(key => {
return typeof(this.#plugins.get(key).plugin.actions) == 'function'
}).map(key => {
return {
identifier: key,
actions: this.#plugins.get(key).plugin.actions()
};
});
if(plugins.length > 0) {
client.send({
event: 'plugins',
2024-04-07 23:45:31 +01:00
data: plugins
});
}
this.emit('open', client);
}
/**
* Handle an incoming message from a WebSocket client.
* @param {WebSocket} ws - The WebSocket connection.
* @param {string|Object} message - The message received from the client.
*/
2024-04-02 15:57:41 +00:00
handleMessage(ws, message) {
const client = this.getValidClient(ws);
if (!client) return;
const chatMessage = new Message(message);
for (const prop of chatMessage.getProps()) {
this.emit(`message:${prop}`, client, chatMessage);
const value = chatMessage.get(prop);
if(typeof(value) != 'string' || value.indexOf(' ') < 0) continue;
this.emit(`message:${prop}:${value}`, client, chatMessage);
}
this.emit('message', client, chatMessage);
}
/**
* Handle the closing of a WebSocket connection.
* @param {WebSocket} ws - The WebSocket connection.
*/
handleClose(ws) {
const client = this.getValidClient(ws);
if (!client) return;
this.emit('close', client, 'closed');
this.#clients.delete(client.id);
2024-04-02 15:57:41 +00:00
}
/**
* Get the valid client object associated with the WebSocket connection.
* @param {WebSocket} ws - The WebSocket connection.
* @returns {Object|null} The valid client object or null if the client is not valid.
*/
getValidClient(ws) {
const clientId = ws.data?.clientId;
if (!clientId || !this.#clients.has(clientId)) {
ws.close(1011, 'Invalid client');
this.emit('close', ws, 'invalid');
return null;
}
return this.#clients.get(clientId);
2024-04-02 15:57:41 +00:00
}
/**
* Handle the drain event of a WebSocket connection.
* @param {WebSocket} ws - The WebSocket connection.
*/
2024-04-02 15:57:41 +00:00
handleDrain(ws) {
// Handle socket drain event
}
/**
* Send a message to a specific client.
* @param {string} clientId - The ID of the client to send the message to.
* @param {Object} message - The message to send.
*/
sendTo(clientId, message) {
const client = this.#clients.get(clientId);
if (client) {
client.send(JSON.stringify(message));
}
}
/**
* Register an event listener.
* @param {string} event - The event name.
* @param {function} listener - The event listener function.
*/
on(event, listener) {
if (!this.#listeners.has(event)) {
this.#listeners.set(event, []);
}
this.#listeners.get(event).push(listener);
}
/**
* Remove an event listener.
* @param {string} event - The event name.
* @param {function} listener - The event listener function to remove.
*/
off(event, listener) {
if (this.#listeners.has(event)) {
const listeners = this.#listeners.get(event);
const index = listeners.indexOf(listener);
if (index !== -1) {
listeners.splice(index, 1);
}
}
}
/**
* Emit an event.
* @param {string} event - The event name.
* @param {...*} args - The arguments to pass to the event listeners.
*/
emit(event, ...args) {
if (this.#listeners.has(event)) {
this.#listeners.get(event).forEach((listener) => listener(...args));
}
}
2024-04-02 15:57:41 +00:00
}