diff --git a/datasources/ammo.js b/datasources/ammo.js deleted file mode 100644 index 241f3ea2..00000000 --- a/datasources/ammo.js +++ /dev/null @@ -1,15 +0,0 @@ -// datasource for ammo -const WorkerKV = require('../utils/worker-kv'); - -class AmmoAPI extends WorkerKV { - constructor() { - super('AMMO_DATA'); - } - - async getList() { - await this.init(); - return this.cache.data; - } -} - -module.exports = AmmoAPI; diff --git a/datasources/barters.js b/datasources/barters.js index e8dfbb14..14cda806 100644 --- a/datasources/barters.js +++ b/datasources/barters.js @@ -2,7 +2,7 @@ const WorkerKV = require('../utils/worker-kv'); class BartersAPI extends WorkerKV { constructor() { - super('BARTER_DATA_V2'); + super('barter_data'); } async getList() { diff --git a/datasources/crafts.js b/datasources/crafts.js index 5fc8849a..8782471a 100644 --- a/datasources/crafts.js +++ b/datasources/crafts.js @@ -3,7 +3,7 @@ const WorkerKV = require('../utils/worker-kv'); class CraftsAPI extends WorkerKV { constructor(){ - super('CRAFT_DATA_V2'); + super('craft_data'); } async getList() { diff --git a/datasources/hideout-legacy.js b/datasources/hideout-legacy.js deleted file mode 100644 index 86fb9a22..00000000 --- a/datasources/hideout-legacy.js +++ /dev/null @@ -1,62 +0,0 @@ -class HideoutLegacyAPI { - constructor(){ - this.moduleList = false; - } - - async getList(){ - if(this.moduleList){ - return this.moduleList; - } - - const hideoutData = await ITEM_DATA.get('HIDEOUT_DATA', 'json'); - const returnData = []; - - for(const hideoutModule of hideoutData.data){ - const newRequirement = { - id: hideoutModule.id, - name: hideoutModule.module, - level: hideoutModule.level, - itemRequirements: hideoutModule.require.map((hideoutRequirement) => { - if(hideoutRequirement.type !== 'item'){ - return false; - } - - return { - item: hideoutRequirement.name, - quantity: hideoutRequirement.quantity, - count: hideoutRequirement.quantity, - }; - }), - moduleRequirements: hideoutModule.require.map((hideoutRequirement) => { - if(hideoutRequirement.type !== 'module'){ - return false; - } - - return { - name: hideoutRequirement.name, - level: hideoutRequirement.quantity, - }; - }).filter(Boolean), - }; - - newRequirement.itemRequirements = newRequirement.itemRequirements.filter(Boolean); - returnData.push(newRequirement); - } - - for(const hideoutModule of returnData){ - hideoutModule.moduleRequirements = hideoutModule.moduleRequirements.map((basicModuleObject) => { - return this.getModule(basicModuleObject.name, basicModuleObject.level, returnData); - }); - } - - this.moduleList = returnData; - - return returnData; - } - - async getModule(name, level, moduleList) { - return moduleList.find(hideoutModule => hideoutModule.name === name && hideoutModule.level === level); - } -} - -module.exports = HideoutLegacyAPI; diff --git a/datasources/hideout.js b/datasources/hideout.js index b88fd2d5..936f6087 100644 --- a/datasources/hideout.js +++ b/datasources/hideout.js @@ -2,7 +2,7 @@ const WorkerKV = require('../utils/worker-kv'); class HideoutAPI extends WorkerKV { constructor() { - super('HIDEOUT_DATA_V3'); + super('hideout_data'); } async getList(){ @@ -42,6 +42,21 @@ class HideoutAPI extends WorkerKV { } return Promise.reject(new Error(`No hideout station found with id ${id}`)); } + + async getLegacyList() { + await this.init(); + return this.cache.legacy; + } + + async getLegacyModule(name, level) { + await this.init(); + for (const module of this.cache.legacy) { + if (module.name === name && module.quantity === level) { + return module; + } + } + return Promise.reject(new Error(`No hideout module with id ${id} found`)); + } } module.exports = HideoutAPI; diff --git a/datasources/historical-prices.js b/datasources/historical-prices.js index a828d6c2..3fb20a36 100644 --- a/datasources/historical-prices.js +++ b/datasources/historical-prices.js @@ -2,7 +2,7 @@ const WorkerKV = require('../utils/worker-kv'); class historicalPricesAPI extends WorkerKV { constructor() { - super('HISTORICAL_PRICES'); + super('historical_price_data'); } async getByItemId(itemId) { @@ -10,8 +10,8 @@ class historicalPricesAPI extends WorkerKV { if (!this.cache) { return Promise.reject(new Error('Historical prices cache is empty')); } - if (!this.cache[itemId]) return []; - return this.cache[itemId]; + if (!this.cache.data[itemId]) return []; + return this.cache.data[itemId]; } } diff --git a/datasources/index.js b/datasources/index.js index c0afc0cb..c2f980d8 100644 --- a/datasources/index.js +++ b/datasources/index.js @@ -1,32 +1,27 @@ -const AmmoAPI = require('./ammo'); const BartersAPI = require('./barters'); const CraftsAPI = require('./crafts'); -const HideoutLegacyAPI = require('./hideout-legacy'); const HideoutAPI = require('./hideout'); const HistoricalPricesAPI = require('./historical-prices'); const ItemsAPI = require('./items'); -const QuestsAPI = require('./quests'); +const MapAPI = require('./maps'); +//const QuestsAPI = require('./quests'); const status = require('./status'); +const TasksAPI = require('./tasks'); const TraderInventoryAPI = require('./trader-inventory'); const TradersAPI = require('./traders'); -const TasksAPI = require('./tasks'); -const MapAPI = require('./maps'); class DataSource { constructor(){ - this.ammo = new AmmoAPI(); this.barter = new BartersAPI(); this.craft = new CraftsAPI(); - this.hideoutLegacy = new HideoutLegacyAPI(); this.hideout = new HideoutAPI(); this.historicalPrice = new HistoricalPricesAPI(); this.item = new ItemsAPI(); - this.quest = new QuestsAPI(); + this.map = new MapAPI(); + this.status = status; this.traderInventory = new TraderInventoryAPI(); this.trader = new TradersAPI(); this.task = new TasksAPI(); - this.status = status, - this.map = new MapAPI(); this.initialized = false; this.loading = false; @@ -57,6 +52,7 @@ class DataSource { this.barter.init(), this.craft.init(), this.hideout.init(), + this.historicalPrice.init(), this.item.init(), this.map.init(), this.task.init(), @@ -65,6 +61,9 @@ class DataSource { ]).then(() => { this.initialized = true; this.loading = false; + }).catch(error => { + this.loading = false; + return Promise.reject(error); }); } catch (error) { console.error('error initializing data api', error.stack); diff --git a/datasources/items.js b/datasources/items.js index 9bee38ff..133971aa 100644 --- a/datasources/items.js +++ b/datasources/items.js @@ -2,7 +2,7 @@ const WorkerKV = require('../utils/worker-kv'); class ItemsAPI extends WorkerKV { constructor() { - super('ITEM_CACHE_V4'); + super('item_data'); } formatItem(rawItem) { @@ -16,6 +16,7 @@ class ItemsAPI extends WorkerKV { return { price: traderPrice.price, currency: traderPrice.currency, + currencyItem: traderPrice.currencyItem, priceRUB: traderPrice.priceRUB, vendor: { trader: traderPrice.trader, @@ -348,6 +349,19 @@ class ItemsAPI extends WorkerKV { await this.init(); return this.cache.armorMats[matKey]; } + + async getAmmoList() { + const allAmmo = await this.getItemsByBsgCategoryId('5485a8684bdc2da71d8b4567').then(ammoItems => { + // ignore bb + return ammoItems.filter(item => item.id !== '6241c316234b593b5676b637'); + }); + return allAmmo.map(item => { + return { + ...item, + ...item.properties + }; + }); + } } module.exports = ItemsAPI; diff --git a/datasources/maps.js b/datasources/maps.js index 4006d20d..db067214 100644 --- a/datasources/maps.js +++ b/datasources/maps.js @@ -2,7 +2,7 @@ const WorkerKV = require('../utils/worker-kv'); class MapAPI extends WorkerKV { constructor() { - super('MAP_DATA_V2'); + super('map_data'); } async getList() { diff --git a/datasources/quests.js b/datasources/quests.js deleted file mode 100644 index 0e172613..00000000 --- a/datasources/quests.js +++ /dev/null @@ -1,82 +0,0 @@ -class QuestsAPI { - async getList() { - const quests = await ITEM_DATA.get('QUEST_DATA', 'json'); - - if(!quests){ - return {}; - } - const returnData = []; - - for(const quest of quests){ - const parsedQuestData = { - ...quest, - requirements: quest.require, - wikiLink: quest.wiki, - reputation: quest.reputation.map((reputationData) => { - return { - trader: reputationData.trader, - amount: reputationData.rep, - }; - }), - objectives: quest.objectives.map((objectiveData) => { - const formattedObjective = { - ...objectiveData, - }; - - if(objectiveData.type === 'collect' || objectiveData.type === 'find' || objectiveData.type === 'place'){ - formattedObjective.targetItem = formattedObjective.target; - - if(!formattedObjective.targetItem.id){ - //console.log(`${quest.id} - ${formattedObjective.target}`); - formattedObjective.targetItem = null; - } - } else if (objectiveData.type === 'mark') { - formattedObjective.targetItem = formattedObjective.tool; - - if(!formattedObjective.targetItem.id){ - //console.log(`${quest.id} - ${formattedObjective.tool}`); - formattedObjective.targetItem = null; - } - } - - if(!Array.isArray(formattedObjective.target)){ - formattedObjective.target = [formattedObjective.target]; - } - - return formattedObjective; - }), - }; - - parsedQuestData.requirements.quests = parsedQuestData.requirements.quests.map((stringOrArray) => { - if(Array.isArray(stringOrArray)){ - return stringOrArray; - } - - return [stringOrArray]; - }); - - returnData.push(parsedQuestData); - } - - for(const quest of returnData){ - if(quest.require.quests.length === 0){ - quest.require.prerequisiteQuests = [[]]; - continue; - } - - let questsList = []; - - for(const questList of quest.require.quests){ - questsList.push(questList.map((id) => { - return returnData.find(tempQuest => tempQuest.id === id); - })); - } - - quest.require.prerequisiteQuests = questsList; - } - - return returnData; - } -} - -module.exports = QuestsAPI; diff --git a/datasources/tasks.js b/datasources/tasks.js index 6f1c271f..6fd09151 100644 --- a/datasources/tasks.js +++ b/datasources/tasks.js @@ -2,7 +2,7 @@ const WorkerKV = require('../utils/worker-kv'); class TasksAPI extends WorkerKV { constructor() { - super('TASK_DATA_V2'); + super('quest_data'); } async getList() { @@ -104,6 +104,22 @@ class TasksAPI extends WorkerKV { return rawTask; }); } + + async getQuests() { + await this.init(); + return this.cache.legacy; + } + + async getQuest(id) { + await this.init(); + const quests = await this.getQuests(); + for (const quest of quests) { + if (quest.id === id) { + return quest; + } + } + return Promise.reject(new Error(`No quest with id ${id} found`)); + } } module.exports = TasksAPI; diff --git a/datasources/trader-inventory.js b/datasources/trader-inventory.js index d1e4be15..0f7ea0c2 100644 --- a/datasources/trader-inventory.js +++ b/datasources/trader-inventory.js @@ -2,7 +2,7 @@ const WorkerKV = require('../utils/worker-kv'); class TraderInventoryAPI extends WorkerKV { constructor() { - super('TRADER_ITEMS_V2'); + super('trader_price_data'); this.traderCache = false; } @@ -14,8 +14,7 @@ class TraderInventoryAPI extends WorkerKV { try { const traderCache = {}; - for (const id in this.cache) { - const itemOffers = this.cache[id]; + for (const itemOffers of Object.values(this.cache.data)) { for (const offer of itemOffers) { if (!traderCache[offer.vendor.trader_id]) traderCache[offer.vendor.trader_id] = []; traderCache[offer.vendor.trader_id].push(offer); @@ -29,10 +28,10 @@ class TraderInventoryAPI extends WorkerKV { async getByItemId(itemId) { await this.init(); - if(!this.cache[itemId]){ + if(!this.cache.data[itemId]){ return []; } - return this.cache[itemId]; + return this.cache.data[itemId]; } async getPricesForTrader(traderId) { diff --git a/datasources/traders.js b/datasources/traders.js index d7646879..4fea41fb 100644 --- a/datasources/traders.js +++ b/datasources/traders.js @@ -38,7 +38,7 @@ const traderNameIdMap = { class TradersAPI extends WorkerKV { constructor() { - super('TRADER_DATA_V2'); + super('trader_data'); } async getList() { diff --git a/index.js b/index.js index 5d885db0..7a282fd8 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,4 @@ //const crypto = require('crypto'); -const { EventEmitter } = require('events'); const { makeExecutableSchema } = require('@graphql-tools/schema'); const { mergeTypeDefs } = require('@graphql-tools/merge'); @@ -22,19 +21,17 @@ const twitch = require('./custom-endpoints/twitch'); let schema = false; let loadingSchema = false; -//const schemaEvents = new EventEmitter(); -//schemaEvents.setMaxListeners(0); +const skipCache = ENVIRONMENT !== 'production' || false; -async function getSchema() { - if (schema) { +/** + * Example of how router can be used in an application + * */ + +async function getSchema(data) { + if (schema){ return schema; } if (loadingSchema) { - /*return new Promise((resolve) => { - schemaEvents.once('loaded', () => { - resolve(schema); - }); - });*/ return new Promise((resolve) => { const isDone = () => { if (this.loadingSchema === false) { @@ -47,10 +44,9 @@ async function getSchema() { }); } loadingSchema = true; - return dynamicTypeDefs(dataAPI).then(dynamicTypeDefs => { - schema = makeExecutableSchema({ typeDefs: mergeTypeDefs([typeDefs, dynamicTypeDefs]), resolvers: resolvers }); + return dynamicTypeDefs(data).then(dynamicTypeDefs => { + schema = makeExecutableSchema({typeDefs: mergeTypeDefs([typeDefs, dynamicTypeDefs]), resolvers: resolvers}); loadingSchema = false; - //schemaEvents.emit('loaded'); return schema; }).catch(error => { loadingSchema = false; @@ -59,10 +55,13 @@ async function getSchema() { } addEventListener('fetch', event => { + //console.time(event.request.cf.tlsExportedAuthenticator.clientFinished+' total response'); + //console.log('environment', ENVIRONMENT); event.respondWith(handleRequest(event)); }); async function graphqlHandler(event, graphQLOptions) { + //console.time(event.request.cf.tlsExportedAuthenticator.clientFinished+' checkPoint'); const request = event.request; const url = new URL(request.url); let query = false; @@ -70,7 +69,10 @@ async function graphqlHandler(event, graphQLOptions) { if (request.method === 'POST') { try { + //console.timeEnd(event.request.cf.tlsExportedAuthenticator.clientFinished+' checkPoint'); + //console.time(event.request.cf.tlsExportedAuthenticator.clientFinished+' request.json'); const requestBody = await request.json(); + //console.timeEnd(event.request.cf.tlsExportedAuthenticator.clientFinished+' request.json'); query = requestBody.query; variables = requestBody.variables; } catch (jsonError) { @@ -80,11 +82,22 @@ async function graphqlHandler(event, graphQLOptions) { status: 503, }); } - } - - if (request.method === 'GET') { + } else if (request.method === 'GET') { query = url.searchParams.get('query'); variables = url.searchParams.get('variables'); + } else { + return new Response(null, { + status: 501, + }); + } + // Check for empty /graphql query + if (!query || query.trim() === "") { + return new Response('GraphQL requires a query in the body of the request', + { + status: 200, + headers: { 'cache-control': 'public, max-age=2592000' } + } + ); } // default headers @@ -95,14 +108,18 @@ async function graphqlHandler(event, graphQLOptions) { }; // Check the cache service for data first - If cached data exists, return it - const cachedResponse = await cacheMachine.get(query); - if (cachedResponse) { - // Construct a new response with the cached data - const newResponse = new Response(cachedResponse, headers); - // Add a custom 'X-CACHE: HIT' header so we know the request hit the cache - newResponse.headers.append('X-CACHE', 'HIT'); - // Return the new cached response - return newResponse; + if (!skipCache) { + const cachedResponse = await cacheMachine.get(query); + if (cachedResponse) { + // Construct a new response with the cached data + const newResponse = new Response(cachedResponse, headers); + // Add a custom 'X-CACHE: HIT' header so we know the request hit the cache + newResponse.headers.append('X-CACHE', 'HIT'); + // Return the new cached response + return newResponse; + } + } else { + console.log(`Skipping cache in ${ENVIRONMENT} environment`); } /* const queryHashString = JSON.stringify({ @@ -124,18 +141,26 @@ async function graphqlHandler(event, graphQLOptions) { } } */ - await dataAPI.init(); - const result = await graphql(await getSchema(), query, {}, { data: dataAPI, util: graphqlUtil }, variables); + //console.time(event.request.cf.tlsExportedAuthenticator.clientFinished+' init') + /*try { + await dataAPI.init(); + } catch (error) { + console.log('init error', error, error.stack); + }*/ + //console.timeEnd(event.request.cf.tlsExportedAuthenticator.clientFinished+' init') + const result = await graphql(await getSchema(dataAPI), query, {}, {data: dataAPI, util: graphqlUtil}, variables); const body = JSON.stringify(result); // Update the cache with the results of the query - // using waitUntil doens't hold up returning a response but keeps the worker alive as long as needed - event.waitUntil(cacheMachine.put(query, body)); + if (!skipCache) { + // using waitUntil doens't hold up returning a response but keeps the worker alive as long as needed + event.waitUntil(cacheMachine.put(query, body)); + } /* if(!result.errors && !url.hostname.includes('localhost') && !url.hostname.includes('tutorial.cloudflareworkers.com')){ await QUERY_CACHE.put(queryHash, body, {expirationTtl: 300}); } */ - + //console.timeEnd(event.request.cf.tlsExportedAuthenticator.clientFinished+' total response') return new Response(body, { headers: { 'content-type': 'application/json', @@ -179,18 +204,6 @@ const handleRequest = async event => { const request = event.request; const url = new URL(request.url); - // Check for empty /graphql query - if (url.pathname === "/graphql" && request.method === 'POST') { - const json = await request.clone().json(); - if (json.query.trim() === "") { - // Clone the response so that it's no longer immutable - const response = new Response('GraphQL requires a query in the body of the request', { status: 200 }); - // Add a cache control header - response.headers.append('cache-control', 'public, max-age=2592000'); - return response; - } - } - try { if (url.pathname === '/webhook/nightbot') { return nightbot(request, dataAPI); @@ -234,8 +247,3 @@ const handleRequest = async event => { return new Response(graphQLOptions.debug ? err : 'Something went wrong', { status: 500 }); } }; - -(async () => { - initSchema(); - dataAPI.init(); -})(); diff --git a/loader.js b/loader.js index 62fb701e..bd5e444d 100644 --- a/loader.js +++ b/loader.js @@ -21,8 +21,8 @@ if (typeof QUERY_CACHE === 'undefined') { } } -if (typeof ITEM_DATA === 'undefined') { - global.ITEM_DATA = { +if (typeof DATA_CACHE === 'undefined') { + global.DATA_CACHE = { get: async (what) => { console.log(`trying to get ${what}`) diff --git a/package.json b/package.json index 48ea5e46..46e3df3a 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "test": "echo \"Error: no test specified\"", "format": "prettier --write '**/*.{js,css,json,md}'", "dev": "wrangler --env development dev", - "ci": "wrangler --env development --config script/ci/wrangler-ci.toml dev", + "ci": "wrangler --env development dev", "local": "wrangler dev" }, "author": "Oskar Risberg ", diff --git a/resolvers/ammoResolver.js b/resolvers/ammoResolver.js index b22876c5..7c111cd7 100644 --- a/resolvers/ammoResolver.js +++ b/resolvers/ammoResolver.js @@ -1,7 +1,7 @@ module.exports = { Query: { ammo(obj, args, context, info) { - return context.data.ammo.getList(); + return context.data.item.getAmmoList(); } }, Ammo: { diff --git a/resolvers/barterResolver.js b/resolvers/barterResolver.js index 00f15da9..616cd271 100644 --- a/resolvers/barterResolver.js +++ b/resolvers/barterResolver.js @@ -7,7 +7,7 @@ module.exports = { Barter: { taskUnlock(data, args, context) { if (!data || !data.taskUnlock) return null; - return context.data.task.get(data.taskUnlock); + return context.data.quest.get(data.taskUnlock); }, trader(data, args, context) { return context.data.trader.get(data.trader_id); diff --git a/resolvers/hideoutResolver.js b/resolvers/hideoutResolver.js index e75a6093..d807f8fe 100644 --- a/resolvers/hideoutResolver.js +++ b/resolvers/hideoutResolver.js @@ -1,7 +1,7 @@ module.exports = { Query: { hideoutModules(obj, args, context, info) { - return context.data.hideoutLegacy.getList(); + return context.data.hideout.getLegacyList(); }, hideoutStations(obj, args, context, info) { return context.data.hideout.getList(); @@ -29,5 +29,12 @@ module.exports = { station(data, args, context) { return context.data.hideout.getStation(data.station); } + }, + HideoutModule: { + moduleRequirements(data, args, context) { + return data.moduleRequirements.map(req => { + return context.data.hideout.getLegacyModule(req.name, req.quantity); + }); + } } }; diff --git a/resolvers/taskResolver.js b/resolvers/taskResolver.js index bc40a7f7..915c1e60 100644 --- a/resolvers/taskResolver.js +++ b/resolvers/taskResolver.js @@ -16,7 +16,7 @@ module.exports = { return context.data.task.get(args.id); }, quests(obj, args, context, info) { - return context.data.quest.getList(); + return context.data.task.getQuests(); } }, Task: { @@ -287,9 +287,18 @@ module.exports = { return context.data.item.getItem(data.targetItem) } }, + QuestRequirement: { + prerequisiteQuests(data, args, context) { + return data.prerequisiteQuests.map(questArray => { + return questArray.map(questId => { + return context.data.task.getQuest(questId); + }); + }); + } + }, QuestRewardReputation: { async trader(data, args, context) { - return context.data.trader.getByName(data.trader); + return context.data.trader.get(context.data.trader.getDataIdMap()[data.trader]); } } }; diff --git a/script/ci/wrangler-ci.toml b/script/ci/wrangler-ci.toml deleted file mode 100644 index 72919779..00000000 --- a/script/ci/wrangler-ci.toml +++ /dev/null @@ -1,22 +0,0 @@ -compatibility_date = "2021-12-14" -name = "api" -type = "webpack" -account_id = "424ad63426a1ae47d559873f929eb9fc" -zone_id = "777d475095752ccbe5d1d49e690a305b" -workers_dev = true -webpack_config = "webpack.config.js" -# routes = ["api.tarkov.dev/graphql", "api.tarkov.dev/graphql*", "api.tarkov.dev/___graphql", "api.tarkov.dev/webhook*"] -kv-namespaces = [ - { binding = "ITEM_DATA", id = "2973a2dd070e4a348d87084171efe11a", preview_id = "2973a2dd070e4a348d87084171efe11a" }, - { binding = "QUERY_CACHE", id = "7ae67967cff24ceaa31ca58c5a6da798", preview_id = "7ae67967cff24ceaa31ca58c5a6da798" } -] - -[env.development] -# routes = ["dev.api.tarkov.dev/graphql", "dev.api.tarkov.dev/graphql*", "dev.api.tarkov.dev/___graphql", "dev.api.tarkov.dev/webhook*"] -kv-namespaces = [ - { binding = "ITEM_DATA", id = "2973a2dd070e4a348d87084171efe11a", preview_id = "2973a2dd070e4a348d87084171efe11a" }, - { binding = "QUERY_CACHE", id = "7ae67967cff24ceaa31ca58c5a6da798", preview_id = "7ae67967cff24ceaa31ca58c5a6da798" } -] - -# [secrets] -# CACHE_BASIC_AUTH diff --git a/utils/worker-kv.js b/utils/worker-kv.js index a8d95174..3b9b42f9 100644 --- a/utils/worker-kv.js +++ b/utils/worker-kv.js @@ -1,61 +1,50 @@ -const {EventEmitter} = require('events'); +const zlib = require('zlib'); class WorkerKV { constructor(kvName){ this.cache = false; this.loading = false; this.kvName = kvName; - this.events = new EventEmitter(); - this.events.setMaxListeners(0); + this.loadingPromises = []; + this.loadingInterval = false; } async init(){ if (this.cache){ //console.log('already loaded', this.kvName); - return true; + return; } if (this.loading) { - //console.log('waiting for load', this.kvName); - return new Promise((resolve, reject) => { - try { - this.events.once('loaded', () => { - //console.log(this.kvName, 'loaded event handled'); - resolve(); - }); - } catch (error) { - console.log(error); - reject(error); - } + return new Promise((resolve) => { + this.loadingPromises.push(resolve); }); - /*return new Promise((resolve) => { - const isDone = () => { - if (this.loading === false) { - resolve(); - } else { - try { - setTimeout(isDone, 5); - } catch (error) { - console.log(error.stack); - reject(error); - } - } - } - isDone(); - });*/ } this.loading = true; + this.loadingInterval = setInterval(() => { + if (this.loading) return; + let resolve = false; + while (resolve = this.loadingPromises.shift()) { + resolve(); + } + clearInterval(this.loadingInterval); + }, 5); + //console.time('kv load '+this.kvName); return new Promise((resolve, reject) => { - ITEM_DATA.get(this.kvName, 'json').then(data => { - this.cache = data; + DATA_CACHE.getWithMetadata(this.kvName, 'text').then(response => { + const data = response.value; + const metadata = response.metadata; + //console.timeEnd('kv load '+this.kvName); + if (metadata && metadata.compression) { + if (metadata.compression = 'gzip') { + this.cache = JSON.parse(zlib.gunzipSync(Buffer.from(data, metadata.encoding)).toString()); + } else { + return reject(new Error(`${metadata.compression} is not a recognized compression type`)); + } + } else { + this.cache = JSON.parse(data); + } this.loading = false; //console.log(this.kvName, 'listeners', this.events.listenerCount('loaded')); - try { - //console.time(this.kvName+' emit'); - this.events.emit('loaded'); - //console.timeEnd(this.kvName+' emit'); - } catch (error) { - console.log(error); - } resolve(); }).catch(error => { this.loading = false; diff --git a/webpack.config.js b/webpack.config.js index f8407520..7b220c1b 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,5 +1,5 @@ const config = { - mode: 'none', // "production" | "development" | "none" + mode: 'production', // "production" | "development" | "none" resolve: { extensions: ['*', '.mjs', '.js', '.json'] }, diff --git a/webpack.dev.js b/webpack.dev.js new file mode 100644 index 00000000..f8407520 --- /dev/null +++ b/webpack.dev.js @@ -0,0 +1,19 @@ +const config = { + mode: 'none', // "production" | "development" | "none" + resolve: { + extensions: ['*', '.mjs', '.js', '.json'] + }, + target: 'webworker', + entry: './index.js', + module: { + rules: [ + { + test: /\.mjs$/, + include: /node_modules/, + type: 'javascript/auto' + } + ] + } +}; + +module.exports = config; diff --git a/wrangler.toml b/wrangler.toml index 3fc8a0ea..4573fdc6 100644 --- a/wrangler.toml +++ b/wrangler.toml @@ -7,19 +7,22 @@ workers_dev = true webpack_config = "webpack.config.js" routes = ["api.tarkov.dev/graphql", "api.tarkov.dev/graphql*", "api.tarkov.dev/___graphql", "api.tarkov.dev/webhook*"] kv-namespaces = [ - { binding = "ITEM_DATA", id = "2973a2dd070e4a348d87084171efe11a", preview_id = "2973a2dd070e4a348d87084171efe11a" }, - { binding = "QUERY_CACHE", id = "7ae67967cff24ceaa31ca58c5a6da798", preview_id = "7ae67967cff24ceaa31ca58c5a6da798" } + { binding = "DATA_CACHE", id = "2e6feba88a9e4097b6d2209191ed4ae5", preview_id = "17fd725f04984e408d4a70b37c817171" }, + { binding = "QUERY_CACHE", id = "7ae67967cff24ceaa31ca58c5a6da798", preview_id = "cf717460f7eb40299a0f8f844d157051" } ] vars = { ENVIRONMENT = "production" } + [env.development] +webpack_config = "webpack.dev.js" routes = [] -#routes = ["dev.api.tarkov.dev/graphql", "dev.api.tarkov.dev/graphql*", "dev.api.tarkov.dev/___graphql", "dev.api.tarkov.dev/webhook*"] kv-namespaces = [ - { binding = "ITEM_DATA", id = "2973a2dd070e4a348d87084171efe11a", preview_id = "2973a2dd070e4a348d87084171efe11a" }, - { binding = "QUERY_CACHE", id = "7ae67967cff24ceaa31ca58c5a6da798", preview_id = "7ae67967cff24ceaa31ca58c5a6da798" } + { binding = "DATA_CACHE", id = "17fd725f04984e408d4a70b37c817171", preview_id = "17fd725f04984e408d4a70b37c817171" }, + { binding = "QUERY_CACHE", id = "cf717460f7eb40299a0f8f844d157051", preview_id = "cf717460f7eb40299a0f8f844d157051" } ] vars = { ENVIRONMENT = "development" } # [secrets] # CACHE_BASIC_AUTH +# TWITCH_CLIENT_ID +# TWITCH_TOKEN