2020-07-23 22:40:20 +02:00
const path = require ( 'path' ) ;
2020-07-24 20:49:32 +02:00
const chalk = require ( 'chalk' ) ;
2020-07-23 22:40:20 +02:00
2020-07-04 12:23:10 +02:00
const { Observer } = require ( "../../../interfaces" ) ;
2020-07-23 22:40:20 +02:00
const { Util , Collection } = require ( '../../../../util/' ) ;
const CONSTANTS = {
IMAGES : {
PREMIUM _LIMIT : 2 ,
UPLOAD _LIMIT : {
'0' : 8 ,
'1' : 8 ,
'2' : 50 ,
'3' : 100
} ,
MB _DIVIDER : 1024 * 1024 ,
PREMIUM _DELETE : {
'0' : 0 ,
'1' : 0 ,
'2' : 2 ,
'3' : 4
}
} ,
DAY : 24 * 60 * 60
} ;
2020-07-04 12:23:10 +02:00
class MessageCache extends Observer {
constructor ( client ) {
super ( client , {
name : 'messageCache' ,
2021-06-09 01:45:34 +02:00
priority : 0 ,
disabled : false
2020-07-04 12:23:10 +02:00
} ) ;
this . client = client ;
this . hooks = [
2020-07-23 22:40:20 +02:00
[ 'message' , this . cache . bind ( this ) ] ,
[ 'messageDelete' , this . cacheUpdate . bind ( this ) ]
2020-07-04 12:23:10 +02:00
] ;
2020-07-23 22:40:20 +02:00
this . messages = new Collection ( ) ;
setInterval ( ( ) => {
this . _sweepCache ( ) ;
this . _sweepDatabase ( ) ;
2020-07-24 20:31:52 +02:00
} , 3600 * 1000 ) ; // 1 hour
2020-07-23 22:40:20 +02:00
}
async cache ( message ) {
if ( ! this . client . _built
|| message . webhookID
|| message . author . bot
2020-07-28 20:49:34 +02:00
|| ! message . guild
|| ! message . guild . available ) return undefined ;
2020-07-23 22:40:20 +02:00
await message . guild . settings ( ) ;
const data = await this . _grabMessageData ( message ) ;
this . messages . set ( message . id , data ) ;
}
async cacheUpdate ( message ) {
2020-07-24 20:31:52 +02:00
const cachedMessage = this . messages . get ( message . id ) ;
if ( ! cachedMessage ) return undefined ;
cachedMessage . deleted = true ;
return this . messages . set ( message . id , cachedMessage ) ;
2020-07-23 22:40:20 +02:00
}
async _grabMessageData ( message ) {
const metadata = {
guild : message . guild . id ,
message : message . id ,
author : message . author . id ,
2020-07-24 20:31:52 +02:00
channel : message . channel . id ,
2020-07-23 22:40:20 +02:00
content : message . content ,
id : message . id ,
timestamp : message . createdTimestamp ,
deleted : false ,
attachments : [ ] ,
2020-07-24 20:31:52 +02:00
removeAt : Math . floor ( Date . now ( ) / 1000 + CONSTANTS . IMAGES . PREMIUM _DELETE [ message . guild . premium ] * 24 * 60 * 60 )
2020-07-23 22:40:20 +02:00
} ;
const { _settings : guildSettings } = message . guild ;
const { messageLog } = guildSettings ;
let ignoredRole = false ;
if ( messageLog . enabled && messageLog . ignoredRoles . length > 0 ) {
for ( const role of message . member . roles . cache . keys ( ) ) {
if ( messageLog . ignoredRoles . includes ( role ) ) ignoredRole = true ;
}
}
if ( message . attachments . size > 0
&& message . guild . premium >= 2
&& messageLog . channel
2021-06-06 15:30:53 +02:00
&& ! messageLog . ignore . includes ( message . channel . id )
2020-07-23 22:40:20 +02:00
&& ! ignoredRole ) {
2020-07-25 08:02:22 +02:00
let size = 0 ;
2020-07-23 22:40:20 +02:00
for ( const attachment of message . attachments . values ( ) ) {
const data = {
size : attachment . size ,
dimensions : { x : attachment . width , y : attachment . height } ,
extension : path . extname ( attachment . name ) ,
url : attachment . proxyURL || attachment . url ,
name : attachment . name ,
id : attachment . id
} ;
const fsize = data . size / CONSTANTS . IMAGES . MB _DIVIDER ; // File size in MB
2020-07-28 05:00:24 +02:00
if ( fsize > CONSTANTS . IMAGES . UPLOAD _LIMIT [ message . guild . premiumTier ] ) {
2020-07-23 22:40:20 +02:00
metadata . attachments . push ( data ) ;
2020-07-28 05:00:24 +02:00
continue ; //Cannot upload images larger than the guild's upload limit (Users w/ nitro can upload more than that, but the bot will be unable to post them.)
2020-07-23 22:40:20 +02:00
}
const buffer = await Util . downloadAsBuffer ( attachment . proxyURL || attachment . url ) . catch ( ( err ) => {
2021-06-10 02:50:56 +02:00
this . client . logger . error ( ` Failed to download buffer for " ${ chalk . bold ( data . name ) } ". \n ${ err . stack || err } \n https://discord.com/channels/ ${ message . guild . id } / ${ message . channel . id } / ${ message . id } ` ) ;
2020-07-23 22:40:20 +02:00
return null ;
} ) ;
2020-07-25 08:02:22 +02:00
2020-07-28 05:00:24 +02:00
if ( buffer ) {
if ( fsize < 15 ) {
2020-08-08 00:21:28 +02:00
const result = await this . client . storageManager . mongodb . attachments . insertOne ( {
attachmentId : attachment . id ,
buffer
2020-07-23 22:40:20 +02:00
} ) ;
2020-07-24 20:31:52 +02:00
data . index = result ? . insertedId ;
2020-07-28 05:00:24 +02:00
} else {
//Upload using GridFS, not a priority right now.
2021-06-10 02:50:56 +02:00
//this.client.logger.error(`Temporary logging; attachment "${chalk.bold(data.name)}" exceeds 15mb.`);
2020-07-23 22:40:20 +02:00
}
}
metadata . attachments . push ( data ) ;
2020-07-25 08:02:22 +02:00
size += fsize ;
2020-07-23 22:40:20 +02:00
}
2020-07-28 05:00:24 +02:00
this . client . logger . debug ( ` ${ chalk . bold ( '[IMAGE]' ) } User ${ message . author . tag } in guild ${ message . guild . name } (# ${ message . channel . name } ) uploaded ${ message . attachments . size } attachment ${ message . attachments . size === 1 ? '' : 's' } ( ${ size . toFixed ( 2 ) } mb). ` ) ;
2020-08-08 00:21:28 +02:00
await this . client . storageManager . mongodb . messages . insertOne ( metadata ) ;
2020-07-23 22:40:20 +02:00
}
return metadata ; //NOTE: It is NOT GARAUNTEED FOR EVERY ATTACHMENT TO HAVE AN INDEX. If theres no index, it either failed to be pushed to database or could not be saved.
2020-07-04 12:23:10 +02:00
}
2020-07-23 22:40:20 +02:00
async _sweepDatabase ( ) {
2020-08-08 00:21:28 +02:00
const messages = await this . client . storageManager . mongodb . messages . find ( {
removeAt : {
$lt : Date . now ( ) / 1000
2020-07-23 22:40:20 +02:00
}
} ) ;
if ( messages . length > 0 ) {
const attachmentIds = messages . map ( ( m ) => m . attachments ) . reduce ( ( a , b ) => b . concat ( a ) ) . filter ( ( a ) => a ) . map ( ( a ) => a . index ) ;
2020-08-08 00:21:28 +02:00
const deleteAttachments = await this . client . storageManager . mongodb . attachments . deleteMany ( {
_id : { $in : attachmentIds }
2020-07-23 22:40:20 +02:00
} ) ;
const msgIds = messages . map ( ( m ) => m . _id ) ;
2020-08-08 00:21:28 +02:00
const deleteMessages = await this . client . storageManager . mongodb . messages . deleteMany ( {
_id : { $in : msgIds }
2020-07-23 22:40:20 +02:00
} ) ;
2020-07-28 05:00:24 +02:00
const messageCount = deleteMessages . deletedCount ;
const attachmentCount = deleteAttachments . deletedCount ;
2020-08-17 22:26:57 +02:00
this . client . logger . info ( ` ${ chalk . bold ( '[IMAGE]' ) } Trashed ${ messageCount } message ${ messageCount === 1 ? '' : 's' } and ${ attachmentCount } attachment ${ attachmentCount === 1 ? '' : 's' } . ` ) ;
2020-07-28 05:00:24 +02:00
2020-07-23 22:40:20 +02:00
}
}
_sweepCache ( ) {
const ms = 3600000 ; // 1 hour in ms ( i think )
const filtered = this . messages . filter ( ( m ) => {
const time = Date . now ( ) - m . timestamp ;
return time < ms ;
} ) ;
2020-07-04 12:23:10 +02:00
2020-07-23 22:40:20 +02:00
const difference = this . messages . size - filtered . size ;
if ( difference > 0 ) {
this . client . logger . debug ( ` Trashed ${ difference } items from the message cache. ` ) ;
this . messages = filtered ;
}
return filtered ;
2020-07-04 12:23:10 +02:00
}
}
module . exports = MessageCache ;