2016-11-01 01:28:17 +02:00
var console = require ( "console" ) ; //for console logging
var Dns = require ( "dns" ) ; //for connectivity checking
var Url = require ( "url" ) ; //for url parsing
var Uri = require ( "urijs" ) ; //for finding urls within message strings
var Discord = require ( "discord.io" ) ; //for obvious reasons
var FeedRead = require ( "feed-read" ) ; //for rss feed reading
var BotConfig = require ( "./botConfig.json" ) ; //bot config file containing bot token
var Config = require ( "./config.json" ) ; //config file containing other settings
2016-10-29 20:31:16 +03:00
2016-11-01 19:23:39 +02:00
var verboseLogging = false ;
2016-10-30 22:15:15 +02:00
//get a URL object from the feedUrl so we can examine it and check connectivity later
var url = Url . parse ( Config . feedUrl ) ;
2016-10-29 20:31:16 +03:00
2016-10-30 22:15:15 +02:00
//placeholder for our bot - we need to check for connectivity before assigning this though
var bot ;
2016-11-01 02:04:35 +02:00
var latestFeedLink = "" ;
2016-11-01 01:28:17 +02:00
var linkRegExp = new RegExp ( [ "http" , "https" , "www" ] . join ( "|" ) ) ;
var cachedLinks = [ ] ;
//caches a link so we can check again later
function cacheLink ( link ) {
2016-11-01 01:44:14 +02:00
//cheaty way to get around http and https not matching
link = link . replace ( "https://" , "http://" ) ;
2016-11-01 01:28:17 +02:00
//store the new link if not stored already
2016-11-01 02:04:35 +02:00
if ( ! cachedLinks . includes ( link ) ) {
2016-11-01 01:28:17 +02:00
cachedLinks . push ( link ) ;
logEvent ( "Cached URL: " + link ) ;
}
//get rid of the first array element if we have reached our cache limit
if ( cachedLinks . length > ( Config . numLinksToCache || 10 ) )
cachedLinks . shift ( ) ;
}
2016-10-30 22:15:15 +02:00
//check if we can connect to discordapp.com to authenticate the bot
Dns . resolve ( "discordapp.com" , function ( err ) {
2016-11-01 01:28:17 +02:00
if ( err ) reportError ( "CONNECTION ERROR: Unable to locate discordapp.com to authenticate the bot (you are probably not connected to the internet). Details: " + ( err . message || err ) ) ;
2016-10-30 22:15:15 +02:00
else {
//if there was no error, go ahead and create and authenticate the bot
bot = new Discord . Client ( {
token : BotConfig . token ,
autorun : true
} ) ;
//when the bot is ready, set a polling interval for the rss feed
bot . on ( "ready" , function ( ) {
2016-11-01 01:28:17 +02:00
logEvent ( new Date ( ) . toLocaleString ( ) + " Registered bot " + bot . username + " - (" + bot . id + ")" ) ;
2016-10-29 20:31:16 +03:00
2016-11-01 01:28:17 +02:00
//as we don't have any links cached, we need to check recent messages
checkPreviousMessagesForLinks ( ) ;
logEvent ( "Setting up timer to check feed every " + Config . pollingInterval + " milliseconds" ) ;
2016-10-30 22:15:15 +02:00
setInterval ( checkFeedAndPost , Config . pollingInterval ) ;
} ) ;
2016-11-01 19:09:09 +02:00
bot . on ( "disconnect" , function ( err , code ) {
logEvent ( "Bot was disconnected. Code: " + code + ". Details: " + ( err . message || err ) ) ;
logEvent ( "Trying to reconnect bot" ) ;
bot . connect ( ) ;
} ) ;
2016-10-30 22:15:15 +02:00
bot . on ( "message" , function ( user , userID , channelID , message ) {
2016-11-01 01:28:17 +02:00
//check if the message is a link, cache it if it is
2016-11-01 02:24:34 +02:00
if ( linkRegExp . test ( message ) && ( message !== latestFeedLink ) ) {
logEvent ( "Detected posted link: " + message ) ;
2016-11-01 02:54:10 +02:00
//detect the url inside the string, and cache it
Uri . withinString ( message , function ( url ) {
cacheLink ( url ) ;
return url ;
} ) ;
2016-10-30 22:15:15 +02:00
}
2016-10-29 20:31:16 +03:00
} ) ;
}
2016-10-29 21:09:10 +03:00
} ) ;
function checkFeedAndPost ( ) {
2016-10-30 22:15:15 +02:00
//check that we have an internet connection (well not exactly - check that we have a connection to the host of the feedUrl)
Dns . resolve ( url . host , function ( err ) {
2016-11-01 01:28:17 +02:00
if ( err ) reportError ( "CONNECTION ERROR: Cannot resolve host (you are probably not connected to the internet). Details: " + ( err . message || err ) ) ;
else FeedRead ( Config . feedUrl , checkLinkAndPost ) ;
2016-10-30 21:39:46 +02:00
} ) ;
}
2016-10-29 21:09:10 +03:00
2016-10-30 22:15:15 +02:00
//checks if the link has been posted previously, posts if not
2016-10-30 21:39:46 +02:00
function checkLinkAndPost ( err , articles ) {
2016-11-01 01:28:17 +02:00
if ( err ) reportError ( "FEED ERROR: Error reading RSS feed. Details: " + ( err . message || err ) ) ;
else {
//get the latest link and check if it has already been posted and cached
2016-11-01 02:04:35 +02:00
var latestLink = articles [ 0 ] . link . replace ( "https" , "http" ) ;
2016-11-01 01:28:17 +02:00
if ( ! cachedLinks . includes ( latestLink ) ) {
logEvent ( "Attempting to post new link: " + latestLink ) ;
bot . sendMessage ( {
to : Config . channelID ,
message : latestLink
2016-11-01 19:09:09 +02:00
} , function ( err , message ) {
reportError ( "ERROR: Failed to send message: " + ( err . message || err ) + " " + message ) ;
logEvent ( "Checking bot connectivity" ) ;
if ( bot . connected )
logEvent ( "Connectivity seems fine - I have no idea why the message didn't post" ) ;
else {
reportError ( "Bot appears to be disconnected! Attempting to reconnect..." )
bot . connect ( ) ;
}
2016-11-01 01:28:17 +02:00
} ) ;
cacheLink ( latestLink ) ;
}
2016-11-01 02:04:35 +02:00
else if ( latestFeedLink != latestLink )
logEvent ( "Didn't post new feed link because already detected as posted " + latestLink ) ;
latestFeedLink = latestLink ;
2016-11-01 01:28:17 +02:00
}
}
2016-10-29 21:09:10 +03:00
2016-11-01 01:28:17 +02:00
//gets last 100 messages and extracts any links found (for use on startup)
function checkPreviousMessagesForLinks ( ) {
var limit = 100 ;
logEvent ( "Attempting to check past " + limit + " messages for links" ) ;
2016-10-30 21:39:46 +02:00
bot . getMessages ( {
channelID : Config . channelID ,
2016-11-01 01:28:17 +02:00
limit : limit
2016-10-30 21:39:46 +02:00
} , function ( err , messages ) {
2016-11-01 01:28:17 +02:00
if ( err ) reportError ( "Error fetching discord messages. Details: " + ( err . message || err ) ) ;
else {
logEvent ( "Pulled last " + messages . length + " messages, scanning for links" ) ;
2016-11-01 02:04:35 +02:00
var messageContents = messages . map ( ( x ) => { return x . content ; } ) . reverse ( ) ;
2016-11-01 01:28:17 +02:00
for ( var message in messageContents ) {
message = messageContents [ message ] ;
if ( linkRegExp . test ( message ) )
2016-11-01 02:54:10 +02:00
//detect the url inside the string, and cache it
Uri . withinString ( message , function ( url ) {
cacheLink ( url ) ;
return url ;
} ) ;
2016-11-01 01:28:17 +02:00
}
}
} ) ;
}
2016-10-29 21:09:10 +03:00
2016-11-01 02:04:35 +02:00
function logEvent ( message ) {
2016-11-01 02:17:54 +02:00
console . log ( new Date ( ) . toLocaleString ( ) + " " + message ) ;
2016-11-01 01:28:17 +02:00
}
2016-10-30 21:39:46 +02:00
2016-11-01 01:28:17 +02:00
//logs error to console with a timestamp
function reportError ( message ) {
console . log ( new Date ( ) . toLocaleString ( ) + " ERROR: " + message ) ;
2016-10-29 21:09:10 +03:00
}