diff --git a/index.js b/index.js index 157376c..5e1e9d7 100644 --- a/index.js +++ b/index.js @@ -17,6 +17,7 @@ const winston = require('winston'), postgres = new (require('./lib/postgres'))(CONFIG.database_url, CONFIG.enable_bulk_inserts), gameData = new (require('./lib/game_data'))(CONFIG.game_files_update_interval, CONFIG.enable_game_file_updates), errors = require('./errors'), + PairScheduler = require('./lib/pair_scheduler'), Job = require('./lib/job'); if (CONFIG.max_simultaneous_requests === undefined) { @@ -34,24 +35,31 @@ if (args.steam_data) { CONFIG.bot_settings.steam_user.dataDirectory = args.steam_data; } +const pairs = []; for (let [i, loginData] of CONFIG.logins.entries()) { - const settings = Object.assign({}, CONFIG.bot_settings); - if (CONFIG.proxies && CONFIG.proxies.length > 0) { - const proxy = CONFIG.proxies[i % CONFIG.proxies.length]; - - if (proxy.startsWith('http://')) { - settings.steam_user = Object.assign({}, settings.steam_user, {httpProxy: proxy}); - } else if (proxy.startsWith('socks5://')) { - settings.steam_user = Object.assign({}, settings.steam_user, {socksProxy: proxy}); - } else { - console.log(`Invalid proxy '${proxy}' in config, must prefix with http:// or socks5://`); - process.exit(1); - } - } - - botController.addBot(loginData, settings); + const settings = Object.assign({}, CONFIG.bot_settings); + let proxy = null; + + if (CONFIG.proxies && CONFIG.proxies.length > 0) { + proxy = CONFIG.proxies[i % CONFIG.proxies.length]; + + if (proxy.startsWith('http://')) { + settings.steam_user = Object.assign({}, settings.steam_user, { httpProxy: proxy }); + } else if (proxy.startsWith('socks5://')) { + settings.steam_user = Object.assign({}, settings.steam_user, { socksProxy: proxy }); + } else { + console.log(`Invalid proxy '${proxy}' in config, must prefix with http:// or socks5://`); + process.exit(1); + } + } + + const bot = botController.addBot(loginData, settings); // RETURN bot + pairs.push({ bot: bot.id, proxy }); // COLLECT pair } +const scheduler = new PairScheduler(pairs); +botController.setScheduler(scheduler); + postgres.connect(); // Setup and configure express diff --git a/lib/bot_controller.js b/lib/bot_controller.js index 0d8a25e..fc1a6d1 100644 --- a/lib/bot_controller.js +++ b/lib/bot_controller.js @@ -8,13 +8,18 @@ class BotController extends EventEmitter { super(); this.readyEvent = false; - this.bots = []; + this.bots = []; + this.byId = new Map(); + this.scheduler = null; } addBot(loginData, settings) { let bot = new Bot(settings); bot.logIn(loginData.user, loginData.pass, loginData.auth); + this.bots.push(bot); + this.byId.set(bot.id, bot); + bot.on('ready', () => { if (!this.readyEvent && this.hasBotOnline()) { this.readyEvent = true; @@ -29,7 +34,7 @@ class BotController extends EventEmitter { } }); - this.bots.push(bot); + return bot; } getFreeBot() { @@ -60,11 +65,29 @@ class BotController extends EventEmitter { } lookupFloat(data) { - let freeBot = this.getFreeBot(); + const pair = this.getFreePair(); + if (pair) return pair.bot.sendFloatRequest(data); + const freeBot = this.getFreeBot(); if (freeBot) return freeBot.sendFloatRequest(data); - else return Promise.reject(errors.NoBotsAvailable); + + return Promise.reject(errors.NoBotsAvailable); } + + setScheduler(scheduler) { + this.scheduler = scheduler; + } + + getFreePair() { + if (!this.scheduler) return null; + const tries = this.bots.length; + for (let i = 0; i < tries; i++) { + const { bot: botId, proxy } = this.scheduler.next(); + const b = this.byId.get(botId); + if (b && b.ready && !b.busy) return { bot: b, proxy }; + } + return null; + } } module.exports = BotController; diff --git a/lib/pairScheduler.js b/lib/pairScheduler.js new file mode 100644 index 0000000..2a05f2a --- /dev/null +++ b/lib/pairScheduler.js @@ -0,0 +1,21 @@ +class PairScheduler{ + constructor(pairs) { + this.clock = 1; + this.items = pairs.map(x => ({ ...x, lastUsed: 0 })); + } + next() { + let min = this.items[0], idx = 0; + for (let i = 1; i < this.items.length; i++) { + if (this.items[i].lastUsed < min.lastUsed) { + min = this.items[i]; + idx = i; + } + } + this.items[idx].lastUsed = this.clock++; + return { bot: this.items[idx].bot, proxy: this.items[idx].proxy }; + } + all() { + return this.items.map(({ bot, proxy }) => ({ bot, proxy })); + } +} +module.exports = PairScheduler; \ No newline at end of file