const fs = require("fs") const request = require("request-promise-native") const sleep = require("util").promisify(setTimeout) const low = require("lowdb") const FileAsync = require("lowdb/adapters/FileAsync") const express = require("express") const app = express() const port = 3000 const patch = "8.24.1"; const key = "RGAPI-dce1850a-0954-4b1e-8072-77a26739f076"; let appRateLimit1; let appRateLimit120; let appRateLimitCount1; let appRateLimitCount120; // Express routing // --------------- let rules = [ ["/lol", "index.html"], ["/lol/script.js", "script.js"], ["/lol/style.css", "style.css"], ]; for (i in rules) { let path = rules[i][0]; let file = rules[i][1]; app.get(path, (req, res) => { res.sendFile(__dirname + "/html/" + file); }); } // --------------- // Riot API request // ---------------- const regions = { "BR": "br1.api.riotgames.com", "EUNE": "eun1.api.riotgames.com", "EUW": "euw1.api.riotgames.com", "JP": "jp1.api.riotgames.com", "KR": "kr.api.riotgames.com", "LAN": "la1.api.riotgames.com", "LAS": "la2.api.riotgames.com", "NA": "na1.api.riotgames.com", "OCE": "oc1.api.riotgames.com", "TR": "tr1.api.riotgames.com", "RU": "ru.api.riotgames.com", "PBE": "pbe1.api.riotgames.com", }; 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 { console.log("[Info] request: " + req); 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)); if (typeof result.body == "object") return result.body; return JSON.parse(result.body); } catch (err) { console.log("[Error] riotRequest: " + err.message); return await riotRequest(region, url, params, retries - 1); } } // ---------------- // User functionality // ------------------ let users = {}; let nameLookup = {}; async function loadUserDb(region, accountId) { if (!users[region]) users[region] = {}; if (users[region][accountId]) return; let adapter = new FileAsync(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; console.log("[Info] getting game summaries for " + summoner + " from " + region); try { 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("[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) });