2023-10-01 19:11:27 -07:00
// Mercury RSS Client - git.supernets.org/hgw/mercury
// ____ ___ ___ ____________ _________ __
// / __ `__ \/ _ \/ ___/ ___/ / / / ___/ / / /
// / / / / / / __/ / / /__/ /_/ / / / /_/ /
// /_/ /_/ /_/\___/_/ \___/\__,_/_/ \__, /
// COLD HARD FEEDS /____/
//
2023-12-03 20:00:56 -08:00
//var config = require('./config/default.json');
2023-10-01 19:11:25 -07:00
//var uconfig = require('./config/usersettings.json');
2023-10-01 19:11:23 -07:00
var irc = require ( "irc" ) ;
var fs = require ( "fs" ) ;
var readline = require ( 'readline' ) ;
const { Worker } = require ( 'worker_threads' ) ;
2023-12-03 20:00:56 -08:00
const { setMaxIdleHTTPParsers } = require ( "http" ) ;
2023-10-01 19:11:23 -07:00
//var randomWords = require('better-random-words');
2023-12-03 20:00:56 -08:00
const timer = ms => new Promise ( res => setTimeout ( res , ms ) )
console . log ( '[bot] Checking if config file exists' )
if ( fs . existsSync ( './config/default.json' ) ) {
var config = require ( './config/default.json' ) ;
console . log ( '[bot] Config file exists, can proceed with initialisation' )
} else {
console . log ( '[bot] The config file, default.json, does not exist in the config folder. Mercury can not start.' )
process . exit ( )
}
timer ( 100 )
2023-10-01 19:11:25 -07:00
warningMsg = ' ' + config . colours . brackets + '[ ' + config . colours . warning + 'WARNING ' + config . colours . brackets + '] '
errorMsg = ' ' + config . colours . brackets + '[ ' + config . colours . error + 'ERROR ' + config . colours . brackets + '] '
2023-10-01 19:11:25 -07:00
var bot = new irc . Client ( config . irc . server , config . irc . nickname , {
channels : config . irc . channels ,
secure : config . irc . ssl ,
port : config . irc . port ,
autoRejoin : config . irc . autorejoin ,
userName : config . irc . username ,
realName : config . irc . realname ,
2023-10-01 19:11:26 -07:00
floodProtection : config . floodprotect . flood _protection ,
floodProtectionDelay : config . floodprotect . flood _protection _delay
2023-10-01 19:11:23 -07:00
} ) ;
2023-10-01 19:11:26 -07:00
const msgTimeout = new Set ( ) ;
const msgTimeoutMsg = new Set ( ) ;
2023-10-01 19:11:23 -07:00
2023-10-01 19:11:25 -07:00
const isValidUrl = urlString => {
var urlPattern = new RegExp ( '^(https?:\\/\\/)?' + // validate protocol
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // validate domain name
'((\\d{1,3}\\.){3}\\d{1,3}))' + // validate OR ip (v4) address
'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // validate port and path
'(\\?[;&a-z\\d%_.~+=-]*)?' + // validate query string
'(\\#[-a-z\\d_]*)?$' , 'i' ) ; // validate fragment locator
2023-12-01 05:48:30 -08:00
consoleLog ( '[bot.isValidUrl] Testing URL: ' + urlString )
2023-10-01 19:11:25 -07:00
return ! ! urlPattern . test ( urlString ) ;
}
2023-10-01 19:11:26 -07:00
function consoleLog ( log ) {
if ( config . misc . logging === "true" ) {
console . log ( log )
} else {
return ;
}
}
2023-10-01 19:11:27 -07:00
var hostmask = null
2023-10-01 19:11:27 -07:00
function checkConfigValidity ( ) {
2023-12-03 20:00:56 -08:00
consoleLog ( ` [bot.checkConfigValidity] Opening config validator ` )
2023-10-01 19:11:27 -07:00
const worker = new Worker ( ` ./commands/cvc.js ` , { } ) ;
worker . once ( 'message' , ( string ) => {
if ( string == 'kill' ) {
process . exit ( )
} else if ( string == 'allg' ) {
2023-12-03 20:00:56 -08:00
consoleLog ( '[bot.checkConfigValidity] Config seems valid, continuing' )
2023-10-01 19:11:27 -07:00
}
} ) ;
}
2023-10-01 19:11:27 -07:00
function checkUserHostmask ( user ) {
return new Promise ( function ( resolve , reject ) {
setTimeout ( ( ) => {
bot . whois ( user , function ( callback ) {
hostmask = callback . user + "@" + callback . host
consoleLog ( '[main.checkUserHostmask] User hostmask is ' + hostmask )
resolve ( hostmask )
} )
} , 750 )
} )
}
function openPostWorker ( chan , command , d1 , d2 , d3 , d4 , d5 , d6 ) {
2023-10-01 19:11:26 -07:00
consoleLog ( ` [bot.openPostWorker] Opening ${ command } worker ` )
2023-10-01 19:11:26 -07:00
const worker = new Worker ( ` ./commands/ ${ command } .js ` , {
workerData : {
2023-10-01 19:11:27 -07:00
d1 , d2 , d3 , d4 , d5 , d6
2023-10-01 19:11:26 -07:00
}
} ) ;
worker . once ( 'message' , ( string ) => {
2023-10-01 19:11:27 -07:00
consoleLog ( ` [bot.openPostWorker.finalising] Got output from ${ command } , sending to ` + chan ) ;
2023-10-01 19:11:26 -07:00
bot . say ( chan , string ) ;
} ) ;
}
2023-10-01 19:11:23 -07:00
async function help ( chan , sub ) {
2023-10-01 19:11:27 -07:00
if ( sub != undefined ) {
var sub = sub . toLowerCase ( )
}
2023-10-01 19:11:26 -07:00
openPostWorker ( chan , 'help' , sub )
2023-10-01 19:11:23 -07:00
}
2023-10-01 19:11:25 -07:00
async function opt ( chan , user , setting , setting2 , value , value2 ) {
2023-10-01 19:11:27 -07:00
if ( setting == undefined && setting2 == undefined && value == undefined && value2 == undefined ) {
openPostWorker ( chan , 'help' , 'opt' )
}
2023-10-01 19:11:27 -07:00
if ( setting == 'operset' || setting == "get" ) {
2023-10-01 19:11:27 -07:00
await checkUserHostmask ( user )
}
openPostWorker ( chan , 'options' , user , setting , setting2 , value , value2 , hostmask )
2023-10-01 19:11:25 -07:00
}
2023-10-01 19:11:25 -07:00
async function feed ( chan , nick , provfeed , n ) {
2023-10-01 19:11:25 -07:00
var userconf = fs . readFileSync ( './config/usersettings.json' )
var uconfig = JSON . parse ( userconf )
2023-10-01 19:11:27 -07:00
if ( isValidUrl ( provfeed ) === false ) {
consoleLog ( '[bot.feed] Provided feed is not a URL, transforming to lowercase' )
var provfeed = provfeed . toLowerCase ( )
}
2023-10-01 19:11:26 -07:00
var predefinedFeeds = [ 'twitter' , 'github' ]
var predefString = provfeed . split ( "/" )
2023-10-01 19:11:24 -07:00
if ( provfeed === undefined ) {
2023-10-01 19:11:26 -07:00
consoleLog ( '[bot.feed] No feed provided' )
2023-10-01 19:11:25 -07:00
bot . say ( chan , errorMsg + " No feed has been provided." )
return ;
2023-10-01 19:11:25 -07:00
} else if ( provfeed === 'me' ) {
2023-10-01 19:11:26 -07:00
consoleLog ( '[bot.feed] \"me\" was passed, correcting to ' + nick )
2023-10-01 19:11:25 -07:00
var provfeed = nick ;
2023-10-01 19:11:23 -07:00
}
2023-10-01 19:11:24 -07:00
if ( n === undefined ) {
2023-10-01 19:11:27 -07:00
consoleLog ( '[bot.feed] No post was passed, reverting to ' + config . feed . default _amount + ', your set default.' )
2023-10-01 19:11:25 -07:00
var n = config . feed . default _amount ;
2023-10-01 19:11:23 -07:00
}
2023-10-01 19:11:26 -07:00
2023-10-01 19:11:26 -07:00
if ( isValidUrl ( provfeed ) === true ) { //URL Lookup
2023-10-01 19:11:26 -07:00
consoleLog ( '[bot.feed] Valid URL requested' )
2023-10-01 19:11:27 -07:00
openPostWorker ( chan , 'feed-preset' , provfeed , n , nick ) ;
2023-10-01 19:11:26 -07:00
2023-10-01 19:11:27 -07:00
} else if ( predefinedFeeds . includes ( predefString [ 0 ] ) ) { //Predefined Feed lookup
consoleLog ( '[bot.feed] Detected predefined feed: ' + predefString [ 0 ] )
2023-10-01 19:11:27 -07:00
openPostWorker ( chan , "feed-predef" , provfeed , n , nick )
2023-10-01 19:11:26 -07:00
2023-10-01 19:11:26 -07:00
} else if ( provfeed === nick ) { //User Feed Lookup
2023-10-01 19:11:26 -07:00
consoleLog ( '[bot.feed] User feed requested' )
2023-10-01 19:11:26 -07:00
if ( uconfig [ nick ] !== undefined ) { //If users nickname exists in json file
openPostWorker ( chan , 'feed-list' , provfeed , n , nick ) ;
} else { //If it does not
2023-10-01 19:11:25 -07:00
bot . say ( chan , "You have no saved feeds" )
return ;
}
2023-12-01 05:48:30 -08:00
} else if ( uconfig [ nick ] . alias [ provfeed . toUpperCase ( ) ] !== undefined ) { //Alias Lookup
2023-10-01 19:11:26 -07:00
consoleLog ( '[bot.feed] Alias requested' )
2023-10-01 19:11:26 -07:00
var provfeed = uconfig [ nick ] . alias [ provfeed . toUpperCase ( ) ]
2023-10-01 19:11:27 -07:00
openPostWorker ( chan , "feed-preset" , provfeed , n , nick ) ;
2023-10-01 19:11:26 -07:00
} else {
2023-10-01 19:11:26 -07:00
consoleLog ( '[bot.feed] No valid feed entered' )
bot . say ( chan , errorMsg + " Your chosen feed or alias is not valid" )
2023-10-01 19:11:25 -07:00
}
2023-10-01 19:11:23 -07:00
}
2023-10-01 19:11:24 -07:00
async function twitter ( chan , provfeed , n ) {
if ( provfeed === undefined ) {
2023-10-01 19:11:26 -07:00
consoleLog ( '[bot.twitter] No twitter account provided' )
2023-10-01 19:11:25 -07:00
bot . say ( chan , errorMsg + " No account has been provided." )
return ;
2023-10-01 19:11:24 -07:00
}
if ( n === undefined ) {
2023-10-01 19:11:25 -07:00
var n = config . twitter . default _amount ;
2023-10-01 19:11:24 -07:00
}
2023-10-01 19:11:26 -07:00
openPostWorker ( chan , "twitter" , provfeed , n )
2023-10-01 19:11:24 -07:00
}
2023-10-01 19:11:23 -07:00
bot . addListener ( 'message' , function ( nick , to , text , from ) {
2023-10-01 19:11:27 -07:00
if ( text . startsWith ( config . irc . prefix ) ) {
if ( msgTimeout . has ( to ) ) {
if ( msgTimeoutMsg . has ( "yes" ) ) {
return ;
} else {
bot . say ( to , errorMsg + " You are sending commands too quickly" )
msgTimeoutMsg . add ( "yes" ) ;
setTimeout ( ( ) => {
msgTimeoutMsg . delete ( "yes" ) ;
} , config . floodprotect . command _listen _timeout )
}
2023-10-01 19:11:26 -07:00
} else {
2023-10-01 19:11:27 -07:00
var args = text . split ( ' ' ) ;
2023-10-01 19:11:27 -07:00
var command = args [ 0 ] . toLowerCase ( )
if ( command === config . irc . prefix + 'help' ) {
2023-10-01 19:11:27 -07:00
help ( to , args [ 1 ] ) ;
2023-10-01 19:11:27 -07:00
} else if ( command === config . irc . prefix + 'feed' ) {
2023-10-01 19:11:27 -07:00
if ( args [ 1 ] == undefined ) {
help ( to , "feed" )
} else {
feed ( to , nick , args [ 1 ] , args [ 2 ] ) ;
}
2023-10-01 19:11:27 -07:00
} else if ( command === config . irc . prefix + 'opt' ) {
2023-10-01 19:11:27 -07:00
if ( args [ 1 ] == undefined ) {
help ( to , "opt" )
} else {
opt ( to , nick , args [ 1 ] , args [ 2 ] , args [ 3 ] , args [ 4 ] )
}
2023-10-01 19:11:27 -07:00
}
msgTimeout . add ( to ) ;
2023-10-01 19:11:26 -07:00
setTimeout ( ( ) => {
2023-10-01 19:11:27 -07:00
msgTimeout . delete ( to ) ;
} , config . floodprotect . command _listen _timeout )
2023-10-01 19:11:26 -07:00
}
2023-10-01 19:11:23 -07:00
}
} ) ;
bot . addListener ( 'error' , function ( message ) {
2023-10-01 19:11:26 -07:00
consoleLog ( '[ERROR]' + message )
2023-10-01 19:11:23 -07:00
} ) ;
2023-10-01 19:11:27 -07:00
async function init ( ) {
consoleLog ( '[bot.init] Checking if user settings file exists' )
fs . open ( './config/usersettings.json' , 'r' , function ( err , fd ) {
if ( err ) {
2023-10-01 19:11:27 -07:00
fs . writeFile ( './config/usersettings.json' , '' , function ( err ) {
if ( err ) {
consoleLog ( err ) ;
consoleLog ( '[bot.init] [FATAL] User settings file could not be created. Mercury can not start' )
process . exit ( )
}
} ) ;
try {
fs . writeFileSync ( './config/usersettings.json' , "\{\n\}" )
} catch ( e ) {
consoleLog ( e )
consoleLog ( '[bot.init] [FATAL] User settings file was created but is not writable, could be a permissions issue. Mercury can not start' )
process . exit ( )
}
2023-12-03 20:00:56 -08:00
timer ( 100 )
2023-10-01 19:11:27 -07:00
consoleLog ( '[bot.init] User settings file has been created' )
2023-10-01 19:11:27 -07:00
} else {
consoleLog ( "[bot.init] User settings file exists" ) ;
}
2023-10-01 19:11:27 -07:00
} ) ;
2023-12-03 20:00:56 -08:00
await timer ( 500 )
2023-12-03 20:20:48 -08:00
try {
if ( config . errorhandling . validity _override === "TRUE" ) {
2023-12-03 20:34:58 -08:00
consoleLog ( '[bot.init] [WARNING] Config validity override switch enabled, will not check for validity. This may have unintended side-effects, if you run in to issues with this enabled, you are on your own.' )
2023-12-03 20:20:48 -08:00
}
} catch ( e ) {
consoleLog ( '[bot.init] Checking config validity' )
checkConfigValidity ( )
}
2023-12-03 20:00:56 -08:00
await timer ( 2000 )
2023-10-01 19:11:27 -07:00
if ( config . irc . ssl == "true" ) {
consoleLog ( '[bot.init] Initialisation completed, connecting to ' + config . irc . server + '/' + config . irc . port + ' (SSL) as ' + config . irc . nickname ) ;
} else {
consoleLog ( '[bot.init] Initialisation completed, connecting to ' + config . irc . server + '/' + config . irc . port + ' as ' + config . irc . nickname ) ;
}
consoleLog ( '[bot] Welcome to Mercury' ) ;
2023-10-01 19:11:27 -07:00
}
init ( )
2023-10-01 19:11:26 -07:00
process . on ( 'uncaughtException' , function ( err ) {
console . error ( err ) ;
if ( config . errorhandling . log _errors _to _irc == 'true' ) {
bot . say ( config . errorhandling . error _channel , errorMsg + " " + err . stack . split ( '\n' , 1 ) . join ( " " ) )
}
} ) ;