module.exports = class CooldownService { constructor(database, command) { this.database = database; this.ESMBot = database.ESMBot; this.util = this.ESMBot.util; this.r = database.r; this.command = command; this.message = command.message; this.CLIENT_PROFILE = { id: "", steam_uid: "", preferences: {} }; } async addCooldown() { // Preinit these variables let defaults = [2, "seconds"]; let communityID = null; // Get the user from the database based on the ID let user = await this.r.table("users").get(this.message.author.id).run(); // We didn't find the user, create the user in our database (first time running a command) if (user == null) { user = _.cloneDeep(this.CLIENT_PROFILE); user.id = this.message.author.id; await this.r.table("users").insert(user).run(); } // Check to see if our command has configuration for cooldown if (this.util.hasOwnPropertyTree(this.command.configuration, "cooldown")) { defaults = this.command.configuration.cooldown.default; communityID = this.getCommunityIDFromParams(); // Check to see if the community is valid if (await this.database.isValidCommunity(communityID)) { // Get the configurations for this community let community = await this.r.table("communities").get(communityID).run(); // If we have configuration for this command, take the cooldown information from the community if (this.util.hasOwnPropertyTree(community, "command_configuration", this.command.name)) { if (!this.util.isEmpty(community.command_configuration[this.command.name].cooldown)) { defaults = community.command_configuration[this.command.name].cooldown; } } } } // Start building our cooldown query let query = { command_name: this.command.name }; // If the user has a steam_uid on their account, go ahead and add it to the cooldown if (!_.isEmpty(user.steam_uid)) { query.steam_uid = user.steam_uid; } else { query.user_id = user.id; } // If we previously got a community ID, go ahead and use that for the query. if (!this.util.isEmpty(communityID)) { query.community_id = communityID; // Same thing with server_id if (this.command.params.serverID) { query.server_id = this.command.params.serverID; } } // Check to see if we have a cooldown already let cooldown = _.first(await this.r.table("cooldowns").filter(query).run()); // If we don't have a cooldown for this query yet, use the query as a starting point for the new cooldown if (cooldown == null) { cooldown = query; } // Store these values for future checking cooldown.quantity = defaults[0]; cooldown.type = defaults[1]; if (cooldown.type === "times") { // Since the cooldown is a quantity cooldown, increment the previous value or start it off at 1 cooldown.amount = (cooldown.amount || 0) + 1; // Cleanup if we've switched if (cooldown.hasOwnProperty("expires_at")) { delete cooldown.expires_at; } } else { // Since the cooldown is some sort of time (hour, min, sec, etc), set the new cooldown cooldown.expires_at = moment.utc().add(cooldown.quantity, cooldown.type).toDate(); // Cleanup if we've switched if (cooldown.hasOwnProperty("amount")) { delete cooldown.amount; } } // Insert it into the DB await this.r.table("cooldowns").insert(cooldown, { conflict: "replace" }).run(); } async getCooldown() { // Get the user from the DB let user = await this.r.table("users").get(this.message.author.id).run(); // We didn't find the user, create the user in our database (first time running a command) if (user == null) { user = _.cloneDeep(this.CLIENT_PROFILE); user.id = this.message.author.id; await this.r.table("users").insert(user).run(); } // Lets start building our query let query = { command_name: this.command.name }; let community = null; let communityID = this.getCommunityIDFromParams(); // Check to see if our command has configuration for cooldown if (this.util.hasOwnPropertyTree(this.command.configuration, "cooldown")) { // Check to see if the community is valid if (await this.database.isValidCommunity(communityID)) { // Get the community we are using community = await this.r.table("communities").get(communityID).run(); // Add the community ID to the query since we have one query.community_id = community.id // Add the server ID if we have it if (this.command.params.serverID) { query.server_id = this.command.params.serverID; } } } // We are requiring registration for this command, use the steam_uid instead of user_id if (this.command.permissions.requires_registration) { query.steam_uid = user.steam_uid; } else { query.user_id = user.id; } // Go get our cooldown based on our query let cooldown = _.first(await this.r.table("cooldowns").filter(query).run()); // If we don't have a cooldown, it's more than likely we've never used this command (let them through) if (cooldown == null) return {}; // If we have a community, we may need to adjust the cooldown if the values have changed if (community != null) { // If we have configuration for this command, take the cooldown information from the community if (this.util.hasOwnPropertyTree(community, "command_configuration", this.command.name, "cooldown")) { let cooldownInfo = community.command_configuration[this.command.name].cooldown; let times = { "seconds": 1, "minutes": 60, "hours": 3600, "days": 86400, "times": 99999999 }; // Normal time cooldown, check if the values have changed if (cooldownInfo[1] !== "times" && this.hasCooldownChanged(cooldownInfo, cooldown)) { // Calculate each time into seconds let originalTime = cooldown.quantity * times[cooldown.type]; let newTime = cooldownInfo[0] * times[cooldownInfo[1]]; // Looks like our times have changed, we need to update our expires_at if (originalTime > newTime) { cooldown.expires_at = moment.utc(cooldown.expires_at).subtract(originalTime - newTime, "s").toDate(); } } // Ensure the data is correct cooldown.quantity = cooldownInfo[0]; cooldown.type = cooldownInfo[1]; } } return cooldown; } async resetCooldown(communityID, commandName, userID) { // Get the user, we need the steam UID let user = await this.r.table("users").get(userID).run(); // Create the user in case they aren't? if (user == null) { user = _.cloneDeep(this.CLIENT_PROFILE); user.id = userID; await this.r.table("users").insert(user).run(); } // Go and delete any cooldowns that match the following SQL // DELETE FROM cooldowns WHERE community_id = communityID AND command_name = commandName AND (steam_uid = user.steam_uid OR user_id = user.id) let ret = await this.r.table("cooldowns").filter((cooldown) => { return cooldown("community_id").eq(communityID).and( cooldown("command_name").eq(commandName) ).and( cooldown("steam_uid").eq(user.steam_uid).or(cooldown("user_id").eq(user.id)) ); }).delete().run(); return ret.errors === 0; } async resetCooldownForCommand() { let userID = this.message ? this.message.author.id : this.info.author.id; // Get the user, we need the steam UID let user = await this.r.table("users").get(userID).run(); // Create the user in case they aren't? if (user == null) { user = _.cloneDeep(this.CLIENT_PROFILE); user.id = userID; await this.r.table("users").insert(user).run(); } // Go and delete any cooldowns let ret = await this.r.table("cooldowns").filter((cooldown) => { return cooldown("community_id").eq(this.command.communityID || null).and( cooldown("command_name").eq(this.command.name) ).and( cooldown("server_id").eq(this.command.params.serverID || null).default(true) ).and( cooldown("steam_uid").eq(user.steam_uid || null).or(cooldown("user_id").eq(user.id)) ); }).delete().run(); return ret.errors === 0; } getCommunityIDFromParams() { return this.util.getCommunityID( this.command.params.serverID || this.command.params.communityID ); } hasCooldownChanged(communityCooldown, userCooldown) { return (communityCooldown[0] !== userCooldown.quantity) || (communityCooldown[1] !== userCooldown.type); } }