xmppjs-chat-bot
Version:
Server-side XMPP chat bot
115 lines • 4.64 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.HandlerNoDuplicate = void 0;
const abstract_1 = require("./abstract");
const handlers_directory_1 = require("../handlers_directory");
const DEFAULT_DELAY_SECONDS = 60;
const PRUNE_DELAY_SECONDS = 5 * 60;
class HandlerNoDuplicate extends abstract_1.Handler {
constructor(id, room, options) {
super(id, room, options);
this.userMessages = new Map();
this.delay ?? (this.delay = DEFAULT_DELAY_SECONDS * 1000);
this.applyToModerators ?? (this.applyToModerators = false);
this.roomMessageListener = (stanza, fromUser) => {
try {
this.roomMessage(stanza, fromUser);
}
catch (err) {
if (err instanceof Error) {
this.logger.error(err.name + ': ' + err.message);
}
else {
this.logger.error(err);
}
}
};
}
loadOptions(options) {
if (!options || typeof options !== 'object') {
return;
}
if (('applyToModerators' in options) && (typeof options.applyToModerators === 'boolean')) {
this.applyToModerators = options.applyToModerators;
}
if (('delay' in options) && (options.delay === undefined || (typeof options.delay === 'number'))) {
const newDelay = (options.delay ?? DEFAULT_DELAY_SECONDS) * 1000;
this.delay = newDelay;
}
if (('reason' in options) && (options.reason === undefined || (typeof options.reason === 'string'))) {
this.reason = options.reason;
}
}
roomMessage(stanza, fromUser) {
let content = stanza.body();
if (!content) {
return;
}
content = this.normalizeMessage(content);
const userKey = stanza.occupantId() ?? fromUser.jid.toString();
let messages = this.userMessages.get(userKey);
if (!messages) {
messages = new Map();
this.userMessages.set(userKey, messages);
}
const lastSent = messages.get(content);
const now = Date.now();
messages.set(content, now);
if (!lastSent) {
return;
}
const limit = now - this.delay;
if (lastSent < limit) {
return;
}
this.logger.debug(`user ${userKey} has already sent a similar messages at ${lastSent}, which is after ${limit}`);
if (!this.applyToModerators && fromUser.isModerator()) {
this.logger.debug(`Ignoring the no-duplicate rule, as the user ${userKey} is moderator.`);
return;
}
this.room.moderateMessage(stanza, this.reason).catch((err) => { this.logger.error(err); });
}
normalizeMessage(s) {
return s.replace('\n', ' ').trim().replace(/\s\s+/g, ' ').toLocaleLowerCase();
}
pruneUserMessages() {
const timestamp = Date.now() - this.delay;
const dateStr = (new Date(timestamp)).toISOString();
this.logger.debug(`Pruning user messages with timestamp older than ${timestamp.toString()} (<= ${dateStr})...`);
this.userMessages.forEach((messages, userKey) => {
this.logger.debug('Pruning user ' + userKey + ' messages...');
messages.forEach((msgTimestamp, content) => {
if (msgTimestamp >= timestamp) {
return;
}
this.logger.debug('Pruning a message sent at ' + msgTimestamp.toString());
messages.delete(content);
});
if (messages.size === 0) {
this.logger.debug(`User ${userKey} has no more message in their map, deleting it.`);
this.userMessages.delete(userKey);
}
});
this.logger.debug('Prune is finished.');
}
start() {
this.room.on('room_message', this.roomMessageListener);
if (this.pruneTimeout) {
clearInterval(this.pruneTimeout);
}
this.pruneTimeout = setInterval(() => {
this.pruneUserMessages();
}, PRUNE_DELAY_SECONDS * 1000);
}
stop() {
this.room.off('room_message', this.roomMessageListener);
if (this.pruneTimeout) {
clearInterval(this.pruneTimeout);
this.pruneTimeout = undefined;
}
this.userMessages.clear();
}
}
exports.HandlerNoDuplicate = HandlerNoDuplicate;
handlers_directory_1.HandlersDirectory.singleton().register('no-duplicate', HandlerNoDuplicate);
//# sourceMappingURL=no-duplicate.js.map