]> gitweb.ps.run Git - lolstats/blob - index.js
data
[lolstats] / index.js
1 const fs = require("fs")
2 const request = require("request-promise-native")
3 const low = require("lowdb")
4 const FileAsync = require("lowdb/adapters/FileAsync")
5
6 const express = require("express")
7 const app = express()
8 const port = 3000
9
10 const patch = "8.24.1";
11 const key = "RGAPI-dce1850a-0954-4b1e-8072-77a26739f076";
12
13 let appRateLimit1 = 10;
14 let appRateLimit120 = 100;
15 let appRateLimitCount1;
16 let appRateLimitCount120;
17
18 // Express routing
19 // ---------------
20 let rules = [
21   ["/lol", "index.html"],
22   ["/lol/script.js", "script.js"],
23   ["/lol/style.css", "style.css"],
24 ];
25
26 for (i in rules) {
27   let path = rules[i][0];
28   let file = rules[i][1];
29   app.get(path, (req, res) => {
30     res.sendFile(__dirname + "/html/" + file);
31   });
32 }
33 // ---------------
34
35 // Riot API request
36 // ----------------
37 const regions = {
38   "BR": "br1.api.riotgames.com",
39   "EUNE": "eun1.api.riotgames.com",
40   "EUW": "euw1.api.riotgames.com",
41   "JP": "jp1.api.riotgames.com",
42   "KR": "kr.api.riotgames.com",
43   "LAN": "la1.api.riotgames.com",
44   "LAS": "la2.api.riotgames.com",
45   "NA": "na1.api.riotgames.com",
46   "OCE": "oc1.api.riotgames.com",
47   "TR": "tr1.api.riotgames.com",
48   "RU": "ru.api.riotgames.com",
49   "PBE": "pbe1.api.riotgames.com",
50 };
51
52 let requests = [];
53
54 async function executeRequest() {
55   if (requests.length > 0) {
56     let req = requests.shift();
57     if (req.retries < 1) req.rej();
58     else {
59       try {
60         console.log("[Info] request: " + req.url);
61         let result = await request({uri: req.url, resolveWithFullResponse: true, json: true});
62
63         let appRateLimit = result.headers["x-app-rate-limit"];
64         let appRateLimitCount = result.headers["x-app-rate-limit-count"];
65         appRateLimit1 = appRateLimit.split(",")[0].split(":")[0];
66         appRateLimit120 = appRateLimit.split(",")[1].split(":")[0];
67         appRateLimitCount1 = appRateLimitCount.split(",")[0].split(":")[0];
68         appRateLimitCount120 = appRateLimitCount.split(",")[1].split(":")[0];
69
70         if (typeof result.body == "object") req.res(result.body);
71         else req.res(JSON.parse(result.body));
72       } catch (err) {
73         console.log("[Error] riotRequest: " + err.message);
74         req.retries--;
75         requests.push(req);
76       }
77     }
78   }
79   let delay1 = 1000 / (appRateLimit1 - 1);
80   let delay120 = 120000 / (appRateLimit120 - 1);
81   setTimeout(executeRequest, Math.max(delay1, delay120));
82 }
83 executeRequest();
84
85 async function riotRequest(region, url, params, retries) {
86   let req = "https://" + regions[region] + url + "?api_key=" + key;
87   for (p in params) {
88     req += "&" + p + "=" + params[p];
89   }
90   return new Promise((resolve, reject) => {
91     requests.push({ url: req, retries: 5, res: resolve, rej: reject });
92   });
93 }
94 // ----------------
95
96 // User functionality
97 // ------------------
98 let users = {};
99 let nameLookup = {};
100
101 async function loadUserDb(region, accountId) {
102   if (!users[region]) users[region] = {};
103   if (users[region][accountId]) return;
104   let adapter = new FileAsync("data/" + region + "/" + accountId + ".json");
105   let db = await low(adapter);
106   await db.defaults({ games: [], gameSummaries: [], account: {} })
107     .write();
108   users[region][accountId] = db;
109 }
110
111 async function loadUserInfo(region, summonerName) {
112   if (!nameLookup[region]) nameLookup[region] = {};
113   if (nameLookup[region][summonerName]) return;
114   let user = await riotRequest(region, "/lol/summoner/v4/summoners/by-name/" + summonerName, {}, 5);
115   let accountId = user.accountId;
116   await loadUserDb(region, accountId);
117   users[region][accountId].set("account", user);
118   nameLookup[region][summonerName] = accountId;
119 }
120
121 async function loadGameSummaries(region, accountId) {
122   let totalGames;
123   let bI = 0, eI = 100;
124
125   loop1:
126   do {
127     let matchlist = await riotRequest(region, "/lol/match/v4/matchlists/by-account/" + accountId, { beginIndex: bI, endIndex: eI }, 5);
128     totalGames = matchlist.totalGames;
129     for (m in matchlist.matches) {
130       let match = matchlist.matches[m];
131       if (users[region][accountId].get("gameSummaries").find({ gameId: match.gameId }).value()) {
132         break loop1;
133       }
134       users[region][accountId].get("gameSummaries").push(match).write();
135     }
136     bI = eI;
137     eI += 100;
138   } while (bI <= totalGames);
139   users[region][accountId].write();
140   users[region][accountId].set("gameSummaries",
141     users[region][accountId].get("gameSummaries").sortBy("timestamp").sortedUniqBy((x) => x.gameId).value()).write();
142 }
143
144 app.get("/lol/matches", async (req, res) => {
145   let region = req.query.region;
146   let summoner = req.query.summoner;
147   console.log("[Info] getting game summaries for " + summoner + " from " + region);
148   try {
149     await loadUserInfo(region, summoner);
150     let accountId = nameLookup[region][summoner];
151     await loadGameSummaries(region, accountId);
152     let matches = users[region][accountId].get("gameSummaries").value();
153     console.log(matches.length);
154     res.send(JSON.stringify(matches));
155   } catch (err) {
156     console.log("[Error] GET /lol/matches: " + err);
157     res.send("error");
158   }
159 });
160 // ------------------
161
162 // Static Data
163 // -----------
164 let champions;
165 let champLookup = {};
166 function loadChampions() {
167   request("http://ddragon.leagueoflegends.com/cdn/" + patch + "/data/en_US/champion.json", (err, res, body) => {
168     if (err) console.log("[Error] loadChampions: " + err);
169     champions = JSON.parse(body).data;
170     for (c in champions) {
171       champLookup[champions[c].key] = c;
172     }
173   });
174 }
175
176 app.get("/lol/champions", (req, res) => {
177   res.send(JSON.stringify(Object.keys(champions)));
178 });
179
180 app.get("/lol/champlookup", (req, res) => {
181   res.send(JSON.stringify(champLookup));
182 });
183 // -----------
184
185 loadChampions();
186 app.listen(port, () => {
187   console.log("Listening on port %d", port)
188 });