UNPKG

@castery/caster-discord

Version:

🤖⛓️ The Discord platform for caster

446 lines (369 loc) 8.53 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } var Joi = require('joi'); var caster = require('@castery/caster'); var createDebug = _interopDefault(require('debug')); var discord_js = require('discord.js'); function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; } /** * Platform context name * * @type {string} */ const PLATFORM_NAME = 'discord'; /** * Supported platform types * * @type {Object} */ const supportedContextTypes = caster.MessageContext.defaultSupportedContextTypes({ message: true }); /** * Supported platform attachments * * @type {Object} */ const supportedAttachmentTypes = caster.MessageContext.defaultSupportedAttachmentTypes({ image: true, video: true, document: true }); /** * Default options platform * * @type {Object} */ const defaultOptions = { id: null, adapter: {}, prefix: ['!'] }; /** * Default options platform schema * * @type {Object} * * @extends {defaultOptions} */ const defaultOptionsSchema = Joi.object().keys({ id: Joi.string().allow(null), adapter: Joi.object(), prefix: Joi.array() }); const { SUPPORTED_CONTEXT_TYPES, SUPPORTED_ATTACHMENT_TYPES } = caster.contextProps; const enumTypesMessage = { text: 'channel' }; /** * Incoming vk context * * @public */ class DiscordMessageContext extends caster.MessageContext { /** * Constructor * * @param {Caster} caster * @param {Message} message * @param {number} id */ constructor(caster$$1, { id, message, $text = null }) { super(caster$$1); this.platform = { id, name: PLATFORM_NAME }; const { type } = message.channel; this.from = { id: message.channel.id, type: type in enumTypesMessage ? enumTypesMessage[type] : type }; this.sender = { id: message.author.id, type: 'user' }; this.text = message.content; this.$text = $text; this.raw = message; } /** * Returns supported context types * * @return {Object} */ get [SUPPORTED_CONTEXT_TYPES]() { return supportedContextTypes; } /** * Returns supported attachment types * * @return {Object} */ get [SUPPORTED_ATTACHMENT_TYPES]() { return supportedAttachmentTypes; } /** * Sends a message to the current dialog * * @param {mixed} text * @param {Object} options * * @return {Promise<mixed>} */ send(text, options = {}) { if (typeof text === 'object') { options = text; } else { options.text = text; } this.to = this.from; this.text = options.text; const message = new DiscordMessageContext(this.caster, { id: this.platform.id, message: this.raw }); message.to = this.from; message.state = _objectSpread({}, this.state); message.text = options.text; if ('attachments' in options) { if (!Array.isArray(options.attachments)) { message.attachments = [options.attachments]; } else { message.attachments = options.attachments; } } return this.caster.dispatchOutcoming(message); } /** * Responds to a message with a mention * * @param {mixed} text * @param {Object} options * * @return {Promise<mixed>} */ reply(text, options = {}) { if (typeof text === 'object') { options = text; } else { options.text = text; } options.text = `<@${this.sender.id}>, ${options.text}`; return this.send(options); } } const debug = createDebug('caster-discord'); /** * Platform for integration with social network VK * * @public */ class DiscordPlatform extends caster.Platform { /** * Constructor * * @param {Object} options */ constructor(options = {}) { super(); Object.assign(this.options, defaultOptions); this.discord = new discord_js.Client(); this.casters = new Set(); if (Object.keys(options).length > 0) { this.setOptions(options); } this.setReplacePrefix(); this.addDefaultEvents(); } /** * @inheritdoc */ setOptions(options) { super.setOptions(options); if ('adapter' in options) { const { adapter } = this.options; if ('token' in options) { this.discord.login(adapter.token); } } return this; } /** * @inheritdoc */ getOptionsSchema() { return defaultOptionsSchema; } /** * @inheritdoc */ getAdapter() { return this.discord; } /** * Returns the platform id * * @return {string} */ getId() { return this.options.id; } /** * Returns the platform name * * @return {string} */ getPlatformName() { return PLATFORM_NAME; } /** * @inheritdoc */ async start() { await this.discord.login(this.options.adapter.token); if (this.options.id === null) { this.setOptions({ id: this.discord.user.id }); } } /** * @inheritdoc */ async stop() { await this.discord.destroy(); } /** * @inheritdoc */ async subscribe(caster$$1) { this.casters.add(caster$$1); if (!this.isStarted()) { await this.start(); } caster$$1.outcoming.addPlatform(this, async (context, next) => { if (context.getPlatformName() !== PLATFORM_NAME) { return await next(); } if (context.getPlatformId() !== this.options.id) { return await next(); } if (supportedContextTypes[context.type] !== true) { throw new caster.UnsupportedContextTypeError({ type: context.type }); } const channel = this.discord.channels.get(context.to.id); if ('attachments' in context) { for (const _ref of context.attachments) { const { type } = _ref; if (supportedAttachmentTypes[type] !== true) { throw new caster.UnsupportedAttachmentTypeError({ type }); } } await Promise.all(context.attachments.map(({ source }) => channel.send('', { file: source }))); } if (context.text) { await channel.send(context.text); } }); } /** * @inheritdoc */ async unsubscribe(caster$$1) { this.casters.delete(caster$$1); caster$$1.outcoming.removePlatform(this); if (this.casters.size === 0 && this.isStarted()) { await this.stop(); } } /** * Add default events discord */ addDefaultEvents() { // eslint-disable-next-line no-console this.discord.on('error', console.error); this.discord.on('message', message => { /* Ignore other bots and self */ if (message.author.bot) { return; } let $text = message.content; if ($text !== null) { if (!this.hasPrefix.test($text)) { return; } $text = $text.replace(this.replacePrefix, ''); } for (const caster$$1 of this.casters) { caster$$1.dispatchIncoming(new DiscordMessageContext(caster$$1, { id: this.options.id, message, $text })); } }); } /** * Sets replace prefix */ setReplacePrefix() { let { prefix } = this.options; prefix = String.raw`^(?:${prefix.join('|')})`; this.hasPrefix = new RegExp(String.raw`${prefix}.+`, 'i'); this.replacePrefix = new RegExp(String.raw`${prefix}?[, ]*`, 'i'); } } exports.DiscordPlatform = DiscordPlatform; exports.default = DiscordPlatform;