2021-01-07 22:02:38 -08:00
/ * T h e A r t i f i c e r w a s b u i l t i n m e m o r y o f B a b k a
* With love , Ean
*
* December 21 , 2020
* /
2021-01-07 05:34:14 -08:00
import { Message } from "https://deno.land/x/discordeno@10.0.0/mod.ts" ;
2021-01-07 11:00:46 -08:00
// split2k(longMessage) returns shortMessage[]
// split2k takes a long string in and cuts it into shorter strings to be sent in Discord
2021-01-07 05:34:14 -08:00
const split2k = ( chunk : string ) : string [ ] = > {
2021-01-07 11:00:46 -08:00
// Replace any malformed newline characters
2021-01-07 05:34:14 -08:00
chunk = chunk . replace ( /\\n/g , "\n" ) ;
const bites = [ ] ;
2021-01-07 11:00:46 -08:00
// While there is more characters than allowed to be sent in discord
2021-01-07 05:34:14 -08:00
while ( chunk . length > 2000 ) {
2021-01-07 11:00:46 -08:00
// Take 2001 chars to see if word magically ends on char 2000
2021-01-07 05:34:14 -08:00
let bite = chunk . substr ( 0 , 2001 ) ;
2021-01-07 11:00:46 -08:00
const lastI = bite . lastIndexOf ( " " ) ;
if ( lastI < 2000 ) {
// If there is a final word before the 2000 split point, split right after that word
bite = bite . substr ( 0 , lastI ) ;
2021-01-07 05:34:14 -08:00
} else {
2021-01-07 11:00:46 -08:00
// Else cut exactly 2000 characters
2021-01-07 05:34:14 -08:00
bite = bite . substr ( 0 , 2000 ) ;
}
2021-01-07 11:00:46 -08:00
// Push and remove the bite taken out of the chunk
2021-01-07 05:34:14 -08:00
bites . push ( bite ) ;
chunk = chunk . slice ( bite . length ) ;
}
// Push leftovers into bites
bites . push ( chunk ) ;
return bites ;
} ;
2021-01-07 11:00:46 -08:00
// ask(prompt) returns string
// ask prompts the user at command line for message
const ask = async ( question : string , stdin = Deno . stdin , stdout = Deno . stdout ) : Promise < string > = > {
2021-01-07 05:34:14 -08:00
const buf = new Uint8Array ( 1024 ) ;
// Write question to console
await stdout . write ( new TextEncoder ( ) . encode ( question ) ) ;
// Read console's input into answer
const n = < number > await stdin . read ( buf ) ;
const answer = new TextDecoder ( ) . decode ( buf . subarray ( 0 , n ) ) ;
return answer . trim ( ) ;
} ;
2021-01-07 11:00:46 -08:00
// cmdPrompt(logChannel, botName, sendMessage) returns nothing
// cmdPrompt creates an interactive CLI for the bot, commands can vary
2021-01-07 05:34:14 -08:00
const cmdPrompt = async ( logChannel : string , botName : string , sendMessage : ( c : string , m : string ) = > Promise < Message > ) : Promise < void > = > {
let done = false ;
while ( ! done ) {
2021-01-07 11:00:46 -08:00
// Get a command and its args
2021-01-07 05:34:14 -08:00
const fullCmd = await ask ( "cmd> " ) ;
2021-01-07 11:00:46 -08:00
// Split the args off of the command and prep the command
2021-01-07 05:34:14 -08:00
const args = fullCmd . split ( " " ) ;
const command = args . shift ( ) ? . toLowerCase ( ) ;
2021-01-07 11:00:46 -08:00
// All commands below here
// exit or e
// Fully closes the bot
2021-01-07 05:34:14 -08:00
if ( command === "exit" || command === "e" ) {
console . log ( ` ${ botName } Shutting down. \ n \ nGoodbye. ` ) ;
done = true ;
Deno . exit ( 0 ) ;
2021-01-07 11:00:46 -08:00
}
// stop
// Closes the CLI only, leaving the bot running truly headless
else if ( command === "stop" ) {
2021-01-07 05:34:14 -08:00
console . log ( ` Closing ${ botName } CLI. Bot will continue to run. \ n \ nGoodbye. ` ) ;
done = true ;
2021-01-07 11:00:46 -08:00
}
// m [channel] [message]
// Sends [message] to specified [channel]
else if ( command === "m" ) {
2021-01-07 05:34:14 -08:00
try {
const channelID = args . shift ( ) || "" ;
const message = args . join ( " " ) ;
2021-01-07 11:00:46 -08:00
// Utilize the split2k function to ensure a message over 2000 chars is not sent
2021-01-07 05:34:14 -08:00
const messages = split2k ( message ) ;
for ( let i = 0 ; i < messages . length ; i ++ ) {
sendMessage ( channelID , messages [ i ] ) . catch ( reason = > {
console . error ( reason ) ;
} ) ;
}
}
catch ( e ) {
console . error ( e ) ;
}
2021-01-07 11:00:46 -08:00
}
// ml [message]
// Sends a message to the specified log channel
else if ( command === "ml" ) {
2021-01-07 05:34:14 -08:00
const message = args . join ( " " ) ;
2021-01-07 11:00:46 -08:00
// Utilize the split2k function to ensure a message over 2000 chars is not sent
2021-01-07 05:34:14 -08:00
const messages = split2k ( message ) ;
for ( let i = 0 ; i < messages . length ; i ++ ) {
sendMessage ( logChannel , messages [ i ] ) . catch ( reason = > {
console . error ( reason ) ;
} ) ;
}
2021-01-07 11:00:46 -08:00
}
// help or h
// Shows a basic help menu
else if ( command === "help" || command === "h" ) {
2021-01-07 05:34:14 -08:00
console . log ( ` ${ botName } CLI Help: \ n \ nAvailable Commands: \ n exit - closes bot \ n stop - closes the CLI \ n m [ChannelID] [messgae] - sends message to specific ChannelID as the bot \ n ml [message] sends a message to the specified botlog \ n help - this message ` ) ;
2021-01-07 11:00:46 -08:00
}
// Unhandled commands die here
else {
2021-01-07 05:34:14 -08:00
console . log ( "undefined command" ) ;
}
}
} ;
2021-01-07 11:00:46 -08:00
// sendIndirectMessage(originalMessage, messageContent, sendMessage, sendDirectMessage) returns Message
// sendIndirectMessage determines if the message needs to be sent as a direct message or as a normal message
const sendIndirectMessage = async ( originalMessage : Message , messageContent : string , sendMessage : ( c : string , m : string ) = > Promise < Message > , sendDirectMessage : ( c : string , m : string ) = > Promise < Message > ) : Promise < Message > = > {
if ( originalMessage . guildID === "" ) {
// guildID was empty, meaning the original message was sent as a DM
return await sendDirectMessage ( originalMessage . author . id , messageContent ) ;
2021-01-07 05:34:14 -08:00
} else {
2021-01-07 11:00:46 -08:00
// guildID was not empty, meaning the original message was sent in a server
return await sendMessage ( originalMessage . channelID , messageContent ) ;
2021-01-07 05:34:14 -08:00
}
} ;
export default { split2k , cmdPrompt , sendIndirectMessage } ;