@castery/caster-discord
Version:
🤖⛓️ The Discord platform for caster
446 lines (369 loc) • 8.53 kB
JavaScript
'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;