quake3 server connector | Cell 1 | test specific channel | Search

The code imports necessary modules and defines constants and functions for interpreting and reading commands from Discord channels. It includes functions for interpreting a single command and reading all commands from specified channels, which can be filtered by channel ID, username, or empty string.

Run example

npm run import -- "respond discord commands"

respond discord commands

var importer = require('../Core')
var discordApi = importer.import("discord api")
var {authorizeGateway, privateChannels, interactions} = importer.import("authorize discord")
var {
    discordCommands,
    challengeCommand,
    configCommand,
    connectCommand,
    rconCommand,
    chatCommand,
} = importer.import("discord commands")

var DEFAULT_USERNAME = 'Orbb'

function interpretCommand(message) {
    return Object.keys(discordCommands)
       .filter(k => message.content.match(discordCommands[k])
              || (message.attachments && message.attachments.filter(a => a.filename.match(discordCommands[k])).length > 0)
              || (message.embeds && message.embeds.filter(e => (e.title && e.title.match(discordCommands[k]))
                                                          || (e.description && e.description.match(discordCommands[k]))).length > 0))
}

async function readAllCommands(specificChannel) {
    // matching format  @megamind  challenge freon dm17 , :thumbsup:   :thumbsdown: .
    var private = false
    var messages = []
    var responses = []
    var channels = []
    var commands = []
    var launches = []
    
    if(specificChannel == '@me') {
        // only read channel if it was updated within the last hour
        var userChannels = Object
            .keys(privateChannels)
            .filter(k => privateChannels[k] > Date.now() - 1000 * 60 * 60)
            .map(k => ({id: k}))
        channels.push.apply(channels, userChannels)
        specificChannel = ''
        private = true
    } else {
        var guilds = await discordApi.userGuilds()
        console.log(`Reading ${guilds.length} guilds`)
        for(var i = 0; i < guilds.length; i++) {
            channels.push.apply(channels, await discordApi.guildChannels(guilds[i].id))
        }
    }
    
    console.log(`Reading ${channels.length} channels`)
    for(var i = 0; i < channels.length; i++) {
        if(!specificChannel
           || channels[i].id == specificChannel
           || (typeof specificChannel == 'string'
              && (specificChannel.length === 0
                 || (channels[i].name
                     && channels[i].name.match(new RegExp(specificChannel, 'ig'))
                    )
                 )
              )
          ) {
            console.log(`Reading ${channels[i].name}`)
            messages.push.apply(messages, await discordApi.channelMessages(channels[i].id))
        }
    }
    
    // find commands in channel history
    console.log(`Reading ${messages.length} messages`)
    for(var j = 0; j < messages.length; j++) {
        var applicableCommands = interpretCommand(messages[j])
        if(applicableCommands.length > 0
          && messages[j].author.username != DEFAULT_USERNAME) {
            messages[j].commands = applicableCommands
            messages[j].private = private
            commands.push(messages[j])
            if((messages[j].reactions || [])
                .filter(a => a.emoji.name == '\u{1F44D}').length > 0) {
                launches.push(messages[j])
            }
        }
        if(messages[j].content.match(/```BOT/ig)) {
            responses.push(messages[j])
            if((messages[j].reactions || [])
                .filter(a => a.emoji.name == '\u{1F44D}').length > 0) {
                var l = messages.filter(m => messages[j].content.match('```BOT'+m.id))[0]
                if(!l) continue
                l.launching = true
                l.reactions = l.reactions || []
                l.reactions.push.apply(l.reactions, messages[j].reactions)
                if(l) launches.push(l)
            }
        }
    }
        
    // find all commands in interactions
    var interactionsCount = Object.keys(interactions)
        .reduce((sum, i) => {return sum + interactions[i].length}, 0)
    console.log(`Reading ${Object.keys(interactions).length} channels with ${interactionsCount} interactions`)
    Object.keys(interactions).forEach(i => {
        for(var c in interactions[i]) {
            interactions[i][c].commands = [interactions[i][c].data.name.toUpperCase()]
            interactions[i][c].author = interactions[i][c].member.user
            interactions[i][c].content = interactions[i][c].data.name + ' '
                + (interactions[i][c].data.options || []).map(o => o.value).join(' ')
            interactions[i][c].interaction = true
            commands.push(interactions[i][c])
        }
        interactions[i] = []
    })


    // exclude commands that already got a response
    return commands
        .filter(c => responses.filter(r => r.content.match(new RegExp('```BOT'+c.id))).length === 0)
        .concat(launches)
        .filter(c => responses.filter(r => r.content.match(new RegExp('```BOT'+c.id+'L'))).length === 0)
        .filter((c, i, arr) => arr.indexOf(c) === i)
}

