2020-04-20 20:52:22 +00:00
const fs = require ( "fs" ) ;
2019-09-13 20:02:41 +00:00
const database = require ( "../utils/database.js" ) ;
const logger = require ( "../utils/logger.js" ) ;
const collections = require ( "../utils/collections.js" ) ;
2020-09-10 18:31:41 +00:00
const commands = [ ... collections . aliases . keys ( ) , ... collections . commands . keys ( ) ] ;
2019-09-13 20:02:41 +00:00
// run when someone sends a message
Class commands, improved sharding, and many other changes (#88)
* Load commands recursively
* Sort commands
* Missed a couple of spots
* missed even more spots apparently
* Ported commands in "fun" category to new class-based format, added babel eslint plugin
* Ported general commands, removed old/unneeded stuff, replaced moment with day, many more fixes I lost track of
* Missed a spot
* Removed unnecessary abort-controller package, add deprecation warning for mongo database
* Added imagereload, clarified premature end message
* Fixed docker-compose path issue, added total bot uptime to stats, more fixes for various parts
* Converted image commands into classes, fixed reload, ignore another WS event, cleaned up command handler and image runner
* Converted music/soundboard commands to class format
* Cleanup unnecessary logs
* awful tag command class port
* I literally somehow just learned that you can leave out the constructor in classes
* Pass client directly to commands/events, cleaned up command handler
* Migrated bot to eris-sharder, fixed some error handling stuff
* Remove unused modules
* Fixed type returning
* Switched back to Eris stable
* Some fixes and cleanup
* might wanna correct this
* Implement image command ratelimiting
* Added Bot token prefix, added imagestats, added running endpoint to API
2021-04-12 16:16:12 +00:00
module . exports = async ( client , message ) => {
2019-09-13 20:02:41 +00:00
// ignore dms and other bots
if ( message . author . bot ) return ;
2019-12-16 23:14:29 +00:00
// don't run command if bot can't send messages
2021-03-12 20:42:07 +00:00
if ( message . channel . guild && ! message . channel . permissionsOf ( client . user . id ) . has ( "sendMessages" ) ) return ;
2019-12-16 23:14:29 +00:00
2020-09-10 01:14:01 +00:00
// this is here to prevent reading the database if a message is unrelated
let valid = false ;
2020-09-10 18:31:41 +00:00
for ( const key of commands ) {
2020-09-12 18:57:25 +00:00
if ( message . content . toLowerCase ( ) . includes ( key ) ) {
2020-09-10 01:14:01 +00:00
valid = true ;
break ;
}
}
if ( ! valid ) return ;
2020-12-18 02:32:19 +00:00
let prefixCandidate ;
2020-12-26 18:17:10 +00:00
if ( message . channel . guild ) {
if ( collections . prefixCache . has ( message . channel . guild . id ) ) {
prefixCandidate = collections . prefixCache . get ( message . channel . guild . id ) ;
} else {
let guildDB = message . channel . guild ? await database . getGuild ( message . channel . guild . id ) : null ;
if ( message . channel . guild && ! ( guildDB && guildDB . disabled ) ) {
guildDB = await database . fixGuild ( message . channel . guild ) ;
}
prefixCandidate = guildDB . prefix ;
collections . prefixCache . set ( message . channel . guild . id , guildDB . prefix ) ;
2020-12-18 02:32:19 +00:00
}
2020-11-05 21:40:18 +00:00
}
2020-12-18 02:32:19 +00:00
2021-03-18 14:29:03 +00:00
let prefix ;
let isMention = false ;
if ( message . channel . guild ) {
const user = message . channel . guild . members . get ( client . user . id ) ;
if ( message . content . startsWith ( user . mention ) ) {
prefix = ` ${ user . mention } ` ;
isMention = true ;
} else if ( message . content . startsWith ( ` <@ ${ client . user . id } > ` ) ) { // workaround for member.mention not accounting for both mention types
prefix = ` <@ ${ client . user . id } > ` ;
isMention = true ;
} else {
prefix = prefixCandidate ;
}
} else {
prefix = "" ;
}
2019-09-13 20:02:41 +00:00
// ignore other stuff
2020-03-14 23:22:09 +00:00
if ( message . content . startsWith ( prefix ) === false ) return ;
2019-09-13 20:02:41 +00:00
// separate commands and args
2021-03-18 14:29:03 +00:00
const replace = isMention ? ` @ ${ client . user . username } ` : prefix ;
const content = message . cleanContent . substring ( replace . length ) . trim ( ) ;
2021-03-16 20:45:10 +00:00
const rawContent = message . content . substring ( prefix . length ) . trim ( ) ;
2020-01-13 16:31:01 +00:00
const args = content . split ( / +/g ) ;
2021-03-16 20:59:59 +00:00
args . shift ( ) ;
2021-03-16 20:45:10 +00:00
const command = rawContent . split ( / +/g ) . shift ( ) . toLowerCase ( ) ;
2019-09-13 20:02:41 +00:00
2020-04-10 02:40:52 +00:00
// don't run if message is in a disabled channel
2020-12-26 18:17:10 +00:00
if ( message . channel . guild ) {
if ( collections . disabledCache . has ( message . channel . guild . id ) ) {
const disabled = collections . disabledCache . get ( message . channel . guild . id ) ;
if ( disabled . includes ( message . channel . id ) && command != "channel" ) return ;
} else if ( message . channel . guild ) {
const guildDB = await database . getGuild ( message . channel . guild . id ) ;
collections . disabledCache . set ( message . channel . guild . id , guildDB . disabled ) ;
if ( guildDB . disabled . includes ( message . channel . id ) && command !== "channel" ) return ;
}
2020-12-18 02:32:19 +00:00
}
2020-04-10 02:40:52 +00:00
2019-09-13 20:02:41 +00:00
// check if command exists
const cmd = collections . commands . get ( command ) || collections . commands . get ( collections . aliases . get ( command ) ) ;
if ( ! cmd ) return ;
// actually run the command
Class commands, improved sharding, and many other changes (#88)
* Load commands recursively
* Sort commands
* Missed a couple of spots
* missed even more spots apparently
* Ported commands in "fun" category to new class-based format, added babel eslint plugin
* Ported general commands, removed old/unneeded stuff, replaced moment with day, many more fixes I lost track of
* Missed a spot
* Removed unnecessary abort-controller package, add deprecation warning for mongo database
* Added imagereload, clarified premature end message
* Fixed docker-compose path issue, added total bot uptime to stats, more fixes for various parts
* Converted image commands into classes, fixed reload, ignore another WS event, cleaned up command handler and image runner
* Converted music/soundboard commands to class format
* Cleanup unnecessary logs
* awful tag command class port
* I literally somehow just learned that you can leave out the constructor in classes
* Pass client directly to commands/events, cleaned up command handler
* Migrated bot to eris-sharder, fixed some error handling stuff
* Remove unused modules
* Fixed type returning
* Switched back to Eris stable
* Some fixes and cleanup
* might wanna correct this
* Implement image command ratelimiting
* Added Bot token prefix, added imagestats, added running endpoint to API
2021-04-12 16:16:12 +00:00
logger . log ( "log" , ` ${ message . author . username } ( ${ message . author . id } ) ran command ${ command } ` ) ;
2019-09-13 20:02:41 +00:00
try {
2020-12-18 02:32:19 +00:00
await database . addCount ( collections . aliases . has ( command ) ? collections . aliases . get ( command ) : command ) ;
2021-03-05 18:03:17 +00:00
const startTime = new Date ( ) ;
Class commands, improved sharding, and many other changes (#88)
* Load commands recursively
* Sort commands
* Missed a couple of spots
* missed even more spots apparently
* Ported commands in "fun" category to new class-based format, added babel eslint plugin
* Ported general commands, removed old/unneeded stuff, replaced moment with day, many more fixes I lost track of
* Missed a spot
* Removed unnecessary abort-controller package, add deprecation warning for mongo database
* Added imagereload, clarified premature end message
* Fixed docker-compose path issue, added total bot uptime to stats, more fixes for various parts
* Converted image commands into classes, fixed reload, ignore another WS event, cleaned up command handler and image runner
* Converted music/soundboard commands to class format
* Cleanup unnecessary logs
* awful tag command class port
* I literally somehow just learned that you can leave out the constructor in classes
* Pass client directly to commands/events, cleaned up command handler
* Migrated bot to eris-sharder, fixed some error handling stuff
* Remove unused modules
* Fixed type returning
* Switched back to Eris stable
* Some fixes and cleanup
* might wanna correct this
* Implement image command ratelimiting
* Added Bot token prefix, added imagestats, added running endpoint to API
2021-04-12 16:16:12 +00:00
const commandClass = new cmd ( client , message , args , message . content . substring ( prefix . length ) . trim ( ) . replace ( command , "" ) . trim ( ) ) ;
const result = await commandClass . run ( ) ; // we also provide the message content as a parameter for cases where we need more accuracy
2021-03-05 18:03:17 +00:00
const endTime = new Date ( ) ;
2020-04-12 19:51:48 +00:00
if ( typeof result === "string" || ( typeof result === "object" && result . embed ) ) {
2019-09-13 20:02:41 +00:00
await client . createMessage ( message . channel . id , result ) ;
2020-04-12 19:51:48 +00:00
} else if ( typeof result === "object" && result . file ) {
2020-04-24 02:14:03 +00:00
if ( result . file . length > 8388119 && process . env . TEMPDIR !== "" ) {
2020-04-20 20:52:22 +00:00
const filename = ` ${ Math . random ( ) . toString ( 36 ) . substring ( 2 , 15 ) } . ${ result . name . split ( "." ) [ 1 ] } ` ;
2020-08-13 13:47:41 +00:00
await fs . promises . writeFile ( ` ${ process . env . TEMPDIR } / ${ filename } ` , result . file ) ;
2020-04-20 20:52:22 +00:00
await client . createMessage ( message . channel . id , {
embed : {
color : 16711680 ,
2020-12-08 02:42:36 +00:00
title : "Here's your image!" ,
2021-03-05 18:03:17 +00:00
url : ` ${ process . env . TMP _DOMAIN == "" ? "https://projectlounge.pw/tmp" : process . env . TMP _DOMAIN } / ${ filename } ` ,
2020-04-20 20:52:22 +00:00
image : {
2021-03-05 18:03:17 +00:00
url : ` ${ process . env . TMP _DOMAIN == "" ? "https://projectlounge.pw/tmp" : process . env . TMP _DOMAIN } / ${ filename } `
2020-12-08 02:42:36 +00:00
} ,
footer : {
text : "The result image was more than 8MB in size, so it was uploaded to an external site instead."
} ,
2021-03-05 18:03:17 +00:00
} ,
content : ( endTime - startTime ) >= 180000 ? message . author . mention : undefined
2020-04-20 20:52:22 +00:00
} ) ;
} else {
2021-03-05 18:03:17 +00:00
await client . createMessage ( message . channel . id , result . text ? result . text : ( ( endTime - startTime ) >= 180000 ? message . author . mention : undefined ) , result ) ;
2020-04-20 20:52:22 +00:00
}
2019-09-13 20:02:41 +00:00
}
} catch ( error ) {
2020-07-17 00:54:03 +00:00
if ( error . toString ( ) . includes ( "Request entity too large" ) ) {
await client . createMessage ( message . channel . id , ` ${ message . author . mention } , the resulting file was too large to upload. Try again with a smaller image if possible. ` ) ;
2021-01-04 16:29:18 +00:00
} else if ( error . toString ( ) . includes ( "UDP timed out" ) ) {
await client . createMessage ( message . channel . id , ` ${ message . author . mention } , I couldn't contact the image API in time (most likely due to it being overloaded). Try running your command again. ` ) ;
2020-07-17 00:54:03 +00:00
} else if ( error . toString ( ) . includes ( "Timed out" ) ) {
await client . createMessage ( message . channel . id , ` ${ message . author . mention } , the request timed out before I could download that image. Try uploading your image somewhere else. ` ) ;
} else {
2020-02-25 21:07:36 +00:00
logger . error ( error . toString ( ) ) ;
2020-09-01 22:10:19 +00:00
await client . createMessage ( message . channel . id , "Uh oh! I ran into an error while running this command. Please report the content of the attached file here or on the esmBot Support server: <https://github.com/esmBot/esmBot/issues>" , [ {
2020-02-25 21:07:36 +00:00
file : Buffer . from ( ` Message: ${ error } \n \n Stack Trace: ${ error . stack } ` ) ,
name : "error.txt"
} ] ) ;
}
2019-09-13 20:02:41 +00:00
}
} ;