feat(plugins) Base plugins for rooms and permissions
This commit is contained in:
150
lib/WetSock/Plugins/PermissionPlugin.js
Normal file
150
lib/WetSock/Plugins/PermissionPlugin.js
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
/**
|
||||||
|
* Plugin for handling permissions.
|
||||||
|
*/
|
||||||
|
class PermissionsPlugin {
|
||||||
|
/**
|
||||||
|
* Predefined roles and their corresponding permissions.
|
||||||
|
*/
|
||||||
|
static defaultRoles = {
|
||||||
|
OWNER: 0o777,
|
||||||
|
ADMIN: 0o755,
|
||||||
|
MODERATOR: 0o644,
|
||||||
|
MEMBER: 0o444,
|
||||||
|
GUEST: 0o400,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actions and their corresponding required permissions.
|
||||||
|
*/
|
||||||
|
static defaultActions = {
|
||||||
|
SEND_MESSAGE: 0o400,
|
||||||
|
MUTE_MEMBER: 0o200,
|
||||||
|
KICK_MEMBER: 0o200,
|
||||||
|
GRANT_PERMISSION: 0o100,
|
||||||
|
REVOKE_PERMISSION: 0o100,
|
||||||
|
ASSIGN_ROLE: 0o100,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new instance of the PermissionsPlugin.
|
||||||
|
* @param {Object} [config={}] - The configuration object.
|
||||||
|
* @param {Object} [config.roles] - The custom roles and their corresponding permissions.
|
||||||
|
* @param {Object} [config.actions] - The custom actions and their corresponding required permissions.
|
||||||
|
*/
|
||||||
|
constructor(config = {}) {
|
||||||
|
this.roles = {
|
||||||
|
...PermissionsPlugin.defaultRoles,
|
||||||
|
...config.roles
|
||||||
|
};
|
||||||
|
this.actions = {
|
||||||
|
...PermissionsPlugin.defaultActions,
|
||||||
|
...config.actions
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the plugin.
|
||||||
|
* @param {Object} server - The server instance.
|
||||||
|
*/
|
||||||
|
initialize(server) {
|
||||||
|
this.server = server;
|
||||||
|
this.contexts = new Map();
|
||||||
|
|
||||||
|
// Listen for the 'permissions:init' event
|
||||||
|
server.on('permissions:init', (pluginId, context, initContext) => {
|
||||||
|
const key = pluginId + context;
|
||||||
|
this.contexts.set(key, new Map());
|
||||||
|
initContext({
|
||||||
|
get: (...args) => this.getPermissions(key, ...args),
|
||||||
|
has: (...args) => this.hasPermission(key, ...args),
|
||||||
|
can: (...args) => this.hasPermission(key, ...args),
|
||||||
|
add: (...args) => this.grantPermission(key, ...args),
|
||||||
|
remove: (...args) => this.revokePermission(key, ...args),
|
||||||
|
role: (...args) => this.assignRole(key, ...args),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the permissions for the specified key and identifier.
|
||||||
|
* @param {string} key - The unique key identifying the plugin and context.
|
||||||
|
* @param {string} identifier - The identifier of the entity (e.g., user, member).
|
||||||
|
* @returns {Object} The permissions object.
|
||||||
|
*/
|
||||||
|
getPermissions(key, identifier) {
|
||||||
|
const context = this.contexts.get(key);
|
||||||
|
if (context) {
|
||||||
|
const permissions = context.get(identifier);
|
||||||
|
if (permissions) {
|
||||||
|
const result = {};
|
||||||
|
for (const [action, requiredPermission] of Object.entries(this.actions)) {
|
||||||
|
result[action] = this.hasPermission(permissions, requiredPermission);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the specified key and identifier has the given permission.
|
||||||
|
* @param {string} key - The unique key identifying the plugin and context.
|
||||||
|
* @param {string} identifier - The identifier of the entity (e.g., user, member).
|
||||||
|
* @param {string} action - The action to check permissions for.
|
||||||
|
* @returns {boolean} True if the identifier has the permission, false otherwise.
|
||||||
|
*/
|
||||||
|
hasPermission(key, identifier, action) {
|
||||||
|
const context = this.contexts.get(key);
|
||||||
|
if (context) {
|
||||||
|
const permissions = context.get(identifier);
|
||||||
|
if (permissions) {
|
||||||
|
const requiredPermission = this.actions[action];
|
||||||
|
return (permissions & requiredPermission) === requiredPermission;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Grant permission to the specified key and identifier for the given action.
|
||||||
|
* @param {string} key - The unique key identifying the plugin and context.
|
||||||
|
* @param {string} identifier - The identifier of the entity (e.g., user, member).
|
||||||
|
* @param {string} action - The action to grant permission for.
|
||||||
|
*/
|
||||||
|
grantPermission(key, identifier, action) {
|
||||||
|
const context = this.contexts.get(key);
|
||||||
|
if (context) {
|
||||||
|
const permissions = context.get(identifier) || 0;
|
||||||
|
context.set(identifier, permissions | this.actions[action]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Revoke permission from the specified key and identifier for the given action.
|
||||||
|
* @param {string} key - The unique key identifying the plugin and context.
|
||||||
|
* @param {string} identifier - The identifier of the entity (e.g., user, member).
|
||||||
|
* @param {string} action - The action to revoke permission for.
|
||||||
|
*/
|
||||||
|
revokePermission(key, identifier, action) {
|
||||||
|
const context = this.contexts.get(key);
|
||||||
|
if (context) {
|
||||||
|
const permissions = context.get(identifier);
|
||||||
|
if (permissions) {
|
||||||
|
context.set(identifier, permissions & ~this.actions[action]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assign a role to the specified key and identifier.
|
||||||
|
* @param {string} key - The unique key identifying the plugin and context.
|
||||||
|
* @param {string} identifier - The identifier of the entity (e.g., user, member).
|
||||||
|
* @param {string} role - The role to assign.
|
||||||
|
*/
|
||||||
|
assignRole(key, identifier, role) {
|
||||||
|
const context = this.contexts.get(key);
|
||||||
|
if (context) {
|
||||||
|
context.set(identifier, this.roles[role]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
124
lib/WetSock/Plugins/Rooms/Room.js
Normal file
124
lib/WetSock/Plugins/Rooms/Room.js
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
/**
|
||||||
|
* Represents a chat room.
|
||||||
|
*/
|
||||||
|
class Room {
|
||||||
|
/**
|
||||||
|
* Create a new room instance.
|
||||||
|
* @param {string} id - The unique identifier of the room.
|
||||||
|
* @param {Object} [config={}] - The configuration options for the room.
|
||||||
|
*/
|
||||||
|
constructor(id, config = {}) {
|
||||||
|
this.id = id;
|
||||||
|
this.members = new Map();
|
||||||
|
this.config = {
|
||||||
|
notifyMuteUnmute: config.notifyMuteUnmute || false,
|
||||||
|
notifyKick: config.notifyKick || false,
|
||||||
|
inactivityTimeout: config.inactivityTimeout || 60_000,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a member to the room.
|
||||||
|
* @param {string} memberId - The unique identifier of the member.
|
||||||
|
* @param {Object} memberData - Additional data associated with the member.
|
||||||
|
*/
|
||||||
|
add(memberId, memberData) {
|
||||||
|
this.members.set(memberId, {
|
||||||
|
...memberData,
|
||||||
|
lastActivity: Date.now(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a member from the room.
|
||||||
|
* @param {string} memberId - The unique identifier of the member.
|
||||||
|
*/
|
||||||
|
remove(memberId) {
|
||||||
|
this.members.delete(memberId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the data of a member in the room.
|
||||||
|
* @param {string} memberId - The unique identifier of the member.
|
||||||
|
* @returns {Object|undefined} The member data or undefined if the member is not found.
|
||||||
|
*/
|
||||||
|
get(memberId) {
|
||||||
|
return this.members.get(memberId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a member is muted in the room.
|
||||||
|
* @param {string} memberId - The unique identifier of the member.
|
||||||
|
* @returns {boolean} True if the member is muted, false otherwise.
|
||||||
|
*/
|
||||||
|
isMuted(memberId) {
|
||||||
|
const memberData = this.get(memberId);
|
||||||
|
return memberData ? memberData.muted : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a member is kicked from the room.
|
||||||
|
* @param {string} memberId - The unique identifier of the member.
|
||||||
|
* @returns {boolean} True if the member is kicked, false otherwise.
|
||||||
|
*/
|
||||||
|
isKicked(memberId) {
|
||||||
|
const memberData = this.get(memberId);
|
||||||
|
return memberData ? memberData.kicked : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mute a member in the room.
|
||||||
|
* @param {string} memberId - The unique identifier of the member.
|
||||||
|
*/
|
||||||
|
mute(memberId) {
|
||||||
|
const memberData = this.get(memberId);
|
||||||
|
if (memberData) {
|
||||||
|
memberData.muted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unmute a member in the room.
|
||||||
|
* @param {string} memberId - The unique identifier of the member.
|
||||||
|
*/
|
||||||
|
unmute(memberId) {
|
||||||
|
const memberData = this.get(memberId);
|
||||||
|
if (memberData) {
|
||||||
|
memberData.muted = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kick a member from the room.
|
||||||
|
* @param {string} memberId - The unique identifier of the member.
|
||||||
|
*/
|
||||||
|
kick(memberId) {
|
||||||
|
const memberData = this.get(memberId);
|
||||||
|
if (memberData) {
|
||||||
|
memberData.kicked = Date.now();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the last activity timestamp of a member in the room.
|
||||||
|
* @param {string} memberId - The unique identifier of the member.
|
||||||
|
*/
|
||||||
|
update(memberId) {
|
||||||
|
const memberData = this.get(memberId);
|
||||||
|
if (memberData) {
|
||||||
|
memberData.lastActivity = Date.now();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Purge inactive members from the room based on the inactivity timeout.
|
||||||
|
*/
|
||||||
|
purge() {
|
||||||
|
const now = Date.now();
|
||||||
|
for (const [memberId, memberData] of this.members.entries()) {
|
||||||
|
if (now - memberData.lastActivity > this.config.inactivityTimeout) {
|
||||||
|
this.kick(memberId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
306
lib/WetSock/Plugins/Rooms/RoomPlugin.js
Normal file
306
lib/WetSock/Plugins/Rooms/RoomPlugin.js
Normal file
@@ -0,0 +1,306 @@
|
|||||||
|
import BasePlugin from '../BasePlugin';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Plugin for handling room-related operations.
|
||||||
|
*/
|
||||||
|
export default class RoomPlugin extends BasePlugin {
|
||||||
|
#rooms = new Map();
|
||||||
|
#clients = new Map();
|
||||||
|
#config = {
|
||||||
|
allowMultipleRooms: true,
|
||||||
|
alwaysMainChannel: false,
|
||||||
|
notifyMuteUnmute: false,
|
||||||
|
notifyKick: false,
|
||||||
|
inactivityTimeout: 60_000,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the plugin.
|
||||||
|
* @param {Object} wetsock - The WetSock server instance.
|
||||||
|
* @param {Object} config - The configuration options for the plugin.
|
||||||
|
*/
|
||||||
|
initialize(wetsock, config = {}) {
|
||||||
|
super.initialize(wetsock);
|
||||||
|
this.#config = { ...this.#config, ...config };
|
||||||
|
wetsock.on('message', this.onMessage.bind(this));
|
||||||
|
wetsock.on('close', this.onClose.bind(this));
|
||||||
|
setInterval(this.#purge.bind(this), this.#config.inactivityTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle incoming messages from clients.
|
||||||
|
* @param {Object} client - The client object.
|
||||||
|
* @param {Object} message - The message object.
|
||||||
|
* @returns {boolean} - True if the message was handled, false otherwise.
|
||||||
|
*/
|
||||||
|
onMessage(client, message) {
|
||||||
|
if (typeof message === 'object' && message.type && this[message.type]) {
|
||||||
|
return this[message.type](client, message);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle a client disconnecting.
|
||||||
|
* @param {Object} client - The client object.
|
||||||
|
*/
|
||||||
|
onClose(client) {
|
||||||
|
const clientRooms = this.#clients.get(client.id);
|
||||||
|
if (clientRooms) {
|
||||||
|
for (const roomId of clientRooms) {
|
||||||
|
const room = this.#rooms.get(roomId);
|
||||||
|
if (room) {
|
||||||
|
room.members.delete(client.id);
|
||||||
|
this._getServer().publish(roomId, `${client.id} has left the room`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.#clients.delete(client.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actions () {
|
||||||
|
return Object.getOwnPropertyNames(
|
||||||
|
Object.getPrototypeOf(this)
|
||||||
|
).filter((prop) => {
|
||||||
|
return ![
|
||||||
|
"constructor",
|
||||||
|
"initialize",
|
||||||
|
"onMessage",
|
||||||
|
"onClose",
|
||||||
|
"actions"
|
||||||
|
].includes(prop) && typeof this[prop] === 'function'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle a client joining a room.
|
||||||
|
* @param {Object} client - The client object.
|
||||||
|
* @param {Object} message - The message object.
|
||||||
|
* @param {string} message.roomId - The ID of the room to join.
|
||||||
|
*/
|
||||||
|
join(client, { roomId }) {
|
||||||
|
const room = this.#rooms.get(roomId);
|
||||||
|
if (room) {
|
||||||
|
const memberData = room.members.get(client.id);
|
||||||
|
if (memberData && memberData.kicked) {
|
||||||
|
client.send({ type: 'error', message: 'You have been kicked from this room and cannot rejoin' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!this.#config.allowMultipleRooms && this.#clients.has(client.id)) {
|
||||||
|
client.send({ type: 'error', message: 'You can only be in one room at a time' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
client.ws.subscribe(roomId);
|
||||||
|
room.add(client.id, {
|
||||||
|
muted: memberData ? memberData.muted : false,
|
||||||
|
lastActivity: Date.now()
|
||||||
|
});
|
||||||
|
this.#clients.set(client.id, (this.#clients.get(client.id) || new Set()).add(roomId));
|
||||||
|
this._getServer().publish(roomId, `${client.id} has joined the room`);
|
||||||
|
} else {
|
||||||
|
client.send({ type: 'error', message: `Room ${roomId} does not exist` });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle a client leaving a room.
|
||||||
|
* @param {Object} client - The client object.
|
||||||
|
* @param {Object} message - The message object.
|
||||||
|
* @param {string} message.roomId - The ID of the room to leave.
|
||||||
|
*/
|
||||||
|
leave(client, { roomId }) {
|
||||||
|
const room = this.#rooms.get(roomId);
|
||||||
|
if (room) {
|
||||||
|
client.ws.unsubscribe(roomId);
|
||||||
|
room.members.delete(client.id);
|
||||||
|
const clientRooms = this.#clients.get(client.id);
|
||||||
|
if (clientRooms) {
|
||||||
|
clientRooms.delete(roomId);
|
||||||
|
if (clientRooms.size === 0 && !this.#config.alwaysMainChannel) {
|
||||||
|
this.#clients.delete(client.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._getServer().publish(roomId, `${client.id} has left the room`);
|
||||||
|
} else {
|
||||||
|
client.send({ type: 'error', message: `Room ${roomId} does not exist` });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle creating a new room.
|
||||||
|
* @param {Object} client - The client object.
|
||||||
|
* @param {Object} message - The message object.
|
||||||
|
* @param {string} message.roomId - The ID of the room to create.
|
||||||
|
*/
|
||||||
|
create(client, { roomId }) {
|
||||||
|
if (this.#rooms.has(roomId)) {
|
||||||
|
client.send({ type: 'error', message: `Room ${roomId} already exists` });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const room = new Room(roomId);
|
||||||
|
this.#rooms.set(roomId, room);
|
||||||
|
client.ws.subscribe(roomId);
|
||||||
|
room.add(client.id, { muted: false, lastActivity: Date.now() });
|
||||||
|
this.#clients.set(client.id, (this.#clients.get(client.id) || new Set()).add(roomId));
|
||||||
|
|
||||||
|
// Initialize the permissions for the room
|
||||||
|
this._getServer().emit('permissions:init', this.constructor.name, roomId, (permissions) => {
|
||||||
|
room.permissions = permissions;
|
||||||
|
permissions.role(client.id, 'OWNER');
|
||||||
|
});
|
||||||
|
|
||||||
|
client.send({ type: 'success', message: `Room ${roomId} created successfully` });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle sending a message to a room.
|
||||||
|
* @param {Object} client - The client object.
|
||||||
|
* @param {Object} message - The message object.
|
||||||
|
* @param {string} message.roomId - The ID of the room to send the message to.
|
||||||
|
* @param {string} message.content - The content of the message.
|
||||||
|
* @returns {boolean} - True if the message was sent successfully, false otherwise.
|
||||||
|
*/
|
||||||
|
send(client, { roomId, content }) {
|
||||||
|
const room = this.#rooms.get(roomId);
|
||||||
|
if (room && room.get(client.id)) {
|
||||||
|
if (!room.permissions.can(client.id, 'SEND_MESSAGE')) {
|
||||||
|
client.send({ type: 'error', message: 'You do not have permission to send messages in this room' });
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const memberData = room.members.get(client.id);
|
||||||
|
if (memberData.muted) {
|
||||||
|
client.send({ type: 'error', message: 'You are muted and cannot send messages in this room' });
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
room.update(client.id);
|
||||||
|
this._getServer().publish(roomId, `${client.id}: ${content}`);
|
||||||
|
this.emit('rooms:message', client, message.roomId, message.content);
|
||||||
|
this.emit(`rooms:message:${message.roomId}`, client, message.content);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
client.send({ type: 'error', message: 'You are not allowed to send messages in this room' });
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle kicking a member from a room.
|
||||||
|
* @param {Object} client - The client object.
|
||||||
|
* @param {Object} message - The message object.
|
||||||
|
* @param {string} message.roomId - The ID of the room.
|
||||||
|
* @param {string} message.memberId - The ID of the member to kick.
|
||||||
|
*/
|
||||||
|
kick(client, { roomId, memberId }) {
|
||||||
|
const room = this.#rooms.get(roomId);
|
||||||
|
if (room && room.get(memberId)) {
|
||||||
|
if (!room.permissions.can(client.id, 'KICK_MEMBER')) {
|
||||||
|
client.send({ type: 'error', message: 'You do not have permission to kick members from this room' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const member = this._getServer().getValidClient(memberId);
|
||||||
|
if (member) {
|
||||||
|
member.ws.unsubscribe(roomId);
|
||||||
|
room.members.set(memberId, { id: memberId, muted: true, kicked: Date.now() });
|
||||||
|
const clientRooms = this.#clients.get(memberId);
|
||||||
|
if (clientRooms) {
|
||||||
|
clientRooms.delete(roomId);
|
||||||
|
if (clientRooms.size === 0 && !this.#config.alwaysMainChannel) {
|
||||||
|
this.#clients.delete(memberId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.#config.notifyKick) {
|
||||||
|
this._getServer().publish(roomId, `${memberId} has been kicked from the room`);
|
||||||
|
}
|
||||||
|
member.send({ type: 'kicked', roomId });
|
||||||
|
}
|
||||||
|
client.send({ type: 'success', message: `Member ${memberId} has been kicked from room ${roomId}` });
|
||||||
|
} else {
|
||||||
|
client.send({ type: 'error', message: `Cannot kick member ${memberId} from room ${roomId}` });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle muting a member in a room.
|
||||||
|
* @param {Object} client - The client object.
|
||||||
|
* @param {Object} message - The message object.
|
||||||
|
* @param {string} message.roomId - The ID of the room.
|
||||||
|
* @param {string} message.memberId - The ID of the member to mute.
|
||||||
|
*/
|
||||||
|
mute(client, { roomId, memberId }) {
|
||||||
|
const room = this.#rooms.get(roomId);
|
||||||
|
if (room && room.get(memberId)) {
|
||||||
|
if (!room.permissions.can(client.id, 'MUTE_MEMBER')) {
|
||||||
|
client.send({ type: 'error', message: 'You do not have permission to mute members in this room' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
room.members.get(memberId).muted = true;
|
||||||
|
const member = this._getServer().getValidClient(memberId);
|
||||||
|
if (member && this.#config.notifyMuteUnmute) {
|
||||||
|
member.send({ type: 'muted', roomId });
|
||||||
|
}
|
||||||
|
client.send({ type: 'success', message: `Member ${memberId} has been muted in room ${roomId}` });
|
||||||
|
} else {
|
||||||
|
client.send({ type: 'error', message: `Cannot mute member ${memberId} in room ${roomId}` });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle unmuting a member in a room.
|
||||||
|
* @param {Object} client - The client object.
|
||||||
|
* @param {Object} message - The message object.
|
||||||
|
* @param {string} message.roomId - The ID of the room.
|
||||||
|
* @param {string} message.memberId - The ID of the member to unmute.
|
||||||
|
*/
|
||||||
|
unmute(client, { roomId, memberId }) {
|
||||||
|
const room = this.#rooms.get(roomId);
|
||||||
|
if (room && room.get(memberId)) {
|
||||||
|
if (!room.permissions.can(client.id, 'UNMUTE_MEMBER')) {
|
||||||
|
client.send({ type: 'error', message: 'You do not have permission to unmute members in this room' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
room.members.get(memberId).muted = false;
|
||||||
|
const member = this._getServer().getValidClient(memberId);
|
||||||
|
if (member && this.#config.notifyMuteUnmute) {
|
||||||
|
member.send({ type: 'unmuted', roomId });
|
||||||
|
}
|
||||||
|
client.send({ type: 'success', message: `Member ${memberId} has been unmuted in room ${roomId}` });
|
||||||
|
} else {
|
||||||
|
client.send({ type: 'error', message: `Cannot unmute member ${memberId} in room ${roomId}` });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for inactive members in each room and kick them.
|
||||||
|
*/
|
||||||
|
#purge() {
|
||||||
|
for (const [roomId, room] of this.#rooms.entries()) {
|
||||||
|
const now = Date.now();
|
||||||
|
for (const [memberId, memberData] of room.members.entries()) {
|
||||||
|
if (now - memberData.lastActivity > this.#config.inactivityTimeout) {
|
||||||
|
this.kick(null, { roomId, memberId });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Broadcast a message to a specific room or all rooms.
|
||||||
|
* @param {string} roomId - The ID of the room to broadcast to. If not provided, the message will be broadcast to all rooms.
|
||||||
|
* @param {string} message - The message to broadcast.
|
||||||
|
*/
|
||||||
|
#broadcast(message, roomId) {
|
||||||
|
if (this.#rooms.has(roomId)) {
|
||||||
|
this._getServer().publish(roomId, message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(roomId == 'all') {
|
||||||
|
for (const room of this.#rooms.values()) {
|
||||||
|
this._getServer().publish(room.id, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user