X-Git-Url: https://gitweb.ps.run/lolstats/blobdiff_plain/52d1869f8b5510dab338fcabcefa48b86980a9f1..HEAD:/index.js diff --git a/index.js b/index.js index e9cc8c5..b8ddb22 100644 --- a/index.js +++ b/index.js @@ -1,17 +1,22 @@ -const express = require("express") const fs = require("fs") const request = require("request-promise-native") +const low = require("lowdb") +const FileAsync = require("lowdb/adapters/FileAsync") + +const express = require("express") const app = express() const port = 3000 -const sleep = require('util').promisify(setTimeout) const patch = "8.24.1"; -const key = "RGAPI-c6cae96a-c4b0-4842-9017-ddd736f3f628"; -let appRateLimit1; -let appRateLimit120; +const key = "RGAPI-dce1850a-0954-4b1e-8072-77a26739f076"; + +let appRateLimit1 = 10; +let appRateLimit120 = 100; let appRateLimitCount1; let appRateLimitCount120; +// Express routing +// --------------- let rules = [ ["/lol", "index.html"], ["/lol/script.js", "script.js"], @@ -25,53 +30,10 @@ for (i in rules) { res.sendFile(__dirname + "/html/" + file); }); } +// --------------- -async function riotRequest(region, url, params, retries) { - if (retries < 1) throw "Error too many tries"; - let req = "https://" + regions[region] + url + "?api_key=" + key; - for (p in params) { - req += "&" + p + "=" + params[p]; - } - try { - let result = await request({uri: req, resolveWithFullResponse: true, json: true}); - let appRateLimit = result.headers["x-app-rate-limit"]; - let appRateLimitCount = result.headers["x-app-rate-limit-count"]; - appRateLimit1 = appRateLimit.split(",")[0].split(":")[0]; - appRateLimit120 = appRateLimit.split(",")[1].split(":")[0]; - appRateLimitCount1 = appRateLimitCount.split(",")[0].split(":")[0]; - appRateLimitCount120 = appRateLimitCount.split(",")[1].split(":")[0]; - let delay1 = 1000 / (appRateLimit1 - 1); - let delay120 = 120000 / (appRateLimit120 - 1); - await sleep(Math.max(delay1, delay120)); - console.log(Math.max(delay1, delay120)); - return result.body; - } catch (err) { - console.log(err.message); - return await riotRequest(region, url, params, retries - 1); - } -} - -async function getAllMatches(region, accountId) { - let matches = []; - let totalGames; - let bI = 0, eI = 99; - - do { - let m = await riotRequest(region, "/lol/match/v4/matchlists/by-account/" + accountId, { beginIndex: bI, endIndex: eI }, 5); - console.log(m); - totalGames = m.totalGames; - matches = matches.concat(m.matches); - console.log("Added games " + bI + " to " + eI + ", " + matches.length + " of " + totalGames); - bI = eI + 1; - eI += 100; - } while (bI <= totalGames); - - return matches; -} - -// Static Data -// ----------- - +// Riot API request +// ---------------- const regions = { "BR": "br1.api.riotgames.com", "EUNE": "eun1.api.riotgames.com", @@ -86,54 +48,141 @@ const regions = { "RU": "ru.api.riotgames.com", "PBE": "pbe1.api.riotgames.com", }; -app.get("/lol/regions", (req, res) => { - res.send(JSON.stringify(regions)); -}); -let champions = null; -function getChampions(cb) { - request("http://ddragon.leagueoflegends.com/cdn/" + patch + "/data/en_US/champion.json", (err, res, body) => { - champions = JSON.parse(body).data; - cb(); + +let requests = []; + +async function executeRequest() { + if (requests.length > 0) { + let req = requests.shift(); + if (req.retries < 1) req.rej(); + else { + try { + console.log("[Info] request: " + req.url); + let result = await request({uri: req.url, resolveWithFullResponse: true, json: true}); + + let appRateLimit = result.headers["x-app-rate-limit"]; + let appRateLimitCount = result.headers["x-app-rate-limit-count"]; + appRateLimit1 = appRateLimit.split(",")[0].split(":")[0]; + appRateLimit120 = appRateLimit.split(",")[1].split(":")[0]; + appRateLimitCount1 = appRateLimitCount.split(",")[0].split(":")[0]; + appRateLimitCount120 = appRateLimitCount.split(",")[1].split(":")[0]; + + if (typeof result.body == "object") req.res(result.body); + else req.res(JSON.parse(result.body)); + } catch (err) { + console.log("[Error] riotRequest: " + err.message); + req.retries--; + requests.push(req); + } + } + } + let delay1 = 1000 / (appRateLimit1 - 1); + let delay120 = 120000 / (appRateLimit120 - 1); + setTimeout(executeRequest, Math.max(delay1, delay120)); +} +executeRequest(); + +async function riotRequest(region, url, params, retries) { + let req = "https://" + regions[region] + url + "?api_key=" + key; + for (p in params) { + req += "&" + p + "=" + params[p]; + } + return new Promise((resolve, reject) => { + requests.push({ url: req, retries: 5, res: resolve, rej: reject }); }); } -app.get("/lol/champions", (req, res) => { - if (champions == null) - getChampions(() => { - res.send(JSON.stringify(Object.keys(champions))); - }); - else - res.send(JSON.stringify(Object.keys(champions))); -}); +// ---------------- + +// User functionality +// ------------------ let users = {}; -if (fs.existsSync("users.js")) { - fs.readFile("users.js", (err, data) => { - users = JSON.parse(data); - }); +let nameLookup = {}; + +async function loadUserDb(region, accountId) { + if (!users[region]) users[region] = {}; + if (users[region][accountId]) return; + let adapter = new FileAsync("data/" + region + "/" + accountId + ".json"); + let db = await low(adapter); + await db.defaults({ games: [], gameSummaries: [], account: {} }) + .write(); + users[region][accountId] = db; } + +async function loadUserInfo(region, summonerName) { + if (!nameLookup[region]) nameLookup[region] = {}; + if (nameLookup[region][summonerName]) return; + let user = await riotRequest(region, "/lol/summoner/v4/summoners/by-name/" + summonerName, {}, 5); + let accountId = user.accountId; + await loadUserDb(region, accountId); + users[region][accountId].set("account", user); + nameLookup[region][summonerName] = accountId; +} + +async function loadGameSummaries(region, accountId) { + let totalGames; + let bI = 0, eI = 100; + + loop1: + do { + let matchlist = await riotRequest(region, "/lol/match/v4/matchlists/by-account/" + accountId, { beginIndex: bI, endIndex: eI }, 5); + totalGames = matchlist.totalGames; + for (m in matchlist.matches) { + let match = matchlist.matches[m]; + if (users[region][accountId].get("gameSummaries").find({ gameId: match.gameId }).value()) { + break loop1; + } + users[region][accountId].get("gameSummaries").push(match).write(); + } + bI = eI; + eI += 100; + } while (bI <= totalGames); + users[region][accountId].write(); + users[region][accountId].set("gameSummaries", + users[region][accountId].get("gameSummaries").sortBy("timestamp").sortedUniqBy((x) => x.gameId).value()).write(); +} + app.get("/lol/matches", async (req, res) => { let region = req.query.region; let summoner = req.query.summoner; - let regionUrl = regions[region]; + console.log("[Info] getting game summaries for " + summoner + " from " + region); try { - let data = await riotRequest(region, "/lol/summoner/v4/summoners/by-name/" + summoner, {}, 5); - let accountId = data.accountId; - if (users[accountId]) { - res.send(JSON.stringify(users[accountId])); - return; - } - let matches = await getAllMatches(region, accountId); - users[accountId] = matches; - fs.writeFile("users.js", JSON.stringify(users), (err) => { - console.log("Error writing file: " + err); - }); - res.send(matches); + await loadUserInfo(region, summoner); + let accountId = nameLookup[region][summoner]; + await loadGameSummaries(region, accountId); + let matches = users[region][accountId].get("gameSummaries").value(); + console.log(matches.length); + res.send(JSON.stringify(matches)); } catch (err) { - console.log(err); + console.log("[Error] GET /lol/matches: " + err); + res.send("error"); } }); +// ------------------ +// Static Data +// ----------- +let champions; +let champLookup = {}; +function loadChampions() { + request("http://ddragon.leagueoflegends.com/cdn/" + patch + "/data/en_US/champion.json", (err, res, body) => { + if (err) console.log("[Error] loadChampions: " + err); + champions = JSON.parse(body).data; + for (c in champions) { + champLookup[champions[c].key] = c; + } + }); +} + +app.get("/lol/champions", (req, res) => { + res.send(JSON.stringify(Object.keys(champions))); +}); + +app.get("/lol/champlookup", (req, res) => { + res.send(JSON.stringify(champLookup)); +}); // ----------- +loadChampions(); app.listen(port, () => { console.log("Listening on port %d", port) });