async function respondCommand(specificChannel) {
    await authorizeGateway()
    var commands = await readAllCommands(specificChannel)
    for(var i = 0; i < commands.length; i++) {
        if(commands[i].commands.includes('CHALLENGE'))
            await challengeCommand(commands[i])
        else if(commands[i].commands.includes('CONFIG')) 
            await configCommand(commands[i])
        else if(commands[i].commands.includes('CONNECT'))
            await connectCommand(commands[i])
        else if(commands[i].commands.includes('RCON'))
            await rconCommand(commands[i])
        else if(commands[i].commands.includes('HELLO'))
            await chatCommand(commands[i])
        else if(commands[i].private) {
            console.log('Unknown command', commands[i])
            //await unknownCommand(commands[i])
        }
    }
}

module.exports = respondCommand

What the code could have been:

const { importer } = require('../Core');
const {
  discordApi,
  authorizeGateway,
  privateChannels,
  interactions
} = importer.import('discord API');
const {
  discordCommands,
  challengeCommand,
  configCommand,
  connectCommand,
  rconCommand,
  chatCommand
} = importer.import('discord commands');

const DEFAULT_USERNAME = 'Orbb';

class CommandInterpreter {
  static async interpretCommand(message) {
    const applicableCommands = Object.keys(discordCommands)
     .filter(k => message.content.match(discordCommands[k])
        || (message.attachments && message.attachments.filter(a => a.filename.match(discordCommands[k])).length > 0)
        || (message.embeds && message.embeds.filter(e => (e.title && e.title.match(discordCommands[k]))
          || (e.description && e.description.match(discordCommands[k]))).length > 0))
     .map(c => ({ command: c, message }));
    return applicableCommands;
  }
}

class CommandReader {
  static async readAllCommands(specificChannel) {
    const channels = [];
    const messages = [];
    const responses = [];
    const launches = [];
    const commands = [];

    if (specificChannel === '@me') {
      const userChannels = Object.keys(privateChannels)
       .filter(k => privateChannels[k] > Date.now() - 1000 * 60 * 60)
       .map(k => ({ id: k }));
      channels.push(...userChannels);
      specificChannel = '';
    } else {
      const guilds = await discordApi.userGuilds();
      console.log(`Reading ${guilds.length} guilds`);
      for (const guild of guilds) {
        const guildChannels = await discordApi.guildChannels(guild.id);
        channels.push(...guildChannels);
      }
    }

    console.log(`Reading ${channels.length} channels`);
    for (const channel of channels) {
      if (!specificChannel || channel.id === specificChannel || (typeof specificChannel ==='string' && (specificChannel.length === 0 || channel.name.match(new RegExp(specificChannel, 'ig'))))) {
        console.log(`Reading ${channel.name}`);
        const channelMessages = await discordApi.channelMessages(channel.id);
        messages.push(...channelMessages);
      }
    }

    console.log(`Reading ${messages.length} messages`);
    for (const message of messages) {
      const applicableCommands = await CommandInterpreter.interpretCommand(message);
      if (applicableCommands.length > 0 && message.author.username!== DEFAULT_USERNAME) {
        message.commands = applicableCommands.map(c => c.command);
        commands.push(message);
        if ((message.reactions || []).filter(r => r.emoji.name === '\u{1F44D}').length > 0) {
          launches.push(message);
        }
      }
    }

    const interactionCount = Object.keys(interactions).reduce((sum, i) => sum + interactions[i].length, 0);
    console.log(`Reading ${Object.keys(interactions).length} channels with ${interactionCount} interactions`);
    Object.keys(interactions).forEach(channelId => {
      interactions[channelId].forEach(interaction => {
        interaction.commands = [interaction.data.name.toUpperCase()];
        interaction.author = interaction.member.user;
        interaction.content = interaction.data.name +'' + (interaction.data.options || []).map(o => o.value).join(' ');
        interaction.interaction = true;
        commands.push(interaction);
      });
      interactions[channelId] = [];
    });

    return commands
     .filter(command =>!responses.find(response => response.content.match(new RegExp(````BOT${command.id}`))))
     .concat(launches)
     .filter(command =>!responses.find(response => response.content.match(new RegExp(````BOT${command.id}L`))))
     .filter((command, index, array) => array.indexOf(command) === index);
  }
}

