diff --git a/server/src/configs/default.json b/server/src/configs/default.json index eeb09204a..2b1d4f0cd 100644 --- a/server/src/configs/default.json +++ b/server/src/configs/default.json @@ -356,9 +356,7 @@ "migrationTableName": "knex_migrations", "joinGymBadgeTable": false, "hideOldQuests": false, - "maxConnections": 10, - "startupDelayMs": 1000, - "availableRetryCount": 5 + "maxConnections": 10 }, "schemas": [ { diff --git a/server/src/index.js b/server/src/index.js index f174e14bf..cfa439500 100644 --- a/server/src/index.js +++ b/server/src/index.js @@ -15,8 +15,8 @@ const Backend = require('i18next-fs-backend') const { ValidationError } = require('apollo-server-core') const { ApolloServer } = require('apollo-server-express') -const { Db } = require('./services/initialization') const config = require('./services/config') +const { Db, Event } = require('./services/initialization') const { sessionStore } = require('./services/sessionStore') const rootRouter = require('./routes/rootRouter') const typeDefs = require('./graphql/typeDefs') @@ -37,7 +37,7 @@ const server = new ApolloServer({ debug: config.devOptions.queryDebug, context: ({ req, res }) => { const perms = req.user ? req.user.perms : req.session.perms - return { req, res, Db, perms, version } + return { req, res, Db, Event, perms, version } }, formatError: (e) => { if (config.devOptions.enabled) { diff --git a/server/src/models/Pokestop.js b/server/src/models/Pokestop.js index 7f0cc44d3..06407d0a8 100644 --- a/server/src/models/Pokestop.js +++ b/server/src/models/Pokestop.js @@ -456,6 +456,7 @@ module.exports = class Pokestop extends Model { const finalList = new Set() const quests = {} const stops = {} + quests.items = await this.query() .select('quest_item_id') .from(isMad ? 'trs_quest' : 'pokestop') @@ -602,10 +603,6 @@ module.exports = class Pokestop extends Model { } }) - if (finalList.size === 0) { - return fetchQuests() - } - if (hasMultiInvasions) { stops.invasions = await this.query() .leftJoin('incident', 'pokestop.id', 'incident.pokestop_id') @@ -620,12 +617,16 @@ module.exports = class Pokestop extends Model { ]) .where(multiInvasionMs ? 'expiration_ms' : 'incident.expiration', '>=', ts * (multiInvasionMs ? 1000 : 1)) .orderBy('grunt_type') - } else { + } else if (hasMultiInvasions === false) { stops.invasions = await this.query() .select(isMad ? 'incident_grunt_type AS grunt_type' : 'grunt_type') .where(isMad ? 'incident_expiration' : 'incident_expire_timestamp', '>=', isMad ? this.knex().fn.now() : ts) .groupBy('grunt_type') .orderBy('grunt_type') + } else { + stops.invasions = Object.keys(Event.masterfile.invasions) + .filter(grunt => +grunt < 100) + .map(i => ({ grunt_type: i })) } stops.lures = await this.query() .select(isMad ? 'active_fort_modifier AS lure_id' : 'lure_id') @@ -640,7 +641,7 @@ module.exports = class Pokestop extends Model { default: rewards.forEach(reward => finalList.add(`i${reward.grunt_type}`)); break } }) - return [...finalList] + return finalList.size === 0 ? fetchQuests() : [...finalList] } static parseRdmRewards = (quest) => { diff --git a/server/src/services/DbCheck.js b/server/src/services/DbCheck.js index 594cbf3a9..e17c5994f 100644 --- a/server/src/services/DbCheck.js +++ b/server/src/services/DbCheck.js @@ -1,4 +1,3 @@ -/* eslint-disable no-await-in-loop */ /* eslint-disable no-console */ const knex = require('knex') const { raw } = require('objection') @@ -17,7 +16,7 @@ module.exports = class DbCheck { if (!this.models[capital]) { this.models[capital] = [] } - this.models[capital].push({ connection: i, isMad: false }) + this.models[capital].push({ connection: i }) }) return knex({ client: 'mysql2', @@ -36,21 +35,7 @@ module.exports = class DbCheck { }, }, }) - }); - (async () => { - await this.determineType() - await this.pvp() - await this.pokestopChecks() - })() - } - - static async isMadDb(connection) { - try { - await connection('trs_quest').limit(1).first() - return true - } catch (e) { - return false - } + }) } static getDistance(args, isMad) { @@ -58,20 +43,36 @@ module.exports = class DbCheck { } async determineType() { - console.log('[DB] Determining database types..') + console.log(`[DB] Determining database types for ${this.connections.length} connection${this.connections.length > 1 ? 's' : ''}`) await Promise.all(this.connections.map(async (schema, i) => { - const isMad = await DbCheck.isMadDb(schema) - Object.entries(this.models).forEach(([category, sources]) => { - try { + try { + const isMad = await schema('trs_quest').columnInfo().then(col => Object.keys(col).length > 0) + const pvpV2 = await schema('pokemon').columnInfo().then(col => 'pvp' in col) + const [hasRewardAmount, hasAltQuests] = await schema('pokestop').columnInfo() + .then(columns => ([ + ['quest_reward_amount', 'item_reward_amount'].some(c => c in columns), + 'alternative_quest_type' in columns, + ])) + const [hasMultiInvasions, multiInvasionMs] = await schema('incident').columnInfo() + .then(columns => ([ + 'character' in columns, + 'expiration_ms' in columns, + ])) + Object.entries(this.models).forEach(([category, sources]) => { sources.forEach((source, j) => { if (source.connection === i) { this.models[category][j].isMad = isMad + this.models[category][j].pvpV2 = pvpV2 + this.models[category][j].hasRewardAmount = hasRewardAmount + this.models[category][j].hasAltQuests = hasAltQuests + this.models[category][j].hasMultiInvasions = hasMultiInvasions + this.models[category][j].multiInvasionMs = multiInvasionMs } }) - } catch (e) { - console.error('[DB]', e.message) - } - }) + }) + } catch (e) { + console.error('[DB]', e.message) + } })) } @@ -92,7 +93,7 @@ module.exports = class DbCheck { this.models[model][i].SubModel = models[model].bindKnex(this.connections[source.connection]) }) } - console.log(`[DB] Bound ${model} to ${sources.length} connections`) + console.log(`[DB] Bound ${model} to ${sources.length} connection${sources.length > 1 ? 's' : ''}`) }) } catch (e) { console.error(` @@ -118,59 +119,6 @@ module.exports = class DbCheck { return [] } - async pvp() { - await Promise.all(this.models.Pokemon.map(async (source) => { - try { - await source.SubModel.query() - .whereNotNull('pvp') - .limit(1) - source.pvpV2 = true - } catch (_) { - source.pvpV2 = false - } - })) - } - - async pokestopChecks() { - await Promise.all(this.models.Pokestop.map(async (source) => { - try { - if (!source.isMad) { - await source.SubModel.query() - .whereNotNull('quest_reward_amount') - .limit(1) - } - source.hasRewardAmount = true - } catch (_) { - source.hasRewardAmount = false - } - try { - await source.SubModel.query() - .whereNotNull('alternative_quest_type') - .limit(1) - source.hasAltQuests = true - } catch (_) { - source.hasAltQuests = false - } - try { - await source.SubModel.query() - .leftJoin('incident', 'pokestop.id', 'incident.pokestop_id') - .limit(1) - source.hasMultiInvasions = true - } catch (_) { - source.hasMultiInvasions = false - } - try { - await source.SubModel.query() - .leftJoin('incident', 'pokestop.id', 'incident.pokestop_id') - .select('expiration_ms') - .limit(1) - source.multiInvasionMs = true - } catch (_) { - source.multiInvasionMs = false - } - })) - } - async getAll(model, perms, args, userId, method = 'getAll') { const data = await Promise.all(this.models[model].map(async (source) => ( source.SubModel[method](perms, args, source, userId) @@ -179,15 +127,11 @@ module.exports = class DbCheck { } async getOne(model, id, method = 'getOne') { - const sources = this.models[model] - let foundObj - let source = 0 - while (!foundObj && source < sources.length) { - const found = await sources[source].SubModel[method](id, sources[source]) - foundObj = found - source += 1 - } - return foundObj || {} + const data = await Promise.all(this.models[model].map(async (source) => ( + source.SubModel[method](id, source) + ))) + const cleaned = DbCheck.deDupeResults(data.filter(Boolean)) + return (Array.isArray(cleaned) ? cleaned[0] : cleaned) || {} } async search(model, perms, args, method = 'search') { @@ -218,7 +162,7 @@ module.exports = class DbCheck { const results = await Promise.all(this.models[model].map(async (source) => ( source.SubModel.getAvailable(source) ))) - console.log(`[DB] Updating available for ${model}`) + console.log(`[DB] Setting available for ${model}`) if (results.length === 1) return results[0] if (results.length > 1) { const returnSet = new Set() diff --git a/server/src/services/EventManager.js b/server/src/services/EventManager.js index b146f939e..e2f500102 100644 --- a/server/src/services/EventManager.js +++ b/server/src/services/EventManager.js @@ -1,5 +1,3 @@ -/* eslint-disable no-promise-executor-return */ -/* eslint-disable no-await-in-loop */ /* eslint-disable no-console */ const { promises: fs } = require('fs') const path = require('path') @@ -10,33 +8,17 @@ const fetchJson = require('./api/fetchJson') const initWebhooks = require('./initWebhooks') module.exports = class EventManager { - constructor(config, masterfile, Db, Pvp) { + constructor(masterfile) { this.masterfile = masterfile this.invasions = masterfile.invasions this.available = { gyms: [], pokestops: [], pokemon: [], nests: [] } this.uicons = [] this.baseUrl = 'https://raw.githubusercontent.com/WatWowMap/wwm-uicons/main/' this.webhookObj = {} - this.pokestopTry = 1 + } - setTimeout(async () => { - // Set initials, comes with a timeout just to make sure all databases get configured first - await this.getUicons(config.icons.styles) - this.available.gyms = await Db.getAvailable('Gym') - this.available.nests = await Db.getAvailable('Nest') - this.available.pokemon = await Db.getAvailable('Pokemon') - this.available.pokestops = await Db.getAvailable('Pokestop') - while (!this.available.pokestops.length && this.pokestopTry <= config.database.settings.availableRetryCount) { - console.log(`[EVENT] No pokestops found, trying again in 1 second (attempt ${this.pokestopTry} / ${config.database.settings.availableRetryCount})`) - await new Promise(resolve => setTimeout(resolve, 1000)) - this.available.pokestops = await Db.getAvailable('Pokestop') - this.pokestopTry += 1 - } - await this.getMasterfile() - await this.getInvasions() - await this.getWebhooks(config) - }, config.database.settings.startupDelayMs) - this.setTimers(config, Db, Pvp) + async setAvailable(category, model, Db) { + this.available[category] = await Db.getAvailable(model) } setTimers(config, Db, Pvp) { diff --git a/server/src/services/api/fetchQuests.js b/server/src/services/api/fetchQuests.js index 6eb156882..21f02241d 100644 --- a/server/src/services/api/fetchQuests.js +++ b/server/src/services/api/fetchQuests.js @@ -24,6 +24,9 @@ module.exports = async function fetchQuests() { questsInfo.push(`i${grunt}`) } }) + for (let i = 1; i <= 5; i += 1) { + questsInfo.push(`l50${i}`) + } return questsInfo } catch (e) { console.warn(e, '\nUnable to fetch available quests and invasions from GitHub') diff --git a/server/src/services/initialization.js b/server/src/services/initialization.js index 6de8eeb18..3dbb157fe 100644 --- a/server/src/services/initialization.js +++ b/server/src/services/initialization.js @@ -1,3 +1,4 @@ +/* eslint-disable no-console */ const { database: { schemas: exampleSchemas }, } = require('../configs/local.example.json') @@ -10,9 +11,26 @@ const PvpWrapper = require('./PvpWrapper') const Db = new DbCheck(exampleSchemas, config.database, config.devOptions.queryDebug, config.api) const Pvp = config.api.pvp.reactMapHandlesPvp ? new PvpWrapper(config.api.pvp) : null +const Event = new EventManager(staticMf) + +Event.setTimers(config, Db, Pvp) + +Db.determineType() + .then(async () => { + await Promise.all([ + Event.getUicons(config.icons.styles), + Event.getMasterfile(), + Event.getInvasions(), + Event.getWebhooks(config), + Event.setAvailable('gyms', 'Gym', Db), + Event.setAvailable('pokestops', 'Pokestop', Db), + Event.setAvailable('pokemon', 'Pokemon', Db), + Event.setAvailable('nests', 'Nest', Db), + ]) + }) module.exports = { Db, Pvp, - Event: new EventManager(config, staticMf, Db, Pvp), + Event, }