-
Notifications
You must be signed in to change notification settings - Fork 301
/
buildMatch.js
154 lines (143 loc) · 4.89 KB
/
buildMatch.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/**
* Functions to build/cache match object
* */
const constants = require('dotaconstants');
const { promisify } = require('util');
const config = require('../config');
const queries = require('./queries');
const compute = require('../util/compute');
const utility = require('../util/utility');
const cassandra = require('../store/cassandra');
const redis = require('../store/redis');
const db = require('../store/db');
const { computeMatchData } = compute;
const { deserialize, buildReplayUrl, isContributor } = utility;
const getRedisAsync = promisify(redis.get).bind(redis);
async function getMatchData(matchId) {
const result = await cassandra.execute('SELECT * FROM matches where match_id = ?', [Number(matchId)], {
prepare: true,
fetchSize: 1,
autoPage: true,
});
const deserializedResult = result.rows.map(m => deserialize(m));
return Promise.resolve(deserializedResult[0]);
}
async function getPlayerMatchData(matchId) {
const result = await cassandra.execute('SELECT * FROM player_matches where match_id = ?', [Number(matchId)], {
prepare: true,
fetchSize: 24,
autoPage: true,
});
const deserializedResult = result.rows.map(m => deserialize(m));
return Promise.all(deserializedResult.map(r => db.raw(`
SELECT personaname, name, last_login
FROM players
LEFT JOIN notable_players
ON players.account_id = notable_players.account_id
WHERE players.account_id = ?
`, [r.account_id])
.then(names => ({ ...r, ...names.rows[0] }))));
}
async function extendPlayerData(player, match) {
const p = {
...player,
radiant_win: match.radiant_win,
start_time: match.start_time,
duration: match.duration,
cluster: match.cluster,
lobby_type: match.lobby_type,
game_mode: match.game_mode,
is_contributor: isContributor(player.account_id),
};
computeMatchData(p);
const row = await db.first().from('rank_tier').where({ account_id: p.account_id || null });
p.rank_tier = row ? row.rating : null;
return Promise.resolve(p);
}
async function prodataInfo(matchId) {
const result = await db.first(['radiant_team_id', 'dire_team_id', 'leagueid'])
.from('matches')
.where({
match_id: matchId,
});
if (!result) {
return Promise.resolve({});
}
const leaguePromise = db.first().from('leagues').where({
leagueid: result.leagueid,
});
const radiantTeamPromise = db.first().from('teams').where({
team_id: result.radiant_team_id,
});
const direTeamPromise = db.first().from('teams').where({
team_id: result.dire_team_id,
});
const [league, radiantTeam, direTeam] = await Promise.all([leaguePromise, radiantTeamPromise, direTeamPromise]);
return Promise.resolve({
league,
radiant_team: radiantTeam,
dire_team: direTeam,
});
}
async function getMatch(matchId) {
if (!matchId || Number.isNaN(Number(matchId)) || Number(matchId) <= 0) {
return Promise.resolve();
}
const match = await getMatchData(matchId);
if (!match) {
return Promise.resolve();
}
const playersMatchData = await getPlayerMatchData(matchId);
const playersPromise = Promise.all(playersMatchData.map(p => extendPlayerData(p, match)));
const gcdataPromise = db.first().from('match_gcdata').where({
match_id: matchId,
});
const cosmeticsPromise = Promise.all(Object.keys(match.cosmetics || {}).map(itemId => db.first().from('cosmetics').where({
item_id: itemId,
})));
const prodataPromise = prodataInfo(matchId);
const [players, gcdata, prodata, cosmetics] = await Promise.all([playersPromise, gcdataPromise, prodataPromise, cosmeticsPromise]);
let matchResult = {
...match,
...gcdata,
...prodata,
players,
};
if (cosmetics) {
const playersWithCosmetics = matchResult.players.map((p) => {
const hero = constants.heroes[p.hero_id] || {};
const playerCosmetics = cosmetics.filter(Boolean).filter(c => match.cosmetics[c.item_id] === p.player_slot
&& (!c.used_by_heroes || c.used_by_heroes === hero.name));
return {
...p,
cosmetics: playerCosmetics,
};
});
matchResult = {
...matchResult,
players: playersWithCosmetics,
};
}
computeMatchData(matchResult);
if (matchResult.replay_salt) {
matchResult.replay_url = buildReplayUrl(matchResult.match_id, matchResult.cluster, matchResult.replay_salt);
}
const matchWithBenchmarks = await queries.getMatchBenchmarksPromisified(matchResult);
return Promise.resolve(matchWithBenchmarks);
}
async function buildMatch(matchId) {
const key = `match:${matchId}`;
const reply = await getRedisAsync(key);
if (reply) {
return Promise.resolve(JSON.parse(reply));
}
const match = await getMatch(matchId);
if (!match) {
return Promise.resolve();
}
if (match.version && config.ENABLE_MATCH_CACHE) {
await redis.setex(key, config.MATCH_CACHE_SECONDS, JSON.stringify(match));
}
return Promise.resolve(match);
}
module.exports = buildMatch;