class Commander {
  static async respondCommand(specificChannel) {
    await authorizeGateway();
    const commands = await CommandReader.readAllCommands(specificChannel);
    for (const command of commands) {
      if (command.commands.includes('CHALLENGE')) {
        await challengeCommand(command);
      } else if (command.commands.includes('CONFIG')) {
        await configCommand(command);
      } else if (command.commands.includes('CONNECT')) {
        await connectCommand(command);
      } else if (command.commands.includes('RCON')) {
        await rconCommand(command);
      } else if (command.commands.includes('HELLO')) {
        await chatCommand(command);
      } else if (command.private) {
        console.log('Unknown command', command);
        // TODO: implement unknownCommand
      }
    }
  }
}

module.exports = Commander;

Code Breakdown

Requirements and Imports

The code begins by importing necessary modules and variables:

var importer = require('../Core')
var discordApi = importer.import('discord api')
var {authorizeGateway, privateChannels, interactions} = importer.import('authorize discord')
var {
    discordCommands,
    challengeCommand,
    configCommand,
    connectCommand,
    rconCommand,
    chatCommand,
} = importer.import('discord commands')

Constants and Functions

The code defines a constant DEFAULT_USERNAME and two functions: interpretCommand and readAllCommands.

interpretCommand

This function takes a message object as input and returns an array of keys from the discordCommands object that match the message content, attachments, or embeds.

function interpretCommand(message) {
    return Object.keys(discordCommands)
      .filter(k => message.content.match(discordCommands[k])
              || (message.attachments && message.attachments.filter(a => a.filename.match(discordCommands[k])).length > 0)
              || (message.embeds && message.embeds.filter(e => (e.title && e.title.match(discordCommands[k]))
                                                          || (e.description && e.description.match(discordCommands[k]))).length > 0))
}

readAllCommands

This is an asynchronous function that reads all commands from specified channels. It takes a specificChannel parameter, which can be a channel ID, a username, or an empty string.

readAllCommands Function

Main Logic

The function first checks if the specificChannel parameter is @me. If it is, it reads the user's channels that were updated within the last hour. Otherwise, it reads all channels from the user's guilds.

if(specificChannel == '@me') {
    // only read channel if it was updated within the last hour
    var userChannels = Object
       .keys(privateChannels)
       .filter(k => privateChannels[k] > Date.now() - 1000 * 60 * 60)
       .map(k => ({id: k}))
    channels.push.apply(channels, userChannels)
    specificChannel = ''
    private = true
} else {
    var guilds = await discordApi.userGuilds()
    console.log(`Reading ${guilds.length} guilds`)
    for(var i = 0; i < guilds.length; i++) {
        channels.push.apply(channels, await discordApi.guildChannels(guilds[i].id))
    }
}

Reading Channels

If specificChannel is not empty or is a channel ID, the function reads the specified channel. Otherwise, it reads all channels.

console.log(`Reading ${channels.length} channels`)
for(var i = 0; i < channels.length; i++) {
    if(!specificChannel
       || channels[i].id == specificChannel
       || (typeof specificChannel =='string'
          && channels[i].name.match(specificChannel))
    ) {
        // channel logic here
    }
}

Processing Commands

The function processes the commands in each channel and populates the commands, launches, and responses arrays.

// channel logic here