From eaa7dd8c801fccf7f22e59b465e94c2978b41cab Mon Sep 17 00:00:00 2001 From: 3urobeat <35304405+3urobeat@users.noreply.github.com> Date: Sun, 5 Jan 2025 14:08:40 +0100 Subject: [PATCH] refactor: Fix unresolved JsDoc Bot reference better and remove now unnecessary re-import in _preLogin() for previously unresolved Bot & Updater --- src/controller/controller.js | 166 +++++++++++----------- src/data/fileStructure.json | 4 +- types/types.d.ts | 267 +++++++++++++++++++++++++++++++++-- 3 files changed, 337 insertions(+), 100 deletions(-) diff --git a/src/controller/controller.js b/src/controller/controller.js index 72979f88..555ca9fd 100644 --- a/src/controller/controller.js +++ b/src/controller/controller.js @@ -4,7 +4,7 @@ * Created Date: 2021-07-09 16:26:00 * Author: 3urobeat * - * Last Modified: 2025-01-05 13:08:02 + * Last Modified: 2025-01-05 14:06:02 * Modified By: 3urobeat * * Copyright (c) 2021 - 2025 3urobeat @@ -18,6 +18,13 @@ const { EventEmitter } = require("events"); +// "Hack" to get type information in code completion without requiring file during runtime +/** + * @typedef Bot + * @type {import("../bot/bot.js")} + */ + + /** * Constructor - Initializes the controller and starts all bot accounts * @class @@ -25,6 +32,18 @@ const { EventEmitter } = require("events"); const Controller = function() { this.srcdir = srcdir; // Let users see the global var srcdir more easily + /** + * Stores references to all bot account objects mapped to their accountName + * @type {{[key: string]: Bot}} + */ + this.bots = {}; + + /** + * The main bot account + * @type {Bot} + */ + this.main = {}; // Store short-hand reference to the main acc (populated later) + // Create eventEmitter this.events = new EventEmitter(); @@ -279,6 +298,10 @@ Controller.prototype._start = async function() { return this.stop(); } + /** + * The updater object + * @type {import("../updater/updater.js")} + */ this.updater = new Updater(this); // Check if the last update failed and skip the updater for now @@ -315,36 +338,10 @@ Controller.prototype._preLogin = async function() { this.jobManager = new JobManager(this); - // Update Updater IntelliSense without modifying what _start() has already set. Integrity has already been checked - let Updater = require("../updater/updater.js"); // eslint-disable-line - - /** - * The updater object - * @type {Updater} - */ - this.updater; - // Register update check job this.updater._registerUpdateChecker(); - // Check bot.js for errors and load it explicitly again to get IntelliSense support - if (!await this.checkAndGetFile("./src/bot/bot.js", logger, false, false)) return this.stop(); // TODO: Is this still necessary when the dataIntegrity check and updater already ran?? - let Bot = require("../bot/bot.js"); // eslint-disable-line - - /** - * Stores references to all bot account objects mapped to their accountName - * @type {{[key: string]: Bot}} - */ - this.bots = {}; - - /** - * The main bot account - * @type {Bot} - */ - this.main = {}; // Store short-hand reference to the main acc (populated later) - - // Load Controller event handlers & helpers. This must happen after bot.js has been verified require("./events/ready.js"); require("./events/statusUpdate.js"); @@ -394,64 +391,6 @@ Controller.prototype._preLogin = async function() { runOnRegistration: false }); - - // Functions implemented by Controller which require the previously unresolved Bot class import - /** - * Filters the active set of bot accounts by a given criteria - * @param {function(Bot): boolean} predicate Function that returns true if the account should be included in the result - * @returns {Array.} Array of bot instances that match the criteria - */ - this.filterAccounts = function(predicate) {}; // eslint-disable-line - - /** - * Runs internal statusUpdate event code and emits statusUpdate event for plugins - * @param {Bot} bot Bot instance - * @param {Bot.EStatus} newStatus The new status of this bot - */ - this._statusUpdateEvent = function(bot, newStatus) {}; // eslint-disable-line - - /** - * Emits steamGuardInput event for bot & plugins - * @param {Bot} bot Bot instance of the affected account - * @param {function(string): void} submitCode Function to submit a code. Pass an empty string to skip the account. - */ - this._steamGuardInputEvent = function(bot, submitCode) {}; // eslint-disable-line - - /** - * Emits steamGuardQrCode event for bot & plugins - * @param {Bot} bot Bot instance of the affected account - * @param {string} challengeUrl The QrCode Challenge URL supplied by Steam. Display this value using a QR-Code parser and let a user scan it using their Steam Mobile App. - */ - this._steamGuardQrCodeEvent = function(bot, challengeUrl) {}; // eslint-disable-line - - /** - * Check if all friends are in lastcomment database - * @param {Bot} bot Bot object of the account to check - */ - this.checkLastcommentDB = function(bot) {}; // eslint-disable-line - - /** - * Checks the remaining space on the friendlist of a bot account, sends a warning message if it is less than 10 and force unfriends oldest lastcomment db user to always keep room for 1 friend. - * @param {Bot} bot Bot object of the account to check - * @param {function(number|null): void} callback Called with `remaining` (Number) on success or `null` on failure - */ - this.friendListCapacityCheck = function(bot, callback) {}; // eslint-disable-line - - /** - * Retrieves all matching bot accounts and returns them. - * @param {(EStatus|EStatus[]|string)} [statusFilter=EStatus.ONLINE] Optional: EStatus or Array of EStatus's including account statuses to filter. Pass '*' to get all accounts. If omitted, only accs with status 'EStatus.ONLINE' will be returned. - * @param {boolean} [mapToObject=false] Optional: If true, an object will be returned where every bot object is mapped to their accountName. - * @returns {Array.} An array or object if `mapToObject == true` containing all matching bot accounts. Note: This JsDoc type param only specifies the default array version to get IntelliSense support. - */ - this.getBots = function(statusFilter = EStatus.ONLINE, mapToObject = false) {}; // eslint-disable-line - - /** - * Retrieves bot accounts per proxy. This can be used to find the most and least used active proxies for example. - * @param {boolean} [filterOffline=false] Set to true to remove proxies which are offline. Make sure to call `checkAllProxies()` beforehand! - * @returns {Array.<{ bots: Array., proxy: string, proxyIndex: number, isOnline: boolean, lastOnlineCheck: number }>} Bot accounts mapped to their associated proxy - */ - this.getBotsPerProxy = function(filterOffline = false) {}; // eslint-disable-line - }; @@ -480,7 +419,6 @@ Controller.prototype.stop = function() { /* -------- Register functions to let the IntelliSense know what's going on in helper files -------- */ -// NOTE: Functions containing 'Bot' class in JsDoc MUST be referenced in _preLogin() instead, as the the Bot import is not resolved here yet /** * Attempts to log in all bot accounts which are currently offline one after another. @@ -526,6 +464,13 @@ Controller.prototype.relogAccount = function(accountName) {}; // eslint-disable- */ Controller.prototype.respreadProxies = async function() {}; +/** + * Filters the active set of bot accounts by a given criteria + * @param {function(Bot): boolean} predicate Function that returns true if the account should be included in the result + * @returns {Array.} Array of bot instances that match the criteria + */ +Controller.prototype.filterAccounts = function(predicate) {}; // eslint-disable-line + /** * Set of premade functions for filterAccounts() * @type {{ all: Function, statusOffline: Function, statusOnline: Function, statusError: Function, statusSkipped: Function, limited: Function, unlimited: Function }} @@ -537,11 +482,60 @@ Controller.prototype.filters = {}; */ Controller.prototype._readyEvent = function() {}; +/** + * Runs internal statusUpdate event code and emits statusUpdate event for plugins + * @param {Bot} bot Bot instance + * @param {Bot.EStatus} newStatus The new status of this bot + */ +Controller.prototype._statusUpdateEvent = function(bot, newStatus) {}; // eslint-disable-line + +/** + * Emits steamGuardInput event for bot & plugins + * @param {Bot} bot Bot instance of the affected account + * @param {function(string): void} submitCode Function to submit a code. Pass an empty string to skip the account. + */ +Controller.prototype._steamGuardInputEvent = function(bot, submitCode) {}; // eslint-disable-line + +/** + * Emits steamGuardQrCode event for bot & plugins + * @param {Bot} bot Bot instance of the affected account + * @param {string} challengeUrl The QrCode Challenge URL supplied by Steam. Display this value using a QR-Code parser and let a user scan it using their Steam Mobile App. + */ +Controller.prototype._steamGuardQrCodeEvent = function(bot, challengeUrl) {}; // eslint-disable-line + +/** + * Check if all friends are in lastcomment database + * @param {Bot} bot Bot object of the account to check + */ +Controller.prototype.checkLastcommentDB = function(bot) {}; // eslint-disable-line + +/** + * Checks the remaining space on the friendlist of a bot account, sends a warning message if it is less than 10 and force unfriends oldest lastcomment db user to always keep room for 1 friend. + * @param {Bot} bot Bot object of the account to check + * @param {function(number|null): void} callback Called with `remaining` (Number) on success or `null` on failure + */ +Controller.prototype.friendListCapacityCheck = function(bot, callback) {}; // eslint-disable-line + /** * Check for friends who haven't requested comments in config.unfriendtime days and unfriend them */ Controller.prototype._lastcommentUnfriendCheck = function() {} // eslint-disable-line +/** + * Retrieves all matching bot accounts and returns them. + * @param {(EStatus|EStatus[]|string)} [statusFilter=EStatus.ONLINE] Optional: EStatus or Array of EStatus's including account statuses to filter. Pass '*' to get all accounts. If omitted, only accs with status 'EStatus.ONLINE' will be returned. + * @param {boolean} [mapToObject=false] Optional: If true, an object will be returned where every bot object is mapped to their accountName. + * @returns {Array.} An array or object if `mapToObject == true` containing all matching bot accounts. Note: This JsDoc type param only specifies the default array version to get IntelliSense support. + */ +Controller.prototype.getBots = function(statusFilter = EStatus.ONLINE, mapToObject = false) {}; // eslint-disable-line + +/** + * Retrieves bot accounts per proxy. This can be used to find the most and least used active proxies for example. + * @param {boolean} [filterOffline=false] Set to true to remove proxies which are offline. Make sure to call `checkAllProxies()` beforehand! + * @returns {Array.<{ bots: Array., proxy: string, proxyIndex: number, isOnline: boolean, lastOnlineCheck: number }>} Bot accounts mapped to their associated proxy + */ +Controller.prototype.getBotsPerProxy = function(filterOffline = false) {}; // eslint-disable-line + /** * Internal: Handles process's unhandledRejection & uncaughtException error events. * Should a NPM related error be detected it attempts to reinstall all packages using our npminteraction helper function diff --git a/src/data/fileStructure.json b/src/data/fileStructure.json index aaa71a85..e4c5a9f0 100644 --- a/src/data/fileStructure.json +++ b/src/data/fileStructure.json @@ -263,7 +263,7 @@ { "path": "src/controller/controller.js", "url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/src/controller/controller.js", - "checksum": "8ace7a10caf5ab679d187e8ce9f4a057" + "checksum": "925cad54fe5498c43ab40b15d8351c90" }, { "path": "src/controller/events/ready.js", @@ -628,7 +628,7 @@ { "path": "types/types.d.ts", "url": "https://raw.githubusercontent.com/3urobeat/steam-comment-service-bot/beta-testing/types/types.d.ts", - "checksum": "a1961203e60b43e0e4ece4b089b4a04b" + "checksum": "c42ffd93755b217a59a82852946a87e5" } ] } \ No newline at end of file diff --git a/types/types.d.ts b/types/types.d.ts index 747ccdd6..246986ca 100644 --- a/types/types.d.ts +++ b/types/types.d.ts @@ -492,11 +492,262 @@ declare function sortFailedObject(failedObj: any): void; */ declare function handleIterationSkip(commandHandler: CommandHandler, loop: any, bot: Bot, receiverSteamID64: string): boolean; +/** + * Constructor - Initializes an object which represents a user steam account + * @param controller - Reference to the controller object + * @param index - The index of this account in the logininfo object + */ +declare class Bot { + constructor(controller: Controller, index: number); + /** + * Reference to the controller object + */ + controller: Controller; + /** + * Reference to the DataManager object + */ + data: DataManager; + /** + * Login index of this bot account + */ + index: number; + /** + * Status of this bot account + */ + status: EStatus; + /** + * SteamID64's to ignore in the friendMessage event handler. This is used by readChatMessage() to prevent duplicate responses. + */ + friendMessageBlock: string[]; + /** + * Additional login related information for this bot account + */ + loginData: any; + /** + * Username of this bot account + */ + accountName: string; + /** + * Stores the timestamp and reason of the last disconnect. This is used by handleRelog() to take proper action + */ + lastDisconnect: any; + /** + * This SteamUser instance + */ + user: SteamUser; + /** + * This SteamCommunity instance + */ + community: SteamCommunity; + /** + * Calls SteamUser logOn() for this account. This will either trigger the SteamUser loggedOn or error event. + */ + _loginToSteam(): void; + /** + * Handles the SteamUser debug events if enabled in advancedconfig + */ + _attachSteamDebugEvent(): void; + /** + * Handles the SteamUser disconnect event and tries to relog the account + */ + _attachSteamDisconnectedEvent(): void; + /** + * Handles the SteamUser error event + */ + _attachSteamErrorEvent(): void; + /** + * Handles messages, cooldowns and executes commands. + */ + _attachSteamFriendMessageEvent(): void; + /** + * Do some stuff when account is logged in + */ + _attachSteamLoggedOnEvent(): void; + /** + * Accepts a friend request, adds the user to the lastcomment.db database and invites him to your group + */ + _attachSteamFriendRelationshipEvent(): void; + /** + * Accepts a group invite if acceptgroupinvites in the config is true + */ + _attachSteamGroupRelationshipEvent(): void; + /** + * Handles setting cookies and accepting offline friend & group invites + */ + _attachSteamWebSessionEvent(): void; + /** + * Checks if user is blocked, has an active cooldown for spamming or isn't a friend + * @param steamID64 - The steamID64 of the message sender + * @param message - The message string provided by steam-user friendMessage event + * @returns `true` if friendMessage event shouldn't be handled, `false` if user is allowed to be handled + */ + checkMsgBlock(steamID64: any, message: string): boolean; + /** + * Attempts to check if this account has family view (feature to restrict features for child accounts) enabled + * @returns Returns a Promise which resolves with a boolean, indicating whether family view is enabled or not. If request failed, `false` is returned. + */ + checkForFamilyView(): Promise; + /** + * Requests family view unlock key from user and attempts to unlock it + * @returns Returns a Promise which resolves when done + */ + unlockFamilyView(): Promise; + /** + * Internal - Attempts to get a cached family view code for this account from tokens.db + */ + _getFamilyViewCodeFromStorage(callback: any): void; + /** + * Internal - Saves a new family view code for this account to tokens.db + * @param familyViewCode - The family view code to store + */ + _saveFamilyViewCodeToStorage(familyViewCode: string): void; + /** + * Handles aborting a login attempt should an account get stuck to prevent the bot from softlocking (see issue #139) + */ + handleLoginTimeout(): void; + /** + * Handles checking for missing game licenses, requests them and then starts playing + */ + handleMissingGameLicenses(): void; + /** + * Changes the proxy of this bot account. + * @param newProxyIndex - Index of the new proxy inside the DataManager.proxies array. + */ + switchProxy(newProxyIndex: number): void; + /** + * Checks host internet connection, updates the status of all proxies checked >2.5 min ago and switches the proxy of this bot account if necessary. + * @returns Resolves with a boolean indicating whether the proxy was switched when done. A relog is triggered when the proxy was switched. + */ + checkAndSwitchMyProxy(): Promise; + /** + * Attempts to get this account, after failing all logOnRetries, back online after some time. Does not apply to initial logins. + */ + handleRelog(): void; + /** + * Our commandHandler respondModule implementation - Sends a message to a Steam user + * @param _this - The Bot object context + * @param txt - The text to send + * @param retry - Internal: true if this message called itself again to send failure message + * @param part - Internal: Index of which part to send for messages larger than 750 chars + */ + sendChatMessage(_this: any, resInfo: any, txt: string, retry: boolean, part: number): void; + /** + * Waits for a Steam Chat message from this user to this account and resolves their message content. The "normal" friendMessage event handler will be blocked for this user. + * @param steamID64 - The steamID64 of the user to read a message from + * @param timeout - Time in ms after which the Promise will be resolved if user does not respond. Pass 0 to disable (not recommended) + * @returns Resolved with `String` on response or `null` on timeout. + */ + readChatMessage(steamID64: string, timeout: number): Promise; + /** + * Handles the SteamUser debug events if enabled in advancedconfig + */ + _attachSteamDebugEvent(): void; + /** + * Handles the SteamUser disconnect event and tries to relog the account + */ + _attachSteamDisconnectedEvent(): void; + /** + * Handles the SteamUser error event + */ + _attachSteamErrorEvent(): void; + /** + * Handles messages, cooldowns and executes commands. + */ + _attachSteamFriendMessageEvent(): void; + /** + * Do some stuff when account is logged in + */ + _attachSteamLoggedOnEvent(): void; + /** + * Accepts a friend request, adds the user to the lastcomment.db database and invites him to your group + */ + _attachSteamFriendRelationshipEvent(): void; + /** + * Accepts a group invite if acceptgroupinvites in the config is true + */ + _attachSteamGroupRelationshipEvent(): void; + /** + * Handles setting cookies and accepting offline friend & group invites + */ + _attachSteamWebSessionEvent(): void; + /** + * Checks if user is blocked, has an active cooldown for spamming or isn't a friend + * @param steamID64 - The steamID64 of the message sender + * @param message - The message string provided by steam-user friendMessage event + * @returns `true` if friendMessage event shouldn't be handled, `false` if user is allowed to be handled + */ + checkMsgBlock(steamID64: any, message: string): boolean; + /** + * Attempts to check if this account has family view (feature to restrict features for child accounts) enabled + * @returns Returns a Promise which resolves with a boolean, indicating whether family view is enabled or not. If request failed, `false` is returned. + */ + checkForFamilyView(): Promise; + /** + * Requests family view unlock key from user and attempts to unlock it + * @returns Returns a Promise which resolves when done + */ + unlockFamilyView(): Promise; + /** + * Internal - Attempts to get a cached family view code for this account from tokens.db + */ + _getFamilyViewCodeFromStorage(callback: any): void; + /** + * Internal - Saves a new family view code for this account to tokens.db + * @param familyViewCode - The family view code to store + */ + _saveFamilyViewCodeToStorage(familyViewCode: string): void; + /** + * Handles aborting a login attempt should an account get stuck to prevent the bot from softlocking (see issue #139) + */ + handleLoginTimeout(): void; + /** + * Handles checking for missing game licenses, requests them and then starts playing + */ + handleMissingGameLicenses(): void; + /** + * Changes the proxy of this bot account. + * @param newProxyIndex - Index of the new proxy inside the DataManager.proxies array. + */ + switchProxy(newProxyIndex: number): void; + /** + * Checks host internet connection, updates the status of all proxies checked >2.5 min ago and switches the proxy of this bot account if necessary. + * @returns Resolves with a boolean indicating whether the proxy was switched when done. A relog is triggered when the proxy was switched. + */ + checkAndSwitchMyProxy(): Promise; + /** + * Attempts to get this account, after failing all logOnRetries, back online after some time. Does not apply to initial logins. + */ + handleRelog(): void; + /** + * Our commandHandler respondModule implementation - Sends a message to a Steam user + * @param _this - The Bot object context + * @param txt - The text to send + * @param retry - Internal: true if this message called itself again to send failure message + * @param part - Internal: Index of which part to send for messages larger than 750 chars + */ + sendChatMessage(_this: any, resInfo: any, txt: string, retry: boolean, part: number): void; + /** + * Waits for a Steam Chat message from this user to this account and resolves their message content. The "normal" friendMessage event handler will be blocked for this user. + * @param steamID64 - The steamID64 of the user to read a message from + * @param timeout - Time in ms after which the Promise will be resolved if user does not respond. Pass 0 to disable (not recommended) + * @returns Resolved with `String` on response or `null` on timeout. + */ + readChatMessage(steamID64: string, timeout: number): Promise; +} + /** * Constructor - Initializes the controller and starts all bot accounts */ declare class Controller { constructor(); + /** + * Stores references to all bot account objects mapped to their accountName + */ + bots: any; + /** + * The main bot account + */ + main: Bot; /** * Collection of miscellaneous functions for easier access */ @@ -517,6 +768,10 @@ declare class Controller { * The dataManager object */ data: DataManager; + /** + * The updater object + */ + updater: any; /** * Internal: Loads all parts of the application to get IntelliSense support after the updater ran and calls login() when done. */ @@ -525,18 +780,6 @@ declare class Controller { * The JobManager handles the periodic execution of functions which you can register at runtime */ jobManager: JobManager; - /** - * The updater object - */ - updater: Updater; - /** - * Stores references to all bot account objects mapped to their accountName - */ - bots: any; - /** - * The main bot account - */ - main: Bot; /** * The commandHandler object */